<commit_before>use regex::Regex;
use reqwest;
use serde_json;

use crate::web::data::{SolrTermSummary, SolrReferenceSummary};
use crate::web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
    django_url: String,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
            django_url: config.server.django_url.clone(),
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}*", word, word);
                } else {
                    terms_url += &format!("{} ", word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}*", word, word);
                } else {
                    clean_words_for_url += &format!("{} ", word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn motif_search(&self, motif: &str) -> Result<String, String> {
        let search_url = self.django_url.to_owned() + "/motifsearch/query/" + motif;

        match reqwest::get(&search_url) {
            Ok(mut res) => {
                println!("Status: {}", res.status());
                match res.text() {
                    Ok(text) => Ok(text),
                    Err(err) => Err(format!("Error getting text from motif search: {:?}", err)),
                }
            },
            Err(err) => {
                Err(format!("Motif search error: {:?}", err))
            }
        }
    }
}
<commit_msg>Pass pattern to motif search using query params<commit_after>use regex::Regex;
use serde_json;

use crate::web::data::{SolrTermSummary, SolrReferenceSummary};
use crate::web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
    django_url: String,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
            django_url: config.server.django_url.clone(),
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}*", word, word);
                } else {
                    terms_url += &format!("{} ", word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):\s*)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w\d\-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}*", word, word);
                } else {
                    clean_words_for_url += &format!("{} ", word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn motif_search(&self, pattern: &str) -> Result<String, String> {
        let search_url = self.django_url.to_owned() + "/motifsearch/query/";
        let params = [("pattern", pattern)];
        let client = reqwest::Client::new();
        let request = client.get(&search_url).query(&params);
        let result = request.send();

        match result {
            Ok(mut res) => {
                println!("Status: {}", res.status());
                match res.text() {
                    Ok(text) => Ok(text),
                    Err(err) => Err(format!("Error getting text from motif search: {:?}", err)),
                }
            },
            Err(err) => {
                Err(format!("Motif search error: {:?}", err))
            }
        }
    }
}
<|endoftext|>


<commit_before>use prolog::ast::*;
use prolog::builtins::*;
use prolog::codegen::*;
use prolog::heap_iter::*;
use prolog::heap_print::*;
use prolog::fixtures::*;

pub(crate) mod machine_state;

use std::collections::HashMap;
use std::ops::Index;
use std::rc::Rc;
use std::vec::Vec;

pub struct Machine {
    ms: machine_state::MachineState,
    code: Code,
    code_dir: CodeDir,
    op_dir: OpDir,
    cached_query: Option
}

impl Index<CodePtr> for Machine {
    type Output = Line;

    fn index(&self, ptr: CodePtr) -> &Self::Output {
        match ptr {
            CodePtr::TopLevel(_, p) => {
                match &self.cached_query {
                    &Some(ref cq) => &cq[p],
                    &None => panic!("Out-of-bounds top level index.")
                }
            },
            CodePtr::DirEntry(p) => &self.code[p]
        }
    }
}

impl Machine {
    pub fn new() -> Self {
        let (code, code_dir, op_dir) = build_code_dir();

        Machine {
            ms: machine_state::MachineState::new(),
            code: code,
            code_dir: code_dir,
            op_dir: op_dir,
            cached_query: None
        }
    }

    pub fn failed(&self) -> bool {
        self.ms.fail
    }

    fn add_user_code<'a>(&mut self, name: Rc<Atom>, arity: usize, offset: usize) -> EvalSession<'a>
    {
        match self.code_dir.get(&(name.clone(), arity)) {
            Some(&(PredicateKeyType::BuiltIn, _)) =>
                return EvalSession::ImpermissibleEntry(format!("{}/{}", name, arity)),
            _ => {}
        };

        self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
        EvalSession::EntrySuccess
    }

    pub fn add_fact<'a>(&mut self, fact: &Term, mut code: Code) -> EvalSession<'a>
    {
        match fact {
            &Term::Clause(_, ref name, _) | &Term::Constant(_, Constant::Atom(ref name)) => {
                let p = self.code.len();
                let arity = fact.arity();

                self.code.append(&mut code);
                self.add_user_code(name.clone(), arity, p)
            },
            _ => EvalSession::NamelessEntry
        }
    }

    pub fn add_rule<'a>(&mut self, rule: &Rule, mut code: Code) -> EvalSession<'a>
    {
        match &rule.head.0 {
            &QueryTerm::Term(Term::Clause(_, ref name, _))
          | &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref name))) => {
                let p = self.code.len();
                let arity = rule.head.0.arity();

                self.code.append(&mut code);
                self.add_user_code(name.clone(), arity, p)
            },
            _ => EvalSession::NamelessEntry
        }
    }

    pub fn add_predicate<'a>(&mut self, clauses: &Vec<PredicateClause>, mut code: Code)
                             -> EvalSession<'a>
    {
        let p = self.code.len();

        if let Some(ref clause) = clauses.first() {
            if let Some(name) = clause.name() {
                let arity = clause.arity();

                self.code.append(&mut code);
                self.add_user_code(name.clone(), arity, p)
            } else {
                EvalSession::NamelessEntry
            }
        } else {
            EvalSession::ImpermissibleEntry(String::from("predicate must have clauses."))
        }
    }

    fn cached_query_size(&self) -> usize {
        match &self.cached_query {
            &Some(ref query) => query.len(),
            _ => 0
        }
    }

    fn execute_instr(&mut self)
    {
        let instr = match self.ms.p {
            CodePtr::TopLevel(_, p) => {
                match &self.cached_query {
                    &Some(ref cq) => &cq[p],
                    &None => return
                }
            },
            CodePtr::DirEntry(p) => &self.code[p]
        };

        match instr {
            &Line::Arithmetic(ref arith_instr) =>
                self.ms.execute_arith_instr(arith_instr),
            &Line::BuiltIn(ref built_in_instr) =>
                self.ms.execute_built_in_instr(&self.code_dir, built_in_instr),
            &Line::Choice(ref choice_instr) =>
                self.ms.execute_choice_instr(choice_instr),
            &Line::Cut(ref cut_instr) =>
                self.ms.execute_cut_instr(cut_instr),
            &Line::Control(ref control_instr) =>
                self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
            &Line::Fact(ref fact) => {
                for fact_instr in fact {
                    if self.failed() {
                        break;
                    }

                    self.ms.execute_fact_instr(&fact_instr);
                }

                self.ms.p += 1;
            },
            &Line::Indexing(ref indexing_instr) =>
                self.ms.execute_indexing_instr(&indexing_instr),
            &Line::IndexedChoice(ref choice_instr) =>
                self.ms.execute_indexed_choice_instr(choice_instr),
            &Line::Query(ref query) => {
                for query_instr in query {
                    if self.failed() {
                        break;
                    }

                    self.ms.execute_query_instr(&query_instr);
                }

                self.ms.p += 1;
            }
        }
    }

    fn backtrack(&mut self)
    {
        if self.ms.b > 0 {
            let b = self.ms.b - 1;

            self.ms.b0 = self.ms.or_stack[b].b0;
            self.ms.p  = self.ms.or_stack[b].bp;

            if let CodePtr::TopLevel(_, p) = self.ms.p {
                self.ms.fail = p == 0;
            } else {
                self.ms.fail = false;
            }
        } else {
            self.ms.p = CodePtr::TopLevel(0, 0);
        }
    }

    fn query_stepper<'a>(&mut self)
    {
        loop
        {
            self.execute_instr();

            if self.failed() {
                self.backtrack();
            }

            match self.ms.p {
                CodePtr::DirEntry(p) if p < self.code.len() => {},
                _ => break
            };
        }
    }

    fn record_var_places<'a>(&self,
                             chunk_num: usize,
                             alloc_locs: &AllocVarDict<'a>,
                             heap_locs: &mut HeapVarDict<'a>)
    {
        for (var, var_data) in alloc_locs {
            match var_data {
                &VarData::Perm(_) => {
                    let e = self.ms.e;

                    let r = var_data.as_reg_type().reg_num();
                    let addr = self.ms.and_stack[e][r].clone();

                    heap_locs.insert(var, addr);
                },
                &VarData::Temp(cn, _, _) if cn == chunk_num => {
                    let r = var_data.as_reg_type();
                    let addr = self.ms[r].clone();

                    heap_locs.insert(var, addr);
                },
                _ => {}
            }
        }
    }

    fn run_query<'a>(&mut self, alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
    {
        let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());

        while self.ms.p < end_ptr {
            if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
                match &self[CodePtr::TopLevel(cn, p)] {
                    &Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
                        self.record_var_places(cn, alloc_locs, heap_locs);
                        cn += 1;
                    },
                    _ => {}
                }

                self.ms.p = CodePtr::TopLevel(cn, p);
            }

            self.query_stepper();

            match self.ms.p {
                CodePtr::TopLevel(_, p) if p > 0 => {},
                _ => break
            };
        }
    }

    fn fail<'a>(&mut self) -> EvalSession<'a>
    {
        if self.ms.ball.1.len() > 0 {
            let h = self.ms.heap.h;
            self.ms.copy_and_align_ball_to_heap();

            EvalSession::QueryFailureWithException(self.print_term(&Addr::HeapCell(h)))
        } else {
            EvalSession::QueryFailure
        }
    }

    pub fn submit_decl<'a>(&mut self, decl: &Declaration) -> EvalSession<'a>
    {
        match decl {
            &Declaration::Op(prec, spec, ref name) => {
                if is_infix!(spec) {
                    match self.op_dir.get(&(name.clone(), Fixity::Post)) {
                        Some(_) => return EvalSession::OpIsInfixAndPostFix,
                        _ => {}
                    };
                }

                if is_postfix!(spec) {
                    match self.op_dir.get(&(name.clone(), Fixity::In)) {
                        Some(_) => return EvalSession::OpIsInfixAndPostFix,
                        _ => {}
                    };
                }

                if prec > 0 {
                    match spec {
                        XFY | XFX | YFX => self.op_dir.insert((name.clone(), Fixity::In),
                                                              (spec, prec)),
                        XF | YF => self.op_dir.insert((name.clone(), Fixity::Post), (spec, prec)),
                        FX | FY => self.op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)),
                        _ => None
                    };
                } else {
                    self.op_dir.remove(&(name.clone(), Fixity::Pre));
                    self.op_dir.remove(&(name.clone(), Fixity::In));
                    self.op_dir.remove(&(name.clone(), Fixity::Post));
                }

                EvalSession::EntrySuccess
            }
        }
    }

    pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
    {
        let mut heap_locs = HashMap::new();

        self.cached_query = Some(code);
        self.run_query(&alloc_locs, &mut heap_locs);

        if self.failed() {
            self.fail()
        } else {
            EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
        }
    }

    pub fn continue_query<'a>(&mut self, alloc_l: &AllocVarDict<'a>, heap_l: &mut HeapVarDict<'a>)
                              -> EvalSession<'a>
    {
        if !self.or_stack_is_empty() {
            let b = self.ms.b - 1;
            self.ms.p = self.ms.or_stack[b].bp;

            if let CodePtr::TopLevel(_, 0) = self.ms.p {
                return EvalSession::QueryFailure;
            }

            self.run_query(alloc_l, heap_l);

            if self.failed() {
                self.fail()
            } else {
                EvalSession::SubsequentQuerySuccess
            }
        } else {
            EvalSession::QueryFailure
        }
    }

    fn print_var(&self, r: Ref) -> String
    {
        let disp = DisplayFormatter {};
        let iter = HeapCellIterator::new(&self.ms, r);

        let mut printer = HeapCellPrinter::new(iter, disp);

        printer.print()
    }

    // NEW ---
    fn print_term(&self, addr: &Addr) -> String
    {
        match addr {
            &Addr::Con(ref c) =>
                format!("{}", c),
            &Addr::Lis(h) | &Addr::HeapCell(h) | &Addr::Str(h) =>
                self.print_var(Ref::HeapCell(h)),
            &Addr::StackCell(fr, sc) =>
                self.print_var(Ref::StackCell(fr, sc))
        }
    }

    pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
        let mut result = String::new();

        for (var, addr) in var_dir {
            if result != "" {
                result += "\n\r";
            }

            result += var.as_str();
            result += " = ";

            result += self.print_term(addr).as_str();
        }

        result
    }

    pub fn or_stack_is_empty(&self) -> bool {
        self.ms.b == 0
    }

    pub fn clear(&mut self) {
        self.reset();
        self.code.clear();
        self.code_dir.clear();
    }

    pub fn reset(&mut self) {
        self.ms.reset();
    }

    pub fn op_dir(&self) -> &OpDir {
        &self.op_dir
    }
}
<commit_msg>remove commented out print_term<commit_after>use prolog::ast::*;
use prolog::builtins::*;
use prolog::codegen::*;
use prolog::heap_iter::*;
use prolog::heap_print::*;
use prolog::fixtures::*;

pub(crate) mod machine_state;

use std::collections::HashMap;
use std::ops::Index;
use std::rc::Rc;
use std::vec::Vec;

pub struct Machine {
    ms: machine_state::MachineState,
    code: Code,
    code_dir: CodeDir,
    op_dir: OpDir,
    cached_query: Option
}

impl Index<CodePtr> for Machine {
    type Output = Line;

    fn index(&self, ptr: CodePtr) -> &Self::Output {
        match ptr {
            CodePtr::TopLevel(_, p) => {
                match &self.cached_query {
                    &Some(ref cq) => &cq[p],
                    &None => panic!("Out-of-bounds top level index.")
                }
            },
            CodePtr::DirEntry(p) => &self.code[p]
        }
    }
}

impl Machine {
    pub fn new() -> Self {
        let (code, code_dir, op_dir) = build_code_dir();

        Machine {
            ms: machine_state::MachineState::new(),
            code: code,
            code_dir: code_dir,
            op_dir: op_dir,
            cached_query: None
        }
    }

    pub fn failed(&self) -> bool {
        self.ms.fail
    }

    fn add_user_code<'a>(&mut self, name: Rc<Atom>, arity: usize, offset: usize) -> EvalSession<'a>
    {
        match self.code_dir.get(&(name.clone(), arity)) {
            Some(&(PredicateKeyType::BuiltIn, _)) =>
                return EvalSession::ImpermissibleEntry(format!("{}/{}", name, arity)),
            _ => {}
        };

        self.code_dir.insert((name, arity), (PredicateKeyType::User, offset));
        EvalSession::EntrySuccess
    }

    pub fn add_fact<'a>(&mut self, fact: &Term, mut code: Code) -> EvalSession<'a>
    {
        match fact {
            &Term::Clause(_, ref name, _) | &Term::Constant(_, Constant::Atom(ref name)) => {
                let p = self.code.len();
                let arity = fact.arity();

                self.code.append(&mut code);
                self.add_user_code(name.clone(), arity, p)
            },
            _ => EvalSession::NamelessEntry
        }
    }

    pub fn add_rule<'a>(&mut self, rule: &Rule, mut code: Code) -> EvalSession<'a>
    {
        match &rule.head.0 {
            &QueryTerm::Term(Term::Clause(_, ref name, _))
          | &QueryTerm::Term(Term::Constant(_, Constant::Atom(ref name))) => {
                let p = self.code.len();
                let arity = rule.head.0.arity();

                self.code.append(&mut code);
                self.add_user_code(name.clone(), arity, p)
            },
            _ => EvalSession::NamelessEntry
        }
    }

    pub fn add_predicate<'a>(&mut self, clauses: &Vec<PredicateClause>, mut code: Code)
                             -> EvalSession<'a>
    {
        let p = self.code.len();

        if let Some(ref clause) = clauses.first() {
            if let Some(name) = clause.name() {
                let arity = clause.arity();

                self.code.append(&mut code);
                self.add_user_code(name.clone(), arity, p)
            } else {
                EvalSession::NamelessEntry
            }
        } else {
            EvalSession::ImpermissibleEntry(String::from("predicate must have clauses."))
        }
    }

    fn cached_query_size(&self) -> usize {
        match &self.cached_query {
            &Some(ref query) => query.len(),
            _ => 0
        }
    }

    fn execute_instr(&mut self)
    {
        let instr = match self.ms.p {
            CodePtr::TopLevel(_, p) => {
                match &self.cached_query {
                    &Some(ref cq) => &cq[p],
                    &None => return
                }
            },
            CodePtr::DirEntry(p) => &self.code[p]
        };

        match instr {
            &Line::Arithmetic(ref arith_instr) =>
                self.ms.execute_arith_instr(arith_instr),
            &Line::BuiltIn(ref built_in_instr) =>
                self.ms.execute_built_in_instr(&self.code_dir, built_in_instr),
            &Line::Choice(ref choice_instr) =>
                self.ms.execute_choice_instr(choice_instr),
            &Line::Cut(ref cut_instr) =>
                self.ms.execute_cut_instr(cut_instr),
            &Line::Control(ref control_instr) =>
                self.ms.execute_ctrl_instr(&self.code_dir, control_instr),
            &Line::Fact(ref fact) => {
                for fact_instr in fact {
                    if self.failed() {
                        break;
                    }

                    self.ms.execute_fact_instr(&fact_instr);
                }

                self.ms.p += 1;
            },
            &Line::Indexing(ref indexing_instr) =>
                self.ms.execute_indexing_instr(&indexing_instr),
            &Line::IndexedChoice(ref choice_instr) =>
                self.ms.execute_indexed_choice_instr(choice_instr),
            &Line::Query(ref query) => {
                for query_instr in query {
                    if self.failed() {
                        break;
                    }

                    self.ms.execute_query_instr(&query_instr);
                }

                self.ms.p += 1;
            }
        }
    }

    fn backtrack(&mut self)
    {
        if self.ms.b > 0 {
            let b = self.ms.b - 1;

            self.ms.b0 = self.ms.or_stack[b].b0;
            self.ms.p  = self.ms.or_stack[b].bp;

            if let CodePtr::TopLevel(_, p) = self.ms.p {
                self.ms.fail = p == 0;
            } else {
                self.ms.fail = false;
            }
        } else {
            self.ms.p = CodePtr::TopLevel(0, 0);
        }
    }

    fn query_stepper<'a>(&mut self)
    {
        loop
        {
            self.execute_instr();

            if self.failed() {
                self.backtrack();
            }

            match self.ms.p {
                CodePtr::DirEntry(p) if p < self.code.len() => {},
                _ => break
            };
        }
    }

    fn record_var_places<'a>(&self,
                             chunk_num: usize,
                             alloc_locs: &AllocVarDict<'a>,
                             heap_locs: &mut HeapVarDict<'a>)
    {
        for (var, var_data) in alloc_locs {
            match var_data {
                &VarData::Perm(_) => {
                    let e = self.ms.e;

                    let r = var_data.as_reg_type().reg_num();
                    let addr = self.ms.and_stack[e][r].clone();

                    heap_locs.insert(var, addr);
                },
                &VarData::Temp(cn, _, _) if cn == chunk_num => {
                    let r = var_data.as_reg_type();
                    let addr = self.ms[r].clone();

                    heap_locs.insert(var, addr);
                },
                _ => {}
            }
        }
    }

    fn run_query<'a>(&mut self, alloc_locs: &AllocVarDict<'a>, heap_locs: &mut HeapVarDict<'a>)
    {
        let end_ptr = CodePtr::TopLevel(0, self.cached_query_size());

        while self.ms.p < end_ptr {
            if let CodePtr::TopLevel(mut cn, p) = self.ms.p {
                match &self[CodePtr::TopLevel(cn, p)] {
                    &Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
                        self.record_var_places(cn, alloc_locs, heap_locs);
                        cn += 1;
                    },
                    _ => {}
                }

                self.ms.p = CodePtr::TopLevel(cn, p);
            }

            self.query_stepper();

            match self.ms.p {
                CodePtr::TopLevel(_, p) if p > 0 => {},
                _ => break
            };
        }
    }

    fn fail<'a>(&mut self) -> EvalSession<'a>
    {
        if self.ms.ball.1.len() > 0 {
            let h = self.ms.heap.h;
            self.ms.copy_and_align_ball_to_heap();

            EvalSession::QueryFailureWithException(self.print_term(&Addr::HeapCell(h)))
        } else {
            EvalSession::QueryFailure
        }
    }

    pub fn submit_decl<'a>(&mut self, decl: &Declaration) -> EvalSession<'a>
    {
        match decl {
            &Declaration::Op(prec, spec, ref name) => {
                if is_infix!(spec) {
                    match self.op_dir.get(&(name.clone(), Fixity::Post)) {
                        Some(_) => return EvalSession::OpIsInfixAndPostFix,
                        _ => {}
                    };
                }

                if is_postfix!(spec) {
                    match self.op_dir.get(&(name.clone(), Fixity::In)) {
                        Some(_) => return EvalSession::OpIsInfixAndPostFix,
                        _ => {}
                    };
                }

                if prec > 0 {
                    match spec {
                        XFY | XFX | YFX => self.op_dir.insert((name.clone(), Fixity::In),
                                                              (spec, prec)),
                        XF | YF => self.op_dir.insert((name.clone(), Fixity::Post), (spec, prec)),
                        FX | FY => self.op_dir.insert((name.clone(), Fixity::Pre), (spec,prec)),
                        _ => None
                    };
                } else {
                    self.op_dir.remove(&(name.clone(), Fixity::Pre));
                    self.op_dir.remove(&(name.clone(), Fixity::In));
                    self.op_dir.remove(&(name.clone(), Fixity::Post));
                }

                EvalSession::EntrySuccess
            }
        }
    }

    pub fn submit_query<'a>(&mut self, code: Code, alloc_locs: AllocVarDict<'a>) -> EvalSession<'a>
    {
        let mut heap_locs = HashMap::new();

        self.cached_query = Some(code);
        self.run_query(&alloc_locs, &mut heap_locs);

        if self.failed() {
            self.fail()
        } else {
            EvalSession::InitialQuerySuccess(alloc_locs, heap_locs)
        }
    }

    pub fn continue_query<'a>(&mut self, alloc_l: &AllocVarDict<'a>, heap_l: &mut HeapVarDict<'a>)
                              -> EvalSession<'a>
    {
        if !self.or_stack_is_empty() {
            let b = self.ms.b - 1;
            self.ms.p = self.ms.or_stack[b].bp;

            if let CodePtr::TopLevel(_, 0) = self.ms.p {
                return EvalSession::QueryFailure;
            }

            self.run_query(alloc_l, heap_l);

            if self.failed() {
                self.fail()
            } else {
                EvalSession::SubsequentQuerySuccess
            }
        } else {
            EvalSession::QueryFailure
        }
    }

    fn print_var(&self, r: Ref) -> String
    {
        let disp = DisplayFormatter {};
        let iter = HeapCellIterator::new(&self.ms, r);

        let mut printer = HeapCellPrinter::new(iter, disp);

        printer.print()
    }

    fn print_term(&self, addr: &Addr) -> String
    {
        match addr {
            &Addr::Con(ref c) =>
                format!("{}", c),
            &Addr::Lis(h) | &Addr::HeapCell(h) | &Addr::Str(h) =>
                self.print_var(Ref::HeapCell(h)),
            &Addr::StackCell(fr, sc) =>
                self.print_var(Ref::StackCell(fr, sc))
        }
    }

    pub fn heap_view(&self, var_dir: &HeapVarDict) -> String {
        let mut result = String::new();

        for (var, addr) in var_dir {
            if result != "" {
                result += "\n\r";
            }

            result += var.as_str();
            result += " = ";

            result += self.print_term(addr).as_str();
        }

        result
    }

    pub fn or_stack_is_empty(&self) -> bool {
        self.ms.b == 0
    }

    pub fn clear(&mut self) {
        self.reset();
        self.code.clear();
        self.code_dir.clear();
    }

    pub fn reset(&mut self) {
        self.ms.reset();
    }

    pub fn op_dir(&self) -> &OpDir {
        &self.op_dir
    }
}
<|endoftext|>


<commit_before>
use std::cmp;
use std::ops::Range;

use assembler::u12;
use assembler::u12::*;

#[derive(PartialEq, Eq, Debug)]
pub struct DataRange {
  /// The first address populated by the bytes in the range.
  start_address: U12,
  /// The bytes occupying the range.
  data: Vec<u8>
}

impl DataRange {

  /**
   @param start_address The address of the first element in the data range in the result.
   @return A new data range from the start address with zero elements.
   */
  pub fn new(start_address: U12) -> Self {
    DataRange {
      start_address: start_address,
      data: Vec::new()
    }
  }

  /**
   @return The number of bytes in the data range.
   */
  pub fn len(&self) -> usize {
    self.data.len()
  }

  /**
   @return An immutable reference to the data underlying the range.
   */
  pub fn data(&self) -> &Vec<u8> {
    &self.data
  }

  /**
   @return A half-open range { address | start <= address < end } representing addresses in the range.
   */
  pub fn address_range(&self) -> Range<U12> {
    Range {
      start: self.start_address,
        end: self.start_address.wrapping_add(self.len().as_u12().unwrap())
    }
  }

  /**
   @return The number of bytes remaining to store data in the range.
   */
  pub fn bytes_remaining(&self) -> usize {
    let total_space_in_range = (u12::MAX - self.start_address).as_usize() + 1;
    total_space_in_range - self.len()
  }

  /**
   Appends the slice to the end of the data range. Checks for capacity in advance.
   @param data The bytes to append to the data range.
   */
  pub fn append(&mut self, data: &[u8]) -> bool {
    if self.bytes_remaining() >= data.len() {
      self.data.extend_from_slice(data);
      true
    } else {
      false
    }
  }

  /**
   @return YES if the supplied range intersects the receiver.
   */
  pub fn intersects(&self, range: &DataRange) -> bool {
    let lhs_range =  self.address_range();
    let rhs_range = range.address_range();

    // Ranges intersect if the greater of the two starts is less than the smaller of the two ends (half-open).
    cmp::max(lhs_range.start, rhs_range.start) < cmp::min(lhs_range.end, rhs_range.end)
  }

}

// MARK: - Public Functions

/**
 @param ranges A list of data ranges.
 @return A list of pairs of overlapping data ranges.
 */
pub fn find_overlapping_data_ranges<'a>(ranges: &'a [DataRange]) -> Vec<(&'a DataRange, &'a DataRange)> {
  let mut overlapping_ranges = Vec::new();

  /*
   Compare each data range to each other data range. This is done by evaluating the mathematical
   combination pairs of the data range (order does not matter, pairs must be unique). This has
   complexity O(ranges.len() nCr 2).
   */
  for i in 0..ranges.len() {
    for j in i+1..ranges.len() {
      let lhs = &ranges[i];
      let rhs = &ranges[j];

      if lhs.intersects(rhs) {
        overlapping_ranges.push((lhs, rhs));
      }
    }
  }

  overlapping_ranges
}

// MARK: - Tests

#[cfg(test)]
mod tests {

  use std::iter::repeat;

  use super::*;

  use assembler::u12;
  use assembler::u12::*;

  #[test]
  fn test_empty_ranges() {
    let zero_range = DataRange::new(U12::zero());
    assert_eq!(zero_range.len(), 0);
    assert_eq!(zero_range.bytes_remaining(), 4096);
    assert_eq!(zero_range.address_range(), U12::zero() .. U12::zero());

    let half_address = 0x800.as_u12().unwrap();
    let half_range = DataRange::new(half_address);
    assert_eq!(half_range.len(), 0);
    assert_eq!(half_range.bytes_remaining(), 2048);
    assert_eq!(half_range.address_range(), half_address .. half_address);

    let max_range = DataRange::new(u12::MAX);
    assert_eq!(max_range.len(), 0);
    assert_eq!(max_range.bytes_remaining(), 1);
    assert_eq!(max_range.address_range(), u12::MAX .. u12::MAX);
  }

  #[test]
  fn test_append_within_range() {
    let program_space_start = 0x200.as_u12().unwrap();
    let mut program_space = DataRange::new(program_space_start);
    assert_eq!(program_space.len(), 0);
    assert_eq!(program_space.bytes_remaining(), 3584);
    assert_eq!(program_space.address_range(), program_space_start .. program_space_start);

    // Append a single byte to the data range.
    let one_byte_slice: &[u8] = &[1];
    assert_eq!(program_space.append(one_byte_slice), true);
    assert_eq!(program_space.len(), 1);
    assert_eq!(program_space.bytes_remaining(), 3583);
    assert_eq!(program_space.address_range(), program_space_start .. program_space_start.wrapping_add(U12::from(1)));

    // Append a single byte to the data range.
    let two_byte_slice: &[u8] = &[2, 3];
    assert_eq!(program_space.append(two_byte_slice), true);
    assert_eq!(program_space.len(), 3);
    assert_eq!(program_space.bytes_remaining(), 3581);
    assert_eq!(program_space.address_range(), program_space_start .. program_space_start.wrapping_add(U12::from(3)));

    // Validate the data was appended.
    assert_eq!(program_space.data(), &vec![1,2,3]);
  }

  #[test]
  fn test_append_out_of_range() {
    let mut max_range = DataRange::new(u12::MAX);
    let one_byte_slice: &[u8] = &[1];

    // Append data into the only slot in the data range.
    assert_eq!(max_range.append(one_byte_slice), true);
    assert_eq!(max_range.len(), 1);
    assert_eq!(max_range.bytes_remaining(), 0);
    assert_eq!(max_range.address_range(), u12::MAX .. u12::MIN);

    // Validate the data was appended.
    assert_eq!(max_range.data(), &vec![1]);

    // Attempt to apppend past the end of the data range.
    assert_eq!(max_range.append(one_byte_slice), false);
    assert_eq!(max_range.len(), 1);
    assert_eq!(max_range.bytes_remaining(), 0);
    assert_eq!(max_range.address_range(), u12::MAX .. u12::MIN);

    // Validate the data was not appended.
    assert_eq!(max_range.data(), &vec![1]);
  }

  #[test]
  fn test_intersects() {
    // Case 1: Obviously disjoint (+++++===++), distance: 3.
    let disjoint_1a = range_with_start_and_length(0, 5);
    let disjoint_1b = range_with_start_and_length(8, 2);
    assert_eq!(disjoint_1a.intersects(&disjoint_1b), false);
    assert_eq!(disjoint_1b.intersects(&disjoint_1a), false);

    // Case 2: Tightly disjoint (+++++===++), distance: 1.
    let disjoint_2a = range_with_start_and_length(0, 5);
    let disjoint_2b = range_with_start_and_length(6, 4);
    assert_eq!(disjoint_2a.intersects(&disjoint_2b), false);
    assert_eq!(disjoint_2b.intersects(&disjoint_2a), false);

    // Case 3: Adjacent (++++++++++), distance: 0.
    let adjacent_a = range_with_start_and_length(0, 5);
    let adjacent_b = range_with_start_and_length(5, 5);
    assert_eq!(adjacent_a.intersects(&adjacent_b), false);
    assert_eq!(adjacent_b.intersects(&adjacent_a), false);

    // Case 4: Tail Overlap (++++++v+++) distance: -1.
    let tail_overlap_a = range_with_start_and_length(0, 7);
    let tail_overlap_b = range_with_start_and_length(6, 4);
    assert_eq!(tail_overlap_a.intersects(&tail_overlap_b), true);
    assert_eq!(tail_overlap_b.intersects(&tail_overlap_a), true);

    // Case 5: Wholly Contained Head (v+++++++++) distance: -1.
    let wholly_contained_head_a = range_with_start_and_length(0, 10);
    let wholly_contained_head_b = range_with_start_and_length(0, 1);
    assert_eq!(wholly_contained_head_a.intersects(&wholly_contained_head_b), true);
    assert_eq!(wholly_contained_head_b.intersects(&wholly_contained_head_a), true);

    // Case 6: Wholly Contained Tail (+++++++++v) distance: -1.
    let wholly_contained_tail_a = range_with_start_and_length(0, 10);
    let wholly_contained_tail_b = range_with_start_and_length(9, 1);
    assert_eq!(wholly_contained_tail_a.intersects(&wholly_contained_tail_b), true);
    assert_eq!(wholly_contained_tail_b.intersects(&wholly_contained_tail_a), true);

    // Case 7: Middle of Range (++++vv++++) distance: -2.
    let middle_a = range_with_start_and_length(0, 10);
    let middle_b = range_with_start_and_length(4, 2);
    assert_eq!(middle_a.intersects(&middle_b), true);
    assert_eq!(middle_b.intersects(&middle_a), true);

    // Case 7: Zero Length Range (++++++++++) distance: 0.
    let zero_a = range_with_start_and_length(0, 10);
    let zero_b = range_with_start_and_length(4, 0);
    assert_eq!(zero_a.intersects(&zero_b), false);
    assert_eq!(zero_b.intersects(&zero_a), false);
  }

  // MARK: - Helper Methods

  /// Construct a new zero-filled range at the start address provided with the length provided.
  fn range_with_start_and_length(start: usize, length: usize) -> DataRange {
    let mut range = DataRange::new(start.as_u12().unwrap());
    let data: Vec<u8> = repeat(0u8).take(length).collect();
    range.append(data.as_slice());
    range
  }

}
<commit_msg>Tests for finding adjacent data ranges.<commit_after>
use std::cmp;
use std::ops::Range;

use assembler::u12;
use assembler::u12::*;

#[derive(PartialEq, Eq, Debug)]
pub struct DataRange {
  /// The first address populated by the bytes in the range.
  start_address: U12,
  /// The bytes occupying the range.
  data: Vec<u8>
}

impl DataRange {

  /**
   @param start_address The address of the first element in the data range in the result.
   @return A new data range from the start address with zero elements.
   */
  pub fn new(start_address: U12) -> Self {
    DataRange {
      start_address: start_address,
      data: Vec::new()
    }
  }

  /**
   @return The number of bytes in the data range.
   */
  pub fn len(&self) -> usize {
    self.data.len()
  }

  /**
   @return An immutable reference to the data underlying the range.
   */
  pub fn data(&self) -> &Vec<u8> {
    &self.data
  }

  /**
   @return A half-open range { address | start <= address < end } representing addresses in the range.
   */
  pub fn address_range(&self) -> Range<U12> {
    Range {
      start: self.start_address,
        end: self.start_address.wrapping_add(self.len().as_u12().unwrap())
    }
  }

  /**
   @return The number of bytes remaining to store data in the range.
   */
  pub fn bytes_remaining(&self) -> usize {
    let total_space_in_range = (u12::MAX - self.start_address).as_usize() + 1;
    total_space_in_range - self.len()
  }

  /**
   Appends the slice to the end of the data range. Checks for capacity in advance.
   @param data The bytes to append to the data range.
   */
  pub fn append(&mut self, data: &[u8]) -> bool {
    if self.bytes_remaining() >= data.len() {
      self.data.extend_from_slice(data);
      true
    } else {
      false
    }
  }

  /**
   @return YES if the supplied range intersects the receiver.
   */
  pub fn intersects(&self, range: &DataRange) -> bool {
    let lhs_range =  self.address_range();
    let rhs_range = range.address_range();

    // Ranges intersect if the greater of the two starts is less than the smaller of the two ends (half-open).
    cmp::max(lhs_range.start, rhs_range.start) < cmp::min(lhs_range.end, rhs_range.end)
  }

}

// MARK: - Public Functions

/**
 @param ranges A list of data ranges.
 @return A list of pairs of overlapping data ranges.
 */
pub fn find_overlapping_data_ranges<'a>(ranges: &'a [&'a DataRange]) -> Vec<(&'a DataRange, &'a DataRange)> {
  let mut overlapping_ranges = Vec::new();

  /*
   Compare each data range to each other data range. This is done by evaluating the mathematical
   combination pairs of the data range (order does not matter, pairs must be unique). This has
   complexity O(ranges.len() nCr 2).
   */
  for i in 0..ranges.len() {
    for j in i+1..ranges.len() {
      let lhs = ranges[i];
      let rhs = ranges[j];

      if lhs.intersects(rhs) {
        overlapping_ranges.push((lhs, rhs));
      }
    }
  }

  overlapping_ranges
}

// MARK: - Tests

#[cfg(test)]
mod tests {

  use std::iter::repeat;

  use super::*;

  use assembler::u12;
  use assembler::u12::*;

  #[test]
  fn test_empty_ranges() {
    let zero_range = DataRange::new(U12::zero());
    assert_eq!(zero_range.len(), 0);
    assert_eq!(zero_range.bytes_remaining(), 4096);
    assert_eq!(zero_range.address_range(), U12::zero() .. U12::zero());

    let half_address = 0x800.as_u12().unwrap();
    let half_range = DataRange::new(half_address);
    assert_eq!(half_range.len(), 0);
    assert_eq!(half_range.bytes_remaining(), 2048);
    assert_eq!(half_range.address_range(), half_address .. half_address);

    let max_range = DataRange::new(u12::MAX);
    assert_eq!(max_range.len(), 0);
    assert_eq!(max_range.bytes_remaining(), 1);
    assert_eq!(max_range.address_range(), u12::MAX .. u12::MAX);
  }

  #[test]
  fn test_append_within_range() {
    let program_space_start = 0x200.as_u12().unwrap();
    let mut program_space = DataRange::new(program_space_start);
    assert_eq!(program_space.len(), 0);
    assert_eq!(program_space.bytes_remaining(), 3584);
    assert_eq!(program_space.address_range(), program_space_start .. program_space_start);

    // Append a single byte to the data range.
    let one_byte_slice: &[u8] = &[1];
    assert_eq!(program_space.append(one_byte_slice), true);
    assert_eq!(program_space.len(), 1);
    assert_eq!(program_space.bytes_remaining(), 3583);
    assert_eq!(program_space.address_range(), program_space_start .. program_space_start.wrapping_add(U12::from(1)));

    // Append a single byte to the data range.
    let two_byte_slice: &[u8] = &[2, 3];
    assert_eq!(program_space.append(two_byte_slice), true);
    assert_eq!(program_space.len(), 3);
    assert_eq!(program_space.bytes_remaining(), 3581);
    assert_eq!(program_space.address_range(), program_space_start .. program_space_start.wrapping_add(U12::from(3)));

    // Validate the data was appended.
    assert_eq!(program_space.data(), &vec![1,2,3]);
  }

  #[test]
  fn test_append_out_of_range() {
    let mut max_range = DataRange::new(u12::MAX);
    let one_byte_slice: &[u8] = &[1];

    // Append data into the only slot in the data range.
    assert_eq!(max_range.append(one_byte_slice), true);
    assert_eq!(max_range.len(), 1);
    assert_eq!(max_range.bytes_remaining(), 0);
    assert_eq!(max_range.address_range(), u12::MAX .. u12::MIN);

    // Validate the data was appended.
    assert_eq!(max_range.data(), &vec![1]);

    // Attempt to apppend past the end of the data range.
    assert_eq!(max_range.append(one_byte_slice), false);
    assert_eq!(max_range.len(), 1);
    assert_eq!(max_range.bytes_remaining(), 0);
    assert_eq!(max_range.address_range(), u12::MAX .. u12::MIN);

    // Validate the data was not appended.
    assert_eq!(max_range.data(), &vec![1]);
  }

  #[test]
  fn test_intersects() {
    // Case 1: Obviously disjoint (+++++===++), distance: 3.
    let disjoint_1a = range_with_start_and_length(0, 5);
    let disjoint_1b = range_with_start_and_length(8, 2);
    assert_eq!(disjoint_1a.intersects(&disjoint_1b), false);
    assert_eq!(disjoint_1b.intersects(&disjoint_1a), false);

    // Case 2: Tightly disjoint (+++++===++), distance: 1.
    let disjoint_2a = range_with_start_and_length(0, 5);
    let disjoint_2b = range_with_start_and_length(6, 4);
    assert_eq!(disjoint_2a.intersects(&disjoint_2b), false);
    assert_eq!(disjoint_2b.intersects(&disjoint_2a), false);

    // Case 3: Adjacent (++++++++++), distance: 0.
    let adjacent_a = range_with_start_and_length(0, 5);
    let adjacent_b = range_with_start_and_length(5, 5);
    assert_eq!(adjacent_a.intersects(&adjacent_b), false);
    assert_eq!(adjacent_b.intersects(&adjacent_a), false);

    // Case 4: Tail Overlap (++++++v+++) distance: -1.
    let tail_overlap_a = range_with_start_and_length(0, 7);
    let tail_overlap_b = range_with_start_and_length(6, 4);
    assert_eq!(tail_overlap_a.intersects(&tail_overlap_b), true);
    assert_eq!(tail_overlap_b.intersects(&tail_overlap_a), true);

    // Case 5: Wholly Contained Head (v+++++++++) distance: -1.
    let wholly_contained_head_a = range_with_start_and_length(0, 10);
    let wholly_contained_head_b = range_with_start_and_length(0, 1);
    assert_eq!(wholly_contained_head_a.intersects(&wholly_contained_head_b), true);
    assert_eq!(wholly_contained_head_b.intersects(&wholly_contained_head_a), true);

    // Case 6: Wholly Contained Tail (+++++++++v) distance: -1.
    let wholly_contained_tail_a = range_with_start_and_length(0, 10);
    let wholly_contained_tail_b = range_with_start_and_length(9, 1);
    assert_eq!(wholly_contained_tail_a.intersects(&wholly_contained_tail_b), true);
    assert_eq!(wholly_contained_tail_b.intersects(&wholly_contained_tail_a), true);

    // Case 7: Middle of Range (++++vv++++) distance: -2.
    let middle_a = range_with_start_and_length(0, 10);
    let middle_b = range_with_start_and_length(4, 2);
    assert_eq!(middle_a.intersects(&middle_b), true);
    assert_eq!(middle_b.intersects(&middle_a), true);

    // Case 8: Zero Length Range (++++++++++) distance: 0.
    let zero_a = range_with_start_and_length(0, 10);
    let zero_b = range_with_start_and_length(4, 0);
    assert_eq!(zero_a.intersects(&zero_b), false);
    assert_eq!(zero_b.intersects(&zero_a), false);
  }

  #[test]
  fn test_find_overlapping_data_ranges() {
    /*               */
    /*    0123456789 */
    /* A: ++++++++++ */ let range_a = range_with_start_and_length(0, 10);
    /* B: +++======= */ let range_b = range_with_start_and_length(0,  3);
    /* C: =======+++ */ let range_c = range_with_start_and_length(7,  3);
    /* D: ==++++++== */ let range_d = range_with_start_and_length(2,  6);
    /* E: ========== */ let range_e = range_with_start_and_length(0,  0);
    /*               */

    // Zero ranges cannot overlap.
    assert_eq!(find_overlapping_data_ranges(&[]), vec![]);

    // No one range can overlap.
    assert_eq!(find_overlapping_data_ranges(&[&range_a]), vec![]);
    assert_eq!(find_overlapping_data_ranges(&[&range_b]), vec![]);
    assert_eq!(find_overlapping_data_ranges(&[&range_c]), vec![]);
    assert_eq!(find_overlapping_data_ranges(&[&range_d]), vec![]);
    assert_eq!(find_overlapping_data_ranges(&[&range_e]), vec![]);

    // Non-overlapping data ranges.
    assert_eq!(find_overlapping_data_ranges(&[&range_b, &range_c]), vec![]);
    assert_eq!(find_overlapping_data_ranges(&[&range_b, &range_e]), vec![]);

    // One overlapping range (including when the same range is represented twice).
    assert_eq!(find_overlapping_data_ranges(&[&range_a, &range_a]), vec![(&range_a, &range_a)]);
    assert_eq!(find_overlapping_data_ranges(&[&range_a, &range_b]), vec![(&range_a, &range_b)]);
    assert_eq!(find_overlapping_data_ranges(&[&range_a, &range_c]), vec![(&range_a, &range_c)]);

    // One overlapping range when the zero-range is also included.
    assert_eq!(find_overlapping_data_ranges(&[&range_a, &range_b, &range_e]), vec![(&range_a, &range_b)]);

    // Test all ranges to find the overlapping pairs.
    assert_eq!(find_overlapping_data_ranges(&[&range_a, &range_b, &range_c, &range_d, &range_e]),
      vec![
        (&range_a, &range_b),
        (&range_a, &range_c),
        (&range_a, &range_d),
        (&range_b, &range_d),
        (&range_c, &range_d)
      ]
    );
  }

  // MARK: - Helper Methods

  /// Construct a new zero-filled range at the start address provided with the length provided.
  fn range_with_start_and_length(start: usize, length: usize) -> DataRange {
    let mut range = DataRange::new(start.as_u12().unwrap());
    let data: Vec<u8> = repeat(0u8).take(length).collect();
    range.append(data.as_slice());
    range
  }

}
<|endoftext|>


<commit_before>use base::world::{Chunk, ChunkIndex, World};
use base::math::*;
use glium::{self, DrawParameters, VertexBuffer};
use glium::draw_parameters::{BackfaceCullingMode, DepthTest};
use glium::backend::Facade;
use glium::texture::Texture2d;
use glium::uniforms::SamplerWrapFunction;
use glium::uniforms::MinifySamplerFilter;
use Camera;
use DayTime;
// use SimpleCull;
// use LOCATION;
use util::ToArr;
use world::ChunkRenderer;
use std::rc::Rc;
use base::world::ground::GroundMaterial;

/// Graphical representation of the `base::Chunk`.
pub struct ChunkView {
    offset: AxialPoint,
    renderer: Rc<ChunkRenderer>,
    /// Instance data buffer.
    pillar_buf: VertexBuffer<Instance>, /* save corner positions for draw
                                         * corner_ps: Vec<Point3f>, */
}

impl ChunkView {
    /// Creates the graphical representation of given chunk at the given chunk
    /// offset
    pub fn from_chunk<F: Facade>(chunk: &Chunk,
                                 offset: AxialPoint,
                                 chunk_renderer: Rc<ChunkRenderer>,
                                 facade: &F)
                                 -> Self {

        let mut sections = Vec::new();
        // let mut i = 0;
        // let mut vec = Vec::new();
        {
            // scope so we can borrow mut vec
            // let mut c = |x, pos: Point2f, z| {
            //     if x == 0 || x == CHUNK_SIZE || x == (CHUNK_SIZE * CHUNK_SIZE - CHUNK_SIZE) ||
            //        x == (CHUNK_SIZE * CHUNK_SIZE - 1) {
            //         vec.push(Point3f::new(pos.x, pos.y, z));
            //     }
            // };
            for (axial, pillar) in chunk.pillars() {
                let pos = offset.to_real() + axial.to_real();
                // let height = 150.;
                // save if corner (assume fixed location of corners)
                // c(i, pos, height);
                // c(i, pos, 0.);
                // i += 1;
                for section in pillar.sections() {
                    let g = match section.ground {
                        GroundMaterial::Grass => 1,
                        GroundMaterial::Sand => 2,
                        GroundMaterial::Snow => 3,
                        GroundMaterial::Dirt => 4,
                        GroundMaterial::Stone => 5,
                        GroundMaterial::JungleGrass => 1,
                        GroundMaterial::Mulch => 7,
                        GroundMaterial::Debug => 8,
                    };
                    sections.push(Instance {
                        material_color: section.ground.get_color(),
                        ground: g,
                        offset: [pos.x, pos.y, section.bottom.to_real()],
                        height: (section.top.units() - section.bottom.units()) as f32,
                    });
                }
            }
        }

        ChunkView {
            offset: offset,
            renderer: chunk_renderer,
            pillar_buf: VertexBuffer::dynamic(facade, &sections).unwrap(),
            // corner_ps: vec,
        }
    }

    pub fn draw_shadow<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let uniforms = uniform! {
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullClockwise,
            multisampling: true,
            ..Default::default()
        };

        surface.draw((self.renderer.pillar_vertices(), self.pillar_buf.per_instance().unwrap()),
                  self.renderer.pillar_indices(),
                  self.renderer.shadow_program(),
                  &uniforms,
                  &params)
            .unwrap();
    }

    pub fn update<F: Facade>(&mut self, facade: &F, world: &mut World) {
        let chunk = world.chunk_at(ChunkIndex(self.offset));

        if chunk.is_none() {
            return;
        }

        let mut sections = Vec::new();

        for (axial, pillar) in chunk.unwrap().pillars() {
            let pos = self.offset.to_real() + axial.to_real();
            for section in pillar.sections() {
                let g = match section.ground {
                    GroundMaterial::Grass => 1,
                    GroundMaterial::Sand => 2,
                    GroundMaterial::Snow => 3,
                    GroundMaterial::Dirt => 4,
                    GroundMaterial::Stone => 5,
                    GroundMaterial::JungleGrass => 1,
                    GroundMaterial::Mulch => 7,
                    GroundMaterial::Debug => 8,
                };
                sections.push(Instance {
                    ground: g,
                    material_color: section.ground.get_color(),
                    offset: [pos.x, pos.y, section.bottom.to_real()],
                    height: (section.top.units() - section.bottom.units()) as f32,
                });
            }
        }
        self.pillar_buf = VertexBuffer::dynamic(facade, &sections).unwrap();
    }

    pub fn draw<S: glium::Surface>(&self,
                                   surface: &mut S,
                                   camera: &Camera,
                                   shadow_map: &Texture2d,
                                   depth_view_proj: &Matrix4<f32>,
                                   daytime: &DayTime,
                                   sun_dir: Vector3f) {

        // // such skill much wow :D
        // let mut i = 0;
        // let mut c = || {
        //     let a = i;
        //     i += 1;
        //     &self.corner_ps[a]
        // };
        // let corner = [c(), c(), c(), c(), c(), c(), c(), c()];

        // let render = match frustum.is_vis(corner) {
        //     LOCATION::Outside => 0,
        //     LOCATION::Inside => 1,
        //     LOCATION::Intersect => 1,
        // };
        // if render == 0 {
        //     return;
        // }

        let real_off = self.offset.to_real();
        let player_to_chunk = Point3f::new(real_off.x, real_off.y, camera.position.z) -
                              camera.position;
        if camera.get_look_at_vector().z.abs() < 0.5 &&
           dot(player_to_chunk, camera.get_look_at_vector()) < 0.0 {
            return;
        }

        let uniforms = uniform! {
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
            shadow_map: shadow_map.sampled().wrap_function(SamplerWrapFunction::Clamp),
            depth_view_proj: depth_view_proj.to_arr(),
            sun_dir: sun_dir.to_arr(),
            cam_pos: camera.position.to_arr(),
            sun_color: daytime.get_sun_color().to_arr(),
            sky_light: daytime.get_sky_light().to_arr(),

            // Mipmapping and repeating the textures
            sand_texture:  self.renderer.noise_sand.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            snow_texture:  self.renderer.noise_snow.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            grass_texture: self.renderer.noise_grass.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            stone_texture: self.renderer.noise_stone.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            dirt_texture: self.renderer.noise_dirt.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            mulch_texture: self.renderer.noise_mulch.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),

            normal_sand: &self.renderer.normal_sand,
            normal_snow: &self.renderer.normal_snow,
            normal_grass: &self.renderer.normal_grass,
            normal_stone: &self.renderer.normal_stone,
            normal_dirt: &self.renderer.normal_dirt,
            normal_mulch: &self.renderer.normal_mulch,
        };
        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullCounterClockwise,
            ..Default::default()
        };

        // Draw hexagons
        surface.draw((self.renderer.pillar_vertices(), self.pillar_buf.per_instance().unwrap()),
                  self.renderer.pillar_indices(),
                  self.renderer.program(),
                  &uniforms,
                  &params)
            .unwrap();
    }
}

/// Vertex type used to render chunks (or hex pillars).
#[derive(Debug, Copy, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub normal: [f32; 3],
    pub radius: f32,
    pub tex_coords: [f32; 2],
}

implement_vertex!(Vertex, position, normal, radius, tex_coords);

/// Instance data for each pillar section.
#[derive(Debug, Copy, Clone)]
pub struct Instance {
    ground: i32,
    /// Material color.
    material_color: [f32; 3],
    /// Offset in world coordinates.
    offset: [f32; 3],
    /// Pillar height.
    height: f32,
}

implement_vertex!(Instance, material_color, offset, ground, height);
<commit_msg>Fix format<commit_after>use base::world::{Chunk, ChunkIndex, World};
use base::math::*;
use glium::{self, DrawParameters, VertexBuffer};
use glium::draw_parameters::{BackfaceCullingMode, DepthTest};
use glium::backend::Facade;
use glium::texture::Texture2d;
use glium::uniforms::SamplerWrapFunction;
use glium::uniforms::MinifySamplerFilter;
use Camera;
use DayTime;
// use SimpleCull;
// use LOCATION;
use util::ToArr;
use world::ChunkRenderer;
use std::rc::Rc;
use base::world::ground::GroundMaterial;

/// Graphical representation of the `base::Chunk`.
pub struct ChunkView {
    offset: AxialPoint,
    renderer: Rc<ChunkRenderer>,
    /// Instance data buffer.
    pillar_buf: VertexBuffer<Instance>, /* save corner positions for draw
                                         * corner_ps: Vec<Point3f>, */
}

impl ChunkView {
    /// Creates the graphical representation of given chunk at the given chunk
    /// offset
    pub fn from_chunk<F: Facade>(chunk: &Chunk,
                                 offset: AxialPoint,
                                 chunk_renderer: Rc<ChunkRenderer>,
                                 facade: &F)
                                 -> Self {

        let mut sections = Vec::new();
        // let mut i = 0;
        // let mut vec = Vec::new();
        {
            // scope so we can borrow mut vec
            // let mut c = |x, pos: Point2f, z| {
            // if x == 0 || x == CHUNK_SIZE || x == (CHUNK_SIZE * CHUNK_SIZE -
            // CHUNK_SIZE) ||
            //        x == (CHUNK_SIZE * CHUNK_SIZE - 1) {
            //         vec.push(Point3f::new(pos.x, pos.y, z));
            //     }
            // };
            for (axial, pillar) in chunk.pillars() {
                let pos = offset.to_real() + axial.to_real();
                // let height = 150.;
                // save if corner (assume fixed location of corners)
                // c(i, pos, height);
                // c(i, pos, 0.);
                // i += 1;
                for section in pillar.sections() {
                    let g = match section.ground {
                        GroundMaterial::Grass => 1,
                        GroundMaterial::Sand => 2,
                        GroundMaterial::Snow => 3,
                        GroundMaterial::Dirt => 4,
                        GroundMaterial::Stone => 5,
                        GroundMaterial::JungleGrass => 1,
                        GroundMaterial::Mulch => 7,
                        GroundMaterial::Debug => 8,
                    };
                    sections.push(Instance {
                        material_color: section.ground.get_color(),
                        ground: g,
                        offset: [pos.x, pos.y, section.bottom.to_real()],
                        height: (section.top.units() - section.bottom.units()) as f32,
                    });
                }
            }
        }

        ChunkView {
            offset: offset,
            renderer: chunk_renderer,
            pillar_buf: VertexBuffer::dynamic(facade, &sections).unwrap(), // corner_ps: vec,
        }
    }

    pub fn draw_shadow<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        let uniforms = uniform! {
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
        };

        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullClockwise,
            multisampling: true,
            ..Default::default()
        };

        surface.draw((self.renderer.pillar_vertices(), self.pillar_buf.per_instance().unwrap()),
                  self.renderer.pillar_indices(),
                  self.renderer.shadow_program(),
                  &uniforms,
                  &params)
            .unwrap();
    }

    pub fn update<F: Facade>(&mut self, facade: &F, world: &mut World) {
        let chunk = world.chunk_at(ChunkIndex(self.offset));

        if chunk.is_none() {
            return;
        }

        let mut sections = Vec::new();

        for (axial, pillar) in chunk.unwrap().pillars() {
            let pos = self.offset.to_real() + axial.to_real();
            for section in pillar.sections() {
                let g = match section.ground {
                    GroundMaterial::Grass => 1,
                    GroundMaterial::Sand => 2,
                    GroundMaterial::Snow => 3,
                    GroundMaterial::Dirt => 4,
                    GroundMaterial::Stone => 5,
                    GroundMaterial::JungleGrass => 1,
                    GroundMaterial::Mulch => 7,
                    GroundMaterial::Debug => 8,
                };
                sections.push(Instance {
                    ground: g,
                    material_color: section.ground.get_color(),
                    offset: [pos.x, pos.y, section.bottom.to_real()],
                    height: (section.top.units() - section.bottom.units()) as f32,
                });
            }
        }
        self.pillar_buf = VertexBuffer::dynamic(facade, &sections).unwrap();
    }

    pub fn draw<S: glium::Surface>(&self,
                                   surface: &mut S,
                                   camera: &Camera,
                                   shadow_map: &Texture2d,
                                   depth_view_proj: &Matrix4<f32>,
                                   daytime: &DayTime,
                                   sun_dir: Vector3f) {

        // // such skill much wow :D
        // let mut i = 0;
        // let mut c = || {
        //     let a = i;
        //     i += 1;
        //     &self.corner_ps[a]
        // };
        // let corner = [c(), c(), c(), c(), c(), c(), c(), c()];

        // let render = match frustum.is_vis(corner) {
        //     LOCATION::Outside => 0,
        //     LOCATION::Inside => 1,
        //     LOCATION::Intersect => 1,
        // };
        // if render == 0 {
        //     return;
        // }

        let real_off = self.offset.to_real();
        let player_to_chunk = Point3f::new(real_off.x, real_off.y, camera.position.z) -
                              camera.position;
        if camera.get_look_at_vector().z.abs() < 0.5 &&
           dot(player_to_chunk, camera.get_look_at_vector()) < 0.0 {
            return;
        }

        let uniforms = uniform! {
            proj_matrix: camera.proj_matrix().to_arr(),
            view_matrix: camera.view_matrix().to_arr(),
            shadow_map: shadow_map.sampled().wrap_function(SamplerWrapFunction::Clamp),
            depth_view_proj: depth_view_proj.to_arr(),
            sun_dir: sun_dir.to_arr(),
            cam_pos: camera.position.to_arr(),
            sun_color: daytime.get_sun_color().to_arr(),
            sky_light: daytime.get_sky_light().to_arr(),

            // Mipmapping and repeating the textures
            sand_texture:  self.renderer.noise_sand.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            snow_texture:  self.renderer.noise_snow.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            grass_texture: self.renderer.noise_grass.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            stone_texture: self.renderer.noise_stone.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            dirt_texture: self.renderer.noise_dirt.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),
            mulch_texture: self.renderer.noise_mulch.sampled()
                .minify_filter(MinifySamplerFilter::NearestMipmapLinear)
                .wrap_function(SamplerWrapFunction::Repeat),

            normal_sand: &self.renderer.normal_sand,
            normal_snow: &self.renderer.normal_snow,
            normal_grass: &self.renderer.normal_grass,
            normal_stone: &self.renderer.normal_stone,
            normal_dirt: &self.renderer.normal_dirt,
            normal_mulch: &self.renderer.normal_mulch,
        };
        let params = DrawParameters {
            depth: glium::Depth {
                write: true,
                test: DepthTest::IfLess,
                ..Default::default()
            },
            backface_culling: BackfaceCullingMode::CullCounterClockwise,
            ..Default::default()
        };

        // Draw hexagons
        surface.draw((self.renderer.pillar_vertices(), self.pillar_buf.per_instance().unwrap()),
                  self.renderer.pillar_indices(),
                  self.renderer.program(),
                  &uniforms,
                  &params)
            .unwrap();
    }
}

/// Vertex type used to render chunks (or hex pillars).
#[derive(Debug, Copy, Clone)]
pub struct Vertex {
    pub position: [f32; 3],
    pub normal: [f32; 3],
    pub radius: f32,
    pub tex_coords: [f32; 2],
}

implement_vertex!(Vertex, position, normal, radius, tex_coords);

/// Instance data for each pillar section.
#[derive(Debug, Copy, Clone)]
pub struct Instance {
    ground: i32,
    /// Material color.
    material_color: [f32; 3],
    /// Offset in world coordinates.
    offset: [f32; 3],
    /// Pillar height.
    height: f32,
}

implement_vertex!(Instance, material_color, offset, ground, height);
<|endoftext|>


<commit_before>use std::{fmt, fs, io};
use std::io::Read;
use syntax::{ast, codemap, ptr};
use syntax::parse::token;
use toml;

/// Get the configuration file from arguments.
pub fn file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> {
    for arg in args {
        match arg.node {
            ast::MetaItemKind::Word(ref name) |
            ast::MetaItemKind::List(ref name, _) => {
                if name == &"conf_file" {
                    return Err(("`conf_file` must be a named value", arg.span));
                }
            }
            ast::MetaItemKind::NameValue(ref name, ref value) => {
                if name == &"conf_file" {
                    return if let ast::LitKind::Str(ref file, _) = value.node {
                        Ok(Some(file.clone()))
                    } else {
                        Err(("`conf_file` value must be a string", value.span))
                    };
                }
            }
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Toml(Vec<toml::ParserError>),
    Type(&'static str, &'static str, &'static str),
    UnknownKey(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref errs) => {
                let mut first = true;
                for err in errs {
                    if !first {
                        try!(", ".fmt(f));
                        first = false;
                    }

                    try!(err.fmt(f));
                }

                Ok(())
            }
            Error::Type(key, expected, got) => {
                write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
            }
            Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => {
        /// Type used to store lint configuration.
        pub struct Conf {
            $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+
        }

        impl Default for Conf {
            fn default() -> Conf {
                Conf {
                    $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+
                }
            }
        }

        impl Conf {
            /// Set the property `name` (which must be the `toml` name) to the given value
            #[allow(cast_sign_loss)]
            fn set(&mut self, name: String, value: toml::Value) -> Result<(), Error> {
                match name.as_str() {
                    $(
                        define_Conf!(PAT $toml_name) => {
                            if let Some(value) = define_Conf!(CONV $($ty)+, value) {
                                self.$rust_name = value;
                            }
                            else {
                                return Err(Error::Type(define_Conf!(EXPR $toml_name),
                                                       stringify!($($ty)+),
                                                       value.type_str()));
                            }
                        },
                    )+
                    "third-party" => {
                        // for external tools such as clippy-service
                        return Ok(());
                    }
                    _ => {
                        return Err(Error::UnknownKey(name));
                    }
                }

                Ok(())
            }
        }
    };

    // hack to convert tts
    (PAT $pat: pat) => { $pat };
    (EXPR $e: expr) => { $e };
    (TY $ty: ty) => { $ty };

    // how to read the value?
    (CONV i64, $value: expr) => { $value.as_integer() };
    (CONV u64, $value: expr) => { $value.as_integer().iter().filter_map(|&i| if i >= 0 { Some(i as u64) } else { None }).next() };
    (CONV String, $value: expr) => { $value.as_str().map(Into::into) };
    (CONV Vec<String>, $value: expr) => {{
        let slice = $value.as_slice();

        if let Some(slice) = slice {
            if slice.iter().any(|v| v.as_str().is_none()) {
                None
            }
            else {
                Some(slice.iter().map(|v| v.as_str().unwrap_or_else(|| unreachable!()).to_owned()).collect())
            }
        }
        else {
            None
        }
    }};

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    ("doc-valid-idents", doc_valid_idents, ["MiB", "GiB", "TiB", "PiB", "EiB", "GitHub", "NaN", "GPLv2", "GPLv3", "JavaScript", "IPv4", "IPv6"] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    ("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    ("type-complexity-threshold", type_complexity_threshold, 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    ("single-char-binding-names-threshold", max_single_char_names, 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    ("too-large-for-stack", too_large_for_stack, 200 => u64),
}

/// Read the `toml` configuration file. The function will ignore “File not found” errors iif
/// `!must_exist`, in which case, it will return the default configuration.
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: &str, must_exist: bool) -> (Conf, Vec<Error>) {
    let mut conf = Conf::default();
    let mut errors = Vec::new();

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                errors.push(err.into());
                return (conf, errors);
            }

            buf
        }
        Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => {
            return (conf, errors);
        }
        Err(err) => {
            errors.push(err.into());
            return (conf, errors);
        }
    };

    let mut parser = toml::Parser::new(&file);
    let toml = if let Some(toml) = parser.parse() {
        toml
    } else {
        errors.push(Error::Toml(parser.errors));
        return (conf, errors);
    };

    for (key, value) in toml {
        if let Err(err) = conf.set(key, value) {
            errors.push(err);
        }
    }

    (conf, errors)
}
<commit_msg>added OAuth and TrueType to doc whitelist<commit_after>use std::{fmt, fs, io};
use std::io::Read;
use syntax::{ast, codemap, ptr};
use syntax::parse::token;
use toml;

/// Get the configuration file from arguments.
pub fn file(args: &[ptr::P<ast::MetaItem>]) -> Result<Option<token::InternedString>, (&'static str, codemap::Span)> {
    for arg in args {
        match arg.node {
            ast::MetaItemKind::Word(ref name) |
            ast::MetaItemKind::List(ref name, _) => {
                if name == &"conf_file" {
                    return Err(("`conf_file` must be a named value", arg.span));
                }
            }
            ast::MetaItemKind::NameValue(ref name, ref value) => {
                if name == &"conf_file" {
                    return if let ast::LitKind::Str(ref file, _) = value.node {
                        Ok(Some(file.clone()))
                    } else {
                        Err(("`conf_file` value must be a string", value.span))
                    };
                }
            }
        }
    }

    Ok(None)
}

/// Error from reading a configuration file.
#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Toml(Vec<toml::ParserError>),
    Type(&'static str, &'static str, &'static str),
    UnknownKey(String),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Error::Io(ref err) => err.fmt(f),
            Error::Toml(ref errs) => {
                let mut first = true;
                for err in errs {
                    if !first {
                        try!(", ".fmt(f));
                        first = false;
                    }

                    try!(err.fmt(f));
                }

                Ok(())
            }
            Error::Type(key, expected, got) => {
                write!(f, "`{}` is expected to be a `{}` but is a `{}`", key, expected, got)
            }
            Error::UnknownKey(ref key) => write!(f, "unknown key `{}`", key),
        }
    }
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Error::Io(e)
    }
}

macro_rules! define_Conf {
    ($(#[$doc: meta] ($toml_name: tt, $rust_name: ident, $default: expr => $($ty: tt)+),)+) => {
        /// Type used to store lint configuration.
        pub struct Conf {
            $(#[$doc] pub $rust_name: define_Conf!(TY $($ty)+),)+
        }

        impl Default for Conf {
            fn default() -> Conf {
                Conf {
                    $($rust_name: define_Conf!(DEFAULT $($ty)+, $default),)+
                }
            }
        }

        impl Conf {
            /// Set the property `name` (which must be the `toml` name) to the given value
            #[allow(cast_sign_loss)]
            fn set(&mut self, name: String, value: toml::Value) -> Result<(), Error> {
                match name.as_str() {
                    $(
                        define_Conf!(PAT $toml_name) => {
                            if let Some(value) = define_Conf!(CONV $($ty)+, value) {
                                self.$rust_name = value;
                            }
                            else {
                                return Err(Error::Type(define_Conf!(EXPR $toml_name),
                                                       stringify!($($ty)+),
                                                       value.type_str()));
                            }
                        },
                    )+
                    "third-party" => {
                        // for external tools such as clippy-service
                        return Ok(());
                    }
                    _ => {
                        return Err(Error::UnknownKey(name));
                    }
                }

                Ok(())
            }
        }
    };

    // hack to convert tts
    (PAT $pat: pat) => { $pat };
    (EXPR $e: expr) => { $e };
    (TY $ty: ty) => { $ty };

    // how to read the value?
    (CONV i64, $value: expr) => { $value.as_integer() };
    (CONV u64, $value: expr) => { $value.as_integer().iter().filter_map(|&i| if i >= 0 { Some(i as u64) } else { None }).next() };
    (CONV String, $value: expr) => { $value.as_str().map(Into::into) };
    (CONV Vec<String>, $value: expr) => {{
        let slice = $value.as_slice();

        if let Some(slice) = slice {
            if slice.iter().any(|v| v.as_str().is_none()) {
                None
            }
            else {
                Some(slice.iter().map(|v| v.as_str().unwrap_or_else(|| unreachable!()).to_owned()).collect())
            }
        }
        else {
            None
        }
    }};

    // provide a nicer syntax to declare the default value of `Vec<String>` variables
    (DEFAULT Vec<String>, $e: expr) => { $e.iter().map(|&e| e.to_owned()).collect() };
    (DEFAULT $ty: ty, $e: expr) => { $e };
}

define_Conf! {
    /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about
    ("blacklisted-names", blacklisted_names, ["foo", "bar", "baz"] => Vec<String>),
    /// Lint: CYCLOMATIC_COMPLEXITY. The maximum cyclomatic complexity a function can have
    ("cyclomatic-complexity-threshold", cyclomatic_complexity_threshold, 25 => u64),
    /// Lint: DOC_MARKDOWN. The list of words this lint should not consider as identifiers needing ticks
    ("doc-valid-idents", doc_valid_idents, ["MiB", "GiB", "TiB", "PiB", "EiB", "GitHub", "NaN", "GPLv2", "GPLv3", "JavaScript", "IPv4", "IPv6", "OAuth", "TrueType"] => Vec<String>),
    /// Lint: TOO_MANY_ARGUMENTS. The maximum number of argument a function or method can have
    ("too-many-arguments-threshold", too_many_arguments_threshold, 7 => u64),
    /// Lint: TYPE_COMPLEXITY. The maximum complexity a type can have
    ("type-complexity-threshold", type_complexity_threshold, 250 => u64),
    /// Lint: MANY_SINGLE_CHAR_NAMES. The maximum number of single char bindings a scope may have
    ("single-char-binding-names-threshold", max_single_char_names, 5 => u64),
    /// Lint: BOXED_LOCAL. The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
    ("too-large-for-stack", too_large_for_stack, 200 => u64),
}

/// Read the `toml` configuration file. The function will ignore “File not found” errors iif
/// `!must_exist`, in which case, it will return the default configuration.
/// In case of error, the function tries to continue as much as possible.
pub fn read(path: &str, must_exist: bool) -> (Conf, Vec<Error>) {
    let mut conf = Conf::default();
    let mut errors = Vec::new();

    let file = match fs::File::open(path) {
        Ok(mut file) => {
            let mut buf = String::new();

            if let Err(err) = file.read_to_string(&mut buf) {
                errors.push(err.into());
                return (conf, errors);
            }

            buf
        }
        Err(ref err) if !must_exist && err.kind() == io::ErrorKind::NotFound => {
            return (conf, errors);
        }
        Err(err) => {
            errors.push(err.into());
            return (conf, errors);
        }
    };

    let mut parser = toml::Parser::new(&file);
    let toml = if let Some(toml) = parser.parse() {
        toml
    } else {
        errors.push(Error::Toml(parser.errors));
        return (conf, errors);
    };

    for (key, value) in toml {
        if let Err(err) = conf.set(key, value) {
            errors.push(err);
        }
    }

    (conf, errors)
}
<|endoftext|>