<commit_before>use self::build_tables::build_tables;
use self::parse_grammar::parse_grammar;
use self::prepare_grammar::prepare_grammar;
use self::render::render_c_code;
use crate::error::{Error, Result};
use regex::{Regex, RegexBuilder};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};

mod build_tables;
mod grammars;
mod nfa;
mod npm_files;
mod parse_grammar;
mod prepare_grammar;
mod properties;
mod render;
mod rules;
mod tables;

lazy_static! {
    static ref JSON_COMMENT_REGEX: Regex = RegexBuilder::new("^\\s*//.*")
        .multi_line(true)
        .build()
        .unwrap();
}

pub fn generate_parser_in_directory(
    repo_path: &PathBuf,
    grammar_path: Option<&str>,
    minimize: bool,
    state_ids_to_log: Vec<usize>,
    properties_only: bool,
) -> Result<()> {
    if !properties_only {
        let grammar_path = grammar_path.map_or(repo_path.join("grammar.js"), |s| s.into());
        let grammar_json = load_grammar_file(&grammar_path)?;
        let (language_name, c_code) =
            generate_parser_for_grammar_with_opts(&grammar_json, minimize, state_ids_to_log)?;
        let repo_src_path = repo_path.join("src");
        fs::create_dir_all(&repo_src_path)?;
        fs::write(&repo_src_path.join("parser.c"), c_code)
            .map_err(|e| format!("Failed to write parser.c: {}", e))?;
        ensure_file(&repo_src_path.join("binding.cc"), || {
            npm_files::binding_cc(&language_name)
        })?;
        ensure_file(&repo_path.join("binding.gyp"), || {
            npm_files::binding_gyp(&language_name)
        })?;
        ensure_file(&repo_path.join("index.js"), || {
            npm_files::index_js(&language_name)
        })?;
    }
    properties::generate_property_sheets(repo_path)?;
    Ok(())
}

#[cfg(test)]
pub fn generate_parser_for_grammar(grammar_json: &String) -> Result<(String, String)> {
    let grammar_json = JSON_COMMENT_REGEX.replace_all(grammar_json, "\n");
    generate_parser_for_grammar_with_opts(&grammar_json, true, Vec::new())
}

fn generate_parser_for_grammar_with_opts(
    grammar_json: &str,
    minimize: bool,
    state_ids_to_log: Vec<usize>,
) -> Result<(String, String)> {
    let input_grammar = parse_grammar(grammar_json)?;
    let (syntax_grammar, lexical_grammar, inlines, simple_aliases) =
        prepare_grammar(&input_grammar)?;
    let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables(
        &syntax_grammar,
        &lexical_grammar,
        &simple_aliases,
        &inlines,
        minimize,
        state_ids_to_log,
    )?;
    let c_code = render_c_code(
        &input_grammar.name,
        parse_table,
        main_lex_table,
        keyword_lex_table,
        keyword_capture_token,
        syntax_grammar,
        lexical_grammar,
        simple_aliases,
    );
    Ok((input_grammar.name, c_code))
}

fn load_grammar_file(grammar_path: &PathBuf) -> Result<String> {
    match grammar_path.extension().and_then(|e| e.to_str()) {
        Some("js") => Ok(load_js_grammar_file(grammar_path)?),
        Some("json") => Ok(fs::read_to_string(grammar_path)?),
        _ => Err(Error(format!("Unknown grammar file extension: {:?}", grammar_path))),
    }
}

fn load_js_grammar_file(grammar_path: &PathBuf) -> Result<String> {
    let mut node_process = Command::new("node")
        .env("TREE_SITTER_GRAMMAR_PATH", grammar_path)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .expect("Failed to run `node`");

    let mut node_stdin = node_process
        .stdin
        .take()
        .expect("Failed to open stdin for node");
    let javascript_code = include_bytes!("./dsl.js");
    node_stdin
        .write(javascript_code)
        .expect("Failed to write to node's stdin");
    drop(node_stdin);
    let output = node_process
        .wait_with_output()
        .expect("Failed to read output from node");
    match output.status.code() {
        None => panic!("Node process was killed"),
        Some(0) => {}
        Some(code) => return Err(Error(format!("Node process exited with status {}", code))),
    }

    Ok(String::from_utf8(output.stdout).expect("Got invalid UTF8 from node"))
}

fn ensure_file(path: &PathBuf, f: impl Fn() -> String) -> Result<()> {
    if path.exists() {
        Ok(())
    } else {
        fs::write(path, f()).map_err(|e| Error(format!("Failed to write file {:?}: {}", path, e)))
    }
}
<commit_msg>Write tree_sitter/parser.h file in generate command<commit_after>use self::build_tables::build_tables;
use self::parse_grammar::parse_grammar;
use self::prepare_grammar::prepare_grammar;
use self::render::render_c_code;
use crate::error::{Error, Result};
use regex::{Regex, RegexBuilder};
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process::{Command, Stdio};

mod build_tables;
mod grammars;
mod nfa;
mod npm_files;
mod parse_grammar;
mod prepare_grammar;
mod properties;
mod render;
mod rules;
mod tables;

lazy_static! {
    static ref JSON_COMMENT_REGEX: Regex = RegexBuilder::new("^\\s*//.*")
        .multi_line(true)
        .build()
        .unwrap();
}

pub fn generate_parser_in_directory(
    repo_path: &PathBuf,
    grammar_path: Option<&str>,
    minimize: bool,
    state_ids_to_log: Vec<usize>,
    properties_only: bool,
) -> Result<()> {
    if !properties_only {
        let grammar_path = grammar_path.map_or(repo_path.join("grammar.js"), |s| s.into());
        let grammar_json = load_grammar_file(&grammar_path)?;
        let (language_name, c_code) =
            generate_parser_for_grammar_with_opts(&grammar_json, minimize, state_ids_to_log)?;
        let repo_src_path = repo_path.join("src");
        let repo_header_path = repo_src_path.join("tree_sitter");
        fs::create_dir_all(&repo_src_path)?;
        fs::create_dir_all(&repo_header_path)?;
        fs::write(&repo_src_path.join("parser.c"), c_code)
            .map_err(|e| format!("Failed to write parser.c: {}", e))?;
        ensure_file(&repo_src_path.join("binding.cc"), || {
            npm_files::binding_cc(&language_name)
        })?;
        ensure_file(&repo_path.join("binding.gyp"), || {
            npm_files::binding_gyp(&language_name)
        })?;
        ensure_file(&repo_path.join("index.js"), || {
            npm_files::index_js(&language_name)
        })?;
        ensure_file(&repo_header_path.join("parser.h"), || {
            include_str!("../../../lib/include/tree_sitter/parser.h")
        })?;
    }
    properties::generate_property_sheets(repo_path)?;
    Ok(())
}

#[cfg(test)]
pub fn generate_parser_for_grammar(grammar_json: &String) -> Result<(String, String)> {
    let grammar_json = JSON_COMMENT_REGEX.replace_all(grammar_json, "\n");
    generate_parser_for_grammar_with_opts(&grammar_json, true, Vec::new())
}

fn generate_parser_for_grammar_with_opts(
    grammar_json: &str,
    minimize: bool,
    state_ids_to_log: Vec<usize>,
) -> Result<(String, String)> {
    let input_grammar = parse_grammar(grammar_json)?;
    let (syntax_grammar, lexical_grammar, inlines, simple_aliases) =
        prepare_grammar(&input_grammar)?;
    let (parse_table, main_lex_table, keyword_lex_table, keyword_capture_token) = build_tables(
        &syntax_grammar,
        &lexical_grammar,
        &simple_aliases,
        &inlines,
        minimize,
        state_ids_to_log,
    )?;
    let c_code = render_c_code(
        &input_grammar.name,
        parse_table,
        main_lex_table,
        keyword_lex_table,
        keyword_capture_token,
        syntax_grammar,
        lexical_grammar,
        simple_aliases,
    );
    Ok((input_grammar.name, c_code))
}

fn load_grammar_file(grammar_path: &PathBuf) -> Result<String> {
    match grammar_path.extension().and_then(|e| e.to_str()) {
        Some("js") => Ok(load_js_grammar_file(grammar_path)?),
        Some("json") => Ok(fs::read_to_string(grammar_path)?),
        _ => Err(Error(format!(
            "Unknown grammar file extension: {:?}",
            grammar_path
        ))),
    }
}

fn load_js_grammar_file(grammar_path: &PathBuf) -> Result<String> {
    let mut node_process = Command::new("node")
        .env("TREE_SITTER_GRAMMAR_PATH", grammar_path)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .expect("Failed to run `node`");

    let mut node_stdin = node_process
        .stdin
        .take()
        .expect("Failed to open stdin for node");
    let javascript_code = include_bytes!("./dsl.js");
    node_stdin
        .write(javascript_code)
        .expect("Failed to write to node's stdin");
    drop(node_stdin);
    let output = node_process
        .wait_with_output()
        .expect("Failed to read output from node");
    match output.status.code() {
        None => panic!("Node process was killed"),
        Some(0) => {}
        Some(code) => return Err(Error(format!("Node process exited with status {}", code))),
    }

    Ok(String::from_utf8(output.stdout).expect("Got invalid UTF8 from node"))
}

fn ensure_file<T: AsRef<[u8]>>(path: &PathBuf, f: impl Fn() -> T) -> Result<()> {
    if path.exists() {
        Ok(())
    } else {
        fs::write(path, f().as_ref()).map_err(|e| Error(format!("Failed to write file {:?}: {}", path, e)))
    }
}
<|endoftext|>


<commit_before>extern crate regex;

use std::ascii::AsciiExt;
use std::error::Error;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;
use std::collections::HashMap;
use std::collections::HashSet;
use regex::Regex;

fn load_dictionary() -> (HashMap<(char, usize, usize), HashSet<String>>,
                         HashMap<usize, HashSet<String>>) {
    let path = Path::new("/usr/share/dict/words");
    let display = path.display();

    let file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file,
    };

    let mut ch_position_length_map = HashMap::new();
    let mut length_map = HashMap::new();
    let reader = BufReader::new(file);

    for readline in reader.lines() {
        let line = match readline {
            Err(why) => panic!("couldn't read from {}: {}",
                                display,
                                Error::description(&why)),
            Ok(readline) => readline,
        };

        let word = line.trim();
        for (index, ch) in word.to_ascii_lowercase().chars().enumerate() {
            let key = (ch, index, word.len());

            ch_position_length_map.entry(key).or_insert(
                HashSet::new()).insert(word.to_string());
            length_map.entry(word.len()).or_insert(
                HashSet::new()).insert(word.to_string());
        }
    }
    (ch_position_length_map, length_map)
}

fn match_pattern(pattern : &str,
         ch_position_length_map : &HashMap<(char, usize, usize), HashSet<String>>,
         length_map : &HashMap<usize, HashSet<String>>) -> Vec<String> {
    let pattern_parser = Regex::new(
        r"(?P<number>\d+)|(?P<letter>[A-Za-z])").unwrap();

    let mut pattern_length: usize = 0;
    let mut ch_and_index = Vec::new();

    for number_or_letter in pattern_parser.captures_iter(
            &pattern.to_ascii_lowercase()) {
        if number_or_letter.name("number").is_some() {
            let number_as_string = number_or_letter.name("number").unwrap();
            let number: usize = number_as_string.parse().unwrap();
            pattern_length += number;
        } else {
            let match_word = number_or_letter.name("letter").unwrap();
            let ch = match_word.char_indices().next().unwrap().1;
            ch_and_index.push((ch, pattern_length));
            pattern_length += 1;
        }
    }

    if ch_and_index.is_empty() {
        if length_map.contains_key(&pattern_length) {
            return length_map.get(
                &pattern_length).unwrap().iter().cloned().collect();
        } else {
            return Vec::new();
        }
    }

    let mut word_sets = Vec::new();
    for &(ch, index) in ch_and_index.iter() {
        let key = (ch, index as usize, pattern_length as usize);
        if ch_position_length_map.contains_key(&key) {
            word_sets.push(ch_position_length_map.get(&key).unwrap());
        } else {
            // There are no words of pattern_length that ch at index.
            return Vec::new();
        }
    }

    assert!(!word_sets.is_empty());
    if word_sets.len() == 1 {
        return word_sets.get(0).unwrap().iter().cloned().collect();
    }

    word_sets.sort_by(|a, b| a.len().cmp(&b.len()));
    let mut refined_word_set : HashSet<String> =
        word_sets.get(0).unwrap().intersection(
            word_sets.get(1).unwrap()).cloned().collect();

    for word_set in word_sets.iter().skip(2) {
        refined_word_set = refined_word_set.intersection(
            word_set).cloned().collect();
    }

    return refined_word_set.iter().cloned().collect();
}

fn print_matches(words : Vec<String>) {
    if words.is_empty() {
        println!("\t<No Results>");
    } else {
        let mut sorted_words : Vec<String> = words.into_iter().collect();
        sorted_words.sort();
        for word in sorted_words {
            println!("\t{}", word);
        }
    }
}

fn main() {
    let (ch_position_length_map, length_map) = load_dictionary();

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let matches = match_pattern(&line.unwrap(),
                                    &ch_position_length_map,
                                    &length_map);
        print_matches(matches);
    }
}<commit_msg>Change load_dictionary to take the word file as an argument.<commit_after>extern crate regex;

use std::ascii::AsciiExt;
use std::error::Error;
use std::fs::File;
use std::io;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;
use std::collections::HashMap;
use std::collections::HashSet;
use regex::Regex;

fn load_dictionary(dictionary_path: &Path) -> (
        HashMap<(char, usize, usize), HashSet<String>>,
        HashMap<usize, HashSet<String>>) {
    let display = dictionary_path.display();

    let file = match File::open(dictionary_path) {
        Err(why) => panic!("couldn't open {}: {}",
                           display,
                           Error::description(&why)),
        Ok(file) => file,
    };

    let mut ch_position_length_map = HashMap::new();
    let mut length_map = HashMap::new();
    let reader = BufReader::new(file);

    for readline in reader.lines() {
        let line = match readline {
            Err(why) => panic!("couldn't read from {}: {}",
                                display,
                                Error::description(&why)),
            Ok(readline) => readline,
        };

        let word = line.trim();
        for (index, ch) in word.to_ascii_lowercase().chars().enumerate() {
            let key = (ch, index, word.len());

            ch_position_length_map.entry(key).or_insert(
                HashSet::new()).insert(word.to_string());
            length_map.entry(word.len()).or_insert(
                HashSet::new()).insert(word.to_string());
        }
    }
    (ch_position_length_map, length_map)
}

fn match_pattern(pattern : &str,
         ch_position_length_map : &HashMap<(char, usize, usize), HashSet<String>>,
         length_map : &HashMap<usize, HashSet<String>>) -> Vec<String> {
    let pattern_parser = Regex::new(
        r"(?P<number>\d+)|(?P<letter>[A-Za-z])").unwrap();

    let mut pattern_length: usize = 0;
    let mut ch_and_index = Vec::new();

    for number_or_letter in pattern_parser.captures_iter(
            &pattern.to_ascii_lowercase()) {
        if number_or_letter.name("number").is_some() {
            let number_as_string = number_or_letter.name("number").unwrap();
            let number: usize = number_as_string.parse().unwrap();
            pattern_length += number;
        } else {
            let match_word = number_or_letter.name("letter").unwrap();
            let ch = match_word.char_indices().next().unwrap().1;
            ch_and_index.push((ch, pattern_length));
            pattern_length += 1;
        }
    }

    if ch_and_index.is_empty() {
        if length_map.contains_key(&pattern_length) {
            return length_map.get(
                &pattern_length).unwrap().iter().cloned().collect();
        } else {
            return Vec::new();
        }
    }

    let mut word_sets = Vec::new();
    for &(ch, index) in ch_and_index.iter() {
        let key = (ch, index as usize, pattern_length as usize);
        if ch_position_length_map.contains_key(&key) {
            word_sets.push(ch_position_length_map.get(&key).unwrap());
        } else {
            // There are no words of pattern_length that ch at index.
            return Vec::new();
        }
    }

    assert!(!word_sets.is_empty());
    if word_sets.len() == 1 {
        return word_sets.get(0).unwrap().iter().cloned().collect();
    }

    word_sets.sort_by(|a, b| a.len().cmp(&b.len()));
    let mut refined_word_set : HashSet<String> =
        word_sets.get(0).unwrap().intersection(
            word_sets.get(1).unwrap()).cloned().collect();

    for word_set in word_sets.iter().skip(2) {
        refined_word_set = refined_word_set.intersection(
            word_set).cloned().collect();
    }

    return refined_word_set.iter().cloned().collect();
}

fn print_matches(words : Vec<String>) {
    if words.is_empty() {
        println!("\t<No Results>");
    } else {
        let mut sorted_words : Vec<String> = words.into_iter().collect();
        sorted_words.sort();
        for word in sorted_words {
            println!("\t{}", word);
        }
    }
}

fn main() {
    let dictionary_path = Path::new("/usr/share/dict/words");
    let (ch_position_length_map, length_map) = load_dictionary(
        &dictionary_path);

    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let matches = match_pattern(&line.unwrap(),
                                    &ch_position_length_map,
                                    &length_map);
        print_matches(matches);
    }
}<|endoftext|>


<commit_before>use rustc::lint::*;
use syntax::ast;
use syntax::codemap::{Span, BytePos};
use utils::span_lint;

/// **What it does:** Checks for the presence of `_`, `::` or camel-case words
/// outside ticks in documentation.
///
/// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and
/// camel-case probably indicates some code which should be included between
/// ticks. `_` can also be used for empasis in markdown, this lint tries to
/// consider that.
///
/// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks
/// for is limited, and there are still false positives.
///
/// **Examples:**
/// ```rust
/// /// Do something with the foo_bar parameter. See also that::other::module::foo.
/// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
/// fn doit(foo_bar) { .. }
/// ```
declare_lint! {
    pub DOC_MARKDOWN,
    Warn,
    "presence of `_`, `::` or camel-case outside backticks in documentation"
}

#[derive(Clone)]
pub struct Doc {
    valid_idents: Vec<String>,
}

impl Doc {
    pub fn new(valid_idents: Vec<String>) -> Self {
        Doc { valid_idents: valid_idents }
    }
}

impl LintPass for Doc {
    fn get_lints(&self) -> LintArray {
        lint_array![DOC_MARKDOWN]
    }
}

impl EarlyLintPass for Doc {
    fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) {
        check_attrs(cx, &self.valid_idents, &krate.attrs);
    }

    fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) {
        check_attrs(cx, &self.valid_idents, &item.attrs);
    }
}

/// Cleanup documentation decoration (`///` and such).
///
/// We can't use `syntax::attr::AttributeMethods::with_desugared_doc` or
/// `syntax::parse::lexer::comments::strip_doc_comment_decoration` because we need to keep track of
/// the span but this function is inspired from the later.
#[allow(cast_possible_truncation)]
pub fn strip_doc_comment_decoration((comment, span): (String, Span)) -> Vec<(String, Span)> {
    // one-line comments lose their prefix
    const ONELINERS: &'static [&'static str] = &["///!", "///", "//!", "//"];
    for prefix in ONELINERS {
        if comment.starts_with(*prefix) {
            return vec![(comment[prefix.len()..].to_owned(),
                         Span { lo: span.lo + BytePos(prefix.len() as u32), ..span })];
        }
    }

    if comment.starts_with("/*") {
        return comment[3..comment.len() - 2]
            .lines()
            .map(|line| {
                let offset = line.as_ptr() as usize - comment.as_ptr() as usize;
                debug_assert_eq!(offset as u32 as usize, offset);

                (line.to_owned(), Span { lo: span.lo + BytePos(offset as u32), ..span })
            })
            .collect();
    }

    panic!("not a doc-comment: {}", comment);
}

pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute]) {
    let mut docs = vec![];

    for attr in attrs {
        if attr.is_sugared_doc {
            if let Some(ref doc) = attr.value_str() {
                let doc = doc.to_string();
                docs.extend_from_slice(&strip_doc_comment_decoration((doc, attr.span)));
            }
        }
    }

    if !docs.is_empty() {
        let _ = check_doc(cx, valid_idents, &docs);
    }
}

#[allow(while_let_loop)] // #362
fn check_doc(cx: &EarlyContext, valid_idents: &[String], docs: &[(String, Span)]) -> Result<(), ()> {
    // In markdown, `_` can be used to emphasize something, or, is a raw `_` depending on context.
    // There really is no markdown specification that would disambiguate this properly. This is
    // what GitHub and Rustdoc do:
    //
    // foo_bar test_quz    → foo_bar test_quz
    // foo_bar_baz         → foo_bar_baz (note that the “official” spec says this should be emphasized)
    // _foo bar_ test_quz_ → foo bar test_quz_
    // \_foo bar\_         → _foo bar_
    // (_baz_)             → (baz)
    // foo _ bar _ baz     → foo _ bar _ baz

    /// Character that can appear in a path
    fn is_path_char(c: char) -> bool {
        match c {
            t if t.is_alphanumeric() => true,
            ':' | '_' => true,
            _ => false,
        }
    }

    #[derive(Clone, Debug)]
    /// This type is used to iterate through the documentation characters, keeping the span at the
    /// same time.
    struct Parser<'a> {
        /// First byte of the current potential match
        current_word_begin: usize,
        /// List of lines and their associated span
        docs: &'a [(String, Span)],
        /// Index of the current line we are parsing
        line: usize,
        /// Whether we are in a link
        link: bool,
        /// Whether we are at the beginning of a line
        new_line: bool,
        /// Whether we were to the end of a line last time `next` was called
        reset: bool,
        /// The position of the current character within the current line
        pos: usize,
    }

    impl<'a> Parser<'a> {
        fn advance_begin(&mut self) {
            self.current_word_begin = self.pos;
        }

        fn line(&self) -> (&'a str, Span) {
            let (ref doc, span) = self.docs[self.line];
            (doc, span)
        }

        fn peek(&self) -> Option<char> {
            self.line().0[self.pos..].chars().next()
        }

        #[allow(while_let_on_iterator)] // borrowck complains about for
        fn jump_to(&mut self, n: char) -> Result<bool, ()> {
            while let Some((new_line, c)) = self.next() {
                if c == n {
                    self.advance_begin();
                    return Ok(new_line);
                }
            }

            Err(())
        }

        fn next_line(&mut self) {
            self.pos = 0;
            self.current_word_begin = 0;
            self.line += 1;
            self.new_line = true;
        }

        fn put_back(&mut self, c: char) {
            self.pos -= c.len_utf8();
        }

        #[allow(cast_possible_truncation)]
        fn word(&self) -> (&'a str, Span) {
            let begin = self.current_word_begin;
            let end = self.pos;

            debug_assert_eq!(end as u32 as usize, end);
            debug_assert_eq!(begin as u32 as usize, begin);

            let (doc, mut span) = self.line();
            span.hi = span.lo + BytePos(end as u32);
            span.lo = span.lo + BytePos(begin as u32);

            (&doc[begin..end], span)
        }
    }

    impl<'a> Iterator for Parser<'a> {
        type Item = (bool, char);

        fn next(&mut self) -> Option<(bool, char)> {
            if self.line < self.docs.len() {
                if self.reset {
                    self.line += 1;
                    self.reset = false;
                    self.pos = 0;
                    self.current_word_begin = 0;
                }

                let mut chars = self.line().0[self.pos..].chars();
                let c = chars.next();

                if let Some(c) = c {
                    self.pos += c.len_utf8();
                    let new_line = self.new_line;
                    self.new_line = c == '\n' || (self.new_line && c.is_whitespace());
                    Some((new_line, c))
                } else if self.line == self.docs.len() - 1 {
                    None
                } else {
                    self.new_line = true;
                    self.reset = true;
                    self.pos += 1;
                    Some((true, '\n'))
                }
            } else {
                None
            }
        }
    }

    let mut parser = Parser {
        current_word_begin: 0,
        docs: docs,
        line: 0,
        link: false,
        new_line: true,
        reset: false,
        pos: 0,
    };

    /// Check for fanced code block.
    macro_rules! check_block {
        ($parser:expr, $c:tt, $new_line:expr) => {{
            check_block!($parser, $c, $c, $new_line)
        }};

        ($parser:expr, $c:pat, $c_expr:expr, $new_line:expr) => {{
            fn check_block(parser: &mut Parser, new_line: bool) -> Result<bool, ()> {
                if new_line {
                    let mut lookup_parser = parser.clone();
                    if let (Some((false, $c)), Some((false, $c))) = (lookup_parser.next(), lookup_parser.next()) {
                        *parser = lookup_parser;
                        // 3 or more ` or ~ open a code block to be closed with the same number of ` or ~
                        let mut open_count = 3;
                        while let Some((false, $c)) = parser.next() {
                            open_count += 1;
                        }

                        loop {
                            loop {
                                if try!(parser.jump_to($c_expr)) {
                                    break;
                                }
                            }

                            lookup_parser = parser.clone();
                            let a = lookup_parser.next();
                            let b = lookup_parser.next();
                            if let (Some((false, $c)), Some((false, $c))) = (a, b) {
                                let mut close_count = 3;
                                while let Some((false, $c)) = lookup_parser.next() {
                                    close_count += 1;
                                }

                                if close_count == open_count {
                                    *parser = lookup_parser;
                                    return Ok(true);
                                }
                            }
                        }
                    }
                }

                Ok(false)
            }

            check_block(&mut $parser, $new_line)
        }};
    }

    loop {
        match parser.next() {
            Some((new_line, c)) => {
                match c {
                    '#' if new_line => {
                        // don’t warn on titles
                        parser.next_line();
                    },
                    '`' => {
                        if try!(check_block!(parser, '`', new_line)) {
                            continue;
                        }

                        // not a code block, just inline code
                        try!(parser.jump_to('`'));
                    },
                    '~' => {
                        if try!(check_block!(parser, '~', new_line)) {
                            continue;
                        }

                        // ~ does not introduce inline code, but two of them introduce
                        // strikethrough. Too bad for the consistency but we don't care about
                        // strikethrough.
                    },
                    '[' => {
                        // Check for a reference definition `[foo]:` at the beginning of a line
                        let mut link = true;

                        if new_line {
                            let mut lookup_parser = parser.clone();
                            if lookup_parser.any(|(_, c)| c == ']') {
                                if let Some((_, ':')) = lookup_parser.next() {
                                    lookup_parser.next_line();
                                    parser = lookup_parser;
                                    link = false;
                                }
                            }
                        }

                        parser.advance_begin();
                        parser.link = link;
                    },
                    ']' if parser.link => {
                        parser.link = false;

                        match parser.peek() {
                            Some('(') => {
                                try!(parser.jump_to(')'));
                            },
                            Some('[') => {
                                try!(parser.jump_to(']'));
                            },
                            Some(_) => continue,
                            None => return Err(()),
                        }
                    },
                    c if !is_path_char(c) => {
                        parser.advance_begin();
                    },
                    _ => {
                        if let Some((_, c)) = parser.find(|&(_, c)| !is_path_char(c)) {
                            parser.put_back(c);
                        }

                        let (word, span) = parser.word();
                        check_word(cx, valid_idents, word, span);
                        parser.advance_begin();
                    },
                }

            },
            None => break,
        }
    }

    Ok(())
}

fn check_word(cx: &EarlyContext, valid_idents: &[String], word: &str, span: Span) {
    /// Checks if a string a camel-case, ie. contains at least two uppercase letter (`Clippy` is
    /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded (`IDs` is ok).
    fn is_camel_case(s: &str) -> bool {
        if s.starts_with(|c: char| c.is_digit(10)) {
            return false;
        }

        let s = if s.ends_with('s') {
            &s[..s.len() - 1]
        } else {
            s
        };

        s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 &&
        s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
    }

    fn has_underscore(s: &str) -> bool {
        s != "_" && !s.contains("\\_") && s.contains('_')
    }

    // Trim punctuation as in `some comment (see foo::bar).`
    //                                                   ^^
    // Or even as in `_foo bar_` which is emphasized.
    let word = word.trim_matches(|c: char| !c.is_alphanumeric());

    if valid_idents.iter().any(|i| i == word) {
        return;
    }

    if has_underscore(word) || word.contains("::") || is_camel_case(word) {
        span_lint(cx,
                  DOC_MARKDOWN,
                  span,
                  &format!("you should put `{}` between ticks in the documentation", word));
    }
}
<commit_msg>Rewrite `doc_markdown` to use `pulldown-cmark`<commit_after>use itertools::Itertools;
use pulldown_cmark;
use rustc::lint::*;
use syntax::ast;
use syntax::codemap::{Span, BytePos};
use utils::span_lint;

/// **What it does:** Checks for the presence of `_`, `::` or camel-case words
/// outside ticks in documentation.
///
/// **Why is this bad?** *Rustdoc* supports markdown formatting, `_`, `::` and
/// camel-case probably indicates some code which should be included between
/// ticks. `_` can also be used for empasis in markdown, this lint tries to
/// consider that.
///
/// **Known problems:** Lots of bad docs won’t be fixed, what the lint checks
/// for is limited, and there are still false positives.
///
/// **Examples:**
/// ```rust
/// /// Do something with the foo_bar parameter. See also that::other::module::foo.
/// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
/// fn doit(foo_bar) { .. }
/// ```
declare_lint! {
    pub DOC_MARKDOWN,
    Warn,
    "presence of `_`, `::` or camel-case outside backticks in documentation"
}

#[derive(Clone)]
pub struct Doc {
    valid_idents: Vec<String>,
}

impl Doc {
    pub fn new(valid_idents: Vec<String>) -> Self {
        Doc { valid_idents: valid_idents }
    }
}

impl LintPass for Doc {
    fn get_lints(&self) -> LintArray {
        lint_array![DOC_MARKDOWN]
    }
}

impl EarlyLintPass for Doc {
    fn check_crate(&mut self, cx: &EarlyContext, krate: &ast::Crate) {
        check_attrs(cx, &self.valid_idents, &krate.attrs);
    }

    fn check_item(&mut self, cx: &EarlyContext, item: &ast::Item) {
        check_attrs(cx, &self.valid_idents, &item.attrs);
    }
}

struct Parser<'a> {
    parser: pulldown_cmark::Parser<'a>,
}

impl<'a> Parser<'a> {
    fn new(parser: pulldown_cmark::Parser<'a>) -> Parser<'a> {
        Self { parser }
    }
}

impl<'a> Iterator for Parser<'a> {
    type Item = (usize, pulldown_cmark::Event<'a>);

    fn next(&mut self) -> Option<Self::Item> {
        let offset = self.parser.get_offset();
        self.parser.next().map(|event| (offset, event))
    }
}

/// Cleanup documentation decoration (`///` and such).
///
/// We can't use `syntax::attr::AttributeMethods::with_desugared_doc` or
/// `syntax::parse::lexer::comments::strip_doc_comment_decoration` because we need to keep track of
/// the spans but this function is inspired from the later.
#[allow(cast_possible_truncation)]
pub fn strip_doc_comment_decoration(comment: String, span: Span) -> (String, Vec<(usize, Span)>) {
    // one-line comments lose their prefix
    const ONELINERS: &'static [&'static str] = &["///!", "///", "//!", "//"];
    for prefix in ONELINERS {
        if comment.starts_with(*prefix) {
            let doc = &comment[prefix.len()..];
            let mut doc = doc.to_owned();
            doc.push('\n');
            return (
                doc.to_owned(),
                vec![(doc.len(), Span { lo: span.lo + BytePos(prefix.len() as u32), ..span })]
            );
        }
    }

    if comment.starts_with("/*") {
        let doc = &comment[3..comment.len() - 2];
        let mut sizes = vec![];

        for line in doc.lines() {
            let offset = line.as_ptr() as usize - comment.as_ptr() as usize;
            debug_assert_eq!(offset as u32 as usize, offset);

            sizes.push((line.len(), Span { lo: span.lo + BytePos(offset as u32), ..span }));
        }

        return (doc.to_string(), sizes);
    }

    panic!("not a doc-comment: {}", comment);
}

pub fn check_attrs<'a>(cx: &EarlyContext, valid_idents: &[String], attrs: &'a [ast::Attribute]) {
    let mut doc = String::new();
    let mut spans = vec![];

    for attr in attrs {
        if attr.is_sugared_doc {
            if let Some(ref current) = attr.value_str() {
                let current = current.to_string();
                let (current, current_spans) = strip_doc_comment_decoration(current, attr.span);
                spans.extend_from_slice(&current_spans);
                doc.push_str(&current);
            }
        }
    }

    let mut current = 0;
    for &mut (ref mut offset, _) in &mut spans {
        let offset_copy = *offset;
        *offset = current;
        current += offset_copy;
    }

    println!("{:?}", spans);
    if !doc.is_empty() {
        let parser = Parser::new(pulldown_cmark::Parser::new(&doc));
        let parser = parser.coalesce(|x, y| {
            use pulldown_cmark::Event::*;

            let x_offset = x.0;
            let y_offset = y.0;

            match (x.1, y.1) {
                (Text(x), Text(y)) => Ok((x_offset, Text((x.into_owned() + &y).into()))),
                (x, y) => Err(((x_offset, x), (y_offset, y))),
            }
        });
        check_doc(cx, valid_idents, parser, &spans);
    }
}

fn check_doc<'a, Events: Iterator<Item=(usize, pulldown_cmark::Event<'a>)>>(
    cx: &EarlyContext,
    valid_idents: &[String],
    docs: Events,
    spans: &[(usize, Span)]
) {
    use pulldown_cmark::Event::*;
    use pulldown_cmark::Tag::*;

    let mut in_code = false;

    for (offset, event) in docs {
        println!("{:?}, {:?}", offset, event);
        match event {
            Start(CodeBlock(_)) | Start(Code) => in_code = true,
            End(CodeBlock(_)) | End(Code) => in_code = false,
            Start(_tag) | End(_tag) => (), // We don't care about other tags
            Html(_html) | InlineHtml(_html) => (), // HTML is weird, just ignore it
            FootnoteReference(footnote) => (), // TODO
            SoftBreak => (),
            HardBreak => (),
            Text(text) => {
                if !in_code {
                    let index = match spans.binary_search_by(|c| c.0.cmp(&offset)) {
                        Ok(o) => o,
                        Err(e) => e-1,
                    };

                    let (_, span) = spans[index];
                    check_text(cx, valid_idents, &text, span);
                }
            },
        }
    }
}

fn check_text(cx: &EarlyContext, valid_idents: &[String], text: &str, span: Span) {
    for word in text.split_whitespace() {
        // Trim punctuation as in `some comment (see foo::bar).`
        //                                                   ^^
        // Or even as in `_foo bar_` which is emphasized.
        let word = word.trim_matches(|c: char| !c.is_alphanumeric());

        if valid_idents.iter().any(|i| i == word) {
            continue;
        }

        check_word(cx, word, span);
    }
}

fn check_word(cx: &EarlyContext, word: &str, span: Span) {
    /// Checks if a string is camel-case, ie. contains at least two uppercase letter (`Clippy` is
    /// ok) and one lower-case letter (`NASA` is ok). Plural are also excluded (`IDs` is ok).
    fn is_camel_case(s: &str) -> bool {
        if s.starts_with(|c: char| c.is_digit(10)) {
            return false;
        }

        let s = if s.ends_with('s') {
            &s[..s.len() - 1]
        } else {
            s
        };

        s.chars().all(char::is_alphanumeric) && s.chars().filter(|&c| c.is_uppercase()).take(2).count() > 1 &&
        s.chars().filter(|&c| c.is_lowercase()).take(1).count() > 0
    }

    fn has_underscore(s: &str) -> bool {
        s != "_" && !s.contains("\\_") && s.contains('_')
    }

    if has_underscore(word) || word.contains("::") || is_camel_case(word) {
        span_lint(cx,
                  DOC_MARKDOWN,
                  span,
                  &format!("you should put `{}` between ticks in the documentation", word));
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use anyhow::{Context, Result};

use pueue_lib::settings::Settings;

/// From 0.12.2 on, we aim to have full backward compatibility.
/// For this reason, an old v0.12.2 serialized state has been checked in.
///
/// We have to be able to restore from that state at all costs.
/// Everything else results in a breaking change and needs a major version change.
///
/// On top of simply having an old state, I also added a few non-existing fields.
/// This should be handled as well.
#[test]
fn test_restore_from_old_state() -> Result<()> {
    better_panic::install();
    let old_settings_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("data")
        .join("v0.15.0_settings.yml");

    // Open v0.12.2 file and write old state to it.
    let _: Settings = Settings::read_with_defaults(true, &Some(old_settings_path))
        .context("Failed to read old config with defaults:")?;

    Ok(())
}
<commit_msg>docs: Fix docstring for backward compatibility test<commit_after>use std::path::PathBuf;

use anyhow::{Context, Result};

use pueue_lib::settings::Settings;

/// From 0.15.0 on, we aim to have full backward compatibility.
/// For this reason, an old (slightly modified) v0.15.0 serialized state
/// has been checked in.
///
/// We have to be able to restore from that state at all costs.
/// Everything else results in a breaking change and needs a major version change.
///
/// On top of simply having an old state, I also added a few non-existing fields.
/// This should be handled as well.
#[test]
fn test_restore_from_old_state() -> Result<()> {
    better_panic::install();
    let old_settings_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("tests")
        .join("data")
        .join("v0.15.0_settings.yml");

    // Open v0.12.2 file and write old state to it.
    let _: Settings = Settings::read_with_defaults(true, &Some(old_settings_path))
        .context("Failed to read old config with defaults:")?;

    Ok(())
}
<|endoftext|>


<commit_before>extern crate eventual;

use self::eventual::{Complete, Future};

use std::any::Any;
use std::sync::{Arc, Mutex};

use actors::{ActorContext, InnerMessage, Message, SystemMessage};
use actors::actor_cell::ActorCell;
use actors::cthulhu::Cthulhu;

#[derive(Debug, Eq, Hash, PartialEq)]
/// Path to an actor.
///
/// This enum contains the information for actors whether they are local or distant.
pub enum ActorPath {
    /// Logical path to a local actor.
    Local(String),
    /// Logical path and connection information for a distant actor.
    Distant(ConnectionInfo),
}

impl ActorPath {
    /// Creates a new local ActorPath variant with the given logical_path.
    pub fn new_local(path: String) -> Arc<ActorPath> {
        Arc::new(ActorPath::Local(path))
    }

    /// Gives a reference to the logical path of an actor.
    ///
    /// Note that this gives the local logical path whether the actor is local or not.
    pub fn logical_path(&self) -> &String {
        match *self {
            ActorPath::Local(ref s) => s,
            ActorPath::Distant(ref c) => &(c.distant_logical_path),
        }
    }

    /// Creates an ActirPath for a child of an actor.
    ///
    /// This gives a Local variant, because actors are always created locally.
    pub fn child(&self, name: String) -> Arc<ActorPath> {
        match *self {
            ActorPath::Local(ref s) => {
                let path = format!("{}/{}", s, name);
                ActorPath::new_local(path)
            },
            ActorPath::Distant(_) => panic!("Cannot create a child for a distant actor."),
        }
    }
}

#[derive(Debug, Eq, Hash, PartialEq)]
/// This gives connection informations on how to get to the distant actors.
///
/// *  The distant_logical_path is something like "/user/distant/actor".
/// *  The addr_port is something like "127.0.0.1:12345"
///
/// Note that the storage of the addr_port could be improved, but is not a concern for now.
pub struct ConnectionInfo {
    distant_logical_path: String,
    addr_port: String,
}

#[derive(Clone)]
enum InnerActor {
    Cthulhu(Cthulhu),
    Actor(ActorCell),
    Complete(CompleteRef),
}

#[derive(Clone)]
struct CompleteRef {
    complete: Arc<Mutex<Option<Complete<Box<Any + Send>, &'static str>>>>,
}

impl CompleteRef {
    fn new(complete: Complete<Box<Any + Send>, &'static str>) -> CompleteRef {
        CompleteRef {
            complete: Arc::new(Mutex::new(Some(complete))),
        }
    }

    fn complete(&self, message: InnerMessage) {
        match message {
            InnerMessage::Message(data) => {
                let mut guard = self.complete.lock().unwrap();
                let complete = guard.take();
                *guard = None;
                match complete {
                    Some(complete) => complete.complete(data),
                    None => println!("Tried to send more than one message to a Complete"),
                }
            },
            _ => panic!("Send a weird inner message to a future, this is a bug.")
        }
    }
}

/// An `ActorRef` is the way used to interract with something that acts as an actor.
///
/// This can represent either an ACtor, a Future or Cthulhu (the original actor) whether distant or
/// local.
///
/// It gives the Actor API, it can receive messages, be told to send messages, be asked something
/// and give its ActorPath.
pub struct ActorRef {
    inner_actor: Option<InnerActor>,
    path: Arc<ActorPath>,
}

impl ActorRef {
    /// Creates a new ActorRef to a distant actor, with the given ActorPath.
    pub fn new_distant(path: Arc<ActorPath>) -> ActorRef {
        ActorRef {
            inner_actor: None,
            path: path,
        }
    }

    /// Creates a new ActorRef to Cthulhu, this should only be called once.
    pub fn with_cthulhu(cthulhu: Cthulhu) -> ActorRef {
        let path = ActorPath::new_local("/".to_owned());
        ActorRef {
            inner_actor: Some(InnerActor::Cthulhu(cthulhu)),
            path: path,
        }
    }

    /// Creates a new ActorRef for a local Actor, with the given ActorCell.
    pub fn with_cell(cell: ActorCell, path: Arc<ActorPath>) -> ActorRef {
        ActorRef {
            inner_actor: Some(InnerActor::Actor(cell)),
            path: path,
        }
    }

    /// Creates a new ActorRef to a local Future, with the given `Complete` (a C`omplete` is what is
    /// used to complete a `Future`).
    pub fn with_complete(complete: Complete<Box<Any + Send>, &'static str>) -> ActorRef {
        ActorRef {
            inner_actor: Some(InnerActor::Complete(CompleteRef::new(complete))),
            // FIXME(gamazeps) future registration is not working here, this is not cool.
            path: ActorPath::new_local("local_future".to_owned()),
        }
    }

    /// Receives a system message such as `Start`, `Restart` or a `Failure(ActorRef)`, puts it in
    /// the system mailbox and schedules the actor if needed.
    pub fn receive_system_message(&self, system_message: SystemMessage) {
        let inner = self.inner_actor.as_ref().expect("Tried to put a system message in the mailbox of a distant actor.");
        match *inner {
            InnerActor::Complete(_) => panic!("Futures should not receive system messages."),
            InnerActor::Actor(ref actor) => actor.receive_system_message(system_message),
            InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive_system_message(),
        };
    }

    /// Receives a regular message and puts it in the mailbox and schedules the actor if needed.
    pub fn receive(&self, message: InnerMessage, sender: ActorRef) {
        let inner = self.inner_actor.as_ref().expect("Tried to put a message in the mailbox of a distant actor.");
        match *inner {
            InnerActor::Complete(ref complete) => complete.complete(message),
            InnerActor::Actor(ref actor) => actor.receive_message(message, sender),
            InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive(),
        };
    }

    /// Handles a messages by calling the `receive` method of the underlying actor.
    pub fn handle(&self) {
        let inner = self.inner_actor.as_ref().expect("");
        match *inner {
            InnerActor::Complete(_) => panic!("In the current model futures should not handle messages."),
            InnerActor::Actor(ref actor) => actor.handle_envelope(),
            InnerActor::Cthulhu(ref cthulhu) => cthulhu.handle(),
        };
    }

    /// Gives a clone of the ActorPath.
    pub fn path(&self) -> Arc<ActorPath> {
        self.path.clone()
    }

    /// Makes this ActorRef send a message to anther ActorRef.
    pub fn tell_to<MessageTo: Message>(&self, to: ActorRef, message: MessageTo) {
        let inner = self.inner_actor.as_ref().expect("");
        match *inner {
            InnerActor::Complete(_) => panic!("A future should not be sending a message to an actor this way."),
            InnerActor::Actor(_) => {
                // This is done in order to avoid a trivial cast warning.
                let message: Box<Any + Send> = Box::new(message);
                to.receive(InnerMessage::Message(message), self.clone())
            },
            InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive(),
        };
    }

    /// Sends a message to an ActorRef, the answer to this message will be put in the `Future` given
    /// as return value.
    pub fn ask<MessageTo: Message>(&self, message: MessageTo)
        -> Future<Box<Any + Send>, &'static str> {
        let (complete, future) = Future::<Box<Any + Send>, &'static str>::pair();
        // This is done in order to avoid a trivial cast warning.
        let message: Box<Any + Send> = Box::new(message);
        self.receive(InnerMessage::Message(message), ActorRef::with_complete(complete));
        future
    }
}

impl Clone for ActorRef {
    fn clone(&self) -> ActorRef {
        ActorRef {
            inner_actor: self.inner_actor.clone(),
            path: self.path.clone(),
        }
    }
}
<commit_msg>Fix typo in documentation.<commit_after>extern crate eventual;

use self::eventual::{Complete, Future};

use std::any::Any;
use std::sync::{Arc, Mutex};

use actors::{ActorContext, InnerMessage, Message, SystemMessage};
use actors::actor_cell::ActorCell;
use actors::cthulhu::Cthulhu;

#[derive(Debug, Eq, Hash, PartialEq)]
/// Path to an actor.
///
/// This enum contains the information for actors whether they are local or distant.
pub enum ActorPath {
    /// Logical path to a local actor.
    Local(String),
    /// Logical path and connection information for a distant actor.
    Distant(ConnectionInfo),
}

impl ActorPath {
    /// Creates a new local ActorPath variant with the given logical_path.
    pub fn new_local(path: String) -> Arc<ActorPath> {
        Arc::new(ActorPath::Local(path))
    }

    /// Gives a reference to the logical path of an actor.
    ///
    /// Note that this gives the local logical path whether the actor is local or not.
    pub fn logical_path(&self) -> &String {
        match *self {
            ActorPath::Local(ref s) => s,
            ActorPath::Distant(ref c) => &(c.distant_logical_path),
        }
    }

    /// Creates an ActorPath for a child of an actor.
    ///
    /// This gives a Local variant, because actors are always created locally.
    pub fn child(&self, name: String) -> Arc<ActorPath> {
        match *self {
            ActorPath::Local(ref s) => {
                let path = format!("{}/{}", s, name);
                ActorPath::new_local(path)
            },
            ActorPath::Distant(_) => panic!("Cannot create a child for a distant actor."),
        }
    }
}

#[derive(Debug, Eq, Hash, PartialEq)]
/// This gives connection informations on how to get to the distant actors.
///
/// *  The distant_logical_path is something like "/user/distant/actor".
/// *  The addr_port is something like "127.0.0.1:12345"
///
/// Note that the storage of the addr_port could be improved, but is not a concern for now.
pub struct ConnectionInfo {
    distant_logical_path: String,
    addr_port: String,
}

#[derive(Clone)]
enum InnerActor {
    Cthulhu(Cthulhu),
    Actor(ActorCell),
    Complete(CompleteRef),
}

#[derive(Clone)]
struct CompleteRef {
    complete: Arc<Mutex<Option<Complete<Box<Any + Send>, &'static str>>>>,
}

impl CompleteRef {
    fn new(complete: Complete<Box<Any + Send>, &'static str>) -> CompleteRef {
        CompleteRef {
            complete: Arc::new(Mutex::new(Some(complete))),
        }
    }

    fn complete(&self, message: InnerMessage) {
        match message {
            InnerMessage::Message(data) => {
                let mut guard = self.complete.lock().unwrap();
                let complete = guard.take();
                *guard = None;
                match complete {
                    Some(complete) => complete.complete(data),
                    None => println!("Tried to send more than one message to a Complete"),
                }
            },
            _ => panic!("Send a weird inner message to a future, this is a bug.")
        }
    }
}

/// An `ActorRef` is the way used to interract with something that acts as an actor.
///
/// This can represent either an ACtor, a Future or Cthulhu (the original actor) whether distant or
/// local.
///
/// It gives the Actor API, it can receive messages, be told to send messages, be asked something
/// and give its ActorPath.
pub struct ActorRef {
    inner_actor: Option<InnerActor>,
    path: Arc<ActorPath>,
}

impl ActorRef {
    /// Creates a new ActorRef to a distant actor, with the given ActorPath.
    pub fn new_distant(path: Arc<ActorPath>) -> ActorRef {
        ActorRef {
            inner_actor: None,
            path: path,
        }
    }

    /// Creates a new ActorRef to Cthulhu, this should only be called once.
    pub fn with_cthulhu(cthulhu: Cthulhu) -> ActorRef {
        let path = ActorPath::new_local("/".to_owned());
        ActorRef {
            inner_actor: Some(InnerActor::Cthulhu(cthulhu)),
            path: path,
        }
    }

    /// Creates a new ActorRef for a local Actor, with the given ActorCell.
    pub fn with_cell(cell: ActorCell, path: Arc<ActorPath>) -> ActorRef {
        ActorRef {
            inner_actor: Some(InnerActor::Actor(cell)),
            path: path,
        }
    }

    /// Creates a new ActorRef to a local Future, with the given `Complete` (a C`omplete` is what is
    /// used to complete a `Future`).
    pub fn with_complete(complete: Complete<Box<Any + Send>, &'static str>) -> ActorRef {
        ActorRef {
            inner_actor: Some(InnerActor::Complete(CompleteRef::new(complete))),
            // FIXME(gamazeps) future registration is not working here, this is not cool.
            path: ActorPath::new_local("local_future".to_owned()),
        }
    }

    /// Receives a system message such as `Start`, `Restart` or a `Failure(ActorRef)`, puts it in
    /// the system mailbox and schedules the actor if needed.
    pub fn receive_system_message(&self, system_message: SystemMessage) {
        let inner = self.inner_actor.as_ref().expect("Tried to put a system message in the mailbox of a distant actor.");
        match *inner {
            InnerActor::Complete(_) => panic!("Futures should not receive system messages."),
            InnerActor::Actor(ref actor) => actor.receive_system_message(system_message),
            InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive_system_message(),
        };
    }

    /// Receives a regular message and puts it in the mailbox and schedules the actor if needed.
    pub fn receive(&self, message: InnerMessage, sender: ActorRef) {
        let inner = self.inner_actor.as_ref().expect("Tried to put a message in the mailbox of a distant actor.");
        match *inner {
            InnerActor::Complete(ref complete) => complete.complete(message),
            InnerActor::Actor(ref actor) => actor.receive_message(message, sender),
            InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive(),
        };
    }

    /// Handles a messages by calling the `receive` method of the underlying actor.
    pub fn handle(&self) {
        let inner = self.inner_actor.as_ref().expect("");
        match *inner {
            InnerActor::Complete(_) => panic!("In the current model futures should not handle messages."),
            InnerActor::Actor(ref actor) => actor.handle_envelope(),
            InnerActor::Cthulhu(ref cthulhu) => cthulhu.handle(),
        };
    }

    /// Gives a clone of the ActorPath.
    pub fn path(&self) -> Arc<ActorPath> {
        self.path.clone()
    }

    /// Makes this ActorRef send a message to anther ActorRef.
    pub fn tell_to<MessageTo: Message>(&self, to: ActorRef, message: MessageTo) {
        let inner = self.inner_actor.as_ref().expect("");
        match *inner {
            InnerActor::Complete(_) => panic!("A future should not be sending a message to an actor this way."),
            InnerActor::Actor(_) => {
                // This is done in order to avoid a trivial cast warning.
                let message: Box<Any + Send> = Box::new(message);
                to.receive(InnerMessage::Message(message), self.clone())
            },
            InnerActor::Cthulhu(ref cthulhu) => cthulhu.receive(),
        };
    }

    /// Sends a message to an ActorRef, the answer to this message will be put in the `Future` given
    /// as return value.
    pub fn ask<MessageTo: Message>(&self, message: MessageTo)
        -> Future<Box<Any + Send>, &'static str> {
        let (complete, future) = Future::<Box<Any + Send>, &'static str>::pair();
        // This is done in order to avoid a trivial cast warning.
        let message: Box<Any + Send> = Box::new(message);
        self.receive(InnerMessage::Message(message), ActorRef::with_complete(complete));
        future
    }
}

impl Clone for ActorRef {
    fn clone(&self) -> ActorRef {
        ActorRef {
            inner_actor: self.inner_actor.clone(),
            path: self.path.clone(),
        }
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::RWLock;

pub use entry::Entry;
pub use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;

pub struct Store {
    location: PathBuf,
}

impl Store {

    pub fn create(entry: Entry) -> Result<()> {
        unimplemented!()
    }

    pub fn read(path: PathBuf) -> Result<Arc<RWLock<Entry>>> {
        unimplemented!()
    }

    pub fn update(entry: Arc<RWLock<Entry>>) -> Result<()> {
        unimplemented!()
    }

    pub fn delete(path: PathBuf) -> Result<()> {
        unimplemented!()
    }

}

<commit_msg>Add store-internal cache<commit_after>use std::collections::HashMap;
use std::fs::File;
use std::path::PathBuf;
use std::result::Result as RResult;
use std::sync::Arc;
use std::sync::RWLock;

pub use entry::Entry;
pub use error::StoreError;

pub type Result<T> = RResult<T, StoreError>;

pub struct Store {
    location: PathBuf,

    /**
     * Internal Path->File cache map
     *
     * Caches the files, so they remain flock()ed
     *
     * Could be optimized for a threadsafe HashMap
     */
    cache: Arc<RWLock<HashMap<PathBuf, File>>>,
}

impl Store {

    pub fn create(entry: Entry) -> Result<()> {
        unimplemented!()
    }

    pub fn read(path: PathBuf) -> Result<Arc<RWLock<Entry>>> {
        unimplemented!()
    }

    pub fn update(entry: Arc<RWLock<Entry>>) -> Result<()> {
        unimplemented!()
    }

    pub fn delete(path: PathBuf) -> Result<()> {
        unimplemented!()
    }

}

<|endoftext|>


<commit_before>//! OS-specific functionality.

#![stable(feature = "os", since = "1.0.0")]
#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]

// When documenting libstd we want to show unix/windows/linux/wasi modules as these are the "main
// modules" that are used across platforms, so all modules are enabled when `cfg(doc)` is set.
// This should help show platform-specific functionality in a hopefully cross-platform way in the
// documentation.
// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make
// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038

#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::unix_ext as unix;

#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::windows_ext as windows;

#[cfg(doc)]
#[doc(cfg(target_os = "linux"))]
pub mod linux;

#[cfg(doc)]
#[stable(feature = "wasi_ext_doc", since = "1.35.0")]
pub use crate::sys::wasi_ext as wasi;

// If we're not documenting libstd then we just expose the main modules as we otherwise would.

#[cfg(not(doc))]
#[cfg(any(target_os = "redox", unix, target_os = "vxworks", target_os = "hermit"))]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::ext as unix;

#[cfg(not(doc))]
#[cfg(windows)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::ext as windows;

#[cfg(not(doc))]
#[cfg(any(target_os = "linux", target_os = "l4re"))]
pub mod linux;

#[cfg(not(doc))]
#[cfg(target_os = "wasi")]
pub mod wasi;

#[cfg(target_os = "android")]
pub mod android;
#[cfg(target_os = "dragonfly")]
pub mod dragonfly;
#[cfg(target_os = "emscripten")]
pub mod emscripten;
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
pub mod fortanix_sgx;
#[cfg(target_os = "freebsd")]
pub mod freebsd;
#[cfg(target_os = "fuchsia")]
pub mod fuchsia;
#[cfg(target_os = "haiku")]
pub mod haiku;
#[cfg(target_os = "illumos")]
pub mod illumos;
#[cfg(target_os = "ios")]
pub mod ios;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "netbsd")]
pub mod netbsd;
#[cfg(target_os = "openbsd")]
pub mod openbsd;
#[cfg(target_os = "redox")]
pub mod redox;
#[cfg(target_os = "solaris")]
pub mod solaris;
#[cfg(target_os = "vxworks")]
pub mod vxworks;

pub mod raw;
<commit_msg>Rollup merge of #82712 - CDirkx:cfg-target_os, r=dtolnay<commit_after>//! OS-specific functionality.

#![stable(feature = "os", since = "1.0.0")]
#![allow(missing_docs, nonstandard_style, missing_debug_implementations)]

// When documenting libstd we want to show unix/windows/linux/wasi modules as these are the "main
// modules" that are used across platforms, so all modules are enabled when `cfg(doc)` is set.
// This should help show platform-specific functionality in a hopefully cross-platform way in the
// documentation.
// Note that we deliberately avoid `cfg_if!` here to work around a rust-analyzer bug that would make
// `std::os` submodules unusable: https://github.com/rust-analyzer/rust-analyzer/issues/6038

#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::unix_ext as unix;

#[cfg(doc)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::windows_ext as windows;

#[cfg(doc)]
#[doc(cfg(target_os = "linux"))]
pub mod linux;

#[cfg(doc)]
#[stable(feature = "wasi_ext_doc", since = "1.35.0")]
pub use crate::sys::wasi_ext as wasi;

// If we're not documenting libstd then we just expose the main modules as we otherwise would.

#[cfg(not(doc))]
#[cfg(any(unix, target_os = "hermit"))]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::ext as unix;

#[cfg(not(doc))]
#[cfg(windows)]
#[stable(feature = "rust1", since = "1.0.0")]
pub use crate::sys::ext as windows;

#[cfg(not(doc))]
#[cfg(any(target_os = "linux", target_os = "l4re"))]
pub mod linux;

#[cfg(not(doc))]
#[cfg(target_os = "wasi")]
pub mod wasi;

#[cfg(target_os = "android")]
pub mod android;
#[cfg(target_os = "dragonfly")]
pub mod dragonfly;
#[cfg(target_os = "emscripten")]
pub mod emscripten;
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
pub mod fortanix_sgx;
#[cfg(target_os = "freebsd")]
pub mod freebsd;
#[cfg(target_os = "fuchsia")]
pub mod fuchsia;
#[cfg(target_os = "haiku")]
pub mod haiku;
#[cfg(target_os = "illumos")]
pub mod illumos;
#[cfg(target_os = "ios")]
pub mod ios;
#[cfg(target_os = "macos")]
pub mod macos;
#[cfg(target_os = "netbsd")]
pub mod netbsd;
#[cfg(target_os = "openbsd")]
pub mod openbsd;
#[cfg(target_os = "redox")]
pub mod redox;
#[cfg(target_os = "solaris")]
pub mod solaris;
#[cfg(target_os = "vxworks")]
pub mod vxworks;

pub mod raw;
<|endoftext|>


<commit_before><commit_msg>format: Improve muxer tests<commit_after><|endoftext|>


<commit_before>use std::ffi::CString;
use std::mem::size_of;
use std::os::raw::c_void;
use std::ptr;

use gl;
use gltf;
use gltf::mesh::Indices;

use render::math::*;
use shader::Shader;

#[repr(C)]
#[derive(Debug)]
pub struct Vertex {
    pub position: Vector3,
    pub normal: Vector3,
    pub tangent: Vector4,
    pub tex_coord_0: Vector2,
    pub tex_coord_1: Vector2,
    pub color_0: Vector3,
    // TODO!
    // pub joints_0: Vector4,
    // pub weights_0: Vector4,
}

impl Default for Vertex {
    fn default() -> Self {
        Vertex {
            position: Vector3::zero(),
            normal: Vector3::zero(),
            tangent: Vector4::zero(),
            tex_coord_0: Vector2::zero(),
            tex_coord_1: Vector2::zero(),
            color_0: Vector3::zero(),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Texture {
    pub id: u32,
    pub type_: String,
    pub path: String,
}

pub struct Primitive {
    /*  Mesh Data  */
    pub vertices: Vec<Vertex>,
    pub indices: Vec<u32>,
    pub textures: Vec<Texture>,
    pub vao: u32,

    /*  Render data  */
    vbo: u32,
    ebo: u32,

    // TODO: material, mode, targets
}

impl Primitive {
    pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>) -> Primitive {
        let mut prim = Primitive {
            vertices, indices, textures,
            vao: 0, vbo: 0, ebo: 0
        };

        // now that we have all the required data, set the vertex buffers and its attribute pointers.
        unsafe { prim.setup_primitive() }
        prim
    }

    pub fn from_gltf(g_primitive: gltf::mesh::Primitive) -> Primitive {
        let positions = g_primitive.position().unwrap();
        let normals = g_primitive.normal()
            .expect("NotImplementedYet: Normals required! Calculation of flat normals not implemented yet.");

        let mut tangents = g_primitive.tangent();
        // let mut tex_coords_0 = g_primitive.tex_coord(0);
        // let mut tex_coords_1 = g_primitive.tex_coord(1);
        // let mut colors_0 = g_primitive.color(0);

        let indices = g_primitive.indices().expect("NotImplementedYet: Indices required at the moment!");

        let vertices: Vec<Vertex> = positions
            .zip(normals)
            .map(|(position, normal)| {
                let tangent = match tangents {
                    Some(ref mut tangents) => Vector4::from(tangents.next()
                        .expect("Not enough tangents! Expected 1 per vertex.")),
                    None => Vector4::zero()
                };
                // TODO!!!: tex coord types...8/16/32
                // let tex_coord_0 = match tex_coords_0 {
                //     Some(ref mut tex_coord_0) => Vector2::from(tex_coord_0.next()
                //         .expect("Not enough tex_coords_0! Expected 1 per vertex.")),
                //     None => Vector2::zero()
                // };
                // let tex_coord_1 = match tex_coords_1 {
                //     Some(ref mut tex_coord_1) => Vector2::from(tex_coord_1.next()
                //         .expect("Not enough tex_coords_1! Expected 1 per vertex.")),
                //     None => Vector2::zero()
                // };

                // TODO!!!: Color Types...
                // let color_0 = match colors_0 {
                //     Some(ref mut colors_0) => Vector3::from(colors_0.next()
                //         .expect("Not enough color_0 entries! Expected 1 per vertex.")),
                //     None => Vector3::zero()
                // };
                Vertex {
                    position: Vector3::from(position),
                    normal: Vector3::from(normal),
                    tangent: tangent,
                    // tex_coord_0: tex_coord_0,
                    // tex_coord_1: tex_coord_1,
                    // color_0: color_0,
                    ..Vertex::default()
                }
            })
            .collect();

        // convert indices to u32 if necessary
        let indices: Vec<u32> = match indices {
            Indices::U8(indices) => indices.map(|i| i as u32).collect(),
            Indices::U16(indices) => indices.map(|i| i as u32).collect(),
            Indices::U32(indices) => indices.collect(),
        };

        // TODO: No debug
        // assert_eq!(primitive.mode(), Mode::Triangles);

        // TODO!!: textures
        let textures = Vec::new();
        Primitive::new(vertices, indices, textures)
    }

    /// render the mesh
    pub unsafe fn draw(&self, shader: &Shader) {
        // bind appropriate textures
        let mut diffuse_nr  = 0;
        let mut specular_nr = 0;
        let mut normal_nr   = 0;
        let mut height_nr   = 0;
        for (i, texture) in self.textures.iter().enumerate() {
            gl::ActiveTexture(gl::TEXTURE0 + i as u32); // active proper texture unit before binding
            // retrieve texture number (the N in diffuse_textureN)
            let name = &texture.type_;
            let number = match name.as_str() {
                "texture_diffuse" => {
                    diffuse_nr += 1;
                    diffuse_nr
                },
                "texture_specular" => {
                    specular_nr += 1;
                    specular_nr
                }
                "texture_normal" => {
                    normal_nr += 1;
                    normal_nr
                }
                "texture_height" => {
                    height_nr += 1;
                    height_nr
                }
                _ => panic!("unknown texture type")
            };
            // now set the sampler to the correct texture unit
            let sampler = CString::new(format!("{}{}", name, number)).unwrap();
            gl::Uniform1i(gl::GetUniformLocation(shader.id, sampler.as_ptr()), i as i32);
            // and finally bind the texture
            gl::BindTexture(gl::TEXTURE_2D, texture.id);
        }

        // draw mesh
        gl::BindVertexArray(self.vao);
        gl::DrawElements(gl::TRIANGLES, self.indices.len() as i32, gl::UNSIGNED_INT, ptr::null());
        gl::BindVertexArray(0);

        // always good practice to set everything back to defaults once configured.
        gl::ActiveTexture(gl::TEXTURE0);
    }

    unsafe fn setup_primitive(&mut self) {
        // create buffers/arrays
        gl::GenVertexArrays(1, &mut self.vao);
        gl::GenBuffers(1, &mut self.vbo);
        gl::GenBuffers(1, &mut self.ebo);

        gl::BindVertexArray(self.vao);
        // load data into vertex buffers
        gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
        // A great thing about structs with repr(C) is that their memory layout is sequential for all its items.
        // The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which
        // again translates to 3/2 floats which translates to a byte array.
        let size = (self.vertices.len() * size_of::<Vertex>()) as isize;
        let data = &self.vertices[0] as *const Vertex as *const c_void;
        gl::BufferData(gl::ARRAY_BUFFER, size, data, gl::STATIC_DRAW);

        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);
        let size = (self.indices.len() * size_of::<u32>()) as isize;
        let data = &self.indices[0] as *const u32 as *const c_void;
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, size, data, gl::STATIC_DRAW);

        // set the vertex attribute pointers
        // TODO!!: adapt to new Vertex struct
        let size = size_of::<Vertex>() as i32;
        // vertex positions
        gl::EnableVertexAttribArray(0);
        gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, position) as *const c_void);
        // vertex normals
        gl::EnableVertexAttribArray(1);
        gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, normal) as *const c_void);
        // vertex texture coords
        gl::EnableVertexAttribArray(2);
        gl::VertexAttribPointer(2, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tex_coord_0) as *const c_void);
        // vertex tangent
        gl::EnableVertexAttribArray(3);
        gl::VertexAttribPointer(3, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tangent) as *const c_void);
        // vertex bitangent
        // gl::EnableVertexAttribArray(4);
        // gl::VertexAttribPointer(4, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, bitangent) as *const c_void);

        gl::BindVertexArray(0);
    }
}
<commit_msg>very basic parsing of tex coords, colors<commit_after>use std::ffi::CString;
use std::mem::size_of;
use std::os::raw::c_void;
use std::ptr;

use gl;
use gltf;
use gltf::mesh::{ Indices, TexCoord, Color };

use render::math::*;
use shader::Shader;

#[repr(C)]
#[derive(Debug)]
pub struct Vertex {
    pub position: Vector3,
    pub normal: Vector3,
    pub tangent: Vector4,
    pub tex_coord_0: Vector2,
    pub tex_coord_1: Vector2,
    pub color_0: Vector3, // TODO: vec4 support
    // TODO!
    // pub joints_0: Vector4,
    // pub weights_0: Vector4,
}

impl Default for Vertex {
    fn default() -> Self {
        Vertex {
            position: Vector3::zero(),
            normal: Vector3::zero(),
            tangent: Vector4::zero(),
            tex_coord_0: Vector2::zero(),
            tex_coord_1: Vector2::zero(),
            color_0: Vector3::zero(),
        }
    }
}

#[derive(Clone, Debug)]
pub struct Texture {
    pub id: u32,
    pub type_: String,
    pub path: String,
}

pub struct Primitive {
    /*  Mesh Data  */
    pub vertices: Vec<Vertex>,
    pub indices: Vec<u32>,
    pub textures: Vec<Texture>,
    pub vao: u32,

    /*  Render data  */
    vbo: u32,
    ebo: u32,

    // TODO: material, mode, targets
}

impl Primitive {
    pub fn new(vertices: Vec<Vertex>, indices: Vec<u32>, textures: Vec<Texture>) -> Primitive {
        let mut prim = Primitive {
            vertices, indices, textures,
            vao: 0, vbo: 0, ebo: 0
        };

        // now that we have all the required data, set the vertex buffers and its attribute pointers.
        unsafe { prim.setup_primitive() }
        prim
    }

    pub fn from_gltf(g_primitive: gltf::mesh::Primitive) -> Primitive {
        let positions = g_primitive.position().unwrap();
        let normals = g_primitive.normal()
            .expect("NotImplementedYet: Normals required! Calculation of flat normals not implemented yet.");
        let mut tangents = g_primitive.tangent();

        // TODO!: support the different texcoord and color formats
        let mut tex_coords_0 = match g_primitive.tex_coord(0) {
            Some(tex_coords_0) => {
                Some(match tex_coords_0 {
                    TexCoord::F32(tc) => tc,
                    TexCoord::U8(_) => unimplemented!(),
                    TexCoord::U16(_) => unimplemented!(),
                })
            },
            None => None
        };
        let mut tex_coords_1 = match g_primitive.tex_coord(1) {
            Some(tex_coords_1) => {
                Some(match tex_coords_1 {
                    TexCoord::F32(tc) => tc,
                    TexCoord::U8(_) => unimplemented!(),
                    TexCoord::U16(_) => unimplemented!(),
                })
            },
            None => None
        };
        let mut colors_0 = match g_primitive.color(0) {
            Some(colors_0) => {
                Some(match colors_0 {
                    // Color::RgbU8(Iter<'a, [u8; 3]>),
                    // Color::RgbaU8(Iter<'a, [u8; 4]>),
                    // Color::RgbU16(Iter<'a, [u16; 3]>),
                    // Color::RgbaU16(Iter<'a, [u16; 4]>),
                    Color::RgbF32(c) => c,
                    // Color::RgbaF32(c),
                    _ => unimplemented!()
                })
            }
            None => None
        };

        let indices = g_primitive.indices().expect("NotImplementedYet: Indices required at the moment!");

        let vertices: Vec<Vertex> = positions
            .zip(normals)
            .map(|(position, normal)| {
                let tangent = match tangents {
                    Some(ref mut tangents) => Vector4::from(tangents.next()
                        .expect("Not enough tangents! Expected 1 per vertex.")),
                    None => Vector4::zero()
                };
                let tex_coord_0 = match tex_coords_0 {
                    Some(ref mut tex_coord_0) => {
                        Vector2::from(tex_coord_0.next()
                        .expect("Not enough tex_coords_0! Expected 1 per vertex."))
                    }
                    None => Vector2::zero()
                };
                let tex_coord_1 = match tex_coords_1 {
                    Some(ref mut tex_coord_1) => Vector2::from(tex_coord_1.next()
                        .expect("Not enough tex_coords_1! Expected 1 per vertex.")),
                    None => Vector2::zero()
                };

                let color_0 = match colors_0 {
                    Some(ref mut colors_0) => Vector3::from(colors_0.next()
                        .expect("Not enough color_0 entries! Expected 1 per vertex.")),
                    None => Vector3::zero()
                };
                Vertex {
                    position: Vector3::from(position),
                    normal: Vector3::from(normal),
                    tangent: tangent,
                    tex_coord_0: tex_coord_0,
                    tex_coord_1: tex_coord_1,
                    color_0: color_0,
                    ..Vertex::default()
                }
            })
            .collect();

        // convert indices to u32 if necessary
        // TODO?: use indices as they are?
        let indices: Vec<u32> = match indices {
            Indices::U8(indices) => indices.map(|i| i as u32).collect(),
            Indices::U16(indices) => indices.map(|i| i as u32).collect(),
            Indices::U32(indices) => indices.collect(),
        };

        // TODO: No debug
        // assert_eq!(primitive.mode(), Mode::Triangles);

        // TODO!!: textures
        let textures = Vec::new();
        Primitive::new(vertices, indices, textures)
    }

    /// render the mesh
    pub unsafe fn draw(&self, shader: &Shader) {
        // bind appropriate textures
        let mut diffuse_nr  = 0;
        let mut specular_nr = 0;
        let mut normal_nr   = 0;
        let mut height_nr   = 0;
        for (i, texture) in self.textures.iter().enumerate() {
            gl::ActiveTexture(gl::TEXTURE0 + i as u32); // active proper texture unit before binding
            // retrieve texture number (the N in diffuse_textureN)
            let name = &texture.type_;
            let number = match name.as_str() {
                "texture_diffuse" => {
                    diffuse_nr += 1;
                    diffuse_nr
                },
                "texture_specular" => {
                    specular_nr += 1;
                    specular_nr
                }
                "texture_normal" => {
                    normal_nr += 1;
                    normal_nr
                }
                "texture_height" => {
                    height_nr += 1;
                    height_nr
                }
                _ => panic!("unknown texture type")
            };
            // now set the sampler to the correct texture unit
            let sampler = CString::new(format!("{}{}", name, number)).unwrap();
            gl::Uniform1i(gl::GetUniformLocation(shader.id, sampler.as_ptr()), i as i32);
            // and finally bind the texture
            gl::BindTexture(gl::TEXTURE_2D, texture.id);
        }

        // draw mesh
        gl::BindVertexArray(self.vao);
        gl::DrawElements(gl::TRIANGLES, self.indices.len() as i32, gl::UNSIGNED_INT, ptr::null());
        gl::BindVertexArray(0);

        // always good practice to set everything back to defaults once configured.
        gl::ActiveTexture(gl::TEXTURE0);
    }

    unsafe fn setup_primitive(&mut self) {
        // create buffers/arrays
        gl::GenVertexArrays(1, &mut self.vao);
        gl::GenBuffers(1, &mut self.vbo);
        gl::GenBuffers(1, &mut self.ebo);

        gl::BindVertexArray(self.vao);
        // load data into vertex buffers
        gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
        // A great thing about structs with repr(C) is that their memory layout is sequential for all its items.
        // The effect is that we can simply pass a pointer to the struct and it translates perfectly to a glm::vec3/2 array which
        // again translates to 3/2 floats which translates to a byte array.
        let size = (self.vertices.len() * size_of::<Vertex>()) as isize;
        let data = &self.vertices[0] as *const Vertex as *const c_void;
        gl::BufferData(gl::ARRAY_BUFFER, size, data, gl::STATIC_DRAW);

        gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, self.ebo);
        let size = (self.indices.len() * size_of::<u32>()) as isize;
        let data = &self.indices[0] as *const u32 as *const c_void;
        gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, size, data, gl::STATIC_DRAW);

        // set the vertex attribute pointers
        // TODO!!: adapt to new Vertex struct
        let size = size_of::<Vertex>() as i32;
        // vertex positions
        gl::EnableVertexAttribArray(0);
        gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, position) as *const c_void);
        // vertex normals
        gl::EnableVertexAttribArray(1);
        gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, normal) as *const c_void);
        // vertex texture coords
        gl::EnableVertexAttribArray(2);
        gl::VertexAttribPointer(2, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tex_coord_0) as *const c_void);
        // vertex tangent
        gl::EnableVertexAttribArray(3);
        gl::VertexAttribPointer(3, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tangent) as *const c_void);
        // vertex bitangent
        // gl::EnableVertexAttribArray(4);
        // gl::VertexAttribPointer(4, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, bitangent) as *const c_void);

        gl::BindVertexArray(0);
    }
}
<|endoftext|>