<commit_before>extern crate csv;
extern crate serde_json;
extern crate serde;
#[macro_use]
extern crate serde_derive;

use std::ascii::AsciiExt;
use std::io::{Write, BufReader, BufWriter};
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;
use std::rc::Rc;
use std::env;

const DATA_PATH: &'static str = "misc/data.json";
const SUPPORTED_LANG_PATH: &'static str = "misc/supported_languages.csv";

const TRIGRAPH_COUNT: usize = 300;

#[derive(Debug, Clone, PartialEq, Deserialize)]
struct SupportedLang {
    code: String,
    eng_name: String,
    name: String,
    native_speakers: Option<f64>,
}

#[derive(Debug, Clone, PartialEq)]
struct Lang<'a> {
    info: &'a SupportedLang,
    script: String,
    trigraphs: Vec<String>,
}

fn main() {
    println!("cargo:rerun-if-changed={}", DATA_PATH);
    println!("cargo:rerun-if-changed={}", SUPPORTED_LANG_PATH);
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("lang.rs");
    let mut lang_def = BufWriter::new(File::create(&dest_path).unwrap());

    let data_file = BufReader::new(File::open(DATA_PATH).unwrap());
    let mut lang_reader = csv::ReaderBuilder::new().flexible(true).from_path(SUPPORTED_LANG_PATH).unwrap();

    let mut supported_langs: Vec<SupportedLang> = lang_reader.deserialize().map(Result::unwrap).collect();
    supported_langs.sort_by(|left, right| left.code.cmp(&right.code));

    let supported_lang_codes: HashMap<&str, &SupportedLang> = supported_langs.iter().map(|lang| (&*lang.code, lang)).collect();

    let capitalized_codes: HashMap<&str, String> = supported_langs.iter().map(|lang| (&*lang.code, capitalize_name(&lang.code))).collect();

    let lang_data: HashMap<String, HashMap<String, String>> = serde_json::from_reader(data_file).unwrap();

    let mut scripts: HashMap<String, Vec<Rc<Lang>>> = HashMap::with_capacity(lang_data.len());
    let mut all_langs: Vec<Rc<Lang>> = Vec::new();
    for (script, langs) in &lang_data {
        for (code, trigraphs) in langs {
            let info = match supported_lang_codes.get(&**code) {
                Some(info) => info,
                None => continue,
            };
            let lang = Rc::new(Lang {
                info: info,
                script: script.clone(),
                trigraphs: trigraphs.split('|').map(Into::into).collect()
            });
            if lang.trigraphs.len() != TRIGRAPH_COUNT {
                panic!("Languate {} has {} trigraphs, instead of {}", code, lang.trigraphs.len(), TRIGRAPH_COUNT);
            }

            all_langs.push(lang.clone());
            scripts.entry(script.clone()).or_insert_with(Vec::new).push(lang);
        }
    }

    writeln!(lang_def, "/// Represents a language following [ISO 639-3](https://en.wikipedia.org/wiki/ISO_639-3) standard.").unwrap();
    writeln!(lang_def, "#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)]").unwrap();
    writeln!(lang_def, "pub enum Lang {{").unwrap();
    for (i, supported_lang) in supported_langs.iter().enumerate() {
        writeln!(lang_def, "  /// {} ({})", supported_lang.name, supported_lang.eng_name).unwrap();
        // Number starting at 1, to allow enum optimizations to occur (e.g. Option<Lang> will be smaller)
        writeln!(lang_def, "  {} = {},", capitalize_name(&supported_lang.code), i + 1).unwrap();
    }
    writeln!(lang_def, "}}").unwrap();
    lang_def.flush().unwrap();

    writeln!(lang_def, "#[inline] fn lang_from_code<S: Into<String>>(code: S) -> Option<Lang> {{").unwrap();
    writeln!(lang_def, "  match code.into().to_lowercase().as_ref() {{").unwrap();
    for supported_lang in &supported_langs {
        writeln!(lang_def, "    \"{}\" => Some(Lang::{}),", supported_lang.code, capitalized_codes[&*supported_lang.code]).unwrap();
    }
    writeln!(lang_def, "    _ => None,").unwrap();
    writeln!(lang_def, "  }}").unwrap();
    writeln!(lang_def, "}}").unwrap();

    writeln!(lang_def, "#[inline] fn lang_to_code(lang: Lang) -> &'static str {{").unwrap();
    writeln!(lang_def, "  match lang {{").unwrap();
    for supported_lang in &supported_langs {
        writeln!(lang_def, "    Lang::{} => \"{}\",", capitalized_codes[&*supported_lang.code], supported_lang.code).unwrap();
    }
    writeln!(lang_def, "  }}").unwrap();
    writeln!(lang_def, "}}").unwrap();

    writeln!(lang_def, "#[inline] fn lang_to_name(lang: Lang) -> &'static str {{").unwrap();
    writeln!(lang_def, "  match lang {{").unwrap();
    for supported_lang in &supported_langs {
        writeln!(lang_def, "    Lang::{} => \"{}\",", capitalized_codes[&*supported_lang.code], supported_lang.name).unwrap();
    }
    writeln!(lang_def, "  }}").unwrap();
    writeln!(lang_def, "}}").unwrap();

    writeln!(lang_def, "#[inline] fn lang_to_eng_name(lang: Lang) -> &'static str {{").unwrap();
    writeln!(lang_def, "  match lang {{").unwrap();
    for supported_lang in &supported_langs {
        writeln!(lang_def, "    Lang::{} => \"{}\",", capitalized_codes[&*supported_lang.code], supported_lang.eng_name).unwrap();
    }
    writeln!(lang_def, "  }}").unwrap();
    writeln!(lang_def, "}}").unwrap();

    for (script, script_langs) in &scripts {
        writeln!(lang_def, "/// Languages for script '{}'", script).unwrap();
        writeln!(lang_def, "pub static {}_LANGS: LangProfileList = &[", script.to_ascii_uppercase()).unwrap();
        for lang in script_langs {
            writeln!(lang_def, "  (Lang::{}, &{:?}),", capitalized_codes[&*lang.info.code], lang.trigraphs).unwrap();
        }
        writeln!(lang_def, "];").unwrap();
    }
}

fn capitalize_name(name: &str) -> String {
    let mut name = String::from(name);
    name[0..1].make_ascii_uppercase();
    name
}
<commit_msg>Use #[allow(unused_imports)] for AsciiExt<commit_after>extern crate csv;
extern crate serde_json;
extern crate serde;
#[macro_use]
extern crate serde_derive;

// We need AsciiExt for Rust versions below 1.23.
// For Rust 1.23 and higher AsciiExt is no longer needed, so the compiler produces
// a warning, which we suppress.
// For more details please read the Rust 1.23 release note: https://blog.rust-lang.org/2018/01/04/Rust-1.23.html
#[allow(unused_imports)]
use std::ascii::AsciiExt;

use std::io::{Write, BufReader, BufWriter};
use std::collections::HashMap;
use std::fs::File;
use std::path::Path;
use std::rc::Rc;
use std::env;

const DATA_PATH: &'static str = "misc/data.json";
const SUPPORTED_LANG_PATH: &'static str = "misc/supported_languages.csv";

const TRIGRAPH_COUNT: usize = 300;

#[derive(Debug, Clone, PartialEq, Deserialize)]
struct SupportedLang {
    code: String,
    eng_name: String,
    name: String,
    native_speakers: Option<f64>,
}

#[derive(Debug, Clone, PartialEq)]
struct Lang<'a> {
    info: &'a SupportedLang,
    script: String,
    trigraphs: Vec<String>,
}

fn main() {
    println!("cargo:rerun-if-changed={}", DATA_PATH);
    println!("cargo:rerun-if-changed={}", SUPPORTED_LANG_PATH);
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("lang.rs");
    let mut lang_def = BufWriter::new(File::create(&dest_path).unwrap());

    let data_file = BufReader::new(File::open(DATA_PATH).unwrap());
    let mut lang_reader = csv::ReaderBuilder::new().flexible(true).from_path(SUPPORTED_LANG_PATH).unwrap();

    let mut supported_langs: Vec<SupportedLang> = lang_reader.deserialize().map(Result::unwrap).collect();
    supported_langs.sort_by(|left, right| left.code.cmp(&right.code));

    let supported_lang_codes: HashMap<&str, &SupportedLang> = supported_langs.iter().map(|lang| (&*lang.code, lang)).collect();

    let capitalized_codes: HashMap<&str, String> = supported_langs.iter().map(|lang| (&*lang.code, capitalize_name(&lang.code))).collect();

    let lang_data: HashMap<String, HashMap<String, String>> = serde_json::from_reader(data_file).unwrap();

    let mut scripts: HashMap<String, Vec<Rc<Lang>>> = HashMap::with_capacity(lang_data.len());
    let mut all_langs: Vec<Rc<Lang>> = Vec::new();
    for (script, langs) in &lang_data {
        for (code, trigraphs) in langs {
            let info = match supported_lang_codes.get(&**code) {
                Some(info) => info,
                None => continue,
            };
            let lang = Rc::new(Lang {
                info: info,
                script: script.clone(),
                trigraphs: trigraphs.split('|').map(Into::into).collect()
            });
            if lang.trigraphs.len() != TRIGRAPH_COUNT {
                panic!("Languate {} has {} trigraphs, instead of {}", code, lang.trigraphs.len(), TRIGRAPH_COUNT);
            }

            all_langs.push(lang.clone());
            scripts.entry(script.clone()).or_insert_with(Vec::new).push(lang);
        }
    }

    writeln!(lang_def, "/// Represents a language following [ISO 639-3](https://en.wikipedia.org/wiki/ISO_639-3) standard.").unwrap();
    writeln!(lang_def, "#[derive(PartialEq, Eq, Debug, Hash, Clone, Copy)]").unwrap();
    writeln!(lang_def, "pub enum Lang {{").unwrap();
    for (i, supported_lang) in supported_langs.iter().enumerate() {
        writeln!(lang_def, "  /// {} ({})", supported_lang.name, supported_lang.eng_name).unwrap();
        // Number starting at 1, to allow enum optimizations to occur (e.g. Option<Lang> will be smaller)
        writeln!(lang_def, "  {} = {},", capitalize_name(&supported_lang.code), i + 1).unwrap();
    }
    writeln!(lang_def, "}}").unwrap();
    lang_def.flush().unwrap();

    writeln!(lang_def, "#[inline] fn lang_from_code<S: Into<String>>(code: S) -> Option<Lang> {{").unwrap();
    writeln!(lang_def, "  match code.into().to_lowercase().as_ref() {{").unwrap();
    for supported_lang in &supported_langs {
        writeln!(lang_def, "    \"{}\" => Some(Lang::{}),", supported_lang.code, capitalized_codes[&*supported_lang.code]).unwrap();
    }
    writeln!(lang_def, "    _ => None,").unwrap();
    writeln!(lang_def, "  }}").unwrap();
    writeln!(lang_def, "}}").unwrap();

    writeln!(lang_def, "#[inline] fn lang_to_code(lang: Lang) -> &'static str {{").unwrap();
    writeln!(lang_def, "  match lang {{").unwrap();
    for supported_lang in &supported_langs {
        writeln!(lang_def, "    Lang::{} => \"{}\",", capitalized_codes[&*supported_lang.code], supported_lang.code).unwrap();
    }
    writeln!(lang_def, "  }}").unwrap();
    writeln!(lang_def, "}}").unwrap();

    writeln!(lang_def, "#[inline] fn lang_to_name(lang: Lang) -> &'static str {{").unwrap();
    writeln!(lang_def, "  match lang {{").unwrap();
    for supported_lang in &supported_langs {
        writeln!(lang_def, "    Lang::{} => \"{}\",", capitalized_codes[&*supported_lang.code], supported_lang.name).unwrap();
    }
    writeln!(lang_def, "  }}").unwrap();
    writeln!(lang_def, "}}").unwrap();

    writeln!(lang_def, "#[inline] fn lang_to_eng_name(lang: Lang) -> &'static str {{").unwrap();
    writeln!(lang_def, "  match lang {{").unwrap();
    for supported_lang in &supported_langs {
        writeln!(lang_def, "    Lang::{} => \"{}\",", capitalized_codes[&*supported_lang.code], supported_lang.eng_name).unwrap();
    }
    writeln!(lang_def, "  }}").unwrap();
    writeln!(lang_def, "}}").unwrap();

    for (script, script_langs) in &scripts {
        writeln!(lang_def, "/// Languages for script '{}'", script).unwrap();
        writeln!(lang_def, "pub static {}_LANGS: LangProfileList = &[", script.to_ascii_uppercase()).unwrap();
        for lang in script_langs {
            writeln!(lang_def, "  (Lang::{}, &{:?}),", capitalized_codes[&*lang.info.code], lang.trigraphs).unwrap();
        }
        writeln!(lang_def, "];").unwrap();
    }
}

fn capitalize_name(name: &str) -> String {
    let mut name = String::from(name);
    name[0..1].make_ascii_uppercase();
    name
}
<|endoftext|>


<commit_before>use entity::Entity;
use failure::{err_msg, Fallible};
use language_type::LanguageType;
use std::{
    cell::{Ref, RefCell, RefMut}, ffi::OsStr, fmt::{Display, Formatter, Result}, fs::read_link,
    marker::PhantomData, path::PathBuf,
};
use walkdir::WalkDir;

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed entity description.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Description {
    pub description: Vec<String>,
}

impl Description {
    /// Creates a new Description instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Description;
    ///
    /// let description = Description::new();
    ///
    /// assert!(description.description.is_empty());
    /// ```
    pub fn new() -> Self {
        Self {
            description: Vec::new(),
        }
    }

    /// Sets and formats the description.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Description;
    ///
    /// let mut description = Description::new();
    /// description.set("EQ[this->class_inst->TL_FCT(no1: no1, no2: 10) => 15]");
    ///
    /// assert_eq!(description.description.len(), 4);
    /// ```
    pub fn set(&mut self, description: &str) {
        self.description = description
            .split('\n')
            .map(|desc| {
                String::from(
                    desc.trim_left()
                        .trim_left_matches('*')
                        .trim_left_matches('/')
                        .trim_left(),
                )
            })
            .filter(|ref desc| !desc.is_empty() && desc.as_str() != "**")
            .map(|desc| {
                if desc.chars().next() == Some('#') {
                    desc.replace(" ", "")
                } else {
                    desc
                }
            })
            .collect();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed function argument.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Argument {
    pub name: String,
    pub atype: Option<String>,
    pub value: Option<String>,
}

impl Argument {
    /// Creates a new Argument instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Argument;
    ///
    /// let argument = Argument::new("int1", Some("int"));
    ///
    /// assert_eq!(argument.name, "int1");
    /// assert!(argument.atype.is_some());
    /// assert_eq!(argument.atype.unwrap(), "int");
    /// ```
    pub fn new<S: Into<String>>(name: S, atype: Option<S>) -> Self {
        Self {
            name: name.into(),
            atype: atype.map(S::into),
            value: None,
        }
    }

    /// Sets a value to the argument.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Argument;
    ///
    /// let mut argument = Argument::new("arg", Some("std::string"));
    /// argument.set_value("FirstArg");
    ///
    /// assert!(argument.value.is_some());
    ///
    /// ```
    pub fn set_value(&mut self, value: &str) {
        self.value = Some(String::from(value));
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed function type.
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Function {
    pub name: String,
    pub return_type: Option<String>,
    pub arguments: Vec<Argument>,
    pub description: Option<Description>,
}

impl Function {
    /// Creates a new Function instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let function = Function::new("testFunction");
    ///
    /// assert_eq!(function.name, String::from("testFunction"));
    /// assert!(function.return_type.is_none());
    /// assert!(function.arguments.is_empty());
    /// assert!(function.description.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            return_type: None,
            arguments: Vec::new(),
            description: None,
        }
    }

    /// Creates the format type for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_return_type("int");
    ///
    /// assert_eq!(function.return_type, Some(String::from("int")));
    ///
    /// function.set_return_type("");
    ///
    /// assert_eq!(function.return_type, None);
    /// ```
    pub fn set_return_type(&mut self, ftype: &str) -> Fallible<()> {
        if ftype.is_empty() {
            self.return_type = None;
        } else {
            let ftype_vec: Vec<&str> = ftype.split('(').collect();
            self.return_type = Some(String::from(
                ftype_vec
                    .get(0)
                    .ok_or_else(|| err_msg("Function type can not be parsed from signature."))?
                    .trim_right(),
            ));
        }

        Ok(())
    }

    /// Sets the description for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_description("
    /// # TESTCASE(check_if_sum_works)
    ///    int test_no = 2;
    ///    #EQ[TL_FCT(no1: test_no, no2: 5) => 7]
    ///    #EQ[TL_FCT(no1: 5, no2: 2) => 7]
    ///    EXPECT_EQ(11, test_int_no1(9, 2));
    /// ");
    ///
    /// assert!(function.description.is_some());
    /// ```
    pub fn set_description(&mut self, description: &str) {
        if self.description.is_none() {
            self.description = Some(Description::new());
        }

        if let Some(desc) = &mut self.description {
            desc.set(description);
        }
    }

    /// Sets arguments for the Function.
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        self.arguments = arguments.into();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed enum argument.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Enum {
    pub name: String,
    pub etype: Option<String>,
    pub arguments: Vec<Argument>,
}

impl Enum {
    /// Creates a new Enum instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Enum;
    ///
    /// let enumeration = Enum::new("testEnum");
    ///
    /// assert_eq!(enumeration.name, String::from("testEnum"));
    /// assert!(enumeration.etype.is_none());
    /// assert!(enumeration.arguments.is_empty());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            etype: None,
            arguments: Vec::new(),
        }
    }

    /// Sets arguments for the Enum.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::{Argument, Enum};
    ///
    /// let mut enumeration = Enum::new("testEnum");
    /// let args = vec![Argument::new("Zero", Some("0")), Argument::new("Two", Some("2"))];
    /// enumeration.set_arguments(&args);
    ///
    /// assert_eq!(enumeration.arguments.len(), 2);
    /// ```
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        self.arguments = arguments.into();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed project file.
#[derive(Default, Clone, Debug)]
pub struct ProjectFile<T> {
    pub path: PathBuf,
    pub entities: RefCell<Vec<Entity>>,
    pub pf_type: PhantomData<T>,
}

impl<T> ProjectFile<T>
where
    T: LanguageType,
{
    /// Creates a new ProjectFile instance.
    ///
    /// # Example
    ///
    /// ```
    /// use std::path::PathBuf;
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    ///
    /// assert_eq!(project_file.path, PathBuf::from("test/project_file"));
    /// assert_eq!(project_file.entities().len(), 0);
    /// ```
    pub fn new<S: Into<PathBuf>>(path: S) -> Self {
        Self {
            path: path.into(),
            entities: RefCell::new(Vec::new()),
            pf_type: PhantomData,
        }
    }

    /// Returns a reference to the entities list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::entity::Entity;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    /// project_file.entities_mut().push(Entity::new("testEntity"));
    ///
    /// assert_eq!(project_file.entities().len(), 1);
    /// ```
    pub fn entities(&self) -> Ref<Vec<Entity>> {
        self.entities.borrow()
    }

    /// Returns a mutable reference to the entities list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::entity::Entity;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    /// project_file.entities_mut().push(Entity::new("testEntity"));
    ///
    /// let mut entities = project_file.entities_mut();
    /// assert_eq!(entities.len(), 1);
    ///
    /// entities.clear();
    /// assert_eq!(entities.len(), 0);
    /// ```
    pub fn entities_mut(&self) -> RefMut<Vec<Entity>> {
        self.entities.borrow_mut()
    }
}

impl<T> Display for ProjectFile<T>
where
    T: LanguageType,
{
    /// Formats a ProjectFile to be displayed by std output.
    fn fmt(&self, f: &mut Formatter) -> Result {
        if let Some(path) = self.path.to_str() {
            return write!(f, "{}", path);
        }
        write!(f, "Unable to stringify filename")
    }
}

////////////////////////////////////////////////////////////////////////////////

/// The analyzer which fulfills parsing and entity extraction tasks.
#[derive(Default, Debug)]
pub struct Analysis<T>
where
    T: LanguageType,
{
    pub file_types: &'static [&'static str],
    pub project_files: RefCell<Vec<ProjectFile<T>>>,
}

impl<T> Analysis<T>
where
    T: LanguageType,
{
    /// Creates a new Analysis instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Analysis;
    /// use thinlinelib::language_type::{C, LanguageType};
    ///
    /// let analysis: Analysis<C> = Analysis::new();
    ///
    /// assert_eq!(analysis.file_types, C::file_types());
    /// assert_eq!(analysis.project_files().len(), 0);
    /// ```
    pub fn new() -> Self {
        Self {
            file_types: T::file_types(),
            project_files: RefCell::new(Vec::new()),
        }
    }

    /// Returns a reference to the collected project files for analysis.
    pub fn project_files(&self) -> Ref<Vec<ProjectFile<T>>> {
        self.project_files.borrow()
    }

    /// Returns a mutable reference to the collected project files for analysis.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::{Analysis, ProjectFile};
    /// use thinlinelib::language_type::C;
    ///
    /// let analysis: Analysis<C> = Analysis::new();
    /// let mut project_files = analysis.project_files_mut();
    /// assert_eq!(project_files.len(), 0);
    ///
    /// project_files.push(ProjectFile::new("test/anotherFile"));
    /// assert_eq!(project_files.len(), 1);
    /// ```
    pub fn project_files_mut(&self) -> RefMut<Vec<ProjectFile<T>>> {
        self.project_files.borrow_mut()
    }

    /// Collects all the sources within the given project dir.
    /// Does also work for symlinked files.
    pub fn collect_sources(&self, project_dir: &PathBuf, search_dirs: &[String]) -> Fallible<()> {
        // Check the given project directory
        if !project_dir.exists() || !project_dir.is_dir() {
            return Err(format_err!(
                "The given project dir '{}' does not exist.",
                project_dir
                    .to_str()
                    .ok_or_else(|| err_msg("Unable to stringify project dir path."))?
            ));
        }

        // Traverse through the files within the specified source directories
        // and store them for analyzing purposes
        for src_dir in search_dirs {
            for ext in self.file_types {
                for dir in WalkDir::new(project_dir.join(src_dir).to_str().unwrap_or(".")) {
                    let entry = dir?;
                    if !entry.path().is_dir() && entry.path().extension() == Some(OsStr::new(ext)) {
                        if entry.path_is_symlink() {
                            self.project_files_mut()
                                .push(ProjectFile::new(read_link(entry.path())?));
                        } else {
                            self.project_files_mut()
                                .push(ProjectFile::new(entry.path()));
                        }
                    }
                }
            }
        }

        Ok(())
    }

    /// Extracts function signatures and comments of thinlines parsed files.
    pub fn extract_entities(&self) -> Fallible<()> {
        T::extract_entities(&self)
    }
}
<commit_msg>Fix description.set doctest<commit_after>use entity::Entity;
use failure::{err_msg, Fallible};
use language_type::LanguageType;
use std::{
    cell::{Ref, RefCell, RefMut}, ffi::OsStr, fmt::{Display, Formatter, Result}, fs::read_link,
    marker::PhantomData, path::PathBuf,
};
use walkdir::WalkDir;

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed entity description.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Description {
    pub description: Vec<String>,
}

impl Description {
    /// Creates a new Description instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Description;
    ///
    /// let description = Description::new();
    ///
    /// assert!(description.description.is_empty());
    /// ```
    pub fn new() -> Self {
        Self {
            description: Vec::new(),
        }
    }

    /// Sets and formats the description.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Description;
    ///
    /// let mut description = Description::new();
    /// description.set("EQ[this->class_inst->TL_FCT(no1: no1, no2: 10) => 15]");
    ///
    /// assert_eq!(description.description.len(), 1);
    /// ```
    pub fn set(&mut self, description: &str) {
        self.description = description
            .split('\n')
            .map(|desc| {
                String::from(
                    desc.trim_left()
                        .trim_left_matches('*')
                        .trim_left_matches('/')
                        .trim_left(),
                )
            })
            .filter(|ref desc| !desc.is_empty() && desc.as_str() != "**")
            .map(|desc| {
                if desc.chars().next() == Some('#') {
                    desc.replace(" ", "")
                } else {
                    desc
                }
            })
            .collect();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed function argument.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Argument {
    pub name: String,
    pub atype: Option<String>,
    pub value: Option<String>,
}

impl Argument {
    /// Creates a new Argument instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Argument;
    ///
    /// let argument = Argument::new("int1", Some("int"));
    ///
    /// assert_eq!(argument.name, "int1");
    /// assert!(argument.atype.is_some());
    /// assert_eq!(argument.atype.unwrap(), "int");
    /// ```
    pub fn new<S: Into<String>>(name: S, atype: Option<S>) -> Self {
        Self {
            name: name.into(),
            atype: atype.map(S::into),
            value: None,
        }
    }

    /// Sets a value to the argument.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Argument;
    ///
    /// let mut argument = Argument::new("arg", Some("std::string"));
    /// argument.set_value("FirstArg");
    ///
    /// assert!(argument.value.is_some());
    ///
    /// ```
    pub fn set_value(&mut self, value: &str) {
        self.value = Some(String::from(value));
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed function type.
#[derive(Default, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Function {
    pub name: String,
    pub return_type: Option<String>,
    pub arguments: Vec<Argument>,
    pub description: Option<Description>,
}

impl Function {
    /// Creates a new Function instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let function = Function::new("testFunction");
    ///
    /// assert_eq!(function.name, String::from("testFunction"));
    /// assert!(function.return_type.is_none());
    /// assert!(function.arguments.is_empty());
    /// assert!(function.description.is_none());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            return_type: None,
            arguments: Vec::new(),
            description: None,
        }
    }

    /// Creates the format type for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_return_type("int");
    ///
    /// assert_eq!(function.return_type, Some(String::from("int")));
    ///
    /// function.set_return_type("");
    ///
    /// assert_eq!(function.return_type, None);
    /// ```
    pub fn set_return_type(&mut self, ftype: &str) -> Fallible<()> {
        if ftype.is_empty() {
            self.return_type = None;
        } else {
            let ftype_vec: Vec<&str> = ftype.split('(').collect();
            self.return_type = Some(String::from(
                ftype_vec
                    .get(0)
                    .ok_or_else(|| err_msg("Function type can not be parsed from signature."))?
                    .trim_right(),
            ));
        }

        Ok(())
    }

    /// Sets the description for the Function.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Function;
    ///
    /// let mut function = Function::new("testFunction");
    /// function.set_description("
    /// # TESTCASE(check_if_sum_works)
    ///    int test_no = 2;
    ///    #EQ[TL_FCT(no1: test_no, no2: 5) => 7]
    ///    #EQ[TL_FCT(no1: 5, no2: 2) => 7]
    ///    EXPECT_EQ(11, test_int_no1(9, 2));
    /// ");
    ///
    /// assert!(function.description.is_some());
    /// ```
    pub fn set_description(&mut self, description: &str) {
        if self.description.is_none() {
            self.description = Some(Description::new());
        }

        if let Some(desc) = &mut self.description {
            desc.set(description);
        }
    }

    /// Sets arguments for the Function.
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        self.arguments = arguments.into();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed enum argument.
#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Enum {
    pub name: String,
    pub etype: Option<String>,
    pub arguments: Vec<Argument>,
}

impl Enum {
    /// Creates a new Enum instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Enum;
    ///
    /// let enumeration = Enum::new("testEnum");
    ///
    /// assert_eq!(enumeration.name, String::from("testEnum"));
    /// assert!(enumeration.etype.is_none());
    /// assert!(enumeration.arguments.is_empty());
    /// ```
    pub fn new<S: Into<String>>(name: S) -> Self {
        Self {
            name: name.into(),
            etype: None,
            arguments: Vec::new(),
        }
    }

    /// Sets arguments for the Enum.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::{Argument, Enum};
    ///
    /// let mut enumeration = Enum::new("testEnum");
    /// let args = vec![Argument::new("Zero", Some("0")), Argument::new("Two", Some("2"))];
    /// enumeration.set_arguments(&args);
    ///
    /// assert_eq!(enumeration.arguments.len(), 2);
    /// ```
    pub fn set_arguments(&mut self, arguments: &[Argument]) {
        self.arguments = arguments.into();
    }
}

////////////////////////////////////////////////////////////////////////////////

/// Represents a parsed project file.
#[derive(Default, Clone, Debug)]
pub struct ProjectFile<T> {
    pub path: PathBuf,
    pub entities: RefCell<Vec<Entity>>,
    pub pf_type: PhantomData<T>,
}

impl<T> ProjectFile<T>
where
    T: LanguageType,
{
    /// Creates a new ProjectFile instance.
    ///
    /// # Example
    ///
    /// ```
    /// use std::path::PathBuf;
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    ///
    /// assert_eq!(project_file.path, PathBuf::from("test/project_file"));
    /// assert_eq!(project_file.entities().len(), 0);
    /// ```
    pub fn new<S: Into<PathBuf>>(path: S) -> Self {
        Self {
            path: path.into(),
            entities: RefCell::new(Vec::new()),
            pf_type: PhantomData,
        }
    }

    /// Returns a reference to the entities list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::entity::Entity;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    /// project_file.entities_mut().push(Entity::new("testEntity"));
    ///
    /// assert_eq!(project_file.entities().len(), 1);
    /// ```
    pub fn entities(&self) -> Ref<Vec<Entity>> {
        self.entities.borrow()
    }

    /// Returns a mutable reference to the entities list.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::ProjectFile;
    /// use thinlinelib::entity::Entity;
    /// use thinlinelib::language_type::C;
    ///
    /// let project_file: ProjectFile<C> = ProjectFile::new("test/project_file");
    /// project_file.entities_mut().push(Entity::new("testEntity"));
    ///
    /// let mut entities = project_file.entities_mut();
    /// assert_eq!(entities.len(), 1);
    ///
    /// entities.clear();
    /// assert_eq!(entities.len(), 0);
    /// ```
    pub fn entities_mut(&self) -> RefMut<Vec<Entity>> {
        self.entities.borrow_mut()
    }
}

impl<T> Display for ProjectFile<T>
where
    T: LanguageType,
{
    /// Formats a ProjectFile to be displayed by std output.
    fn fmt(&self, f: &mut Formatter) -> Result {
        if let Some(path) = self.path.to_str() {
            return write!(f, "{}", path);
        }
        write!(f, "Unable to stringify filename")
    }
}

////////////////////////////////////////////////////////////////////////////////

/// The analyzer which fulfills parsing and entity extraction tasks.
#[derive(Default, Debug)]
pub struct Analysis<T>
where
    T: LanguageType,
{
    pub file_types: &'static [&'static str],
    pub project_files: RefCell<Vec<ProjectFile<T>>>,
}

impl<T> Analysis<T>
where
    T: LanguageType,
{
    /// Creates a new Analysis instance.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::Analysis;
    /// use thinlinelib::language_type::{C, LanguageType};
    ///
    /// let analysis: Analysis<C> = Analysis::new();
    ///
    /// assert_eq!(analysis.file_types, C::file_types());
    /// assert_eq!(analysis.project_files().len(), 0);
    /// ```
    pub fn new() -> Self {
        Self {
            file_types: T::file_types(),
            project_files: RefCell::new(Vec::new()),
        }
    }

    /// Returns a reference to the collected project files for analysis.
    pub fn project_files(&self) -> Ref<Vec<ProjectFile<T>>> {
        self.project_files.borrow()
    }

    /// Returns a mutable reference to the collected project files for analysis.
    ///
    /// # Example
    ///
    /// ```
    /// use thinlinelib::analysis::{Analysis, ProjectFile};
    /// use thinlinelib::language_type::C;
    ///
    /// let analysis: Analysis<C> = Analysis::new();
    /// let mut project_files = analysis.project_files_mut();
    /// assert_eq!(project_files.len(), 0);
    ///
    /// project_files.push(ProjectFile::new("test/anotherFile"));
    /// assert_eq!(project_files.len(), 1);
    /// ```
    pub fn project_files_mut(&self) -> RefMut<Vec<ProjectFile<T>>> {
        self.project_files.borrow_mut()
    }

    /// Collects all the sources within the given project dir.
    /// Does also work for symlinked files.
    pub fn collect_sources(&self, project_dir: &PathBuf, search_dirs: &[String]) -> Fallible<()> {
        // Check the given project directory
        if !project_dir.exists() || !project_dir.is_dir() {
            return Err(format_err!(
                "The given project dir '{}' does not exist.",
                project_dir
                    .to_str()
                    .ok_or_else(|| err_msg("Unable to stringify project dir path."))?
            ));
        }

        // Traverse through the files within the specified source directories
        // and store them for analyzing purposes
        for src_dir in search_dirs {
            for ext in self.file_types {
                for dir in WalkDir::new(project_dir.join(src_dir).to_str().unwrap_or(".")) {
                    let entry = dir?;
                    if !entry.path().is_dir() && entry.path().extension() == Some(OsStr::new(ext)) {
                        if entry.path_is_symlink() {
                            self.project_files_mut()
                                .push(ProjectFile::new(read_link(entry.path())?));
                        } else {
                            self.project_files_mut()
                                .push(ProjectFile::new(entry.path()));
                        }
                    }
                }
            }
        }

        Ok(())
    }

    /// Extracts function signatures and comments of thinlines parsed files.
    pub fn extract_entities(&self) -> Fallible<()> {
        T::extract_entities(&self)
    }
}
<|endoftext|>


<commit_before>#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(rocket_codegen)]

#[macro_use]
extern crate clap;
extern crate config;
extern crate diesel;
#[macro_use]
extern crate failure;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate ring;
extern crate rocket;
extern crate rocket_contrib;
extern crate serde;
extern crate yaml_rust;

extern crate _aardwolf as aardwolf;

mod common;
use common::{configure, db_conn_string};

use failure::Error;
use ring::rand::SystemRandom;
use rocket::Rocket;
use rocket_contrib::Template;
use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;
use clap::App;

type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;

fn db_pool(rocket: &Rocket) -> Result<Pool, Error> {
    let database_url = rocket.config().get_str("database_url")?;
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    Ok(r2d2::Pool::builder().build(manager)?)
}

fn app(config: config::Config) -> Result<Rocket, Error> {
    let db_url = db_conn_string(&config)?;

    let c = rocket::Config::build(rocket::config::Environment::Development)
        .address(config.get_str("Web.Listen.address")?)
        .port(config.get::<u16>("Web.Listen.port")?)
        .extra("database_url", db_url.as_str())
        .unwrap();

    let mut routes = Vec::new();

    routes.extend(routes![
        aardwolf::routes::auth::sign_up_form,
        aardwolf::routes::auth::sign_up_form_with_error,
        aardwolf::routes::auth::sign_in_form,
        aardwolf::routes::auth::sign_in_form_with_error,
        aardwolf::routes::auth::sign_up,
        aardwolf::routes::auth::sign_in,
        aardwolf::routes::auth::confirm,
        aardwolf::routes::auth::sign_out,
        aardwolf::routes::app::home,
        aardwolf::routes::app::home_redirect,
    ]);

    #[cfg(debug_assertions)]
    routes.extend(routes![
        // webroot/favicon
        aardwolf::routes::app::webroot,
        // emoji
        aardwolf::routes::app::emoji,
        // fork_awesome
        aardwolf::routes::app::fork_awesome,
        // images
        aardwolf::routes::app::images,
        // javascript
        aardwolf::routes::app::javascript,
        // stylesheets
        aardwolf::routes::app::stylesheets,
        // themes
        aardwolf::routes::app::themes,
    ]);

    let r = rocket::custom(c, true)
        .mount(
            "/api/v1",
            routes![aardwolf::routes::applications::register_application],
        )
        .mount("/", routes)
        .attach(Template::fairing())
        .manage(SystemRandom::new());

    // we need an instance of the app to access the config values in Rocket.toml,
    // so we pass it to the db_pool function, get the pool, and _then_ return the instance
    let pool = db_pool(&r)?;
    Ok(r.manage(pool))
}

fn cli<'a, 'b>(yaml: &'a yaml_rust::yaml::Yaml) -> App<'a, 'b> {
    App::from_yaml(yaml)
        .name(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
}

fn main() {
    let yaml = load_yaml!("cli.yml");
    let cli = cli(&yaml);
    let config = configure(cli).unwrap();

    app(config).unwrap().launch();
}
<commit_msg>Fixing whitespace conflict<commit_after>#![feature(plugin)]
#![feature(custom_derive)]
#![plugin(rocket_codegen)]

#[macro_use]
extern crate clap;
extern crate config;
extern crate diesel;
#[macro_use]
extern crate failure;
extern crate r2d2;
extern crate r2d2_diesel;
extern crate ring;
extern crate rocket;
extern crate rocket_contrib;
extern crate serde;
extern crate yaml_rust;

extern crate _aardwolf as aardwolf;

mod common;
use common::{configure, db_conn_string};

use failure::Error;
use ring::rand::SystemRandom;
use rocket::Rocket;
use rocket_contrib::Template;
use diesel::pg::PgConnection;
use r2d2_diesel::ConnectionManager;
use clap::App;

type Pool = r2d2::Pool<ConnectionManager<PgConnection>>;

fn db_pool(rocket: &Rocket) -> Result<Pool, Error> {
    let database_url = rocket.config().get_str("database_url")?;
    let manager = ConnectionManager::<PgConnection>::new(database_url);
    Ok(r2d2::Pool::builder().build(manager)?)
}

fn app(config: config::Config) -> Result<Rocket, Error> {
    let db_url = db_conn_string(&config)?;

    let c = rocket::Config::build(rocket::config::Environment::Development)
        .address(config.get_str("Web.Listen.address")?)
        .port(config.get::<u16>("Web.Listen.port")?)
        .extra("database_url", db_url.as_str())
        .unwrap();

    let mut routes = Vec::new();

    routes.extend(routes![
        aardwolf::routes::auth::sign_up_form,
        aardwolf::routes::auth::sign_up_form_with_error,
        aardwolf::routes::auth::sign_in_form,
        aardwolf::routes::auth::sign_in_form_with_error,
        aardwolf::routes::auth::sign_up,
        aardwolf::routes::auth::sign_in,
        aardwolf::routes::auth::confirm,
        aardwolf::routes::auth::sign_out,
        aardwolf::routes::app::home,
        aardwolf::routes::app::home_redirect,
    ]);

    #[cfg(debug_assertions)]
    routes.extend(routes![
        // webroot/favicon
        aardwolf::routes::app::webroot,
        // emoji
        aardwolf::routes::app::emoji,
        // fork_awesome
        aardwolf::routes::app::fork_awesome,
        // images
        aardwolf::routes::app::images,
        // javascript
        aardwolf::routes::app::javascript,
        // stylesheets
        aardwolf::routes::app::stylesheets,
        // themes
        aardwolf::routes::app::themes,
    ]);

    let r = rocket::custom(c, true)
        .mount(
            "/api/v1",
            routes![aardwolf::routes::applications::register_application],
        )
        .mount("/", routes)
        .attach(Template::fairing())
        .manage(SystemRandom::new());

    // we need an instance of the app to access the config values in Rocket.toml,
    // so we pass it to the db_pool function, get the pool, and _then_ return the instance
    let pool = db_pool(&r)?;
    Ok(r.manage(pool))
}

fn cli<'a, 'b>(yaml: &'a yaml_rust::yaml::Yaml) -> App<'a, 'b> {
    App::from_yaml(yaml)
        .name(env!("CARGO_PKG_NAME"))
        .version(env!("CARGO_PKG_VERSION"))
        .author(env!("CARGO_PKG_AUTHORS"))
        .about(env!("CARGO_PKG_DESCRIPTION"))
}

fn main() {
    let yaml = load_yaml!("cli.yml");
    let cli = cli(&yaml);
    let config = configure(cli).unwrap();

    app(config).unwrap().launch();
}
<|endoftext|>


<commit_before>fn main() {
    let mut vec = vec![0];

    for x in 0..1000 {
        if x % 3 == 0 {
            vec.push(x);
        } else if x % 5 == 0 {
            vec.push(x);
        }
    }

    let vecsum: u32 = vec.iter().sum();
    println!("The sum of all multiples of 3 and 5 below 1000 equals to {}", vecsum);
}
<commit_msg>optimized code<commit_after>fn main() {
    let mut sum = 0;

    for x in 0..1000 {
        if x % 3 == 0 {
            sum += x;
        } else if x % 5 == 0 {
            sum += x;
        }
    }

    println!("The sum of all multiples of 3 and 5 below 1000 equals to {}", sum);
}
<|endoftext|>


<commit_before>#[deny(warnings)]

#[macro_use]
extern crate log;
#[macro_use]
extern crate glium;
extern crate env_logger;
extern crate lights;

use std::error::Error;
use std::io::prelude::*;

use env_logger::LogBuilder;
use glium::backend::Facade;
use glium::DrawParameters;
use glium::texture::Texture2d;
use glium::index::{IndexBuffer, PrimitiveType};
use glium::{Surface, VertexBuffer, DrawError};

use lights::{App, Api, Painter, load_texture_jpeg, load_texture_png, slurp, slurp_bytes};
use lights::math::*;

mod vertex;

use vertex::Vertex;

fn init_log() {
    LogBuilder::new()
        .parse("info")
        .init()
        .expect("Failed to init the logger");
}

fn main() {
    if let Err(e) = run() {
        writeln!(std::io::stderr(), "{}\n=(", e).unwrap();
        writeln!(std::io::stderr(), "\nGuru meditation {:#?}", e).unwrap();
    }
}

fn run() -> Result<(), Box<std::error::Error>> {
    init_log();
    try!(App::<Matisse>::run());
    Ok(())
}

struct Matisse {
    vertex_shader: String,
    fragment_shader: String,
    vertex_buffer: VertexBuffer<Vertex>,
    index_buffer: IndexBuffer<u16>,
    texture1: Texture2d,
    texture2: Texture2d,
}

impl Painter for Matisse {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    fn new<F: Facade>(facade: &F) -> Result<Matisse, Box<Error>> {
        let shape = Vertex::many(vec![
    // Positions          // Colors           // Texture Coords
             0.5,  0.5, 0.0,   1.0, 0.0, 0.0,   1.0, 1.0,   // Top Right
             0.5, -0.5, 0.0,   0.0, 1.0, 0.0,   1.0, 0.0,   // Bottom Right
            -0.5, -0.5, 0.0,   0.0, 0.0, 1.0,   0.0, 0.0,   // Bottom Left
            -0.5,  0.5, 0.0,   1.0, 1.0, 0.0,   0.0, 1.0    // Top Left
        ]);
        let indices = vec![
            0, 1, 3,
            1, 2, 3
        ];

        let vertex_buffer = try!(VertexBuffer::new(facade, &shape));
        let index_buffer = IndexBuffer::new(facade, PrimitiveType::TrianglesList, &indices)
            .expect("failed to crate an index buffer");

        info!("Start loading textures...");
        let image1 = load_texture_jpeg(&slurp_bytes("./src/bin/textures/container.jpg"));
        let texture1 = glium::texture::Texture2d::new(facade, image1)
            .expect("Failed to load container texture");

        let image2 = load_texture_png(&slurp_bytes("./src/bin/textures/awesomeface.png"));
        let texture2 = glium::texture::Texture2d::new(facade, image2)
            .expect("Failed to load container texture");
        info!("... textures loaded!");

        Ok(Matisse {
            vertex_shader: slurp("./src/bin/shaders/vertex.glsl"),
            fragment_shader: slurp("./src/bin/shaders/fragment.glsl"),
            vertex_buffer: vertex_buffer,
            index_buffer: index_buffer,
            texture1: texture1,
            texture2: texture2,
        })
    }

    fn vertex_shader(&self) -> &str {
        &self.vertex_shader
    }

    fn fragment_shader(&self) -> &str {
        &self.fragment_shader
    }

    fn draw<S: Surface>(&self, api: &mut Api<S>) -> std::result::Result<(), DrawError> {

        let params = DrawParameters { ..Default::default() };

        let transform = id().scale(0.5).rotate(vec3(0.0, 0.0, 1.0), Rad::turn_div_4());

        let uniforms = uniform! {
            tex1: &self.texture1,
            tex2: &self.texture2,
            transform: transform.into_uniform(),
        };

        try!(api.surface.draw(&self.vertex_buffer,
                              &self.index_buffer,
                              api.program,
                              &uniforms,
                              &params));
        Ok(())
    }
}

<commit_msg>minor refactoring<commit_after>#[deny(warnings)]
#[macro_use]
extern crate log;
#[macro_use]
extern crate glium;
extern crate env_logger;
extern crate lights;

use std::error::Error;
use std::io::prelude::*;

use env_logger::LogBuilder;
use glium::backend::Facade;
use glium::DrawParameters;
use glium::texture::Texture2d;
use glium::index::{IndexBuffer, PrimitiveType};
use glium::{Surface, VertexBuffer, DrawError};

use lights::{App, Api, Painter, load_texture_jpeg, load_texture_png, slurp, slurp_bytes};
use lights::math::*;

mod vertex;

use vertex::Vertex;

fn init_log() {
    LogBuilder::new()
        .parse("info")
        .init()
        .expect("Failed to init the logger");
}

fn main() {
    if let Err(e) = run() {
        writeln!(std::io::stderr(), "{}\n=(", e).unwrap();
        writeln!(std::io::stderr(), "\nGuru meditation {:#?}", e).unwrap();
    }
}

fn run() -> Result<(), Box<std::error::Error>> {
    init_log();
    try!(App::<Matisse>::run());
    Ok(())
}

struct Matisse {
    vertex_shader: String,
    fragment_shader: String,
    vertex_buffer: VertexBuffer<Vertex>,
    index_buffer: IndexBuffer<u16>,
    texture1: Texture2d,
    texture2: Texture2d,
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn prepare_shape<F: Facade>(facade: &F)
    -> Result<(VertexBuffer<Vertex>, IndexBuffer<u16>), Box<Error>> {
    let shape = Vertex::many(vec![
         // Positions      // Colors        // Texture Coords
         0.5,  0.5, 0.0,   1.0, 0.0, 0.0,   1.0, 1.0,   // Top Right
         0.5, -0.5, 0.0,   0.0, 1.0, 0.0,   1.0, 0.0,   // Bottom Right
        -0.5, -0.5, 0.0,   0.0, 0.0, 1.0,   0.0, 0.0,   // Bottom Left
        -0.5,  0.5, 0.0,   1.0, 1.0, 0.0,   0.0, 1.0    // Top Left
    ]);
    let indices = vec![
        0, 1, 3,
        1, 2, 3
    ];

    let vertex_buffer = try!(VertexBuffer::new(facade, &shape));
    let index_buffer = IndexBuffer::new(facade, PrimitiveType::TrianglesList, &indices)
        .expect("failed to crate an index buffer");

    Ok((vertex_buffer, index_buffer))

}

impl Painter for Matisse {
    fn new<F: Facade>(facade: &F) -> Result<Matisse, Box<Error>> {
        let (vertex_buffer, index_buffer) = try!(prepare_shape(facade));

        info!("Start loading textures...");
        let image1 = load_texture_jpeg(&slurp_bytes("./src/bin/textures/container.jpg"));
        let texture1 = glium::texture::Texture2d::new(facade, image1)
                           .expect("Failed to load container texture");

        let image2 = load_texture_png(&slurp_bytes("./src/bin/textures/awesomeface.png"));
        let texture2 = glium::texture::Texture2d::new(facade, image2)
                           .expect("Failed to load container texture");
        info!("... textures loaded!");

        Ok(Matisse {
            vertex_shader: slurp("./src/bin/shaders/vertex.glsl"),
            fragment_shader: slurp("./src/bin/shaders/fragment.glsl"),
            vertex_buffer: vertex_buffer,
            index_buffer: index_buffer,
            texture1: texture1,
            texture2: texture2,
        })
    }

    fn vertex_shader(&self) -> &str {
        &self.vertex_shader
    }

    fn fragment_shader(&self) -> &str {
        &self.fragment_shader
    }

    fn draw<S: Surface>(&self, api: &mut Api<S>) -> std::result::Result<(), DrawError> {

        let params = DrawParameters { ..Default::default() };

        let transform = id().scale(0.5).rotate(vec3(0.0, 0.0, 1.0), Rad::turn_div_4());

        let uniforms = uniform! {
            tex1: &self.texture1,
            tex2: &self.texture2,
            transform: transform.into_uniform(),
        };

        try!(api.surface.draw(&self.vertex_buffer,
                              &self.index_buffer,
                              api.program,
                              &uniforms,
                              &params));
        Ok(())
    }
}
<|endoftext|>


<commit_before>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 *
 * Coming:
 * eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args.len() {
                0 => $identity,
                1 => vec::foldl($identity, args, |x, y| {x.$function(y)}),
                _ => vec::foldl(args.head(), args.tail(), |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    if args.len() > 1 {
        fail fmt!("Built-in function 'not' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'car' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'cdr' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'cons' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'append' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'length' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'equal?' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'symbol?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'list?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'null?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<commit_msg>Use vector pattern matching<commit_after>/*
 * Built-in method definitions for scheme
 *
 * Done:
 * +, -, *, / (works on lists of numbers)
 * =, >, <, >=, <= (works on list of numbers)
 * not (works on single argument)
 * list (works on any arguments)
 * list?, null?, symbol? (works on single argument)
 * cons, car, cdr, append
 * equal?
 *
 * Coming:
 * eq?
 *
 *    {'+':op.add, '-':op.sub, '*':op.mul, '/':op.div, 'not':op.not_,
       '>':op.gt, '<':op.lt, '>=':op.ge, '<=':op.le, '=':op.eq,
       'equal?':op.eq, 'eq?':op.is_, 'length':len, 'cons':lambda x,y:[x]+y,
       'car':lambda x:x[0],'cdr':lambda x:x[1:], 'append':op.add,
       'list':lambda *x:list(x), 'list?': lambda x:isa(x,list),
       'null?':lambda x:x==[], 'symbol?':lambda x: isa(x, Symbol)})
 *
 */

macro_rules! math_function {
    ($function:ident $identity:expr) => {
        pub fn $function( args:~[Expression], _:@Environment) -> Expression {
            match args {
                [] => $identity,
                [head] => vec::foldl($identity, ~[head], |x, y| {x.$function(y)}),
                [head, ..tail] => vec::foldl(head, tail, |x, y| {x.$function(y)})
            }
        }
    }
}

math_function!(add Int(0))
math_function!(sub Int(0))
math_function!(mul Int(1))
math_function!(div Int(1))

pub fn equals( args:~[Expression], _:@Environment) -> Expression {
    for args.tail().each() |&expr| {
        if expr != args.head() {
            return Bool(false);
        }
    }
    return Bool(true);
}

pub fn not( args:~[Expression], _:@Environment) -> Expression {
    if args.len() > 1 {
        fail fmt!("Built-in function 'not' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    return Bool(!args[0].to_bool());
}

pub fn car( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'car' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => list.head(),
        _ => fail fmt!("Built-in function 'car' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cdr( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'cdr' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => List(list.tail()),
        _ => fail fmt!("Built-in function 'cdr' requires a list argument. It was called with %s", args[0].to_str())
    }
}

pub fn cons( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'cons' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[1] {
        List(list) => List( ~[args[0]] + list ),
        x => List( ~[args[0]] + ~[x] )
    }
}

pub fn append( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'append' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list1) => {
            match copy args[1] {
                List(list) => List( list1 + list ),
                x => List( list1 + ~[x] )
            }
        }
        _ => fail fmt!("Built-in function 'append' requires a list as the first arguments. It was called with %s", List(args).to_str())
    }
}

pub fn length( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'length' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Int(list.len() as int),
        _ => fail fmt!("Built-in function 'append' requires a list argument. It was called with %s", List(args).to_str())
    }
}

pub fn equal_( args:~[Expression], _:@Environment ) -> Expression {
    if args.len() != 2 {
        fail fmt!("Built-in function 'equal?' takes two arguments. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    Bool(args[0] == args[1])
}

pub fn symbol_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'symbol?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        Symbol(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn list_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'list?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match args[0] {
        List(_) => Bool(true),
        _ => Bool(false)
    }
}

pub fn null_( args:~[Expression], _:@Environment) -> Expression {
    if args.len() != 1 {
        fail fmt!("Built-in function 'null?' takes only one argument. It was called with %u '%s'", args.len(), List(args).to_str());
    }

    match copy args[0] {
        List(list) => Bool(list.len() == 0),
        _ => Bool(false)
    }
}

pub fn list( args:~[Expression], _:@Environment) -> Expression {
    List(args)
}

pub fn builtins() -> ~[(~str,~fn(~[Expression], @Environment) -> Expression)] {
    ~[ (~"+", add), (~"-", sub), (~"*", mul), (~"/", div),
       (~"=", equals), (~"not", not),
       (~"car", car), (~"cdr", cdr),
       (~"cons", cons), (~"append", append),
       (~"list", list), (~"length", length),
       (~"equal?", equal_),
       (~"symbol?", symbol_),
       (~"list?", list_),
       (~"null?", null_)
    ]
}
<|endoftext|>


<commit_before>use crate::aabb::Bounded;
use crate::bvh::{BVH, BVHNode};
use crate::ray::Ray;

/// Iterator traverse a BVH without memory allocations
pub struct BVHIterator<'a, Shape: Bounded> {
    bvh: &'a BVH,
    ray: &'a Ray,
    shapes: &'a [Shape],
    stack: [usize; 32],
    node_index: usize,
    stack_size: usize,
    has_node: bool,
}

impl<'a, Shape: Bounded> BVHIterator<'a, Shape> {
    /// Creates a new BVHIterator
    pub fn new(bvh: &'a BVH, ray: &'a Ray, shapes: &'a [Shape]) -> Self {
        BVHIterator {
            /// Reference to the BVH to traverse
            bvh: bvh,

            /// Reference to the input ray
            ray: ray,

            /// Reference to the input shapes array
            shapes: shapes,

            /// Traversal stack. 4 billion items seems enough?
            stack: [0; 32],

            /// Position of the iterator in bvh.nodes
            node_index: 0,

            /// Size of the traversal stack
            stack_size: 0,

            /// Whether or not we have a valid node (or leaf)
            has_node: true,
        }
    }

    /// Test if stack is empty.
    fn is_stack_empty(&self) -> bool {
        return self.stack_size == 0;
    }

    /// Push node onto stack. Not guarded against overflow.
    fn stack_push(&mut self, node: usize) {
        self.stack[self.stack_size] = node;
        self.stack_size += 1;
    }

    /// Pop the stack and return the node. Not guarded against underflow.
    fn stack_pop(&mut self) -> usize {
        self.stack_size -= 1;
        return self.stack[self.stack_size];
    }

    /// Attempt to move to the left child of the current node.
    fn move_left(&mut self) {
        match self.bvh.nodes[self.node_index] {
            BVHNode::Node {
                child_l_index,
                ref child_l_aabb,
                ..
            } => {
                if self.ray.intersects_aabb(child_l_aabb) {
                    self.node_index = child_l_index;
                    self.has_node = true;
                } else {
                    self.has_node = false;
                }
            }
            BVHNode::Leaf { .. } => {
                self.has_node = false;
            }
        }
    }

    /// Attempt to move to the right child of the current node.
    fn move_right(&mut self) {
        match self.bvh.nodes[self.node_index] {
            BVHNode::Node {
                child_r_index,
                ref child_r_aabb,
                ..
            } => {
                if self.ray.intersects_aabb(child_r_aabb) {
                    self.node_index = child_r_index;
                    self.has_node = true;
                } else {
                    self.has_node = false;
                }
            }
            BVHNode::Leaf { .. } => {
                self.has_node = false;
            }
        }
    }
}

impl<'a, Shape: Bounded> Iterator for BVHIterator<'a, Shape> {
    type Item = &'a Shape;

    fn next(&mut self) -> Option<&'a Shape> {
        loop {
            if self.is_stack_empty() && !self.has_node {
                // Completed traversal.
                break;
            }
            if self.has_node {
                // If we have any node, save it and attempt to move to its left child.
                self.stack_push(self.node_index);
                self.move_left();
            } else {
                // Go back up the stack and see if a node or leaf was pushed.
                self.node_index = self.stack_pop();
                match self.bvh.nodes[self.node_index] {
                    BVHNode::Node { .. } => {
                        // If a node was pushed, now attempt to move to its right child.
                        self.move_right();
                    }
                    BVHNode::Leaf { shape_index, .. } => {
                        // We previously pushed a leaf node. This is the "visit" of the in-order traverse.
                        // Next time we call next we try to pop the stack again.
                        self.has_node = false;
                        return Some(&self.shapes[shape_index]);
                    }
                }
            }
        }
        return None;
    }
}

// Copy of part of the BH testing in testbase.
// TODO: Once iterators are part of the BoundingHierarchy trait we can move all this to testbase.
#[cfg(test)]
mod tests {
    use crate::bvh::{BVHNode, BVH};
    use std::collections::HashSet;
    use std::f32;

    use nalgebra::{Point3, Vector3};

    use crate::aabb::{Bounded, AABB};
    use crate::bounding_hierarchy::BHShape;
    use crate::ray::Ray;

    /// Define some `Bounded` structure.
    pub struct UnitBox {
        pub id: i32,
        pub pos: Point3<f32>,
        node_index: usize,
    }

    impl UnitBox {
        pub fn new(id: i32, pos: Point3<f32>) -> UnitBox {
            UnitBox {
                id: id,
                pos: pos,
                node_index: 0,
            }
        }
    }

    /// `UnitBox`'s `AABB`s are unit `AABB`s centered on the box's position.
    impl Bounded for UnitBox {
        fn aabb(&self) -> AABB {
            let min = self.pos + Vector3::new(-0.5, -0.5, -0.5);
            let max = self.pos + Vector3::new(0.5, 0.5, 0.5);
            AABB::with_bounds(min, max)
        }
    }

    impl BHShape for UnitBox {
        fn set_bh_node_index(&mut self, index: usize) {
            self.node_index = index;
        }

        fn bh_node_index(&self) -> usize {
            self.node_index
        }
    }

    /// Generate 21 `UnitBox`s along the X axis centered on whole numbers (-10,9,..,10).
    /// The index is set to the rounded x-coordinate of the box center.
    pub fn generate_aligned_boxes() -> Vec<UnitBox> {
        // Create 21 boxes along the x-axis
        let mut shapes = Vec::new();
        for x in -10..11 {
            shapes.push(UnitBox::new(x, Point3::new(x as f32, 0.0, 0.0)));
        }
        shapes
    }

    /// Creates a `BoundingHierarchy` for a fixed scene structure.
    pub fn build_some_bvh() -> (Vec<UnitBox>, BVH) {
        let mut boxes = generate_aligned_boxes();
        let bvh = BVH::build(&mut boxes);
        (boxes, bvh)
    }

    /// Given a ray, a bounding hierarchy, the complete list of shapes in the scene and a list of
    /// expected hits, verifies, whether the ray hits only the expected shapes.
    fn traverse_and_verify_vec(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        let ray = Ray::new(ray_origin, ray_direction);
        let hit_shapes = bvh.traverse(&ray, all_shapes);

        assert_eq!(expected_shapes.len(), hit_shapes.len());
        for shape in hit_shapes {
            assert!(expected_shapes.contains(&shape.id));
        }
    }

    fn traverse_and_verify_iterator(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        let ray = Ray::new(ray_origin, ray_direction);
        let it = bvh.traverse_iterator(&ray, all_shapes);

        let mut count = 0;
        for shape in it {
            assert!(expected_shapes.contains(&shape.id));
            count += 1;
        }
        assert_eq!(expected_shapes.len(), count);
    }

    fn traverse_and_verify_base(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        traverse_and_verify_vec(ray_origin, ray_direction, all_shapes, bvh, expected_shapes);
        traverse_and_verify_iterator(ray_origin, ray_direction, all_shapes, bvh, expected_shapes);
    }

    /// Perform some fixed intersection tests on BH structures.
    pub fn traverse_some_bvh() {
        let (all_shapes, bh) = build_some_bvh();

        {
            // Define a ray which traverses the x-axis from afar.
            let origin = Point3::new(-1000.0, 0.0, 0.0);
            let direction = Vector3::new(1.0, 0.0, 0.0);
            let mut expected_shapes = HashSet::new();

            // It should hit everything.
            for id in -10..11 {
                expected_shapes.insert(id);
            }
            traverse_and_verify_base(origin, direction, &all_shapes, &bh, &expected_shapes);
        }

        {
            // Define a ray which traverses the y-axis from afar.
            let origin = Point3::new(0.0, -1000.0, 0.0);
            let direction = Vector3::new(0.0, 1.0, 0.0);

            // It should hit only one box.
            let mut expected_shapes = HashSet::new();
            expected_shapes.insert(0);
            traverse_and_verify_base(origin, direction, &all_shapes, &bh, &expected_shapes);
        }

        {
            // Define a ray which intersects the x-axis diagonally.
            let origin = Point3::new(6.0, 0.5, 0.0);
            let direction = Vector3::new(-2.0, -1.0, 0.0);

            // It should hit exactly three boxes.
            let mut expected_shapes = HashSet::new();
            expected_shapes.insert(4);
            expected_shapes.insert(5);
            expected_shapes.insert(6);
            traverse_and_verify_base(origin, direction, &all_shapes, &bh, &expected_shapes);
        }
    }

    #[test]
    /// Runs some primitive tests for intersections of a ray with a fixed scene given as a BVH.
    fn test_traverse_bvh() {
        traverse_some_bvh();
    }

    #[test]
    /// Verify contents of the bounding hierarchy for a fixed scene structure
    fn test_bvh_shape_indices() {
        use std::collections::HashSet;

        let (all_shapes, bh) = build_some_bvh();

        // It should find all shape indices.
        let expected_shapes: HashSet<_> = (0..all_shapes.len()).collect();
        let mut found_shapes = HashSet::new();

        for node in bh.nodes.iter() {
            match *node {
                BVHNode::Node { .. } => {
                    assert_eq!(node.shape_index(), None);
                }
                BVHNode::Leaf { .. } => {
                    found_shapes.insert(
                        node.shape_index()
                            .expect("getting a shape index from a leaf node"),
                    );
                }
            }
        }

        assert_eq!(expected_shapes, found_shapes);
    }
}
<commit_msg>BVHIterator sponza benches<commit_after>use crate::aabb::Bounded;
use crate::bvh::{BVH, BVHNode};
use crate::ray::Ray;

/// Iterator traverse a BVH without memory allocations
pub struct BVHIterator<'a, Shape: Bounded> {
    bvh: &'a BVH,
    ray: &'a Ray,
    shapes: &'a [Shape],
    stack: [usize; 32],
    node_index: usize,
    stack_size: usize,
    has_node: bool,
}

impl<'a, Shape: Bounded> BVHIterator<'a, Shape> {
    /// Creates a new BVHIterator
    pub fn new(bvh: &'a BVH, ray: &'a Ray, shapes: &'a [Shape]) -> Self {
        BVHIterator {
            /// Reference to the BVH to traverse
            bvh: bvh,

            /// Reference to the input ray
            ray: ray,

            /// Reference to the input shapes array
            shapes: shapes,

            /// Traversal stack. 4 billion items seems enough?
            stack: [0; 32],

            /// Position of the iterator in bvh.nodes
            node_index: 0,

            /// Size of the traversal stack
            stack_size: 0,

            /// Whether or not we have a valid node (or leaf)
            has_node: true,
        }
    }

    /// Test if stack is empty.
    fn is_stack_empty(&self) -> bool {
        return self.stack_size == 0;
    }

    /// Push node onto stack. Not guarded against overflow.
    fn stack_push(&mut self, node: usize) {
        self.stack[self.stack_size] = node;
        self.stack_size += 1;
    }

    /// Pop the stack and return the node. Not guarded against underflow.
    fn stack_pop(&mut self) -> usize {
        self.stack_size -= 1;
        return self.stack[self.stack_size];
    }

    /// Attempt to move to the left child of the current node.
    fn move_left(&mut self) {
        match self.bvh.nodes[self.node_index] {
            BVHNode::Node {
                child_l_index,
                ref child_l_aabb,
                ..
            } => {
                if self.ray.intersects_aabb(child_l_aabb) {
                    self.node_index = child_l_index;
                    self.has_node = true;
                } else {
                    self.has_node = false;
                }
            }
            BVHNode::Leaf { .. } => {
                self.has_node = false;
            }
        }
    }

    /// Attempt to move to the right child of the current node.
    fn move_right(&mut self) {
        match self.bvh.nodes[self.node_index] {
            BVHNode::Node {
                child_r_index,
                ref child_r_aabb,
                ..
            } => {
                if self.ray.intersects_aabb(child_r_aabb) {
                    self.node_index = child_r_index;
                    self.has_node = true;
                } else {
                    self.has_node = false;
                }
            }
            BVHNode::Leaf { .. } => {
                self.has_node = false;
            }
        }
    }
}

impl<'a, Shape: Bounded> Iterator for BVHIterator<'a, Shape> {
    type Item = &'a Shape;

    fn next(&mut self) -> Option<&'a Shape> {
        loop {
            if self.is_stack_empty() && !self.has_node {
                // Completed traversal.
                break;
            }
            if self.has_node {
                // If we have any node, save it and attempt to move to its left child.
                self.stack_push(self.node_index);
                self.move_left();
            } else {
                // Go back up the stack and see if a node or leaf was pushed.
                self.node_index = self.stack_pop();
                match self.bvh.nodes[self.node_index] {
                    BVHNode::Node { .. } => {
                        // If a node was pushed, now attempt to move to its right child.
                        self.move_right();
                    }
                    BVHNode::Leaf { shape_index, .. } => {
                        // We previously pushed a leaf node. This is the "visit" of the in-order traverse.
                        // Next time we call next we try to pop the stack again.
                        self.has_node = false;
                        return Some(&self.shapes[shape_index]);
                    }
                }
            }
        }
        return None;
    }
}

// Copy of part of the BH testing in testbase.
// TODO: Once iterators are part of the BoundingHierarchy trait we can move all this to testbase.
#[cfg(test)]
mod tests {
    use crate::bvh::{BVHNode, BVH};
    use std::collections::HashSet;
    use std::f32;

    use nalgebra::{Point3, Vector3};

    use crate::aabb::{Bounded, AABB};
    use crate::bounding_hierarchy::BHShape;
    use crate::ray::Ray;

    /// Define some `Bounded` structure.
    pub struct UnitBox {
        pub id: i32,
        pub pos: Point3<f32>,
        node_index: usize,
    }

    impl UnitBox {
        pub fn new(id: i32, pos: Point3<f32>) -> UnitBox {
            UnitBox {
                id: id,
                pos: pos,
                node_index: 0,
            }
        }
    }

    /// `UnitBox`'s `AABB`s are unit `AABB`s centered on the box's position.
    impl Bounded for UnitBox {
        fn aabb(&self) -> AABB {
            let min = self.pos + Vector3::new(-0.5, -0.5, -0.5);
            let max = self.pos + Vector3::new(0.5, 0.5, 0.5);
            AABB::with_bounds(min, max)
        }
    }

    impl BHShape for UnitBox {
        fn set_bh_node_index(&mut self, index: usize) {
            self.node_index = index;
        }

        fn bh_node_index(&self) -> usize {
            self.node_index
        }
    }

    /// Generate 21 `UnitBox`s along the X axis centered on whole numbers (-10,9,..,10).
    /// The index is set to the rounded x-coordinate of the box center.
    pub fn generate_aligned_boxes() -> Vec<UnitBox> {
        // Create 21 boxes along the x-axis
        let mut shapes = Vec::new();
        for x in -10..11 {
            shapes.push(UnitBox::new(x, Point3::new(x as f32, 0.0, 0.0)));
        }
        shapes
    }

    /// Creates a `BoundingHierarchy` for a fixed scene structure.
    pub fn build_some_bvh() -> (Vec<UnitBox>, BVH) {
        let mut boxes = generate_aligned_boxes();
        let bvh = BVH::build(&mut boxes);
        (boxes, bvh)
    }

    /// Given a ray, a bounding hierarchy, the complete list of shapes in the scene and a list of
    /// expected hits, verifies, whether the ray hits only the expected shapes.
    fn traverse_and_verify_vec(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        let ray = Ray::new(ray_origin, ray_direction);
        let hit_shapes = bvh.traverse(&ray, all_shapes);

        assert_eq!(expected_shapes.len(), hit_shapes.len());
        for shape in hit_shapes {
            assert!(expected_shapes.contains(&shape.id));
        }
    }

    fn traverse_and_verify_iterator(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        let ray = Ray::new(ray_origin, ray_direction);
        let it = bvh.traverse_iterator(&ray, all_shapes);

        let mut count = 0;
        for shape in it {
            assert!(expected_shapes.contains(&shape.id));
            count += 1;
        }
        assert_eq!(expected_shapes.len(), count);
    }

    fn traverse_and_verify_base(
        ray_origin: Point3<f32>,
        ray_direction: Vector3<f32>,
        all_shapes: &Vec<UnitBox>,
        bvh: &BVH,
        expected_shapes: &HashSet<i32>,
    ) {
        traverse_and_verify_vec(ray_origin, ray_direction, all_shapes, bvh, expected_shapes);
        traverse_and_verify_iterator(ray_origin, ray_direction, all_shapes, bvh, expected_shapes);
    }

    /// Perform some fixed intersection tests on BH structures.
    pub fn traverse_some_bvh() {
        let (all_shapes, bh) = build_some_bvh();

        {
            // Define a ray which traverses the x-axis from afar.
            let origin = Point3::new(-1000.0, 0.0, 0.0);
            let direction = Vector3::new(1.0, 0.0, 0.0);
            let mut expected_shapes = HashSet::new();

            // It should hit everything.
            for id in -10..11 {
                expected_shapes.insert(id);
            }
            traverse_and_verify_base(origin, direction, &all_shapes, &bh, &expected_shapes);
        }

        {
            // Define a ray which traverses the y-axis from afar.
            let origin = Point3::new(0.0, -1000.0, 0.0);
            let direction = Vector3::new(0.0, 1.0, 0.0);

            // It should hit only one box.
            let mut expected_shapes = HashSet::new();
            expected_shapes.insert(0);
            traverse_and_verify_base(origin, direction, &all_shapes, &bh, &expected_shapes);
        }

        {
            // Define a ray which intersects the x-axis diagonally.
            let origin = Point3::new(6.0, 0.5, 0.0);
            let direction = Vector3::new(-2.0, -1.0, 0.0);

            // It should hit exactly three boxes.
            let mut expected_shapes = HashSet::new();
            expected_shapes.insert(4);
            expected_shapes.insert(5);
            expected_shapes.insert(6);
            traverse_and_verify_base(origin, direction, &all_shapes, &bh, &expected_shapes);
        }
    }

    #[test]
    /// Runs some primitive tests for intersections of a ray with a fixed scene given as a BVH.
    fn test_traverse_bvh() {
        traverse_some_bvh();
    }

    #[test]
    /// Verify contents of the bounding hierarchy for a fixed scene structure
    fn test_bvh_shape_indices() {
        use std::collections::HashSet;

        let (all_shapes, bh) = build_some_bvh();

        // It should find all shape indices.
        let expected_shapes: HashSet<_> = (0..all_shapes.len()).collect();
        let mut found_shapes = HashSet::new();

        for node in bh.nodes.iter() {
            match *node {
                BVHNode::Node { .. } => {
                    assert_eq!(node.shape_index(), None);
                }
                BVHNode::Leaf { .. } => {
                    found_shapes.insert(
                        node.shape_index()
                            .expect("getting a shape index from a leaf node"),
                    );
                }
            }
        }

        assert_eq!(expected_shapes, found_shapes);
    }
}

#[cfg(all(feature = "bench", test))]
mod bench {
    use crate::bvh::BVH;
    use crate::testbase::{
        load_sponza_scene, create_ray,
    };

    #[bench]
    /// Benchmark the traversal of a `BVH` with the Sponza scene with Vec return.
    fn bench_intersect_128rays_sponza_vec(b: &mut ::test::Bencher) {
        let (mut triangles, bounds) = load_sponza_scene();
        let bvh = BVH::build(&mut triangles);

        let mut seed = 0;
        b.iter(|| {
            for _ in 0..128
            {
                let ray = create_ray(&mut seed, &bounds);

                // Traverse the `BVH` recursively.
                let hits = bvh.traverse(&ray, &triangles);

                // Traverse the resulting list of positive `AABB` tests
                for triangle in &hits {
                    ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
                }
            }
        });
    }

    #[bench]
    /// Benchmark the traversal of a `BVH` with the Sponza scene with `BVHIterator`.
    fn bench_intersect_128rays_sponza_iter(b: &mut ::test::Bencher) {
        let (mut triangles, bounds) = load_sponza_scene();
        let bvh = BVH::build(&mut triangles);

        let mut seed = 0;
        b.iter(|| {
            for _ in 0..128
            {
                let ray = create_ray(&mut seed, &bounds);

                // Traverse the `BVH` recursively.
                let hits = bvh.traverse_iterator(&ray, &triangles);

                // Traverse the resulting list of positive `AABB` tests
                for triangle in hits {
                    ray.intersects_triangle(&triangle.a, &triangle.b, &triangle.c);
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>use std::default::Default;

use ast::Expression;
use error::ErrorStack;
use stdlib::Stdlib;
use table::Table;
use to_javascript::ToJavaScript;

pub struct Compiler<'a> {
    pub errors: ErrorStack,
    pub stdlib: Stdlib<'a>,
}

impl<'a> Compiler<'a> {
    pub fn new() -> Compiler<'a> {
        let mut stdlib = Stdlib::new(Table::new(None));

        stdlib.populate();

        Compiler {
            errors: ErrorStack(vec![]),
            stdlib: stdlib,
        }
    }

    pub fn compile(&mut self, tree: &mut [Expression]) -> String {
        tree
            .into_iter()
            // TODO: Remove unwrap
            .filter_map(|expr| {
                let result = expr.eval(&mut self.stdlib);

                if result.is_err() {
                    self.errors.0.push(result.clone().unwrap_err());
                }

                result.ok()
            })
            .collect::<Vec<String>>()
            .join(";")
    }
}

impl<'a> Default for Compiler<'a> {
    fn default() -> Self {
        Self::new()
    }
}
<commit_msg>Make stdlib.populate private<commit_after>use std::default::Default;

use ast::Expression;
use error::ErrorStack;
use stdlib::Stdlib;
use table::Table;
use to_javascript::ToJavaScript;

pub struct Compiler<'a> {
    pub errors: ErrorStack,
    pub stdlib: Stdlib<'a>,
}

impl<'a> Compiler<'a> {
    pub fn new() -> Compiler<'a> {
        let stdlib = Stdlib::new(Table::new(None));

        Compiler {
            errors: ErrorStack(vec![]),
            stdlib: stdlib,
        }
    }

    pub fn compile(&mut self, tree: &mut [Expression]) -> String {
        tree
            .into_iter()
            // TODO: Remove unwrap
            .filter_map(|expr| {
                let result = expr.eval(&mut self.stdlib);

                if result.is_err() {
                    self.errors.0.push(result.clone().unwrap_err());
                }

                result.ok()
            })
            .collect::<Vec<String>>()
            .join(";")
    }
}

impl<'a> Default for Compiler<'a> {
    fn default() -> Self {
        Self::new()
    }
}
<|endoftext|>