<commit_before>
use pair::Pair;
use error::{NcclError, ErrorKind};
use token::{Token, TokenKind};

#[allow(dead_code)]
pub struct Parser {
    current: usize,
    tokens: Vec<Token>,
    pair: Pair,
    line: u64,
}

// nccl = (value (":" value)? newline indent value newline)*
// value = [^:]+
// newline = "\n" | "\r\n"
// indent = " "+ | "\t"

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Self {
        Parser {
            current: 0,
            tokens: tokens,
            pair: Pair::new("__top_level__"),
            line: 1,
        }
    }

    pub fn parse(&mut self) -> Result<Pair, NcclError> {
    }

    fn nccl(&mut self) {
        self.value();
        if self.peek().kind != TokenKind::Colon {
            self.newline()?;
            self.indent()?;
        } else {
            self.schema();
        }
    }

    fn value(&mut self) {}

    fn indent(&mut self) {}

    fn matches(&mut self, kind: TokenKind) -> bool {
        if self.check(kind) {
            self.advance();
            true
        } else {
            false
        }
    }

    fn check(&mut self, kind: TokenKind) -> bool {
        if self.is_at_end() {
            false
        } else {
            self.peek().kind == kind
        }
    }

    fn advance(&mut self) -> &Token {
        if !self.is_at_end() {
            self.current += 1;
        }

        self.previous()
    }

    fn is_at_end(&mut self) -> bool {
        self.peek().kind == TokenKind::EOF
    }

    fn peek(&mut self) -> &Token {
        &self.tokens[self.current]
    }

    fn previous(&mut self) -> &Token {
        &self.tokens[self.current - 1]
    }

    fn consume(&mut self, kind: TokenKind, message: &str) -> Result<&Token, NcclError> {
        if self.check(kind) {
            Ok(self.advance())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, message, self.line))
        }
    }
}

<commit_msg>start parser for real<commit_after>
use pair::Pair;
use error::{NcclError, ErrorKind};
use token::{Token, TokenKind};

#[allow(dead_code)]
pub struct Parser {
    current: usize,
    tokens: Vec<Token>,
    pair: Pair,
    line: u64,
}

// nccl = (value (":" value)? newline indent value newline)*
// value = [^:]+
// newline = "\n" | "\r\n"
// indent = " "+ | "\t"

impl Parser {
    pub fn new(tokens: Vec<Token>) -> Self {
        Parser {
            current: 0,
            tokens: tokens,
            pair: Pair::new("__top_level__"),
            line: 1,
        }
    }

    pub fn parse(&mut self) -> Result<Pair, NcclError> {
        Ok(self.pair.clone())
    }

    fn add(&mut self, value: String) {
        self.pair.add(&value);
    }

    fn nccl(&mut self) -> Result<(), NcclError> {
        while !self.is_at_end() {
            self.value()?;
            if self.peek().kind == TokenKind::Colon {
                self.colon()?;
                self.schema()?;
            }
            self.newline()?;
            self.indent()?;
            self.value()?;
            self.newline()?;
        }
        Ok(())
    }

    fn value(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            if self.peek().kind != TokenKind::Value {
            } else {
                return Err(NcclError::new(ErrorKind::ParseError, &format!("Expected value, found {:?}", self.peek().kind), self.line));
            }
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected value, found EOF", self.line))
        }
    }

    fn indent(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected indent, found EOF", self.line))
        }
    }

    fn newline(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected newline, found EOF", self.line))
        }
    }

    fn schema(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected schema, found EOF", self.line))
        }
    }

    fn colon(&mut self) -> Result<(), NcclError> {
        if !self.is_at_end() {
            Ok(())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, "Expected colon, found EOF", self.line))
        }
    }

    fn matches(&mut self, kind: TokenKind) -> bool {
        if self.check(kind) {
            self.advance();
            true
        } else {
            false
        }
    }

    fn check(&mut self, kind: TokenKind) -> bool {
        if self.is_at_end() {
            false
        } else {
            self.peek().kind == kind
        }
    }

    fn advance(&mut self) -> &Token {
        if !self.is_at_end() {
            self.current += 1;
        }

        self.previous()
    }

    fn is_at_end(&mut self) -> bool {
        self.peek().kind == TokenKind::EOF
    }

    fn peek(&mut self) -> &Token {
        &self.tokens[self.current]
    }

    fn previous(&mut self) -> &Token {
        &self.tokens[self.current - 1]
    }

    fn consume(&mut self, kind: TokenKind, message: &str) -> Result<&Token, NcclError> {
        if self.check(kind) {
            Ok(self.advance())
        } else {
            Err(NcclError::new(ErrorKind::ParseError, message, self.line))
        }
    }
}

<|endoftext|>


<commit_before>use syntax_definition::*;
use scope::*;
use onig::{self, Region};
use std::usize;
use std::i32;

#[derive(Debug, Clone)]
pub struct ParseState {
    stack: Vec<StateLevel>,
    first_line: bool,
}

#[derive(Debug, Clone)]
struct StateLevel {
    context: ContextPtr,
    prototype: Option<ContextPtr>,
    captures: Option<(Region, String)>,
}

#[derive(Debug)]
struct RegexMatch {
    regions: Region,
    context: ContextPtr,
    pat_index: usize,
}

impl ParseState {
    pub fn new(syntax: &SyntaxDefinition) -> ParseState {
        let start_state = StateLevel {
            context: syntax.contexts["main"].clone(),
            prototype: None,
            captures: None,
        };
        ParseState {
            stack: vec![start_state],
            first_line: true,
        }
    }

    pub fn parse_line(&mut self, line: &str) -> Vec<(usize, ScopeStackOp)> {
        assert!(self.stack.len() > 0,
                "Somehow main context was popped from the stack");
        let mut match_start = 0;
        let mut res = Vec::new();
        if self.first_line {
            let cur_level = &self.stack[self.stack.len() - 1];
            let context = cur_level.context.borrow();
            if !context.meta_content_scope.is_empty() {
                res.push((0, ScopeStackOp::Push(context.meta_content_scope[0])));
            }
            self.first_line = false;
        }

        let mut regions = Region::with_capacity(8);
        while self.parse_next_token(line, &mut match_start, &mut regions, &mut res) {
        }
        return res;
    }

    fn parse_next_token(&mut self,
                        line: &str,
                        start: &mut usize,
                        regions: &mut Region,
                        ops: &mut Vec<(usize, ScopeStackOp)>)
                        -> bool {
        let cur_match = {
            let cur_level = &self.stack[self.stack.len() - 1];
            let mut min_start = usize::MAX;
            let mut cur_match: Option<RegexMatch> = None;
            let context_chain = self.stack
                .iter()
                .filter_map(|lvl| lvl.prototype.as_ref().map(|x| x.clone()))
                .chain(Some(cur_level.context.clone()).into_iter());
            // println!("{:#?}", cur_level);
            for ctx in context_chain {
                for (pat_context_ptr, pat_index) in context_iter(ctx) {
                    let pat_context = pat_context_ptr.borrow();
                    let match_pat = pat_context.match_at(pat_index);

                    // println!("{:?}", match_pat.regex_str);
                    let refs_regex = if cur_level.captures.is_some() && match_pat.regex.is_none() {
                        let &(ref region, ref s) = cur_level.captures.as_ref().unwrap();
                        Some(match_pat.compile_with_refs(region, s))
                    } else {
                        None
                    };
                    let regex = if let Some(ref rgx) = refs_regex {
                        rgx
                    } else {
                        match_pat.regex.as_ref().unwrap()
                    };
                    // TODO caching
                    let matched = regex.search_with_options(line,
                                                            *start,
                                                            line.len(),
                                                            onig::SEARCH_OPTION_NONE,
                                                            Some(regions));
                    if let Some(match_start) = matched {
                        let match_end = regions.pos(0).unwrap().1;
                        // this is necessary to avoid infinite looping on dumb patterns
                        let does_something = match match_pat.operation {
                            MatchOperation::None => match_start != match_end,
                            _ => true,
                        };
                        if match_start < min_start && does_something {
                            min_start = match_start;
                            cur_match = Some(RegexMatch {
                                regions: regions.clone(),
                                context: pat_context_ptr.clone(),
                                pat_index: pat_index,
                            });
                        }
                    }
                }
            }
            cur_match
        };

        if let Some(reg_match) = cur_match {
            let (_, match_end) = reg_match.regions.pos(0).unwrap();
            *start = match_end;
            let level_context = self.stack[self.stack.len() - 1].context.clone();
            self.exec_pattern(line, reg_match, level_context, ops);
            true
        } else {
            false
        }
    }

    fn exec_pattern(&mut self,
                    line: &str,
                    reg_match: RegexMatch,
                    level_context_ptr: ContextPtr,
                    ops: &mut Vec<(usize, ScopeStackOp)>) {
        let (match_start, match_end) = reg_match.regions.pos(0).unwrap();
        let context = reg_match.context.borrow();
        let pat = context.match_at(reg_match.pat_index);
        let level_context = level_context_ptr.borrow();
        // println!("running pattern {:?}", pat);

        self.push_meta_ops(true, match_start, &*level_context, &pat.operation, ops);
        for s in pat.scope.iter() {
            // println!("pushing {:?} at {}", s, match_start);
            ops.push((match_start, ScopeStackOp::Push(s.clone())));
        }
        if let Some(ref capture_map) = pat.captures {
            // captures could appear in an arbitrary order, have to produce ops in right order
            // ex: ((bob)|(hi))* could match hibob in wrong order, and outer has to push first
            // we don't have to handle a capture matching multiple times, Sublime doesn't
            let mut map: Vec<((usize, i32), ScopeStackOp)> = Vec::new();
            for (cap_index, scopes) in capture_map.iter() {
                if let Some((cap_start, cap_end)) = reg_match.regions.pos(*cap_index) {
                    for scope in scopes.iter() {
                        map.push(((cap_start, -((cap_end - cap_start) as i32)),
                                  ScopeStackOp::Push(scope.clone())));
                    }
                    map.push(((cap_end, i32::MIN), ScopeStackOp::Pop(scopes.len())));
                }
            }
            map.sort_by(|a, b| a.0.cmp(&b.0));
            for ((index, _), op) in map.into_iter() {
                ops.push((index, op));
            }
        }
        if !pat.scope.is_empty() {
            ops.push((match_end, ScopeStackOp::Pop(pat.scope.len())));
        }
        self.push_meta_ops(false, match_end, &*level_context, &pat.operation, ops);

        self.perform_op(line, &reg_match.regions, pat);
    }

    fn push_meta_ops(&self,
                     initial: bool,
                     index: usize,
                     cur_context: &Context,
                     match_op: &MatchOperation,
                     ops: &mut Vec<(usize, ScopeStackOp)>) {
        let involves_pop = match match_op {
            &MatchOperation::Pop => true,
            &MatchOperation::Set(_) => true,
            &MatchOperation::Push(_) => false,
            &MatchOperation::None => false,
        };
        // println!("metas ops for {:?}, is pop: {}, initial: {}",
        //          match_op,
        //          involves_pop,
        //          initial);
        // println!("{:?}", cur_context.meta_scope);
        if involves_pop {
            let v = if initial {
                &cur_context.meta_content_scope
            } else {
                &cur_context.meta_scope
            };
            if !v.is_empty() {
                ops.push((index, ScopeStackOp::Pop(v.len())));
            }
        }
        match match_op {
            &MatchOperation::Push(ref context_refs) |
            &MatchOperation::Set(ref context_refs) => {
                for r in context_refs {
                    let ctx_ptr = r.resolve();
                    let ctx = ctx_ptr.borrow();
                    let v = if initial {
                        &ctx.meta_scope
                    } else {
                        &ctx.meta_content_scope
                    };
                    for scope in v.iter() {
                        ops.push((index, ScopeStackOp::Push(scope.clone())));
                    }
                }
            }
            &MatchOperation::None |
            &MatchOperation::Pop => (),
        }
    }

    fn perform_op(&mut self, line: &str, regions: &Region, pat: &MatchPattern) {
        let ctx_refs = match pat.operation {
            MatchOperation::Push(ref ctx_refs) => ctx_refs,
            MatchOperation::Set(ref ctx_refs) => {
                self.stack.pop();
                ctx_refs
            }
            MatchOperation::Pop => {
                self.stack.pop();
                return;
            }
            MatchOperation::None => return,
        };
        for (i, r) in ctx_refs.iter().enumerate() {
            let proto = if i == 0 {
                pat.with_prototype.clone()
            } else {
                None
            };
            let ctx_ptr = r.resolve();
            let captures = {
                let ctx = ctx_ptr.borrow();
                if ctx.uses_backrefs {
                    Some((regions.clone(), line.to_owned()))
                } else {
                    None
                }
            };
            self.stack.push(StateLevel {
                context: ctx_ptr,
                prototype: proto,
                captures: captures,
            });
        }
    }
}

#[cfg(test)]
mod tests {
    use package_set::PackageSet;
    use parser::*;
    use scope::*;
    use util::debug_print_ops;

    #[test]
    fn can_parse() {
        use scope::ScopeStackOp::{Push, Pop};
        let ps = PackageSet::load_from_folder("testdata/Packages").unwrap();
        let mut state = {
            let syntax = ps.find_syntax_by_name("Ruby on Rails").unwrap();
            ParseState::new(syntax)
        };
        let mut state2 = {
            let syntax = ps.find_syntax_by_name("HTML (Rails)").unwrap();
            ParseState::new(syntax)
        };

        let line = "module Bob::Wow::Troll::Five; 5; end";
        let ops = state.parse_line(line);
        debug_print_ops(line, &ops);

        let test_ops = vec![
            (0, Push(Scope::new("source.ruby.rails").unwrap())),
            (0, Push(Scope::new("meta.module.ruby").unwrap())),
            (0, Push(Scope::new("keyword.control.module.ruby").unwrap())),
            (6, Pop(1)),
            (7, Push(Scope::new("entity.name.type.module.ruby").unwrap())),
            (7, Push(Scope::new("entity.other.inherited-class.module.first.ruby").unwrap())),
            (10, Push(Scope::new("punctuation.separator.inheritance.ruby").unwrap())),
            (12, Pop(1)),
            (12, Pop(1)),
        ];
        assert_eq!(&ops[0..test_ops.len()], &test_ops[..]);

        let line2 = "def lol(wow = 5)";
        let ops2 = state.parse_line(line2);
        debug_print_ops(line2, &ops2);
        let test_ops2 =
            vec![(0, Push(Scope::new("meta.function.method.with-arguments.ruby").unwrap())),
                 (0, Push(Scope::new("keyword.control.def.ruby").unwrap())),
                 (3, Pop(1)),
                 (4, Push(Scope::new("entity.name.function.ruby").unwrap())),
                 (7, Pop(1)),
                 (7, Push(Scope::new("punctuation.definition.parameters.ruby").unwrap())),
                 (8, Pop(1)),
                 (8, Push(Scope::new("variable.parameter.function.ruby").unwrap())),
                 (12, Push(Scope::new("keyword.operator.assignment.ruby").unwrap())),
                 (13, Pop(1)),
                 (14, Push(Scope::new("constant.numeric.ruby").unwrap())),
                 (15, Pop(1)),
                 (15, Pop(1)),
                 (15, Push(Scope::new("punctuation.definition.parameters.ruby").unwrap())),
                 (16, Pop(1)),
                 (16, Pop(1))];
        assert_eq!(ops2, test_ops2);

        let line3 = "<script>var lol = '<% def wow(";
        let ops3 = state2.parse_line(line3);
        debug_print_ops(line3, &ops3);
        let mut test_stack = ScopeStack::new();
        test_stack.push(Scope::new("text.html.ruby").unwrap());
        test_stack.push(Scope::new("text.html.basic").unwrap());
        test_stack.push(Scope::new("source.js.embedded.html").unwrap());
        test_stack.push(Scope::new("string.quoted.single.js").unwrap());
        test_stack.push(Scope::new("source.ruby.rails.embedded.html").unwrap());
        test_stack.push(Scope::new("meta.function.method.with-arguments.ruby").unwrap());
        test_stack.push(Scope::new("variable.parameter.function.ruby").unwrap());
        let mut test_stack2 = ScopeStack::new();
        for &(_, ref op) in ops3.iter() {
            test_stack2.apply(op);
        }
        assert_eq!(test_stack2, test_stack);

        // for testing backrefs
        let line4 = "lol = <<-END wow END";
        let ops4 = state.parse_line(line4);
        debug_print_ops(line4, &ops4);
        let test_ops4 = vec![
            (4, Push(Scope::new("keyword.operator.assignment.ruby").unwrap())),
            (5, Pop(1)),
            (6, Push(Scope::new("string.unquoted.heredoc.ruby").unwrap())),
            (6, Push(Scope::new("punctuation.definition.string.begin.ruby").unwrap())),
            (12, Pop(1)),
            (16, Push(Scope::new("punctuation.definition.string.end.ruby").unwrap())),
            (20, Pop(1)),
            (20, Pop(1)),
        ];
        assert_eq!(ops4, test_ops4);

        // assert!(false);
    }
}
<commit_msg>Initial match caching<commit_after>use syntax_definition::*;
use scope::*;
use onig::{self, Region};
use std::usize;
use std::i32;

#[derive(Debug, Clone)]
pub struct ParseState {
    stack: Vec<StateLevel>,
    first_line: bool,
}

#[derive(Debug, Clone)]
struct StateLevel {
    context: ContextPtr,
    prototype: Option<ContextPtr>,
    captures: Option<(Region, String)>,
}

#[derive(Debug)]
struct RegexMatch {
    regions: Region,
    context: ContextPtr,
    pat_index: usize,
}

// TODO cache actual matching regions
type MatchCache = Vec<bool>;

impl ParseState {
    pub fn new(syntax: &SyntaxDefinition) -> ParseState {
        let start_state = StateLevel {
            context: syntax.contexts["main"].clone(),
            prototype: None,
            captures: None,
        };
        ParseState {
            stack: vec![start_state],
            first_line: true,
        }
    }

    pub fn parse_line(&mut self, line: &str) -> Vec<(usize, ScopeStackOp)> {
        assert!(self.stack.len() > 0,
                "Somehow main context was popped from the stack");
        let mut match_start = 0;
        let mut res = Vec::new();
        if self.first_line {
            let cur_level = &self.stack[self.stack.len() - 1];
            let context = cur_level.context.borrow();
            if !context.meta_content_scope.is_empty() {
                res.push((0, ScopeStackOp::Push(context.meta_content_scope[0])));
            }
            self.first_line = false;
        }

        let mut regions = Region::with_capacity(8);
        let mut match_cache: MatchCache = Vec::with_capacity(64); // TODO find best capacity
        while self.parse_next_token(line, &mut match_start, &mut match_cache, &mut regions, &mut res) {
        }
        return res;
    }

    fn parse_next_token(&mut self,
                        line: &str,
                        start: &mut usize,
                        cache: &mut MatchCache,
                        regions: &mut Region,
                        ops: &mut Vec<(usize, ScopeStackOp)>)
                        -> bool {
        let cur_match = {
            let cur_level = &self.stack[self.stack.len() - 1];
            let mut min_start = usize::MAX;
            let mut cur_match: Option<RegexMatch> = None;
            let context_chain = self.stack
                .iter()
                .filter_map(|lvl| lvl.prototype.as_ref().map(|x| x.clone()))
                .chain(Some(cur_level.context.clone()).into_iter());
            // println!("{:#?}", cur_level);
            let mut overall_index = 0;
            for ctx in context_chain {
                for (pat_context_ptr, pat_index) in context_iter(ctx) {
                    if overall_index < cache.len() && cache[overall_index] == false {
                        overall_index += 1;
                        continue; // we've determined this pattern doesn't match this line anywhere
                    }
                    let pat_context = pat_context_ptr.borrow();
                    let match_pat = pat_context.match_at(pat_index);

                    // println!("{:?}", match_pat.regex_str);
                    let refs_regex = if cur_level.captures.is_some() && match_pat.regex.is_none() {
                        let &(ref region, ref s) = cur_level.captures.as_ref().unwrap();
                        Some(match_pat.compile_with_refs(region, s))
                    } else {
                        None
                    };
                    let regex = if let Some(ref rgx) = refs_regex {
                        rgx
                    } else {
                        match_pat.regex.as_ref().unwrap()
                    };
                    let matched = regex.search_with_options(line,
                                                            *start,
                                                            line.len(),
                                                            onig::SEARCH_OPTION_NONE,
                                                            Some(regions));
                    if overall_index >= cache.len() { // add it to the cache
                        cache.push(matched.is_some());
                    } // TODO update the cache even if this is another time over
                    if let Some(match_start) = matched {
                        let match_end = regions.pos(0).unwrap().1;
                        // this is necessary to avoid infinite looping on dumb patterns
                        let does_something = match match_pat.operation {
                            MatchOperation::None => match_start != match_end,
                            _ => true,
                        };
                        if match_start < min_start && does_something {
                            min_start = match_start;
                            cur_match = Some(RegexMatch {
                                regions: regions.clone(),
                                context: pat_context_ptr.clone(),
                                pat_index: pat_index,
                            });
                        }
                    }

                    overall_index += 1;
                }
            }
            cur_match
        };

        if let Some(reg_match) = cur_match {
            let (_, match_end) = reg_match.regions.pos(0).unwrap();
            *start = match_end;
            let level_context = self.stack[self.stack.len() - 1].context.clone();
            let stack_changed = self.exec_pattern(line, reg_match, level_context, ops);
            if stack_changed {
                cache.clear();
            }
            true
        } else {
            false
        }
    }

    /// Returns true if the stack was changed
    fn exec_pattern(&mut self,
                    line: &str,
                    reg_match: RegexMatch,
                    level_context_ptr: ContextPtr,
                    ops: &mut Vec<(usize, ScopeStackOp)>) -> bool {
        let (match_start, match_end) = reg_match.regions.pos(0).unwrap();
        let context = reg_match.context.borrow();
        let pat = context.match_at(reg_match.pat_index);
        let level_context = level_context_ptr.borrow();
        // println!("running pattern {:?}", pat);

        self.push_meta_ops(true, match_start, &*level_context, &pat.operation, ops);
        for s in pat.scope.iter() {
            // println!("pushing {:?} at {}", s, match_start);
            ops.push((match_start, ScopeStackOp::Push(s.clone())));
        }
        if let Some(ref capture_map) = pat.captures {
            // captures could appear in an arbitrary order, have to produce ops in right order
            // ex: ((bob)|(hi))* could match hibob in wrong order, and outer has to push first
            // we don't have to handle a capture matching multiple times, Sublime doesn't
            let mut map: Vec<((usize, i32), ScopeStackOp)> = Vec::new();
            for (cap_index, scopes) in capture_map.iter() {
                if let Some((cap_start, cap_end)) = reg_match.regions.pos(*cap_index) {
                    for scope in scopes.iter() {
                        map.push(((cap_start, -((cap_end - cap_start) as i32)),
                                  ScopeStackOp::Push(scope.clone())));
                    }
                    map.push(((cap_end, i32::MIN), ScopeStackOp::Pop(scopes.len())));
                }
            }
            map.sort_by(|a, b| a.0.cmp(&b.0));
            for ((index, _), op) in map.into_iter() {
                ops.push((index, op));
            }
        }
        if !pat.scope.is_empty() {
            ops.push((match_end, ScopeStackOp::Pop(pat.scope.len())));
        }
        self.push_meta_ops(false, match_end, &*level_context, &pat.operation, ops);

        self.perform_op(line, &reg_match.regions, pat)
    }

    fn push_meta_ops(&self,
                     initial: bool,
                     index: usize,
                     cur_context: &Context,
                     match_op: &MatchOperation,
                     ops: &mut Vec<(usize, ScopeStackOp)>) {
        let involves_pop = match match_op {
            &MatchOperation::Pop => true,
            &MatchOperation::Set(_) => true,
            &MatchOperation::Push(_) => false,
            &MatchOperation::None => false,
        };
        // println!("metas ops for {:?}, is pop: {}, initial: {}",
        //          match_op,
        //          involves_pop,
        //          initial);
        // println!("{:?}", cur_context.meta_scope);
        if involves_pop {
            let v = if initial {
                &cur_context.meta_content_scope
            } else {
                &cur_context.meta_scope
            };
            if !v.is_empty() {
                ops.push((index, ScopeStackOp::Pop(v.len())));
            }
        }
        match match_op {
            &MatchOperation::Push(ref context_refs) |
            &MatchOperation::Set(ref context_refs) => {
                for r in context_refs {
                    let ctx_ptr = r.resolve();
                    let ctx = ctx_ptr.borrow();
                    let v = if initial {
                        &ctx.meta_scope
                    } else {
                        &ctx.meta_content_scope
                    };
                    for scope in v.iter() {
                        ops.push((index, ScopeStackOp::Push(scope.clone())));
                    }
                }
            }
            &MatchOperation::None |
            &MatchOperation::Pop => (),
        }
    }

    /// Returns true if the stack was changed
    fn perform_op(&mut self, line: &str, regions: &Region, pat: &MatchPattern) -> bool {
        let ctx_refs = match pat.operation {
            MatchOperation::Push(ref ctx_refs) => ctx_refs,
            MatchOperation::Set(ref ctx_refs) => {
                self.stack.pop();
                ctx_refs
            }
            MatchOperation::Pop => {
                self.stack.pop();
                return true;
            }
            MatchOperation::None => return false,
        };
        for (i, r) in ctx_refs.iter().enumerate() {
            let proto = if i == 0 {
                pat.with_prototype.clone()
            } else {
                None
            };
            let ctx_ptr = r.resolve();
            let captures = {
                let ctx = ctx_ptr.borrow();
                if ctx.uses_backrefs {
                    Some((regions.clone(), line.to_owned()))
                } else {
                    None
                }
            };
            self.stack.push(StateLevel {
                context: ctx_ptr,
                prototype: proto,
                captures: captures,
            });
        }
        true
    }
}

#[cfg(test)]
mod tests {
    use package_set::PackageSet;
    use parser::*;
    use scope::*;
    use util::debug_print_ops;

    #[test]
    fn can_parse() {
        use scope::ScopeStackOp::{Push, Pop};
        let ps = PackageSet::load_from_folder("testdata/Packages").unwrap();
        let mut state = {
            let syntax = ps.find_syntax_by_name("Ruby on Rails").unwrap();
            ParseState::new(syntax)
        };
        let mut state2 = {
            let syntax = ps.find_syntax_by_name("HTML (Rails)").unwrap();
            ParseState::new(syntax)
        };

        let line = "module Bob::Wow::Troll::Five; 5; end";
        let ops = state.parse_line(line);
        debug_print_ops(line, &ops);

        let test_ops = vec![
            (0, Push(Scope::new("source.ruby.rails").unwrap())),
            (0, Push(Scope::new("meta.module.ruby").unwrap())),
            (0, Push(Scope::new("keyword.control.module.ruby").unwrap())),
            (6, Pop(1)),
            (7, Push(Scope::new("entity.name.type.module.ruby").unwrap())),
            (7, Push(Scope::new("entity.other.inherited-class.module.first.ruby").unwrap())),
            (10, Push(Scope::new("punctuation.separator.inheritance.ruby").unwrap())),
            (12, Pop(1)),
            (12, Pop(1)),
        ];
        assert_eq!(&ops[0..test_ops.len()], &test_ops[..]);

        let line2 = "def lol(wow = 5)";
        let ops2 = state.parse_line(line2);
        debug_print_ops(line2, &ops2);
        let test_ops2 =
            vec![(0, Push(Scope::new("meta.function.method.with-arguments.ruby").unwrap())),
                 (0, Push(Scope::new("keyword.control.def.ruby").unwrap())),
                 (3, Pop(1)),
                 (4, Push(Scope::new("entity.name.function.ruby").unwrap())),
                 (7, Pop(1)),
                 (7, Push(Scope::new("punctuation.definition.parameters.ruby").unwrap())),
                 (8, Pop(1)),
                 (8, Push(Scope::new("variable.parameter.function.ruby").unwrap())),
                 (12, Push(Scope::new("keyword.operator.assignment.ruby").unwrap())),
                 (13, Pop(1)),
                 (14, Push(Scope::new("constant.numeric.ruby").unwrap())),
                 (15, Pop(1)),
                 (15, Pop(1)),
                 (15, Push(Scope::new("punctuation.definition.parameters.ruby").unwrap())),
                 (16, Pop(1)),
                 (16, Pop(1))];
        assert_eq!(ops2, test_ops2);

        let line3 = "<script>var lol = '<% def wow(";
        let ops3 = state2.parse_line(line3);
        debug_print_ops(line3, &ops3);
        let mut test_stack = ScopeStack::new();
        test_stack.push(Scope::new("text.html.ruby").unwrap());
        test_stack.push(Scope::new("text.html.basic").unwrap());
        test_stack.push(Scope::new("source.js.embedded.html").unwrap());
        test_stack.push(Scope::new("string.quoted.single.js").unwrap());
        test_stack.push(Scope::new("source.ruby.rails.embedded.html").unwrap());
        test_stack.push(Scope::new("meta.function.method.with-arguments.ruby").unwrap());
        test_stack.push(Scope::new("variable.parameter.function.ruby").unwrap());
        let mut test_stack2 = ScopeStack::new();
        for &(_, ref op) in ops3.iter() {
            test_stack2.apply(op);
        }
        assert_eq!(test_stack2, test_stack);

        // for testing backrefs
        let line4 = "lol = <<-END wow END";
        let ops4 = state.parse_line(line4);
        debug_print_ops(line4, &ops4);
        let test_ops4 = vec![
            (4, Push(Scope::new("keyword.operator.assignment.ruby").unwrap())),
            (5, Pop(1)),
            (6, Push(Scope::new("string.unquoted.heredoc.ruby").unwrap())),
            (6, Push(Scope::new("punctuation.definition.string.begin.ruby").unwrap())),
            (12, Pop(1)),
            (16, Push(Scope::new("punctuation.definition.string.end.ruby").unwrap())),
            (20, Pop(1)),
            (20, Pop(1)),
        ];
        assert_eq!(ops4, test_ops4);

        // assert!(false);
    }
}
<|endoftext|>


<commit_before>use super::{Document,Root,RootChild};

trait XmlChar {
    fn is_name_start_char(&self) -> bool;
    fn is_name_char(&self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(&self) -> bool {
        match *self {
            ':'                        |
            'A'..'Z'                   |
            '_'                        |
            'a'..'z'                   |
            '\U000000C0'..'\U000000D6' |
            '\U000000D8'..'\U000000F6' |
            '\U000000F8'..'\U000002FF' |
            '\U00000370'..'\U0000037D' |
            '\U0000037F'..'\U00001FFF' |
            '\U0000200C'..'\U0000200D' |
            '\U00002070'..'\U0000218F' |
            '\U00002C00'..'\U00002FEF' |
            '\U00003001'..'\U0000D7FF' |
            '\U0000F900'..'\U0000FDCF' |
            '\U0000FDF0'..'\U0000FFFD' |
            '\U00010000'..'\U000EFFFF' => true,
            _ => false,
        }
    }

    fn is_name_char(&self) -> bool {
        if self.is_name_start_char() { return true; }
        match *self {
            '-'                |
            '.'                |
            '0'..'9'           |
            '\u00B7'           |
            '\u0300'..'\u036F' |
            '\u203F'..'\u2040' => true,
            _ => false
        }
    }
}
<commit_msg>Add initial dumb parser test and structure<commit_after>use super::{Document,Root,RootChild};

struct Parser;

impl Parser {
    fn new() -> Parser {
        Parser
    }

    fn parse(&self, xml: &str) -> Document {
        let doc = Document::new();

        // Parse the preamble
        let idx = xml.find_str("?>").expect("No preamble end");
        let end_of_preamble = idx + "?>".len();

        let next = end_of_preamble + "<".len();
        let ele = xml.slice_from(next);
        let end = ele.find_str(" ").expect("Couldn't find end of name"); // really find nmtoken
        let name = ele.slice_to(end);

        let e = doc.new_element(name.to_string());
        doc.root().append_child(e);
        doc
    }
}

trait XmlChar {
    fn is_name_start_char(&self) -> bool;
    fn is_name_char(&self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(&self) -> bool {
        match *self {
            ':'                        |
            'A'..'Z'                   |
            '_'                        |
            'a'..'z'                   |
            '\U000000C0'..'\U000000D6' |
            '\U000000D8'..'\U000000F6' |
            '\U000000F8'..'\U000002FF' |
            '\U00000370'..'\U0000037D' |
            '\U0000037F'..'\U00001FFF' |
            '\U0000200C'..'\U0000200D' |
            '\U00002070'..'\U0000218F' |
            '\U00002C00'..'\U00002FEF' |
            '\U00003001'..'\U0000D7FF' |
            '\U0000F900'..'\U0000FDCF' |
            '\U0000FDF0'..'\U0000FFFD' |
            '\U00010000'..'\U000EFFFF' => true,
            _ => false,
        }
    }

    fn is_name_char(&self) -> bool {
        if self.is_name_start_char() { return true; }
        match *self {
            '-'                |
            '.'                |
            '0'..'9'           |
            '\u00B7'           |
            '\u0300'..'\u036F' |
            '\u203F'..'\u2040' => true,
            _ => false
        }
    }
}

trait Hax {
    fn first_child(&self) -> Option<RootChild>;
}

impl Hax for Root {
    fn first_child(&self) -> Option<RootChild> {
        self.children().remove(0)
    }
}

#[test]
fn parses_a_document_with_a_single_element() {
    let parser = Parser::new();
    let doc = parser.parse("<?xml version='1.0' ?><hello />");
    let top = doc.root().first_child().unwrap().element().unwrap();

    assert_eq!(top.name().as_slice(), "hello");
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla Foundation
//
// 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.

#![allow(unused_imports,dead_code,unused_variables)]

use ::compiler::{
    gcc,
    Cacheable,
    CompilerArguments,
    CompileCommand,
    write_temp_file,
};
use dist;
use compiler::args::*;
use compiler::c::{CCompilerImpl, CCompilerKind, Language, ParsedArguments};
use compiler::gcc::ArgData::*;
use futures::future::{self, Future};
use futures_cpupool::CpuPool;
use mock_command::{
    CommandCreator,
    CommandCreatorSync,
    RunCommand,
};
use std::ffi::OsString;
use std::fs::File;
use std::io::{
    self,
    Write,
};
use std::path::{Path, PathBuf};
use std::process;
use util::{run_input_output, OsStrExt};

use errors::*;

/// A unit struct on which to implement `CCompilerImpl`.
#[derive(Clone, Debug)]
pub struct Clang;

impl CCompilerImpl for Clang {
    fn kind(&self) -> CCompilerKind { CCompilerKind::Clang }
    fn parse_arguments(&self,
                       arguments: &[OsString],
                       cwd: &Path) -> CompilerArguments<ParsedArguments>
    {
        gcc::parse_arguments(arguments, cwd, (&gcc::ARGS[..], &ARGS[..]))
    }

    fn preprocess<T>(&self,
                     creator: &T,
                     executable: &Path,
                     parsed_args: &ParsedArguments,
                     cwd: &Path,
                     env_vars: &[(OsString, OsString)],
                     may_dist: bool)
                     -> SFuture<process::Output> where T: CommandCreatorSync
    {
        gcc::preprocess(creator, executable, parsed_args, cwd, env_vars, may_dist)
    }

    fn generate_compile_commands(&self,
                                path_transformer: &mut dist::PathTransformer,
                                executable: &Path,
                                parsed_args: &ParsedArguments,
                                cwd: &Path,
                                env_vars: &[(OsString, OsString)])
                                -> Result<(CompileCommand, Option<dist::CompileCommand>, Cacheable)>
    {
        gcc::generate_compile_commands(path_transformer, executable, parsed_args, cwd, env_vars)
    }
}

counted_array!(pub static ARGS: [ArgInfo<gcc::ArgData>; _] = [
    take_arg!("--serialize-diagnostics", OsString, Separated, PassThrough),
    take_arg!("--target", OsString, Separated, PassThrough),
    take_arg!("-Xclang", OsString, Separated, XClang),
    take_arg!("-add-plugin", OsString, Separated, PassThrough),
    flag!("-fcxx-modules", TooHardFlag),
    flag!("-fmodules", TooHardFlag),
    take_arg!("-fplugin", PathBuf, CanBeConcatenated('='), ExtraHashFile),
    flag!("-fprofile-instr-generate", ProfileGenerate),
    // Can be either -fprofile-instr-use or -fprofile-instr-use=path
    take_arg!("-fprofile-instr-use", OsString, Concatenated, TooHard),
    take_arg!("-gcc-toolchain", OsString, Separated, PassThrough),
    take_arg!("-include-pch", PathBuf, CanBeSeparated, PreprocessorArgumentPath),
    take_arg!("-load", PathBuf, Separated, ExtraHashFile),
    take_arg!("-mllvm", OsString, Separated, PassThrough),
    take_arg!("-target", OsString, Separated, PassThrough),
    flag!("-verify", PreprocessorArgumentFlag),
]);

#[cfg(test)]
mod test {
    use compiler::*;
    use compiler::gcc;
    use futures::Future;
    use futures_cpupool::CpuPool;
    use mock_command::*;
    use std::collections::HashMap;
    use std::path::PathBuf;
    use super::*;
    use test::utils::*;

    fn _parse_arguments(arguments: &[String]) -> CompilerArguments<ParsedArguments> {
        let arguments = arguments.iter().map(OsString::from).collect::<Vec<_>>();
        Clang.parse_arguments(&arguments, ".".as_ref())
    }

    macro_rules! parses {
        ( $( $s:expr ),* ) => {
            match _parse_arguments(&[ $( $s.to_string(), )* ]) {
                CompilerArguments::Ok(a) => a,
                o @ _ => panic!("Got unexpected parse result: {:?}", o),
            }
        }
    }

    #[test]
    fn test_parse_arguments_simple() {
        let a = parses!("-c", "foo.c", "-o", "foo.o");
        assert_eq!(Some("foo.c"), a.input.to_str());
        assert_eq!(Language::C, a.language);
        assert_map_contains!(a.outputs, ("obj", PathBuf::from("foo.o")));
        //TODO: fix assert_map_contains to assert no extra keys!
        assert_eq!(1, a.outputs.len());
        assert!(a.preprocessor_args.is_empty());
        assert!(a.common_args.is_empty());
    }

    #[test]
    fn test_parse_arguments_values() {
        let a = parses!("-c", "foo.cxx", "-arch", "xyz", "-fabc","-I", "include", "-o", "foo.o", "-include", "file");
        assert_eq!(Some("foo.cxx"), a.input.to_str());
        assert_eq!(Language::Cxx, a.language);
        assert_map_contains!(a.outputs, ("obj", PathBuf::from("foo.o")));
        //TODO: fix assert_map_contains to assert no extra keys!
        assert_eq!(1, a.outputs.len());
        assert_eq!(ovec!["-Iinclude", "-include", "file"], a.preprocessor_args);
        assert_eq!(ovec!["-arch", "xyz", "-fabc"], a.common_args);
    }

    #[test]
    fn test_parse_arguments_others() {
        parses!("-c", "foo.c", "-B", "somewhere", "-o", "foo.o");
        parses!("-c", "foo.c", "-target", "x86_64-apple-darwin11", "-o", "foo.o");
        parses!("-c", "foo.c", "-gcc-toolchain", "somewhere", "-o", "foo.o");
    }

    #[test]
    fn test_parse_arguments_clangmodules() {
        assert_eq!(CompilerArguments::CannotCache("-fcxx-modules", None),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-fcxx-modules", "-o", "foo.o"]));
        assert_eq!(CompilerArguments::CannotCache("-fmodules", None),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-fmodules", "-o", "foo.o"]));
    }

    #[test]
    fn test_parse_xclang_invalid() {
        assert_eq!(CompilerArguments::CannotCache("Can't handle Raw arguments with -Xclang", None),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-o", "foo.o", "-Xclang", "broken"]));
        assert_eq!(CompilerArguments::CannotCache("Can't handle UnknownFlag arguments with -Xclang", None),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-o", "foo.o", "-Xclang", "-broken"]));
        assert_eq!(CompilerArguments::CannotCache("argument parse", Some("Unexpected end of args".to_string())),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-o", "foo.o", "-Xclang", "-load"]));
    }

    #[test]
    fn test_parse_xclang_load() {
        let a = parses!("-c", "foo.c", "-o", "foo.o", "-Xclang", "-load", "-Xclang", "plugin.so");
        println!("A {:#?}", a);
        assert_eq!(ovec!["-Xclang", "-load", "-Xclang", "plugin.so"], a.common_args);
        assert_eq!(ovec!["plugin.so"], a.extra_hash_files);
    }

    #[test]
    fn test_parse_xclang_add_plugin() {
        let a = parses!("-c", "foo.c", "-o", "foo.o", "-Xclang", "-add-plugin", "-Xclang", "foo");
        assert_eq!(ovec!["-Xclang", "-add-plugin", "-Xclang", "foo"], a.common_args);
    }

    #[test]
    fn test_parse_xclang_verify() {
        let a = parses!("-c", "foo.c", "-o", "foo.o", "-Xclang", "-verify");
        assert_eq!(ovec!["-Xclang", "-verify"], a.preprocessor_args);
    }

    #[test]
    fn test_parse_fplugin() {
        let a = parses!("-c", "foo.c", "-o", "foo.o", "-fplugin", "plugin.so");
        println!("A {:#?}", a);
        assert_eq!(ovec!["-fplugin", "plugin.so"], a.common_args);
        assert_eq!(ovec!["plugin.so"], a.extra_hash_files);
    }

}
<commit_msg>Add support for '-fdebug-compilation-dir'<commit_after>// Copyright 2016 Mozilla Foundation
//
// 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.

#![allow(unused_imports,dead_code,unused_variables)]

use ::compiler::{
    gcc,
    Cacheable,
    CompilerArguments,
    CompileCommand,
    write_temp_file,
};
use dist;
use compiler::args::*;
use compiler::c::{CCompilerImpl, CCompilerKind, Language, ParsedArguments};
use compiler::gcc::ArgData::*;
use futures::future::{self, Future};
use futures_cpupool::CpuPool;
use mock_command::{
    CommandCreator,
    CommandCreatorSync,
    RunCommand,
};
use std::ffi::OsString;
use std::fs::File;
use std::io::{
    self,
    Write,
};
use std::path::{Path, PathBuf};
use std::process;
use util::{run_input_output, OsStrExt};

use errors::*;

/// A unit struct on which to implement `CCompilerImpl`.
#[derive(Clone, Debug)]
pub struct Clang;

impl CCompilerImpl for Clang {
    fn kind(&self) -> CCompilerKind { CCompilerKind::Clang }
    fn parse_arguments(&self,
                       arguments: &[OsString],
                       cwd: &Path) -> CompilerArguments<ParsedArguments>
    {
        gcc::parse_arguments(arguments, cwd, (&gcc::ARGS[..], &ARGS[..]))
    }

    fn preprocess<T>(&self,
                     creator: &T,
                     executable: &Path,
                     parsed_args: &ParsedArguments,
                     cwd: &Path,
                     env_vars: &[(OsString, OsString)],
                     may_dist: bool)
                     -> SFuture<process::Output> where T: CommandCreatorSync
    {
        gcc::preprocess(creator, executable, parsed_args, cwd, env_vars, may_dist)
    }

    fn generate_compile_commands(&self,
                                path_transformer: &mut dist::PathTransformer,
                                executable: &Path,
                                parsed_args: &ParsedArguments,
                                cwd: &Path,
                                env_vars: &[(OsString, OsString)])
                                -> Result<(CompileCommand, Option<dist::CompileCommand>, Cacheable)>
    {
        gcc::generate_compile_commands(path_transformer, executable, parsed_args, cwd, env_vars)
    }
}

counted_array!(pub static ARGS: [ArgInfo<gcc::ArgData>; _] = [
    take_arg!("--serialize-diagnostics", OsString, Separated, PassThrough),
    take_arg!("--target", OsString, Separated, PassThrough),
    take_arg!("-Xclang", OsString, Separated, XClang),
    take_arg!("-add-plugin", OsString, Separated, PassThrough),
    flag!("-fcxx-modules", TooHardFlag),
    take_arg!("-fdebug-compilation-dir", OsString, Separated, PassThrough),
    flag!("-fmodules", TooHardFlag),
    take_arg!("-fplugin", PathBuf, CanBeConcatenated('='), ExtraHashFile),
    flag!("-fprofile-instr-generate", ProfileGenerate),
    // Can be either -fprofile-instr-use or -fprofile-instr-use=path
    take_arg!("-fprofile-instr-use", OsString, Concatenated, TooHard),
    take_arg!("-gcc-toolchain", OsString, Separated, PassThrough),
    take_arg!("-include-pch", PathBuf, CanBeSeparated, PreprocessorArgumentPath),
    take_arg!("-load", PathBuf, Separated, ExtraHashFile),
    take_arg!("-mllvm", OsString, Separated, PassThrough),
    take_arg!("-target", OsString, Separated, PassThrough),
    flag!("-verify", PreprocessorArgumentFlag),
]);

#[cfg(test)]
mod test {
    use compiler::*;
    use compiler::gcc;
    use futures::Future;
    use futures_cpupool::CpuPool;
    use mock_command::*;
    use std::collections::HashMap;
    use std::path::PathBuf;
    use super::*;
    use test::utils::*;

    fn _parse_arguments(arguments: &[String]) -> CompilerArguments<ParsedArguments> {
        let arguments = arguments.iter().map(OsString::from).collect::<Vec<_>>();
        Clang.parse_arguments(&arguments, ".".as_ref())
    }

    macro_rules! parses {
        ( $( $s:expr ),* ) => {
            match _parse_arguments(&[ $( $s.to_string(), )* ]) {
                CompilerArguments::Ok(a) => a,
                o @ _ => panic!("Got unexpected parse result: {:?}", o),
            }
        }
    }

    #[test]
    fn test_parse_arguments_simple() {
        let a = parses!("-c", "foo.c", "-o", "foo.o");
        assert_eq!(Some("foo.c"), a.input.to_str());
        assert_eq!(Language::C, a.language);
        assert_map_contains!(a.outputs, ("obj", PathBuf::from("foo.o")));
        //TODO: fix assert_map_contains to assert no extra keys!
        assert_eq!(1, a.outputs.len());
        assert!(a.preprocessor_args.is_empty());
        assert!(a.common_args.is_empty());
    }

    #[test]
    fn test_parse_arguments_values() {
        let a = parses!("-c", "foo.cxx", "-arch", "xyz", "-fabc","-I", "include", "-o", "foo.o", "-include", "file");
        assert_eq!(Some("foo.cxx"), a.input.to_str());
        assert_eq!(Language::Cxx, a.language);
        assert_map_contains!(a.outputs, ("obj", PathBuf::from("foo.o")));
        //TODO: fix assert_map_contains to assert no extra keys!
        assert_eq!(1, a.outputs.len());
        assert_eq!(ovec!["-Iinclude", "-include", "file"], a.preprocessor_args);
        assert_eq!(ovec!["-arch", "xyz", "-fabc"], a.common_args);
    }

    #[test]
    fn test_parse_arguments_others() {
        parses!("-c", "foo.c", "-B", "somewhere", "-o", "foo.o");
        parses!("-c", "foo.c", "-target", "x86_64-apple-darwin11", "-o", "foo.o");
        parses!("-c", "foo.c", "-gcc-toolchain", "somewhere", "-o", "foo.o");
    }

    #[test]
    fn test_parse_arguments_clangmodules() {
        assert_eq!(CompilerArguments::CannotCache("-fcxx-modules", None),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-fcxx-modules", "-o", "foo.o"]));
        assert_eq!(CompilerArguments::CannotCache("-fmodules", None),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-fmodules", "-o", "foo.o"]));
    }

    #[test]
    fn test_parse_xclang_invalid() {
        assert_eq!(CompilerArguments::CannotCache("Can't handle Raw arguments with -Xclang", None),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-o", "foo.o", "-Xclang", "broken"]));
        assert_eq!(CompilerArguments::CannotCache("Can't handle UnknownFlag arguments with -Xclang", None),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-o", "foo.o", "-Xclang", "-broken"]));
        assert_eq!(CompilerArguments::CannotCache("argument parse", Some("Unexpected end of args".to_string())),
                   _parse_arguments(&stringvec!["-c", "foo.c", "-o", "foo.o", "-Xclang", "-load"]));
    }

    #[test]
    fn test_parse_xclang_load() {
        let a = parses!("-c", "foo.c", "-o", "foo.o", "-Xclang", "-load", "-Xclang", "plugin.so");
        println!("A {:#?}", a);
        assert_eq!(ovec!["-Xclang", "-load", "-Xclang", "plugin.so"], a.common_args);
        assert_eq!(ovec!["plugin.so"], a.extra_hash_files);
    }

    #[test]
    fn test_parse_xclang_add_plugin() {
        let a = parses!("-c", "foo.c", "-o", "foo.o", "-Xclang", "-add-plugin", "-Xclang", "foo");
        assert_eq!(ovec!["-Xclang", "-add-plugin", "-Xclang", "foo"], a.common_args);
    }

    #[test]
    fn test_parse_xclang_verify() {
        let a = parses!("-c", "foo.c", "-o", "foo.o", "-Xclang", "-verify");
        assert_eq!(ovec!["-Xclang", "-verify"], a.preprocessor_args);
    }

    #[test]
    fn test_parse_fplugin() {
        let a = parses!("-c", "foo.c", "-o", "foo.o", "-fplugin", "plugin.so");
        println!("A {:#?}", a);
        assert_eq!(ovec!["-fplugin", "plugin.so"], a.common_args);
        assert_eq!(ovec!["plugin.so"], a.extra_hash_files);
    }

}
<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::str;
use std::io::{Read, Write, ErrorKind};
use std::result::Result;
use std::net::TcpStream;
use std::time::Duration;
use rand::{thread_rng, Rng};

use super::command::ControlCommandResponse;
use super::command::ControlCommand;
use super::command::COMMAND_SIZE;
use APP_CONF;
use LINE_FEED;
use cache::route::CacheRoute;
use cache::route::ROUTE_HASH_SIZE;

pub struct ControlHandle;

enum ControlHandleError {
    Closed,
    IncompatibleHasher,
    NotRecognized,
    TimedOut,
    ConnectionAborted,
    Interrupted,
    Unknown,
}

#[derive(PartialEq)]
enum ControlHandleMessageResult {
    Continue,
    Close,
}

const MAX_LINE_SIZE: usize = COMMAND_SIZE + ROUTE_HASH_SIZE + 1;
const HASH_VALUE_SIZE: usize = 10;
const HASH_RESULT_SIZE: usize = 7 + ROUTE_HASH_SIZE + 1;
const SHARD_DEFAULT: ControlShard = 0;
const TCP_TIMEOUT_NON_ESTABLISHED: u64 = 20;

pub type ControlShard = u8;

lazy_static! {
    static ref CONNECTED_BANNER: String = format!("CONNECTED <{} v{}>",
        env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}

impl ControlHandleError {
    pub fn to_str(&self) -> &'static str {
        match *self {
            ControlHandleError::Closed => "closed",
            ControlHandleError::IncompatibleHasher => "incompatible_hasher",
            ControlHandleError::NotRecognized => "not_recognized",
            ControlHandleError::TimedOut => "timed_out",
            ControlHandleError::ConnectionAborted => "connection_aborted",
            ControlHandleError::Interrupted => "interrupted",
            ControlHandleError::Unknown => "unknown",
        }
    }
}

impl ControlHandle {
    pub fn client(mut stream: TcpStream) {
        // Configure stream (non-established)
        ControlHandle::configure_stream(&stream, false);

        // Send connected banner
        write!(stream, "{}{}", *CONNECTED_BANNER, LINE_FEED).expect("write failed");

        // Ensure client hasher is compatible
        match Self::ensure_hasher(&stream) {
            Ok(_) => {
                // Configure stream (established)
                ControlHandle::configure_stream(&stream, true);

                // Send started acknowledgement
                write!(stream, "STARTED{}", LINE_FEED).expect("write failed");

                // Select default shard
                let mut shard = SHARD_DEFAULT;

                // Wait for incoming messages
                loop {
                    let mut read = [0; MAX_LINE_SIZE];

                    match stream.read(&mut read) {
                        Ok(n) => {
                            if n == 0 ||
                                Self::on_message(&mut shard, &stream, &read[0..n]) ==
                                    ControlHandleMessageResult::Close
                            {
                                // Should close?
                                break;
                            }
                        }
                        Err(err) => {
                            info!("closing control thread with traceback: {}", err);

                            panic!("closing control channel");
                        }
                    }
                }
            }
            Err(err) => {
                write!(stream, "ENDED {}{}", err.to_str(), LINE_FEED).expect("write failed");
            }
        }
    }

    fn configure_stream(stream: &TcpStream, is_established: bool) {
        let tcp_timeout = if is_established == true {
            APP_CONF.control.tcp_timeout
        } else {
            TCP_TIMEOUT_NON_ESTABLISHED
        };

        assert!(stream.set_nodelay(true).is_ok());

        assert!(
            stream
                .set_read_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
        assert!(
            stream
                .set_write_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
    }

    fn ensure_hasher(mut stream: &TcpStream) -> Result<Option<()>, ControlHandleError> {
        let test_value: String = thread_rng()
            .gen_ascii_chars()
            .take(HASH_VALUE_SIZE)
            .collect();
        let test_hash = CacheRoute::hash(test_value.as_str());

        write!(stream, "HASHREQ {}{}", test_value, LINE_FEED).expect("write failed");

        debug!(
            "sent hasher request: {} and expecting hash: {}",
            test_value,
            test_hash
        );

        loop {
            let mut read = [0; HASH_RESULT_SIZE];

            match stream.read(&mut read) {
                Ok(n) => {
                    if n == 0 {
                        return Err(ControlHandleError::Closed);
                    }

                    let mut parts = str::from_utf8(&read[0..n]).unwrap_or("").split_whitespace();

                    if parts.next().unwrap_or("") == "HASHRES" {
                        let res_hash = parts.next().unwrap_or("");

                        debug!(
                            "got hasher response: {} and expecting: {}",
                            res_hash,
                            test_hash
                        );

                        // Validate hash
                        if res_hash.is_empty() == false && res_hash == test_hash {
                            return Ok(None);
                        }

                        return Err(ControlHandleError::IncompatibleHasher);
                    }

                    return Err(ControlHandleError::NotRecognized);
                }
                Err(err) => {
                    let err_reason = match err.kind() {
                        ErrorKind::TimedOut => ControlHandleError::TimedOut,
                        ErrorKind::ConnectionAborted => ControlHandleError::ConnectionAborted,
                        ErrorKind::Interrupted => ControlHandleError::Interrupted,
                        _ => ControlHandleError::Unknown,
                    };

                    return Err(err_reason);
                }
            }
        }
    }

    fn on_message(
        shard: &mut ControlShard,
        mut stream: &TcpStream,
        message_slice: &[u8],
    ) -> ControlHandleMessageResult {
        let message = str::from_utf8(message_slice).unwrap_or("");

        debug!("got control message on shard {}: {}", shard, message);

        let mut result = ControlHandleMessageResult::Continue;

        let response = match Self::handle_message(shard, &message) {
            Ok(resp) => {
                match resp {
                    ControlCommandResponse::Ok |
                    ControlCommandResponse::Pong |
                    ControlCommandResponse::Ended |
                    ControlCommandResponse::Nil |
                    ControlCommandResponse::Void => {
                        if resp == ControlCommandResponse::Ended {
                            result = ControlHandleMessageResult::Close;
                        }
                        resp.to_str()
                    }
                    _ => ControlCommandResponse::Err.to_str(),
                }
            }
            _ => ControlCommandResponse::Err.to_str(),
        };

        if response.is_empty() == false {
            write!(stream, "{}{}", response, LINE_FEED).expect("write failed");
        }

        return result;
    }

    fn handle_message(
        shard: &mut ControlShard,
        message: &str,
    ) -> Result<ControlCommandResponse, Option<()>> {
        let mut parts = message.split_whitespace();
        let command = parts.next().unwrap_or("");

        debug!("will dispatch command: {}", command);

        match command {
            "" => Ok(ControlCommandResponse::Void),
            "FLUSHB" => ControlCommand::dispatch_flush_bucket(shard, parts),
            "FLUSHA" => ControlCommand::dispatch_flush_auth(shard, parts),
            "PING" => ControlCommand::dispatch_ping(),
            "SHARD" => ControlCommand::dispatch_shard(shard, parts),
            "QUIT" => ControlCommand::dispatch_quit(),
            _ => Ok(ControlCommandResponse::Nil),
        }
    }
}
<commit_msg>Large MAX_LINE_SIZE (account for CRLF)<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::str;
use std::io::{Read, Write, ErrorKind};
use std::result::Result;
use std::net::TcpStream;
use std::time::Duration;
use rand::{thread_rng, Rng};

use super::command::ControlCommandResponse;
use super::command::ControlCommand;
use super::command::COMMAND_SIZE;
use APP_CONF;
use LINE_FEED;
use cache::route::CacheRoute;
use cache::route::ROUTE_HASH_SIZE;

pub struct ControlHandle;

enum ControlHandleError {
    Closed,
    IncompatibleHasher,
    NotRecognized,
    TimedOut,
    ConnectionAborted,
    Interrupted,
    Unknown,
}

#[derive(PartialEq)]
enum ControlHandleMessageResult {
    Continue,
    Close,
}

const MAX_LINE_SIZE: usize = COMMAND_SIZE + ROUTE_HASH_SIZE + 2;
const HASH_VALUE_SIZE: usize = 10;
const HASH_RESULT_SIZE: usize = 7 + ROUTE_HASH_SIZE + 1;
const SHARD_DEFAULT: ControlShard = 0;
const TCP_TIMEOUT_NON_ESTABLISHED: u64 = 20;

pub type ControlShard = u8;

lazy_static! {
    static ref CONNECTED_BANNER: String = format!("CONNECTED <{} v{}>",
        env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"));
}

impl ControlHandleError {
    pub fn to_str(&self) -> &'static str {
        match *self {
            ControlHandleError::Closed => "closed",
            ControlHandleError::IncompatibleHasher => "incompatible_hasher",
            ControlHandleError::NotRecognized => "not_recognized",
            ControlHandleError::TimedOut => "timed_out",
            ControlHandleError::ConnectionAborted => "connection_aborted",
            ControlHandleError::Interrupted => "interrupted",
            ControlHandleError::Unknown => "unknown",
        }
    }
}

impl ControlHandle {
    pub fn client(mut stream: TcpStream) {
        // Configure stream (non-established)
        ControlHandle::configure_stream(&stream, false);

        // Send connected banner
        write!(stream, "{}{}", *CONNECTED_BANNER, LINE_FEED).expect("write failed");

        // Ensure client hasher is compatible
        match Self::ensure_hasher(&stream) {
            Ok(_) => {
                // Configure stream (established)
                ControlHandle::configure_stream(&stream, true);

                // Send started acknowledgement
                write!(stream, "STARTED{}", LINE_FEED).expect("write failed");

                // Select default shard
                let mut shard = SHARD_DEFAULT;

                // Wait for incoming messages
                loop {
                    let mut read = [0; MAX_LINE_SIZE];

                    match stream.read(&mut read) {
                        Ok(n) => {
                            if n == 0 ||
                                Self::on_message(&mut shard, &stream, &read[0..n]) ==
                                    ControlHandleMessageResult::Close
                            {
                                // Should close?
                                break;
                            }
                        }
                        Err(err) => {
                            info!("closing control thread with traceback: {}", err);

                            panic!("closing control channel");
                        }
                    }
                }
            }
            Err(err) => {
                write!(stream, "ENDED {}{}", err.to_str(), LINE_FEED).expect("write failed");
            }
        }
    }

    fn configure_stream(stream: &TcpStream, is_established: bool) {
        let tcp_timeout = if is_established == true {
            APP_CONF.control.tcp_timeout
        } else {
            TCP_TIMEOUT_NON_ESTABLISHED
        };

        assert!(stream.set_nodelay(true).is_ok());

        assert!(
            stream
                .set_read_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
        assert!(
            stream
                .set_write_timeout(Some(Duration::new(tcp_timeout, 0)))
                .is_ok()
        );
    }

    fn ensure_hasher(mut stream: &TcpStream) -> Result<Option<()>, ControlHandleError> {
        let test_value: String = thread_rng()
            .gen_ascii_chars()
            .take(HASH_VALUE_SIZE)
            .collect();
        let test_hash = CacheRoute::hash(test_value.as_str());

        write!(stream, "HASHREQ {}{}", test_value, LINE_FEED).expect("write failed");

        debug!(
            "sent hasher request: {} and expecting hash: {}",
            test_value,
            test_hash
        );

        loop {
            let mut read = [0; HASH_RESULT_SIZE];

            match stream.read(&mut read) {
                Ok(n) => {
                    if n == 0 {
                        return Err(ControlHandleError::Closed);
                    }

                    let mut parts = str::from_utf8(&read[0..n]).unwrap_or("").split_whitespace();

                    if parts.next().unwrap_or("") == "HASHRES" {
                        let res_hash = parts.next().unwrap_or("");

                        debug!(
                            "got hasher response: {} and expecting: {}",
                            res_hash,
                            test_hash
                        );

                        // Validate hash
                        if res_hash.is_empty() == false && res_hash == test_hash {
                            return Ok(None);
                        }

                        return Err(ControlHandleError::IncompatibleHasher);
                    }

                    return Err(ControlHandleError::NotRecognized);
                }
                Err(err) => {
                    let err_reason = match err.kind() {
                        ErrorKind::TimedOut => ControlHandleError::TimedOut,
                        ErrorKind::ConnectionAborted => ControlHandleError::ConnectionAborted,
                        ErrorKind::Interrupted => ControlHandleError::Interrupted,
                        _ => ControlHandleError::Unknown,
                    };

                    return Err(err_reason);
                }
            }
        }
    }

    fn on_message(
        shard: &mut ControlShard,
        mut stream: &TcpStream,
        message_slice: &[u8],
    ) -> ControlHandleMessageResult {
        let message = str::from_utf8(message_slice).unwrap_or("");

        debug!("got control message on shard {}: {}", shard, message);

        let mut result = ControlHandleMessageResult::Continue;

        let response = match Self::handle_message(shard, &message) {
            Ok(resp) => {
                match resp {
                    ControlCommandResponse::Ok |
                    ControlCommandResponse::Pong |
                    ControlCommandResponse::Ended |
                    ControlCommandResponse::Nil |
                    ControlCommandResponse::Void => {
                        if resp == ControlCommandResponse::Ended {
                            result = ControlHandleMessageResult::Close;
                        }
                        resp.to_str()
                    }
                    _ => ControlCommandResponse::Err.to_str(),
                }
            }
            _ => ControlCommandResponse::Err.to_str(),
        };

        if response.is_empty() == false {
            write!(stream, "{}{}", response, LINE_FEED).expect("write failed");
        }

        return result;
    }

    fn handle_message(
        shard: &mut ControlShard,
        message: &str,
    ) -> Result<ControlCommandResponse, Option<()>> {
        let mut parts = message.split_whitespace();
        let command = parts.next().unwrap_or("");

        debug!("will dispatch command: {}", command);

        match command {
            "" => Ok(ControlCommandResponse::Void),
            "FLUSHB" => ControlCommand::dispatch_flush_bucket(shard, parts),
            "FLUSHA" => ControlCommand::dispatch_flush_auth(shard, parts),
            "PING" => ControlCommand::dispatch_ping(),
            "SHARD" => ControlCommand::dispatch_shard(shard, parts),
            "QUIT" => ControlCommand::dispatch_quit(),
            _ => Ok(ControlCommandResponse::Nil),
        }
    }
}
<|endoftext|>


<commit_before>use core::*;

/// Given some cards create sets of possible groups of cards.
#[derive(Debug)]
pub struct CardIter<'a> {
    /// All the possible cards that can be dealt
    possible_cards: &'a [Card],

    /// Set of current offsets being used to create card sets.
    idx: Vec<usize>,

    /// size of card sets requested.
    num_cards: usize,
}

/// `CardIter` is a container for cards and current state.
impl<'a> CardIter<'a> {
    /// Create a new `CardIter` from a slice of cards.
    /// `num_cards` represents how many cards should be in the resulting vector.
    pub fn new(possible_cards: &[Card], num_cards: usize) -> CardIter {
        let mut idx: Vec<usize> = (0..(num_cards as usize)).collect();
        idx[num_cards - 1] -= 1;
        CardIter {
            possible_cards: possible_cards,
            idx: idx,
            num_cards: num_cards,
        }
    }
}

/// The actual `Iterator` for `Card`'s.
impl<'a> Iterator for CardIter<'a> {
    type Item = Vec<Card>;
    fn next(&mut self) -> Option<Vec<Card>> {
        // Keep track of where we are mutating
        let mut current_level: usize = self.num_cards - 1;

        while current_level < self.num_cards {
            // Move the current level forward one.
            self.idx[current_level] += 1;

            // Now check if moving this level forward means that
            // We will need more cards to fill out the rest of the hand
            // then are there.
            let cards_needed_after = self.num_cards - (current_level + 1);
            if self.idx[current_level] + cards_needed_after >= self.possible_cards.len() {
                if current_level == 0 {
                    return None;
                }
                current_level -= 1;
            } else {
                // If we aren't at the end then
                if current_level < self.num_cards - 1 {
                    self.idx[current_level + 1] = self.idx[current_level];
                }
                // Move forward one level
                current_level += 1;
            }
        }

        let result_cards: Vec<Card> = self.idx
            .iter()
            .map(|i| self.possible_cards[*i as usize].clone())
            .collect();
        Some(result_cards)
    }
}

/// This is useful for trying every possible 5 card hand
///
/// Probably not something that's going to be done in real
/// use cases, but still not bad.
impl<'a> IntoIterator for &'a FlatDeck {
    type Item = Vec<Card>;
    type IntoIter = CardIter<'a>;

    fn into_iter(self) -> CardIter<'a> {
        CardIter::new(&self[..], 5)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::card::*;
    use core::hand::*;
    use core::deck::*;
    use core::flat_deck::*;

    #[test]
    fn test_iter_one() {
        let mut h = Hand::default();
        h.push(Card {
            value: Value::Two,
            suit: Suit::Spade,
        });

        for cards in CardIter::new(&h[..], 1) {
            assert_eq!(1, cards.len());
        }

        assert_eq!(1, CardIter::new(&h[..], 1).count());
    }

    #[test]
    fn test_iter_two() {
        let mut h = Hand::default();
        h.push(Card {
            value: Value::Two,
            suit: Suit::Spade,
        });
        h.push(Card {
            value: Value::Three,
            suit: Suit::Spade,
        });
        h.push(Card {
            value: Value::Four,
            suit: Suit::Spade,
        });

        // Make sure that we get the correct number back.
        assert_eq!(3, CardIter::new(&h[..], 2).count());

        // Make sure that everything has two cards and they are different.
        //
        for cards in CardIter::new(&h[..], 2) {
            assert_eq!(2, cards.len());
            assert!(cards[0] != cards[1]);
        }
    }

    #[test]
    fn test_iter_deck() {
        let d: FlatDeck = Deck::default().into();
        assert_eq!(2598960, d.into_iter().count());
    }
}
<commit_msg>Fix iterating over cards when only requesting one card<commit_after>use core::*;

/// Given some cards create sets of possible groups of cards.
#[derive(Debug)]
pub struct CardIter<'a> {
    /// All the possible cards that can be dealt
    possible_cards: &'a [Card],

    /// Set of current offsets being used to create card sets.
    idx: Vec<usize>,

    /// size of card sets requested.
    num_cards: usize,
}

/// `CardIter` is a container for cards and current state.
impl<'a> CardIter<'a> {
    /// Create a new `CardIter` from a slice of cards.
    /// `num_cards` represents how many cards should be in the resulting vector.
    pub fn new(possible_cards: &[Card], num_cards: usize) -> CardIter {
        let mut idx: Vec<usize> = (0..(num_cards as usize)).collect();
        if num_cards > 1 {
            idx[num_cards - 1] -= 1;
        }
        CardIter {
            possible_cards: possible_cards,
            idx: idx,
            num_cards: num_cards,
        }
    }
}

/// The actual `Iterator` for `Card`'s.
impl<'a> Iterator for CardIter<'a> {
    type Item = Vec<Card>;
    fn next(&mut self) -> Option<Vec<Card>> {
        // This is a complete hack.
        //
        // Basically if num_cards == 1 then CardIter::new couldn't
        // set the last index to one less than the starting index,
        // because doing so would cause the unsigend usize to roll over.
        // That means that we need this hack here.
        if self.num_cards == 1 {
            if self.idx[0] < self.possible_cards.len() {
                let c = self.possible_cards[self.idx[0]];
                self.idx[0] += 1;
                return Some(vec![c]);
            } else {
                return None;
            }
        }
        // Keep track of where we are mutating
        let mut current_level: usize = self.num_cards - 1;

        while current_level < self.num_cards {
            // Move the current level forward one.
            self.idx[current_level] += 1;

            // Now check if moving this level forward means that
            // We will need more cards to fill out the rest of the hand
            // then are there.
            let cards_needed_after = self.num_cards - (current_level + 1);
            if self.idx[current_level] + cards_needed_after >= self.possible_cards.len() {
                if current_level == 0 {
                    return None;
                }
                current_level -= 1;
            } else {
                // If we aren't at the end then
                if current_level < self.num_cards - 1 {
                    self.idx[current_level + 1] = self.idx[current_level];
                }
                // Move forward one level
                current_level += 1;
            }
        }

        let result_cards: Vec<Card> = self.idx
            .iter()
            .map(|i| self.possible_cards[*i as usize].clone())
            .collect();
        Some(result_cards)
    }
}

/// This is useful for trying every possible 5 card hand
///
/// Probably not something that's going to be done in real
/// use cases, but still not bad.
impl<'a> IntoIterator for &'a FlatDeck {
    type Item = Vec<Card>;
    type IntoIter = CardIter<'a>;

    fn into_iter(self) -> CardIter<'a> {
        CardIter::new(&self[..], 5)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::card::*;
    use core::hand::*;
    use core::deck::*;
    use core::flat_deck::*;

    #[test]
    fn test_iter_one() {
        let mut h = Hand::default();
        h.push(Card {
            value: Value::Two,
            suit: Suit::Spade,
        });

        for cards in CardIter::new(&h[..], 1) {
            assert_eq!(1, cards.len());
        }

        assert_eq!(1, CardIter::new(&h[..], 1).count());
    }

    #[test]
    fn test_iter_two() {
        let mut h = Hand::default();
        h.push(Card {
            value: Value::Two,
            suit: Suit::Spade,
        });
        h.push(Card {
            value: Value::Three,
            suit: Suit::Spade,
        });
        h.push(Card {
            value: Value::Four,
            suit: Suit::Spade,
        });

        // Make sure that we get the correct number back.
        assert_eq!(3, CardIter::new(&h[..], 2).count());

        // Make sure that everything has two cards and they are different.
        //
        for cards in CardIter::new(&h[..], 2) {
            assert_eq!(2, cards.len());
            assert!(cards[0] != cards[1]);
        }
    }

    #[test]
    fn test_iter_deck() {
        let d: FlatDeck = Deck::default().into();
        assert_eq!(2598960, d.into_iter().count());
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

use std::num::Float;

use seed::Seed;
use util::{lerp, scurve3, scurve5};
use gradients::{GRADIENT2, GRADIENT3, GRADIENT4};

fn get_perlin2_gradient(seed: &Seed, x_whole: int, y_whole: int, x_frac: f32, y_frac: f32) -> f32 {
    let vector = GRADIENT2[seed.get2(x_whole, y_whole) % GRADIENT2.len()];
    x_frac * vector[0] + y_frac * vector[1]
}

fn get_perlin3_gradient(seed: &Seed, x_whole: int, y_whole: int, z_whole: int, x_frac: f32, y_frac: f32, z_frac: f32) -> f32 {
    let vector = GRADIENT3[seed.get3(x_whole, y_whole, z_whole) % GRADIENT3.len()];
    x_frac * vector[0] + y_frac * vector[1] + z_frac * vector[2]
}

fn get_perlin4_gradient(seed: &Seed, x_whole: int, y_whole: int, z_whole: int, w_whole: int, x_frac: f32, y_frac: f32, z_frac: f32, w_frac: f32) -> f32 {
    let vector = GRADIENT4[seed.get4(x_whole, y_whole, z_whole, w_whole) % GRADIENT4.len()];
    x_frac * vector[0] + y_frac * vector[1] + z_frac * vector[2] + w_frac * vector[3]
}

fn perlin2<T: Float>(seed: &Seed, point: &::Point2<T>, quality: ::Quality) -> f32 {
    use Quality::{ Fast, Best };

    let xfloor = point[0].floor().to_f32().unwrap();
    let yfloor = point[1].floor().to_f32().unwrap();

    let x0_whole = xfloor.to_int().unwrap();
    let y0_whole = yfloor.to_int().unwrap();

    let x1_whole = x0_whole + 1;
    let y1_whole = y0_whole + 1;

    let x0_frac = point[0].to_f32().unwrap() - xfloor;
    let y0_frac = point[1].to_f32().unwrap() - yfloor;

    let x1_frac = x0_frac - 1.0;
    let y1_frac = y0_frac - 1.0;

    let (x_curve, y_curve) = match quality {
        Fast => (
            scurve3(x0_frac),
            scurve3(y0_frac),
        ),
        Best => (
            scurve5(x0_frac),
            scurve5(y0_frac),
        )
    };

    let n0 = get_perlin2_gradient(seed, x0_whole, y0_whole, x0_frac, y0_frac);
    let n1 = get_perlin2_gradient(seed, x1_whole, y0_whole, x1_frac, y0_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = get_perlin2_gradient(seed, x0_whole, y1_whole, x0_frac, y1_frac);
    let n1 = get_perlin2_gradient(seed, x1_whole, y1_whole, x1_frac, y1_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);

    lerp(y_curve, interpolated_x0, interpolated_x1)
}

pub fn perlin2_fast<T: Float>(seed: &Seed, point: &::Point2<T>) -> f32 {
    perlin2(seed, point, ::Quality::Fast)
}

pub fn perlin2_best<T: Float>(seed: &Seed, point: &::Point2<T>) -> f32 {
    perlin2(seed, point, ::Quality::Best)
}

fn perlin3<T: Float>(seed: &Seed, point: &::Point3<T>, quality: ::Quality) -> f32 {
    use Quality::{ Fast, Best };

    let xfloor = point[0].floor().to_f32().unwrap();
    let yfloor = point[1].floor().to_f32().unwrap();
    let zfloor = point[2].floor().to_f32().unwrap();

    let x0_whole = xfloor.to_int().unwrap();
    let y0_whole = yfloor.to_int().unwrap();
    let z0_whole = zfloor.to_int().unwrap();

    let x1_whole = x0_whole + 1;
    let y1_whole = y0_whole + 1;
    let z1_whole = z0_whole + 1;

    let x0_frac = point[0].to_f32().unwrap() - xfloor;
    let y0_frac = point[1].to_f32().unwrap() - yfloor;
    let z0_frac = point[2].to_f32().unwrap() - zfloor;

    let x1_frac = x0_frac - 1.0;
    let y1_frac = y0_frac - 1.0;
    let z1_frac = z0_frac - 1.0;

    let (x_curve, y_curve, z_curve) = match quality {
        Fast => (
            scurve3(x0_frac),
            scurve3(y0_frac),
            scurve3(z0_frac),
        ),
        Best => (
            scurve5(x0_frac),
            scurve5(y0_frac),
            scurve5(z0_frac),
        )
    };

    let n0 = get_perlin3_gradient(seed, x0_whole, y0_whole, z0_whole, x0_frac, y0_frac, z0_frac);
    let n1 = get_perlin3_gradient(seed, x1_whole, y0_whole, z0_whole, x1_frac, y0_frac, z0_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = get_perlin3_gradient(seed, x0_whole, y1_whole, z0_whole, x0_frac, y1_frac, z0_frac);
    let n1 = get_perlin3_gradient(seed, x1_whole, y1_whole, z0_whole, x1_frac, y1_frac, z0_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y0 = lerp(y_curve, interpolated_x0, interpolated_x1);

    let n0 = get_perlin3_gradient(seed, x0_whole, y0_whole, z1_whole, x0_frac, y0_frac, z1_frac);
    let n1 = get_perlin3_gradient(seed, x1_whole, y0_whole, z1_whole, x1_frac, y0_frac, z1_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = get_perlin3_gradient(seed, x0_whole, y1_whole, z1_whole, x0_frac, y1_frac, z1_frac);
    let n1 = get_perlin3_gradient(seed, x1_whole, y1_whole, z1_whole, x1_frac, y1_frac, z1_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y1 = lerp(y_curve, interpolated_x0, interpolated_x1);

    lerp(z_curve, interpolated_y0, interpolated_y1)
}

pub fn perlin3_fast<T: Float>(seed: &Seed, point: &::Point3<T>) -> f32 {
    perlin3(seed, point, ::Quality::Fast)
}

pub fn perlin3_best<T: Float>(seed: &Seed, point: &::Point3<T>) -> f32 {
    perlin3(seed, point, ::Quality::Best)
}

fn perlin4<T: Float>(seed: &Seed, point: &::Point4<T>, quality: ::Quality) -> f32 {
    use Quality::{ Fast, Best };

    let xfloor = point[0].floor().to_f32().unwrap();
    let yfloor = point[1].floor().to_f32().unwrap();
    let zfloor = point[2].floor().to_f32().unwrap();
    let wfloor = point[3].floor().to_f32().unwrap();

    let x0_whole = xfloor.to_int().unwrap();
    let y0_whole = yfloor.to_int().unwrap();
    let z0_whole = zfloor.to_int().unwrap();
    let w0_whole = wfloor.to_int().unwrap();

    let x1_whole = x0_whole + 1;
    let y1_whole = y0_whole + 1;
    let z1_whole = z0_whole + 1;
    let w1_whole = w0_whole + 1;

    let x0_frac = point[0].to_f32().unwrap() - xfloor;
    let y0_frac = point[1].to_f32().unwrap() - yfloor;
    let z0_frac = point[2].to_f32().unwrap() - zfloor;
    let w0_frac = point[2].to_f32().unwrap() - wfloor;

    let x1_frac = x0_frac - 1.0;
    let y1_frac = y0_frac - 1.0;
    let z1_frac = z0_frac - 1.0;
    let w1_frac = w0_frac - 1.0;

    let (x_curve, y_curve, z_curve, w_curve) = match quality {
        Fast => (
            scurve3(x0_frac),
            scurve3(y0_frac),
            scurve3(z0_frac),
            scurve3(w0_frac),
        ),
        Best => (
            scurve5(x0_frac),
            scurve5(y0_frac),
            scurve5(z0_frac),
            scurve5(w0_frac),
        )
    };

    let n0 = get_perlin4_gradient(seed, x0_whole, y0_whole, z0_whole, w0_whole, x0_frac, y0_frac, z0_frac, w0_frac);
    let n1 = get_perlin4_gradient(seed, x1_whole, y0_whole, z0_whole, w0_whole, x1_frac, y0_frac, z0_frac, w0_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = get_perlin4_gradient(seed, x0_whole, y1_whole, z0_whole, w0_whole, x0_frac, y1_frac, z0_frac, w0_frac);
    let n1 = get_perlin4_gradient(seed, x1_whole, y1_whole, z0_whole, w0_whole, x1_frac, y1_frac, z0_frac, w0_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y0 = lerp(y_curve, interpolated_x0, interpolated_x1);

    let n0 = get_perlin4_gradient(seed, x0_whole, y0_whole, z1_whole, w0_whole, x0_frac, y0_frac, z1_frac, w0_frac);
    let n1 = get_perlin4_gradient(seed, x1_whole, y0_whole, z1_whole, w0_whole, x1_frac, y0_frac, z1_frac, w0_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = get_perlin4_gradient(seed, x0_whole, y1_whole, z1_whole, w0_whole, x0_frac, y1_frac, z1_frac, w0_frac);
    let n1 = get_perlin4_gradient(seed, x1_whole, y1_whole, z1_whole, w0_whole, x1_frac, y1_frac, z1_frac, w0_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y1 = lerp(y_curve, interpolated_x0, interpolated_x1);
    let interpolated_z0 = lerp(z_curve, interpolated_y0, interpolated_y1);

    let n0 = get_perlin4_gradient(seed, x0_whole, y0_whole, z0_whole, w1_whole, x0_frac, y0_frac, z0_frac, w1_frac);
    let n1 = get_perlin4_gradient(seed, x1_whole, y0_whole, z0_whole, w1_whole, x1_frac, y0_frac, z0_frac, w1_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = get_perlin4_gradient(seed, x0_whole, y1_whole, z0_whole, w1_whole, x0_frac, y1_frac, z0_frac, w1_frac);
    let n1 = get_perlin4_gradient(seed, x1_whole, y1_whole, z0_whole, w1_whole, x1_frac, y1_frac, z0_frac, w1_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y0 = lerp(y_curve, interpolated_x0, interpolated_x1);

    let n0 = get_perlin4_gradient(seed, x0_whole, y0_whole, z1_whole, w1_whole, x0_frac, y0_frac, z1_frac, w1_frac);
    let n1 = get_perlin4_gradient(seed, x1_whole, y0_whole, z1_whole, w1_whole, x1_frac, y0_frac, z1_frac, w1_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = get_perlin4_gradient(seed, x0_whole, y1_whole, z1_whole, w1_whole, x0_frac, y1_frac, z1_frac, w1_frac);
    let n1 = get_perlin4_gradient(seed, x1_whole, y1_whole, z1_whole, w1_whole, x1_frac, y1_frac, z1_frac, w1_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y1 = lerp(y_curve, interpolated_x0, interpolated_x1);
    let interpolated_z1 = lerp(z_curve, interpolated_y0, interpolated_y1);

    lerp(w_curve, interpolated_z0, interpolated_z1)
}

pub fn perlin4_fast<T: Float>(seed: &Seed, point: &::Point4<T>) -> f32 {
    perlin4(seed, point, ::Quality::Fast)
}

pub fn perlin4_best<T: Float>(seed: &Seed, point: &::Point4<T>) -> f32 {
    perlin4(seed, point, ::Quality::Best)
}
<commit_msg>Clean up perlin noise implementations<commit_after>// Copyright 2013 The noise-rs developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

use std::num::Float;

use seed::Seed;
use util::{lerp, scurve3, scurve5};
use gradients::{GRADIENT2, GRADIENT3, GRADIENT4};

fn perlin2<T, F>(seed: &Seed, point: &::Point2<T>, scurve: F) -> f32 where
    T: Float,
    F: Fn(f32) -> f32,
{
    fn gradient(seed: &Seed, x_whole: int, y_whole: int, x_frac: f32, y_frac: f32) -> f32 {
        let vector = GRADIENT2[seed.get2(x_whole, y_whole) % GRADIENT2.len()];
        x_frac * vector[0] + y_frac * vector[1]
    }

    let xfloor = point[0].floor().to_f32().unwrap();
    let yfloor = point[1].floor().to_f32().unwrap();

    let x0_whole = xfloor.to_int().unwrap();
    let y0_whole = yfloor.to_int().unwrap();

    let x1_whole = x0_whole + 1;
    let y1_whole = y0_whole + 1;

    let x0_frac = point[0].to_f32().unwrap() - xfloor;
    let y0_frac = point[1].to_f32().unwrap() - yfloor;

    let x1_frac = x0_frac - 1.0;
    let y1_frac = y0_frac - 1.0;

    let x_curve = scurve(x0_frac);
    let y_curve = scurve(y0_frac);

    let n0 = gradient(seed, x0_whole, y0_whole, x0_frac, y0_frac);
    let n1 = gradient(seed, x1_whole, y0_whole, x1_frac, y0_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = gradient(seed, x0_whole, y1_whole, x0_frac, y1_frac);
    let n1 = gradient(seed, x1_whole, y1_whole, x1_frac, y1_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);

    lerp(y_curve, interpolated_x0, interpolated_x1)
}

pub fn perlin2_fast<T: Float>(seed: &Seed, point: &::Point2<T>) -> f32 {
    perlin2(seed, point, scurve3)
}

pub fn perlin2_best<T: Float>(seed: &Seed, point: &::Point2<T>) -> f32 {
    perlin2(seed, point, scurve5)
}

fn perlin3<T, F>(seed: &Seed, point: &::Point3<T>, scurve: F) -> f32 where
    T: Float,
    F: Fn(f32) -> f32,
{
    fn gradient(seed: &Seed, x_whole: int, y_whole: int, z_whole: int, x_frac: f32, y_frac: f32, z_frac: f32) -> f32 {
        let vector = GRADIENT3[seed.get3(x_whole, y_whole, z_whole) % GRADIENT3.len()];
        x_frac * vector[0] + y_frac * vector[1] + z_frac * vector[2]
    }

    let xfloor = point[0].floor().to_f32().unwrap();
    let yfloor = point[1].floor().to_f32().unwrap();
    let zfloor = point[2].floor().to_f32().unwrap();

    let x0_whole = xfloor.to_int().unwrap();
    let y0_whole = yfloor.to_int().unwrap();
    let z0_whole = zfloor.to_int().unwrap();

    let x1_whole = x0_whole + 1;
    let y1_whole = y0_whole + 1;
    let z1_whole = z0_whole + 1;

    let x0_frac = point[0].to_f32().unwrap() - xfloor;
    let y0_frac = point[1].to_f32().unwrap() - yfloor;
    let z0_frac = point[2].to_f32().unwrap() - zfloor;

    let x1_frac = x0_frac - 1.0;
    let y1_frac = y0_frac - 1.0;
    let z1_frac = z0_frac - 1.0;

    let x_curve = scurve(x0_frac);
    let y_curve = scurve(y0_frac);
    let z_curve = scurve(z0_frac);

    let n0 = gradient(seed, x0_whole, y0_whole, z0_whole, x0_frac, y0_frac, z0_frac);
    let n1 = gradient(seed, x1_whole, y0_whole, z0_whole, x1_frac, y0_frac, z0_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = gradient(seed, x0_whole, y1_whole, z0_whole, x0_frac, y1_frac, z0_frac);
    let n1 = gradient(seed, x1_whole, y1_whole, z0_whole, x1_frac, y1_frac, z0_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y0 = lerp(y_curve, interpolated_x0, interpolated_x1);

    let n0 = gradient(seed, x0_whole, y0_whole, z1_whole, x0_frac, y0_frac, z1_frac);
    let n1 = gradient(seed, x1_whole, y0_whole, z1_whole, x1_frac, y0_frac, z1_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = gradient(seed, x0_whole, y1_whole, z1_whole, x0_frac, y1_frac, z1_frac);
    let n1 = gradient(seed, x1_whole, y1_whole, z1_whole, x1_frac, y1_frac, z1_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y1 = lerp(y_curve, interpolated_x0, interpolated_x1);

    lerp(z_curve, interpolated_y0, interpolated_y1)
}

pub fn perlin3_fast<T: Float>(seed: &Seed, point: &::Point3<T>) -> f32 {
    perlin3(seed, point, scurve3)
}

pub fn perlin3_best<T: Float>(seed: &Seed, point: &::Point3<T>) -> f32 {
    perlin3(seed, point, scurve5)
}

fn perlin4<T, F>(seed: &Seed, point: &::Point4<T>, scurve: F) -> f32 where
    T: Float,
    F: Fn(f32) -> f32,
{
    fn gradient(seed: &Seed, x_whole: int, y_whole: int, z_whole: int, w_whole: int, x_frac: f32, y_frac: f32, z_frac: f32, w_frac: f32) -> f32 {
        let vector = GRADIENT4[seed.get4(x_whole, y_whole, z_whole, w_whole) % GRADIENT4.len()];
        x_frac * vector[0] + y_frac * vector[1] + z_frac * vector[2] + w_frac * vector[3]
    }

    let xfloor = point[0].floor().to_f32().unwrap();
    let yfloor = point[1].floor().to_f32().unwrap();
    let zfloor = point[2].floor().to_f32().unwrap();
    let wfloor = point[3].floor().to_f32().unwrap();

    let x0_whole = xfloor.to_int().unwrap();
    let y0_whole = yfloor.to_int().unwrap();
    let z0_whole = zfloor.to_int().unwrap();
    let w0_whole = wfloor.to_int().unwrap();

    let x1_whole = x0_whole + 1;
    let y1_whole = y0_whole + 1;
    let z1_whole = z0_whole + 1;
    let w1_whole = w0_whole + 1;

    let x0_frac = point[0].to_f32().unwrap() - xfloor;
    let y0_frac = point[1].to_f32().unwrap() - yfloor;
    let z0_frac = point[2].to_f32().unwrap() - zfloor;
    let w0_frac = point[2].to_f32().unwrap() - wfloor;

    let x1_frac = x0_frac - 1.0;
    let y1_frac = y0_frac - 1.0;
    let z1_frac = z0_frac - 1.0;
    let w1_frac = w0_frac - 1.0;

    let x_curve = scurve(x0_frac);
    let y_curve = scurve(y0_frac);
    let z_curve = scurve(z0_frac);
    let w_curve = scurve(w0_frac);

    let n0 = gradient(seed, x0_whole, y0_whole, z0_whole, w0_whole, x0_frac, y0_frac, z0_frac, w0_frac);
    let n1 = gradient(seed, x1_whole, y0_whole, z0_whole, w0_whole, x1_frac, y0_frac, z0_frac, w0_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = gradient(seed, x0_whole, y1_whole, z0_whole, w0_whole, x0_frac, y1_frac, z0_frac, w0_frac);
    let n1 = gradient(seed, x1_whole, y1_whole, z0_whole, w0_whole, x1_frac, y1_frac, z0_frac, w0_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y0 = lerp(y_curve, interpolated_x0, interpolated_x1);

    let n0 = gradient(seed, x0_whole, y0_whole, z1_whole, w0_whole, x0_frac, y0_frac, z1_frac, w0_frac);
    let n1 = gradient(seed, x1_whole, y0_whole, z1_whole, w0_whole, x1_frac, y0_frac, z1_frac, w0_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = gradient(seed, x0_whole, y1_whole, z1_whole, w0_whole, x0_frac, y1_frac, z1_frac, w0_frac);
    let n1 = gradient(seed, x1_whole, y1_whole, z1_whole, w0_whole, x1_frac, y1_frac, z1_frac, w0_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y1 = lerp(y_curve, interpolated_x0, interpolated_x1);
    let interpolated_z0 = lerp(z_curve, interpolated_y0, interpolated_y1);

    let n0 = gradient(seed, x0_whole, y0_whole, z0_whole, w1_whole, x0_frac, y0_frac, z0_frac, w1_frac);
    let n1 = gradient(seed, x1_whole, y0_whole, z0_whole, w1_whole, x1_frac, y0_frac, z0_frac, w1_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = gradient(seed, x0_whole, y1_whole, z0_whole, w1_whole, x0_frac, y1_frac, z0_frac, w1_frac);
    let n1 = gradient(seed, x1_whole, y1_whole, z0_whole, w1_whole, x1_frac, y1_frac, z0_frac, w1_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y0 = lerp(y_curve, interpolated_x0, interpolated_x1);

    let n0 = gradient(seed, x0_whole, y0_whole, z1_whole, w1_whole, x0_frac, y0_frac, z1_frac, w1_frac);
    let n1 = gradient(seed, x1_whole, y0_whole, z1_whole, w1_whole, x1_frac, y0_frac, z1_frac, w1_frac);
    let interpolated_x0 = lerp(x_curve, n0, n1);

    let n0 = gradient(seed, x0_whole, y1_whole, z1_whole, w1_whole, x0_frac, y1_frac, z1_frac, w1_frac);
    let n1 = gradient(seed, x1_whole, y1_whole, z1_whole, w1_whole, x1_frac, y1_frac, z1_frac, w1_frac);
    let interpolated_x1 = lerp(x_curve, n0, n1);
    let interpolated_y1 = lerp(y_curve, interpolated_x0, interpolated_x1);
    let interpolated_z1 = lerp(z_curve, interpolated_y0, interpolated_y1);

    lerp(w_curve, interpolated_z0, interpolated_z1)
}

pub fn perlin4_fast<T: Float>(seed: &Seed, point: &::Point4<T>) -> f32 {
    perlin4(seed, point, scurve3)
}

pub fn perlin4_best<T: Float>(seed: &Seed, point: &::Point4<T>) -> f32 {
    perlin4(seed, point, scurve5)
}
<|endoftext|>