<commit_before>use racer::{self, ast, codecleaner, codeiter, typeinf, util};

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::iter::Iterator;
use std::path::Path;
use std::str::from_utf8;

fn find_close<'a, A>(iter: A, open: u8, close: u8, level_end: u32) -> Option<usize>
    where A: Iterator<Item=&'a u8> {

    let mut count = 0usize;
    let mut levels = 0u32;
    for &b in iter {
        if b == close {
            if levels == level_end { return Some(count); }
            levels -= 1;
        } else if b == open { levels += 1; }
        count += 1;
    }
    None
}

pub fn find_closing_paren(src:&str, pos:usize) -> usize {
    match find_close(src.as_bytes()[pos..].iter(), b'(', b')', 0) {
        Some(count) => pos + count,
        None => src.len()
    }
}

pub fn scope_start(src:&str, point:usize) -> usize {
    let masked_src = mask_comments(&src[..point]);
    match find_close(masked_src.as_bytes().iter().rev(), b'}', b'{', 0) {
        Some(count) => point - count,
        None => 0
    }
}

pub fn find_stmt_start(msrc: &str, point: usize) -> Option<usize> {
    // iterate the scope to find the start of the statement
    let scopestart = scope_start(msrc, point);
    codeiter::iter_stmts(&msrc[scopestart..]).filter_map(|(start, end)|
        if scopestart+end > point { Some(scopestart+start) } else {None}).next()
}

pub fn get_local_module_path(msrc: &str, point: usize) -> Vec<String> {
    let mut v = Vec::new();
    get_local_module_path_(msrc, point, &mut v);
    v
}

fn get_local_module_path_(msrc: &str, point: usize, out: &mut Vec<String>) {
    for (start, end) in codeiter::iter_stmts(msrc) {
        if start < point && end > point {
            let blob = &msrc[start..end];
            if blob.starts_with("pub mod "){
                let p = typeinf::generate_skeleton_for_parsing(blob);
                ast::parse_mod(p).name.map(|name|{
                    let newstart = blob.find("{").unwrap() + 1;
                    out.push(name);
                    get_local_module_path_(&blob[newstart..],
                                       point - start - newstart, out);
                });
            }
        }
    }
}

pub fn find_impl_start(msrc: &str, point: usize, scopestart: usize) -> Option<usize> {

    let len = point-scopestart;
    match codeiter::iter_stmts(&msrc[scopestart..]).find(|&(_, end)| end > len) {
        Some((start, _)) => {
            let blob = &msrc[(scopestart + start)..];
            // TODO:: the following is a bit weak at matching traits. make this better
            if blob.starts_with("impl") ||
                blob.starts_with("trait") || blob.starts_with("pub trait") {
                Some(scopestart + start)
            } else {
                let newstart = blob.find("{").unwrap() + 1;
                find_impl_start(msrc, point, scopestart+start+newstart)
            }
        },
        None => None
    }
}

#[test]
fn finds_subnested_module() {
    let src = "
    pub mod foo {
        pub mod bar {
            here
        }
    }";
    let point = coords_to_point(src, 4, 12);
    let v = get_local_module_path(src, point);
    assert_eq!("foo", &v[0][..]);
    assert_eq!("bar", &v[1][..]);

    let point = coords_to_point(src, 3, 8);
    let v = get_local_module_path(src, point);
    assert_eq!("foo", &v[0][..]);
}

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

    match s.char_indices().rev().find(|&(_, c)| !util::is_ident_char(c)) {
        Some((i,c)) => {
            match c {
                '.' => (&s[..i], &s[(i+1)..], racer::CompletionType::CompleteField),
                ':' => (&s[..(i-1)], &s[(i+1)..], racer::CompletionType::CompletePath),
                _   => (&s[..(i+1)], &s[(i+1)..], racer::CompletionType::CompletePath)
            }
        },
        None => ("", s, racer::CompletionType::CompletePath)
    }

}

pub fn get_start_of_search_expr(src: &str, point: usize) -> usize {
    let mut i = point;
    let mut levels = 0u32;
    for &b in src.as_bytes()[..point].iter().rev() {
        i -= 1;
        match b {
            b'(' => {
                if levels == 0 { return i+1; }
                levels -= 1;
            },
            b')' => { levels += 1; },
            _ => {
                if levels == 0 &&
                    !util::is_search_expr_char(src.char_at(i)) ||
                    util::is_double_dot(src,i) {
                    return i+1;
                }
            }
        }
    }
    0
}

pub fn get_start_of_pattern(src: &str, point: usize) -> usize {
    let mut i = point-1;
    let mut levels = 0u32;
    for &b in src.as_bytes()[..point].iter().rev() {
        match b {
            b'(' => {
                if levels == 0 { return i+1; }
                levels -= 1;
            },
            b')' => { levels += 1; },
            _ => {
                if levels == 0 &&
                    !util::is_pattern_char(src.char_at(i)) {
                    return i+1;
                }
            }
        }
        i -= 1;
    }
    0
}

#[test]
fn get_start_of_pattern_handles_variant() {
    assert_eq!(4, get_start_of_pattern("foo, Some(a) =>",13));
}

#[test]
fn get_start_of_pattern_handles_variant2() {
    assert_eq!(4, get_start_of_pattern("bla, ast::PatTup(ref tuple_elements) => {",36));
}

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

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

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

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

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

pub fn mask_comments(src: &str) -> String {
    let mut result = String::with_capacity(src.len());
    let buf_byte = &[b' '; 128];
    let buffer = from_utf8(buf_byte).unwrap();
    let mut prev: usize = 0;
    for (start, end) in codecleaner::code_chunks(src) {
        for _ in 0..((start-prev)/128) { result.push_str(buffer); }
        result.push_str(&buffer[..((start-prev)%128)]);
        result.push_str(&src[start..end]);
        prev = end;
    }
    result
}

pub fn mask_sub_scopes(src:&str) -> String {
    let mut result = String::with_capacity(src.len());
    let buf_byte = [b' '; 128];
    let buffer = from_utf8(&buf_byte).unwrap();
    let mut levels = 0i32;
    let mut start = 0usize;
    let mut pos = 0usize;

    for &b in src.as_bytes().iter() {
        pos += 1;
        match b {
            b'{' => {
                if levels == 0 {
                    result.push_str(&src[start..(pos)]);
                    start = pos+1;
                }
                levels += 1;
            },
            b'}' => {
                if levels == 1 {
                    let num_spaces = pos-start;
                    for _ in 0..(num_spaces/128) { result.push_str(buffer); }
                    result.push_str(&buffer[..((num_spaces)%128)]);
                    result.push_str("}");
                    start = pos;
                }
                levels -= 1;
            },
            b'\n' if levels > 0 => {
                for _ in 0..((pos-start)/128) { result.push_str(buffer); }
                result.push_str(&buffer[..((pos-start)%128)]);
                result.push('\n');
                start = pos+1;
            },
            _ => {}
        }
    }
    if levels > 0 {
        for _ in 0..((pos - start)/128) { result.push_str(buffer); }
        result.push_str(&buffer[..((pos-start)%128)]);
    } else {
        result.push_str(&src[start..pos]);
    }
    result
}

pub fn end_of_next_scope<'a>(src: &'a str) -> &'a str {
    match find_close(src.as_bytes().iter(), b'{', b'}', 1) {
        Some(count) => &src[..count+1],
        None => ""
    }
}

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

pub fn point_to_coords(src:&str, point:usize) -> (usize, usize) {
    let mut i = 0;
    let mut linestart = 0;
    let mut nlines = 1;  // lines start at 1
    for &b in src[..point].as_bytes().iter() {
        i += 1;
        if b == b'\n' {
            nlines += 1;
            linestart = i;
        }
    }
    (nlines, point - linestart)
}

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

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

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

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

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

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

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

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

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

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

<commit_msg>Fix bug: output charactor coord was off-by-one for each newline<commit_after>use racer::{self, ast, codecleaner, codeiter, typeinf, util};

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::iter::Iterator;
use std::path::Path;
use std::str::from_utf8;

fn find_close<'a, A>(iter: A, open: u8, close: u8, level_end: u32) -> Option<usize>
    where A: Iterator<Item=&'a u8> {

    let mut count = 0usize;
    let mut levels = 0u32;
    for &b in iter {
        if b == close {
            if levels == level_end { return Some(count); }
            levels -= 1;
        } else if b == open { levels += 1; }
        count += 1;
    }
    None
}

pub fn find_closing_paren(src:&str, pos:usize) -> usize {
    match find_close(src.as_bytes()[pos..].iter(), b'(', b')', 0) {
        Some(count) => pos + count,
        None => src.len()
    }
}

pub fn scope_start(src:&str, point:usize) -> usize {
    let masked_src = mask_comments(&src[..point]);
    match find_close(masked_src.as_bytes().iter().rev(), b'}', b'{', 0) {
        Some(count) => point - count,
        None => 0
    }
}

pub fn find_stmt_start(msrc: &str, point: usize) -> Option<usize> {
    // iterate the scope to find the start of the statement
    let scopestart = scope_start(msrc, point);
    codeiter::iter_stmts(&msrc[scopestart..]).filter_map(|(start, end)|
        if scopestart+end > point { Some(scopestart+start) } else {None}).next()
}

pub fn get_local_module_path(msrc: &str, point: usize) -> Vec<String> {
    let mut v = Vec::new();
    get_local_module_path_(msrc, point, &mut v);
    v
}

fn get_local_module_path_(msrc: &str, point: usize, out: &mut Vec<String>) {
    for (start, end) in codeiter::iter_stmts(msrc) {
        if start < point && end > point {
            let blob = &msrc[start..end];
            if blob.starts_with("pub mod "){
                let p = typeinf::generate_skeleton_for_parsing(blob);
                ast::parse_mod(p).name.map(|name|{
                    let newstart = blob.find("{").unwrap() + 1;
                    out.push(name);
                    get_local_module_path_(&blob[newstart..],
                                       point - start - newstart, out);
                });
            }
        }
    }
}

pub fn find_impl_start(msrc: &str, point: usize, scopestart: usize) -> Option<usize> {

    let len = point-scopestart;
    match codeiter::iter_stmts(&msrc[scopestart..]).find(|&(_, end)| end > len) {
        Some((start, _)) => {
            let blob = &msrc[(scopestart + start)..];
            // TODO:: the following is a bit weak at matching traits. make this better
            if blob.starts_with("impl") ||
                blob.starts_with("trait") || blob.starts_with("pub trait") {
                Some(scopestart + start)
            } else {
                let newstart = blob.find("{").unwrap() + 1;
                find_impl_start(msrc, point, scopestart+start+newstart)
            }
        },
        None => None
    }
}

#[test]
fn finds_subnested_module() {
    let src = "
    pub mod foo {
        pub mod bar {
            here
        }
    }";
    let point = coords_to_point(src, 4, 12);
    let v = get_local_module_path(src, point);
    assert_eq!("foo", &v[0][..]);
    assert_eq!("bar", &v[1][..]);

    let point = coords_to_point(src, 3, 8);
    let v = get_local_module_path(src, point);
    assert_eq!("foo", &v[0][..]);
}

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

    match s.char_indices().rev().find(|&(_, c)| !util::is_ident_char(c)) {
        Some((i,c)) => {
            match c {
                '.' => (&s[..i], &s[(i+1)..], racer::CompletionType::CompleteField),
                ':' => (&s[..(i-1)], &s[(i+1)..], racer::CompletionType::CompletePath),
                _   => (&s[..(i+1)], &s[(i+1)..], racer::CompletionType::CompletePath)
            }
        },
        None => ("", s, racer::CompletionType::CompletePath)
    }

}

pub fn get_start_of_search_expr(src: &str, point: usize) -> usize {
    let mut i = point;
    let mut levels = 0u32;
    for &b in src.as_bytes()[..point].iter().rev() {
        i -= 1;
        match b {
            b'(' => {
                if levels == 0 { return i+1; }
                levels -= 1;
            },
            b')' => { levels += 1; },
            _ => {
                if levels == 0 &&
                    !util::is_search_expr_char(src.char_at(i)) ||
                    util::is_double_dot(src,i) {
                    return i+1;
                }
            }
        }
    }
    0
}

pub fn get_start_of_pattern(src: &str, point: usize) -> usize {
    let mut i = point-1;
    let mut levels = 0u32;
    for &b in src.as_bytes()[..point].iter().rev() {
        match b {
            b'(' => {
                if levels == 0 { return i+1; }
                levels -= 1;
            },
            b')' => { levels += 1; },
            _ => {
                if levels == 0 &&
                    !util::is_pattern_char(src.char_at(i)) {
                    return i+1;
                }
            }
        }
        i -= 1;
    }
    0
}

#[test]
fn get_start_of_pattern_handles_variant() {
    assert_eq!(4, get_start_of_pattern("foo, Some(a) =>",13));
}

#[test]
fn get_start_of_pattern_handles_variant2() {
    assert_eq!(4, get_start_of_pattern("bla, ast::PatTup(ref tuple_elements) => {",36));
}

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

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

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

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

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

pub fn mask_comments(src: &str) -> String {
    let mut result = String::with_capacity(src.len());
    let buf_byte = &[b' '; 128];
    let buffer = from_utf8(buf_byte).unwrap();
    let mut prev: usize = 0;
    for (start, end) in codecleaner::code_chunks(src) {
        for _ in 0..((start-prev)/128) { result.push_str(buffer); }
        result.push_str(&buffer[..((start-prev)%128)]);
        result.push_str(&src[start..end]);
        prev = end;
    }
    result
}

pub fn mask_sub_scopes(src:&str) -> String {
    let mut result = String::with_capacity(src.len());
    let buf_byte = [b' '; 128];
    let buffer = from_utf8(&buf_byte).unwrap();
    let mut levels = 0i32;
    let mut start = 0usize;
    let mut pos = 0usize;

    for &b in src.as_bytes().iter() {
        pos += 1;
        match b {
            b'{' => {
                if levels == 0 {
                    result.push_str(&src[start..(pos)]);
                    start = pos+1;
                }
                levels += 1;
            },
            b'}' => {
                if levels == 1 {
                    let num_spaces = pos-start;
                    for _ in 0..(num_spaces/128) { result.push_str(buffer); }
                    result.push_str(&buffer[..((num_spaces)%128)]);
                    result.push_str("}");
                    start = pos;
                }
                levels -= 1;
            },
            b'\n' if levels > 0 => {
                for _ in 0..((pos-start)/128) { result.push_str(buffer); }
                result.push_str(&buffer[..((pos-start)%128)]);
                result.push('\n');
                start = pos+1;
            },
            _ => {}
        }
    }
    if levels > 0 {
        for _ in 0..((pos - start)/128) { result.push_str(buffer); }
        result.push_str(&buffer[..((pos-start)%128)]);
    } else {
        result.push_str(&src[start..pos]);
    }
    result
}

pub fn end_of_next_scope<'a>(src: &'a str) -> &'a str {
    match find_close(src.as_bytes().iter(), b'{', b'}', 1) {
        Some(count) => &src[..count+1],
        None => ""
    }
}

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

pub fn point_to_coords(src:&str, point:usize) -> (usize, usize) {
    let mut i = 0;
    let mut linestart = 0;
    let mut nlines = 1;  // lines start at 1
    for &b in src[..point].as_bytes().iter() {
        i += 1;
        if b == b'\n' {
            nlines += 1;
            linestart = i;
        }
    }
    (nlines, point - linestart)
}

pub fn point_to_coords_from_file(path: &Path, point:usize) -> Option<(usize, usize)> {
    let mut lineno = 0;
    let reader = BufReader::new(File::open(path).unwrap());
    let mut p = 0;
    for line_r in reader.lines() {
        let line = line_r.unwrap();
        lineno += 1;
        if point < (p + line.len()) {
            return Some((lineno, point - p));
        }
        p += line.len() + 1;  // +1 for the newline char
    }
    None
}

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

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

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

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

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

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

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

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

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

<|endoftext|>


<commit_before>#![feature(test)]
#![allow(unused_imports)]
#![cfg_attr(feature = "assign_ops", feature(augmented_assignments))]

extern crate test;
#[macro_use(s)]
extern crate ndarray;
#[cfg(feature = "rblas")]
extern crate rblas;
#[cfg(feature = "rblas")]
use rblas::matrix::Matrix;

use ndarray::{
    OwnedArray,
    zeros,
};
use ndarray::{arr0, arr1, arr2};

use test::black_box;

#[bench]
fn small_iter_1d(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn small_iter_1d_raw(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt); })
}

#[bench]
fn small_iter_2d(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn sum_1d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros(64 * 64);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_1d_raw(bench: &mut test::Bencher)
{
    // this is autovectorized to death (= great performance)
    let a = OwnedArray::<i32, _>::zeros(64 * 64);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.raw_data() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_by_row(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for row in a.inner_iter() {
            for &elt in row {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_raw(bench: &mut test::Bencher)
{
    // this is autovectorized to death (= great performance)
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.raw_data() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout_fold(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        a.fold(0, |acc, elt| acc + *elt)
    });
}

#[bench]
fn scalar_sum_2d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        a.scalar_sum()
    });
}

#[bench]
fn scalar_sum_2d_cutout(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        a.scalar_sum()
    });
}

#[bench]
fn sum_2d_cutout_by_row(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for row in 0..a.shape()[0] {
            for &elt in a.row_iter(row) {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout_outer_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for row in a.inner_iter() {
            for &elt in row {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_transpose_regular(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    a.swap_axes(0, 1);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_transpose_by_row(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    a.swap_axes(0, 1);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for row in 0..a.shape()[0] {
            for &elt in a.row_iter(row) {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn scalar_sum_2d_float(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((64, 64));
    let a = black_box(a.view());
    bench.iter(|| {
        a.scalar_sum()
    });
}

#[bench]
fn scalar_sum_2d_float_cutout(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((66, 66));
    let av = a.view().slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        a.scalar_sum()
    });
}

#[bench]
fn add_2d_regular(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(a.view_mut() + bv);
    });
}

#[cfg(feature = "assign_ops")]
#[bench]
fn add_2d_assign_ops(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    let bv = b.view();
    bench.iter(|| {
        let mut x = a.view_mut();
        x += &bv;
        black_box(x);
    });
}

#[bench]
fn add_2d_cutout(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((66, 66));
    let mut acut = a.slice_mut(s![1..-1, 1..-1]);
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(acut.view_mut() + bv);
    });
}

#[bench]
fn add_2d_broadcast_1_to_2(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros(64);
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(a.view_mut() + bv);
    });
}

#[bench]
fn add_2d_broadcast_0_to_2(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros(());
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(a.view_mut() + bv);
    });
}

#[bench]
fn assign_scalar_2d_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::zeros((64, 64));
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_cutout(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::zeros((66, 66));
    let a = a.slice_mut(s![1..-1, 1..-1]);
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_transposed_large(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::zeros((64, 64));
    a.swap_axes(0, 1);
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_raw_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::zeros((64, 64));
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| for elt in a.raw_data_mut() { *elt = s; });
}

#[bench]
fn bench_iter_diag(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    bench.iter(|| for elt in a.diag_iter() { black_box(elt); })
}

#[bench]
fn bench_row_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    let it = a.row_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_col_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    let it = a.col_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_mat_mul_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((64, 64));
    let b = OwnedArray::<f32, _>::zeros((64, 64));
    let a = black_box(a.view());
    let b = black_box(b.view());
    bench.iter(|| a.mat_mul(&b));
}

#[cfg(feature = "rblas")]
#[bench]
fn bench_mat_mul_rblas_large(bench: &mut test::Bencher)
{
    use rblas::Gemm;
    use rblas::attribute::Transpose;
    use ndarray::blas::AsBlas;

    let mut a = OwnedArray::<f32, _>::zeros((64, 64));
    let mut b = OwnedArray::<f32, _>::zeros((64, 64));
    let mut c = OwnedArray::<f32, _>::zeros((64, 64));
    bench.iter(|| {
        // C ← α AB + β C
        f32::gemm(&1.,
                  Transpose::NoTrans, &a.blas(),
                  Transpose::NoTrans, &b.blas(),
                  &1., &mut c.blas());
    });
}

#[bench]
fn create_iter_4d(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::from_elem((4, 5, 3, 2), 1.0);
    a.swap_axes(0, 1);
    a.swap_axes(2, 1);
    let v = black_box(a.view());

    bench.iter(|| {
        v.into_iter()
    });
}

#[bench]
fn bench_to_owned_n(bench: &mut test::Bencher)
{
    let a = zeros::<f32, _>((32, 32));
    bench.iter(|| a.to_owned());
}

#[bench]
fn bench_to_owned_t(bench: &mut test::Bencher)
{
    let mut a = zeros::<f32, _>((32, 32));
    a.swap_axes(0, 1);
    bench.iter(|| a.to_owned());
}

#[bench]
fn equality(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    bench.iter(|| a == b);
}
<commit_msg>Update bench for changed and deprecated methods<commit_after>#![feature(test)]
#![allow(unused_imports)]
#![cfg_attr(feature = "assign_ops", feature(augmented_assignments))]

extern crate test;
#[macro_use(s)]
extern crate ndarray;
#[cfg(feature = "rblas")]
extern crate rblas;
#[cfg(feature = "rblas")]
use rblas::matrix::Matrix;

use ndarray::{
    OwnedArray,
    zeros,
};
use ndarray::{arr0, arr1, arr2};

use test::black_box;

#[bench]
fn small_iter_1d(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn small_iter_1d_raw(bench: &mut test::Bencher)
{
    let a = arr1::<f32>(&[1., 2., 2.,
                         3., 4., 4.,
                         3., 4., 4.,
                         3., 4., 4.,
                         5., 6., 6.]);
    bench.iter(|| for &elt in a.raw_data().iter() { black_box(elt); })
}

#[bench]
fn small_iter_2d(bench: &mut test::Bencher)
{
    let a = arr2::<f32, _>(&[[1., 2., 2.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [3., 4., 4.],
                          [5., 6., 6.]]);
    bench.iter(|| for &elt in a.iter() { black_box(elt); })
}

#[bench]
fn sum_1d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros(64 * 64);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_1d_raw(bench: &mut test::Bencher)
{
    // this is autovectorized to death (= great performance)
    let a = OwnedArray::<i32, _>::zeros(64 * 64);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.raw_data() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_by_row(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for row in a.inner_iter() {
            for &elt in row {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_raw(bench: &mut test::Bencher)
{
    // this is autovectorized to death (= great performance)
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.raw_data() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout_fold(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        a.fold(0, |acc, elt| acc + *elt)
    });
}

#[bench]
fn scalar_sum_2d_regular(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let a = black_box(a);
    bench.iter(|| {
        a.scalar_sum()
    });
}

#[bench]
fn scalar_sum_2d_cutout(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        a.scalar_sum()
    });
}

#[bench]
fn sum_2d_cutout_by_row(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for row in 0..a.shape()[0] {
            for &elt in a.row_iter(row) {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_cutout_outer_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((66, 66));
    let av = a.slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        let mut sum = 0;
        for row in a.inner_iter() {
            for &elt in row {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn sum_2d_transpose_regular(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    a.swap_axes(0, 1);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for &elt in a.iter() {
            sum += elt;
        }
        sum
    });
}

#[bench]
fn sum_2d_transpose_by_row(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    a.swap_axes(0, 1);
    let a = black_box(a);
    bench.iter(|| {
        let mut sum = 0;
        for row in 0..a.shape()[0] {
            for &elt in a.row_iter(row) {
                sum += elt;
            }
        }
        sum
    });
}

#[bench]
fn scalar_sum_2d_float(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((64, 64));
    let a = black_box(a.view());
    bench.iter(|| {
        a.scalar_sum()
    });
}

#[bench]
fn scalar_sum_2d_float_cutout(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((66, 66));
    let av = a.slice(s![1..-1, 1..-1]);
    let a = black_box(av);
    bench.iter(|| {
        a.scalar_sum()
    });
}

#[bench]
fn add_2d_regular(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(a.view_mut() + bv);
    });
}

#[cfg(feature = "assign_ops")]
#[bench]
fn add_2d_assign_ops(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    let bv = b.view();
    bench.iter(|| {
        let mut x = a.view_mut();
        x += &bv;
        black_box(x);
    });
}

#[bench]
fn add_2d_cutout(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((66, 66));
    let mut acut = a.slice_mut(s![1..-1, 1..-1]);
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(acut.view_mut() + bv);
    });
}

#[bench]
fn add_2d_broadcast_1_to_2(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros(64);
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(a.view_mut() + bv);
    });
}

#[bench]
fn add_2d_broadcast_0_to_2(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros(());
    let bv = b.view();
    bench.iter(|| {
        let _x = black_box(a.view_mut() + bv);
    });
}

#[bench]
fn assign_scalar_2d_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::zeros((64, 64));
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_cutout(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::zeros((66, 66));
    let a = a.slice_mut(s![1..-1, 1..-1]);
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_transposed_large(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::zeros((64, 64));
    a.swap_axes(0, 1);
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| a.assign_scalar(&s))
}

#[bench]
fn assign_scalar_2d_raw_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::zeros((64, 64));
    let mut a = black_box(a);
    let s = 3.;
    bench.iter(|| for elt in a.raw_data_mut() { *elt = s; });
}

#[bench]
fn bench_iter_diag(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    bench.iter(|| for elt in a.diag() { black_box(elt); })
}

#[bench]
fn bench_row_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    let it = a.row_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_col_iter(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((1024, 1024));
    let it = a.col_iter(17);
    bench.iter(|| for elt in it.clone() { black_box(elt); })
}

#[bench]
fn bench_mat_mul_large(bench: &mut test::Bencher)
{
    let a = OwnedArray::<f32, _>::zeros((64, 64));
    let b = OwnedArray::<f32, _>::zeros((64, 64));
    let a = black_box(a.view());
    let b = black_box(b.view());
    bench.iter(|| a.mat_mul(&b));
}

#[cfg(feature = "rblas")]
#[bench]
fn bench_mat_mul_rblas_large(bench: &mut test::Bencher)
{
    use rblas::Gemm;
    use rblas::attribute::Transpose;
    use ndarray::blas::AsBlas;

    let mut a = OwnedArray::<f32, _>::zeros((64, 64));
    let mut b = OwnedArray::<f32, _>::zeros((64, 64));
    let mut c = OwnedArray::<f32, _>::zeros((64, 64));
    bench.iter(|| {
        // C ← α AB + β C
        f32::gemm(&1.,
                  Transpose::NoTrans, &a.blas(),
                  Transpose::NoTrans, &b.blas(),
                  &1., &mut c.blas());
    });
}

#[bench]
fn create_iter_4d(bench: &mut test::Bencher)
{
    let mut a = OwnedArray::from_elem((4, 5, 3, 2), 1.0);
    a.swap_axes(0, 1);
    a.swap_axes(2, 1);
    let v = black_box(a.view());

    bench.iter(|| {
        v.into_iter()
    });
}

#[bench]
fn bench_to_owned_n(bench: &mut test::Bencher)
{
    let a = zeros::<f32, _>((32, 32));
    bench.iter(|| a.to_owned());
}

#[bench]
fn bench_to_owned_t(bench: &mut test::Bencher)
{
    let mut a = zeros::<f32, _>((32, 32));
    a.swap_axes(0, 1);
    bench.iter(|| a.to_owned());
}

#[bench]
fn equality(bench: &mut test::Bencher)
{
    let a = OwnedArray::<i32, _>::zeros((64, 64));
    let b = OwnedArray::<i32, _>::zeros((64, 64));
    bench.iter(|| a == b);
}
<|endoftext|>


<commit_before>static RUST_KEYWORDS: [&str; 76] = [
    "abstract",
    "alignof",
    "as",
    "become",
    "bool",
    "box",
    "Box",
    "break",
    "BytesReader",
    "const",
    "continue",
    "crate",
    "Cow",
    "Default",
    "do",
    "else",
    "enum",
    "Err",
    "extern",
    "f32",
    "f64",
    "false",
    "final",
    "fn",
    "for",
    "HashMap",
    "i32",
    "i64",
    "if",
    "impl",
    "in",
    "let",
    "loop",
    "match",
    "mod",
    "move",
    "mut",
    "None",
    "MessageWrite",
    "offsetof",
    "Ok",
    "Option",
    "override",
    "priv",
    "pub",
    "pure",
    "ref",
    "Result",
    "return",
    "self",
    "Self",
    "sizeof",
    "Some",
    "static",
    "str",
    "String",
    "struct",
    "super",
    "trait",
    "true",
    "type",
    "typeof",
    "u8",
    "u32",
    "u64",
    "unsafe",
    "unsized",
    "use",
    "Vec",
    "virtual",
    "where",
    "while",
    "Write",
    "Writer",
    "yield",
];

/// Ckeck is the identifier is a rust keyword and appends a '_pb' if that's the case
pub fn sanitize_keyword(ident: &mut String) {
    if !ident.contains('.') && RUST_KEYWORDS.contains(&&**ident) {
        ident.push_str("_pb");
    } else {
        *ident = ident
            .split('.')
            .map(|s| {
                if RUST_KEYWORDS.contains(&s) {
                    format!("{}_pb", s)
                } else {
                    s.to_string()
                }
            })
            .collect::<Vec<_>>()
            .join(".");
    }
}
<commit_msg>Fix keywords array length<commit_after>static RUST_KEYWORDS: [&str; 75] = [
    "abstract",
    "alignof",
    "as",
    "become",
    "bool",
    "box",
    "Box",
    "break",
    "BytesReader",
    "const",
    "continue",
    "crate",
    "Cow",
    "Default",
    "do",
    "else",
    "enum",
    "Err",
    "extern",
    "f32",
    "f64",
    "false",
    "final",
    "fn",
    "for",
    "HashMap",
    "i32",
    "i64",
    "if",
    "impl",
    "in",
    "let",
    "loop",
    "match",
    "mod",
    "move",
    "mut",
    "None",
    "MessageWrite",
    "offsetof",
    "Ok",
    "Option",
    "override",
    "priv",
    "pub",
    "pure",
    "ref",
    "Result",
    "return",
    "self",
    "Self",
    "sizeof",
    "Some",
    "static",
    "str",
    "String",
    "struct",
    "super",
    "trait",
    "true",
    "type",
    "typeof",
    "u8",
    "u32",
    "u64",
    "unsafe",
    "unsized",
    "use",
    "Vec",
    "virtual",
    "where",
    "while",
    "Write",
    "Writer",
    "yield",
];

/// Ckeck is the identifier is a rust keyword and appends a '_pb' if that's the case
pub fn sanitize_keyword(ident: &mut String) {
    if !ident.contains('.') && RUST_KEYWORDS.contains(&&**ident) {
        ident.push_str("_pb");
    } else {
        *ident = ident
            .split('.')
            .map(|s| {
                if RUST_KEYWORDS.contains(&s) {
                    format!("{}_pb", s)
                } else {
                    s.to_string()
                }
            })
            .collect::<Vec<_>>()
            .join(".");
    }
}
<|endoftext|>


<commit_before>extern crate hyper:
extern crate futures;

use std::{thread, time};
use futures::future::FutureResult;
use hyper::{Get, StatusCode};
use hyper::header::ContentLength;
use hyper::server::{Http, Service, Request, Response};

fn heavy_work () -> String {
    let duration = time::Duration::from_millis(200);
    thread::sleep(duration);
    "done".to_string()
}

#[derive(Clone, Copy)]
struct Echo;

impl Service for Echo {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = FutureResult<Response, hyper::Error>;
}
/*
fn call(&self, req: Request) -> Self::Future {
    futures::future::ok(match(req.method(), req.path())) {

    }
}
*/

fn main() {
    println!("Hello, world!");
}
<commit_msg>Added server fnished<commit_after>extern crate hyper;
extern crate futures;

use std::{thread, time};
use futures::future::FutureResult;
use hyper::{Get, StatusCode};
use hyper::header::ContentLength;
use hyper::server::{Http, Service, Request, Response};

fn heavy_work () -> String {
    let duration = time::Duration::from_millis(200);
    thread::sleep(duration);
    "done".to_string()
}

#[derive(Clone, Copy)]
struct Echo;

impl Service for Echo {
    type Request = Request;
    type Response = Response;
    type Error = hyper::Error;
    type Future = FutureResult<Response, hyper::Error>;

fn call(&self, req: Request) -> Self::Future {
    futures::future::ok(match(req.method(), req.path()) {
        (&Get, "/data") => {
            let b = heavy_work().into_bytes();
            Response::new().with_header(ContentLength(b.len() as u64))
                .with_body(b)
        }
        _=> Response::new().with_status(StatusCode::NotFound),})

    }
}

fn main() {
    let addr = "0.0.0.0:3000".parse().unwrap();
    let server = Http::new().bind(&addr, || Ok(Echo)).unwrap();
    server.run().unwrap();
}
<|endoftext|>


<commit_before>use std::num::{Zero, One};
use nalgebra::na::{AlgebraicVecExt, Cast, Identity, Translation, Rotate, Transform};
use nalgebra::na;
use narrow::algorithm::simplex::Simplex;
use narrow::algorithm::johnson_simplex::JohnsonSimplex;
use geom::{Cylinder, Cone, Capsule, MinkowskiSum, Implicit};
use ray::{Ray, RayCast, RayCastWithTransform};
use ray;

/// Projects the origin on a geometry unsing the GJK algorithm.
///
/// # Arguments:
///     * geom - the geometry to project the origin on
///     * simplex - the simplex to be used by the GJK algorithm. It must be already initialized
///     with at least one point on the geometry boundary.
pub fn gjk_toi_and_normal_with_ray<S: Simplex<N, V>,
                                   G: Implicit<N, V, M>,
                                   N: Ord + Num + Float + Cast<f32>,
                                   V: AlgebraicVecExt<N> + Clone,
                                   M: Translation<V>>(
                                   m:       &M,
                                   geom:    &G,
                                   simplex: &mut S,
                                   ray:     &Ray<V>)
                                   -> Option<(N, V)> {
    let mut ltoi: N = Zero::zero();

    let _eps: N  = Float::epsilon();
    let _eps_tol = _eps * Cast::from(100.0);
    let _eps_rel = _eps.sqrt();
    let _dim     = na::dim::<V>();

    // initialization
    let mut curr_ray   = Ray::new(ray.orig.clone(), ray.dir.clone());
    let mut dir        = curr_ray.orig - m.translation();

    if dir.is_zero() {
        dir.set(0, One::one())
    }

    let mut old_sq_len: N = Bounded::max_value();

    let mut ldir = dir.clone();
    // FIXME: this converges in more than 100 iterations… something is wrong here…
    loop {
        dir.normalize();

        let support_point = geom.support_point(m, &dir);

        // Clip the ray on the support plane (None <=> t < 0)
        // The configurations are:
        //   dir.dot(ray.dir)  |   t   |               Action
        // −−−−−−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
        //          < 0        |  < 0  | Continue.
        //          < 0        |  > 0  | New lower bound, move the origin.
        //          > 0        |  < 0  | Miss. No intersection.
        //          > 0        |  > 0  | New higher bound.
        match ray::plane_toi_with_ray(&support_point, &dir, &curr_ray) {
            Some(t) => {
                if na::dot(&dir, &ray.dir) < na::zero() {
                    // new lower bound
                    ldir = dir.clone();
                    // XXX: this prevents the normal from being perfectly continuous.
                    // However, without this the algorithm might never converge…
                    // Find a way to fix that.
                    if t <= _eps_rel * ltoi {
                        return Some((ltoi, dir))
                    }

                    ltoi   = ltoi + t;
                    curr_ray.orig = ray.orig + ray.dir * ltoi;
                    dir    = curr_ray.orig - support_point;
                    simplex.reset(-dir);
                    let _M: N = Bounded::max_value();
                    old_sq_len = _M;
                    continue
                }
            },
            None => {
                if na::dot(&dir, &ray.dir) > na::zero() {
                    // miss
                    return None
                }
            }
        }

        simplex.add_point(support_point - curr_ray.orig);

        let proj = simplex.project_origin_and_reduce();
        let sq_len_dir = na::sqnorm(&proj);

        if (simplex.dimension() == _dim ||
            sq_len_dir >= old_sq_len    || // FIXME: hacky way to prevent infinite loop…
            sq_len_dir <= _eps_tol * simplex.max_sq_len()
           ) {
            return Some((ltoi, ldir)) // FIXME: dir or -proj ?
        }

        old_sq_len = sq_len_dir;
        dir        = -proj;
    }
}

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone>
RayCast<N, V> for Cylinder<N> {
    fn toi_and_normal_with_ray(&self, ray: &Ray<V>) -> Option<(N, V)> {
        gjk_toi_and_normal_with_ray(&Identity::new(), self, &mut JohnsonSimplex::<N, V>::new_w_tls(), ray)
    }
}

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone,
     M: Transform<V> + Rotate<V>>
RayCastWithTransform<N, V, M> for Cylinder<N> { }

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone>
RayCast<N, V> for Cone<N> {
    fn toi_and_normal_with_ray(&self, ray: &Ray<V>) -> Option<(N, V)> {
        gjk_toi_and_normal_with_ray(&Identity::new(), self, &mut JohnsonSimplex::<N, V>::new_w_tls(), ray)
    }
}

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone,
     M: Transform<V> + Rotate<V>>
RayCastWithTransform<N, V, M> for Cone<N> { }

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone>
RayCast<N, V> for Capsule<N> {
    fn toi_and_normal_with_ray(&self, ray: &Ray<V>) -> Option<(N, V)> {
        gjk_toi_and_normal_with_ray(&Identity::new(), self, &mut JohnsonSimplex::<N, V>::new_w_tls(), ray)
    }
}

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone,
     M: Transform<V> + Rotate<V>>
RayCastWithTransform<N, V, M> for Capsule<N> { }

impl<'self,
     N:  Ord + Num + Float + Cast<f32> + Clone,
     V:  AlgebraicVecExt<N> + Clone,
     G1: Implicit<N, V, M>,
     G2: Implicit<N, V, M>,
     M>
RayCast<N, V> for MinkowskiSum<'self, M, G1, G2> {
    fn toi_and_normal_with_ray(&self, ray: &Ray<V>) -> Option<(N, V)> {
        gjk_toi_and_normal_with_ray(&Identity::new(), self, &mut JohnsonSimplex::<N, V>::new_w_tls(), ray)
    }
}

impl<'self,
     N:  Ord + Num + Float + Cast<f32> + Clone,
     V:  AlgebraicVecExt<N> + Clone,
     G1: Implicit<N, V, M>,
     G2: Implicit<N, V, M>,
     M:  Rotate<V> + Transform<V>>
RayCastWithTransform<N, V, M> for MinkowskiSum<'self, M, G1, G2> { }
<commit_msg>Improve the accuracy of normal computations for the ray vs implicit intersection.<commit_after>use std::num::{Zero, One};
use nalgebra::na::{AlgebraicVecExt, Cast, Identity, Translation, Rotate, Transform};
use nalgebra::na;
use narrow::algorithm::simplex::Simplex;
use narrow::algorithm::johnson_simplex::JohnsonSimplex;
use geom::{Cylinder, Cone, Capsule, MinkowskiSum, Implicit};
use ray::{Ray, RayCast, RayCastWithTransform};
use ray;

/// Projects the origin on a geometry unsing the GJK algorithm.
///
/// # Arguments:
///     * geom - the geometry to project the origin on
///     * simplex - the simplex to be used by the GJK algorithm. It must be already initialized
///     with at least one point on the geometry boundary.
pub fn gjk_toi_and_normal_with_ray<S: Simplex<N, V>,
                                   G: Implicit<N, V, M>,
                                   N: Ord + Num + Float + Cast<f32>,
                                   V: AlgebraicVecExt<N> + Clone,
                                   M: Translation<V>>(
                                   m:       &M,
                                   geom:    &G,
                                   simplex: &mut S,
                                   ray:     &Ray<V>)
                                   -> Option<(N, V)> {
    let mut ltoi: N = Zero::zero();

    let _eps: N     = Float::epsilon();
    let _eps_tol: N = _eps * na::cast(100.0);
    let _dim        = na::dim::<V>();

    // initialization
    let mut curr_ray   = Ray::new(ray.orig.clone(), ray.dir.clone());
    let mut dir        = curr_ray.orig - m.translation();

    if dir.is_zero() {
        dir.set(0, One::one())
    }

    let mut old_sq_len: N = Bounded::max_value();

    let mut ldir = dir.clone();
    // FIXME: this converges in more than 100 iterations… something is wrong here…
    let mut niter = 0;
    loop {
        niter = niter + 1;
        dir.normalize();

        let support_point = geom.support_point(m, &dir);

        // Clip the ray on the support plane (None <=> t < 0)
        // The configurations are:
        //   dir.dot(ray.dir)  |   t   |               Action
        // −−−−−−−−−−−−−−−−−−−−+−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
        //          < 0        |  < 0  | Continue.
        //          < 0        |  > 0  | New lower bound, move the origin.
        //          > 0        |  < 0  | Miss. No intersection.
        //          > 0        |  > 0  | New higher bound.
        match ray::plane_toi_with_ray(&support_point, &dir, &curr_ray) {
            Some(t) => {
                if na::dot(&dir, &ray.dir) < na::zero() && t > _eps_tol {
                    // new lower bound
                    ldir = dir.clone();
                    ltoi   = ltoi + t;
                    curr_ray.orig = ray.orig + ray.dir * ltoi;
                    dir    = curr_ray.orig - support_point;
                    simplex.reset(-dir);
                    let _M: N = Bounded::max_value();
                    old_sq_len = _M;
                    continue
                }
            },
            None => {
                if na::dot(&dir, &ray.dir) > na::zero() {
                    // miss
                    return None
                }
            }
        }

        simplex.add_point(support_point - curr_ray.orig);

        let proj       = simplex.project_origin_and_reduce();
        let sq_len_dir = na::sqnorm(&proj);

        if (simplex.dimension() == _dim) {
            return Some((ltoi, ldir)) // FIXME: dir or -proj ?
        }
        else if (sq_len_dir <= _eps_tol * simplex.max_sq_len()) {
            // Return ldir: the last projection plane is tangeant to the intersected surface.
            return Some((ltoi, ldir))
        }
        else if (sq_len_dir >= old_sq_len) {
            // use dir instead of proj since this situations means that the new projection is less
            // accurate than the last one (which is stored on dir).
            return Some((ltoi, dir)) // FIXME: dir or -proj ?
        }

        old_sq_len = sq_len_dir;
        dir        = -proj;
    }
}

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone>
RayCast<N, V> for Cylinder<N> {
    fn toi_and_normal_with_ray(&self, ray: &Ray<V>) -> Option<(N, V)> {
        gjk_toi_and_normal_with_ray(&Identity::new(), self, &mut JohnsonSimplex::<N, V>::new_w_tls(), ray)
    }
}

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone,
     M: Transform<V> + Rotate<V>>
RayCastWithTransform<N, V, M> for Cylinder<N> { }

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone>
RayCast<N, V> for Cone<N> {
    fn toi_and_normal_with_ray(&self, ray: &Ray<V>) -> Option<(N, V)> {
        gjk_toi_and_normal_with_ray(&Identity::new(), self, &mut JohnsonSimplex::<N, V>::new_w_tls(), ray)
    }
}

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone,
     M: Transform<V> + Rotate<V>>
RayCastWithTransform<N, V, M> for Cone<N> { }

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone>
RayCast<N, V> for Capsule<N> {
    fn toi_and_normal_with_ray(&self, ray: &Ray<V>) -> Option<(N, V)> {
        gjk_toi_and_normal_with_ray(&Identity::new(), self, &mut JohnsonSimplex::<N, V>::new_w_tls(), ray)
    }
}

impl<N: Ord + Num + Float + Cast<f32> + Clone,
     V: AlgebraicVecExt<N> + Clone,
     M: Transform<V> + Rotate<V>>
RayCastWithTransform<N, V, M> for Capsule<N> { }

impl<'self,
     N:  Ord + Num + Float + Cast<f32> + Clone,
     V:  AlgebraicVecExt<N> + Clone,
     G1: Implicit<N, V, M>,
     G2: Implicit<N, V, M>,
     M>
RayCast<N, V> for MinkowskiSum<'self, M, G1, G2> {
    fn toi_and_normal_with_ray(&self, ray: &Ray<V>) -> Option<(N, V)> {
        gjk_toi_and_normal_with_ray(&Identity::new(), self, &mut JohnsonSimplex::<N, V>::new_w_tls(), ray)
    }
}

impl<'self,
     N:  Ord + Num + Float + Cast<f32> + Clone,
     V:  AlgebraicVecExt<N> + Clone,
     G1: Implicit<N, V, M>,
     G2: Implicit<N, V, M>,
     M:  Rotate<V> + Transform<V>>
RayCastWithTransform<N, V, M> for MinkowskiSum<'self, M, G1, G2> { }
<|endoftext|>


<commit_before>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    // TODO: avoid cloning the pattern if we can?

    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can build up patterns
///
/// Patterns are built in boxes to avoid the need for a lot of copying
///
pub trait PatternBuilder<Symbol> {
    /// Creates an empty pattern
    fn empty() -> Pattern<Symbol>;

    /// Appends a pattern to this one
    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;

    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol> PatternBuilder<Symbol> for Pattern<Symbol> {
    fn empty() -> Pattern<Symbol> {
        Epsilon
    }

    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAll(vec![self, pattern.to_pattern()])
    }

    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAny(vec![self, pattern.to_pattern()])
    }

    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].to_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].to_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".to_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }
}<commit_msg>Add an IntoPattern trait that works by consuming its parameter<commit_after>//
//   Copyright 2016 Andrew Hunter
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
//

//!
//! # Regular language
//!
//! This provides a data structure representing a regular language. This is a more generalised form of a regular
//! expression (it supports symbol types other than simple strings). A regular language using the `u8` symbol forms
//! a simple regular expression.
//!

use std::iter::FromIterator;
use std::ops::Range;

///
/// A Pattern represents a matching pattern in a regular language
///
#[derive(Clone, PartialEq, Eq)]
pub enum Pattern<Symbol> {
    ///
    /// Matches nothing
    ///
    Epsilon,

    ///
    /// Matches a specific literal phrase
    ///
    Match(Vec<Symbol>),

    ///
    /// Matches at least a particular number of repetitions of a pattern
    ///
    /// `RepeatInfinite(0, X)` is the equivalent of the regular expression `X*`, `RepeatInfinite(1, X)` is the equivalent of the regular expression `X+`
    ///
    RepeatInfinite(u32, Box<Pattern<Symbol>>),

    ///
    /// Matches a range of repetitions of a pattern
    ///
    Repeat(Range<u32>, Box<Pattern<Symbol>>),

    ///
    /// Matches a set of sub-patterns in order
    ///
    MatchAll(Vec<Pattern<Symbol>>),

    ///
    /// Matches any one of a set of patterns
    ///
    MatchAny(Vec<Pattern<Symbol>>)
}

pub use Pattern::*;

///
/// Implemented by things that can be converted into a pattern
///
pub trait ToPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn to_pattern(&self) -> Pattern<Symbol>;
}

///
/// Implemented by things that can be converted into a pattern
///
pub trait IntoPattern<Symbol> {
    ///
    /// Converts a particular object into a pattern that will match it
    ///
    fn into_pattern(self) -> Pattern<Symbol>;
}

impl<Symbol> IntoPattern<Symbol> for Pattern<Symbol> {
    fn into_pattern(self) -> Pattern<Symbol> {
        self
    }
}

impl<Symbol> IntoPattern<Symbol> for Box<Pattern<Symbol>> {
    fn into_pattern(self) -> Pattern<Symbol> {
        *self
    }
}

impl<'a, Symbol> IntoPattern<Symbol> for &'a ToPattern<Symbol> {
    fn into_pattern(self) -> Pattern<Symbol> {
        self.to_pattern()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Pattern<Symbol> {
    fn to_pattern(&self) -> Pattern<Symbol> {
        self.clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Box<Pattern<Symbol>> {
    fn to_pattern(&self) -> Pattern<Symbol> {
        (**self).clone()
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for Vec<Symbol> {
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.clone())
    }
}

impl<Symbol: Clone> ToPattern<Symbol> for [Symbol] {
    fn to_pattern(&self) -> Pattern<Symbol> {
        Match(self.to_vec())
    }
}

impl ToPattern<char> for str {
    fn to_pattern(&self) -> Pattern<char> {
        Match(Vec::from_iter(self.chars()))
    }
}

///
/// Implemented by things that can build up patterns
///
/// Patterns are built in boxes to avoid the need for a lot of copying
///
pub trait PatternBuilder<Symbol> {
    /// Creates an empty pattern
    fn empty() -> Pattern<Symbol>;

    /// Appends a pattern to this one
    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;

    /// Matches either this pattern or the specified pattern
    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol>;

    /// Repeats the current pattern forever
    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol>;

    /// Repeats the current pattern for a certain number of iterations
    fn repeat(self, count: Range<u32>) -> Pattern<Symbol>;
}

impl<Symbol> Pattern<Symbol> {

}

impl<Symbol> PatternBuilder<Symbol> for Pattern<Symbol> {
    fn empty() -> Pattern<Symbol> {
        Epsilon
    }

    fn append(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAll(vec![self, pattern.to_pattern()])
    }

    fn or(self, pattern: &ToPattern<Symbol>) -> Pattern<Symbol> {
        MatchAny(vec![self, pattern.to_pattern()])
    }

    fn repeat_forever(self, min_count: u32) -> Pattern<Symbol> {
        RepeatInfinite(min_count, Box::new(self))
    }

    fn repeat(self, count: Range<u32>) -> Pattern<Symbol> {
        Repeat(count, Box::new(self))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn can_convert_vec_to_pattern() {
        let pattern = vec![0, 1, 2].to_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_array_to_pattern() {
        let pattern = [0, 1, 2].to_pattern();

        assert!(pattern == Match(vec![0, 1, 2]));
    }

    #[test]
    fn can_convert_string_to_pattern() {
        let pattern = "abc".to_pattern();

        assert!(pattern == Match(vec!['a', 'b', 'c']));
    }
}<|endoftext|>


<commit_before>use std::mem::size_of;
use std::os::raw::c_void;
use std::path::Path;
use std::ptr;
use std::rc::Rc;

use gl;
use gltf;
use gltf::json::mesh::Mode;
use gltf_importer;
use gltf_utils::PrimitiveIterators;

// use camera::Camera;
use render::math::*;
use render::{Material, Scene};
use shader::*;

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

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

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

pub struct Primitive {
    pub bounds: Bounds,

    vao: u32,
    vbo: u32,
    num_vertices: u32,

    ebo: Option<u32>,
    num_indices: u32,

    material: Rc<Material>,

    pbr_shader: Rc<PbrShader>,

    // TODO!: mode, targets
}

impl Primitive {
    pub fn new(
        bounds: Bounds,
        vertices: Vec<Vertex>,
        indices: Option<Vec<u32>>,
        material: Rc<Material>,
        shader: Rc<PbrShader>,
    ) -> Primitive {
        let num_indices = indices.as_ref().map(|i| i.len()).unwrap_or(0);
        let mut prim = Primitive {
            bounds,
            num_vertices: vertices.len() as u32,
            num_indices: num_indices as u32,
            vao: 0, vbo: 0, ebo: None,
            material,
            pbr_shader: shader,
        };

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

    pub fn from_gltf(
        g_primitive: gltf::Primitive,
        primitive_index: usize,
        mesh_index: usize,
        scene: &mut Scene,
        buffers: &gltf_importer::Buffers,
        base_path: &Path) -> Primitive
    {
        // positions
        let positions = g_primitive.positions(buffers)
            .expect(&format!("primitives must have the POSITION attribute (mesh: {}, primitive: {})",
                mesh_index, primitive_index));

        let bounds = g_primitive.position_bounds()
            .unwrap(); // can't fail if validated "minimally"
        let mut vertices: Vec<Vertex> = positions
            .map(|position| {
                Vertex {
                    position: Vector3::from(position),
                    ..Vertex::default()
                }
            }).collect();

        let mut shader_flags = ShaderFlags::empty();

        // normals
        if let Some(normals) = g_primitive.normals(buffers) {
            for (i, normal) in normals.enumerate() {
                vertices[i].normal = Vector3::from(normal);
            }
            shader_flags |= HAS_NORMALS;
        }
        else {
            debug!("Found no NORMALs for primitive {} of mesh {} \
                   (flat normal calculation not implemented yet)", primitive_index, mesh_index);
        }

        // tangents
        if let Some(tangents) = g_primitive.tangents(buffers) {
            for (i, tangent) in tangents.enumerate() {
                vertices[i].tangent = Vector4::from(tangent);
            }
            shader_flags |= HAS_TANGENTS;
        }
        else {
            debug!("Found no TANGENTS for primitive {} of mesh {} \
                   (tangent calculation not implemented yet)", primitive_index, mesh_index);
        }

        // texture coordinates
        let mut tex_coord_set = 0;
        while let Some(tex_coords) = g_primitive.tex_coords_f32(tex_coord_set, buffers) {
            if tex_coord_set > 1 {
                warn!("Ignoring texture coordinate set {}, \
                        only supporting 2 sets at the moment. (mesh: {}, primitive: {})",
                        tex_coord_set, mesh_index, primitive_index);
                tex_coord_set += 1;
                continue;
            }
            for (i, tex_coord) in tex_coords.enumerate() {
                match tex_coord_set {
                    0 => vertices[i].tex_coord_0 = Vector2::from(tex_coord),
                    1 => vertices[i].tex_coord_1 = Vector2::from(tex_coord),
                    _ => unreachable!()
                }
            }
            shader_flags |= HAS_UV;
            tex_coord_set += 1;
        }

        // colors
        let mut color_set = 0;
        while let Some(colors) = g_primitive.colors_rgba_f32(color_set, 1.0, buffers) {
            if color_set > 0 {
                warn!("Ignoring color set {}, \
                       only supporting 1 set at the moment. (mesh: {}, primitive: {})",
                       color_set, mesh_index, primitive_index);
                color_set += 1;
                continue;
            }
            for (i, c) in colors.enumerate() {
                vertices[i].color_0 = vec4(c[0], c[1], c[2], c[3]);
            }
            shader_flags |= HAS_COLORS;
            color_set += 1;
        }

        let indices: Option<Vec<u32>> = g_primitive.indices_u32(buffers).map(|indices| indices.collect());

        assert_eq!(g_primitive.mode(), Mode::Triangles, "not yet implemented: primitive mode must be Triangles.");

        let g_material = g_primitive.material();

        let mut material = None;
        if let Some(mat) = scene.materials.iter().find(|m| (***m).index == g_material.index()) {
            material = Rc::clone(mat).into()
        }

        if material.is_none() { // no else due to borrow checker madness
            let mat = Rc::new(Material::from_gltf(&g_material, scene, buffers, base_path));
            scene.materials.push(Rc::clone(&mat));
            material = Some(mat);
        };
        let material = material.unwrap();
        shader_flags |= material.shader_flags();

        let mut new_shader = false; // borrow checker workaround
        let shader =
            if let Some(shader) = scene.shaders.get(&shader_flags) {
                Rc::clone(shader)
            }
            else {
                new_shader = true;
                PbrShader::new(shader_flags).into()

            };
        if new_shader {
            scene.shaders.insert(shader_flags, Rc::clone(&shader));
        }

        Primitive::new(bounds.into(), vertices, indices, material, shader)
    }

    /// render the mesh
    pub unsafe fn draw(&self, model_matrix: &Matrix4, mvp_matrix: &Matrix4, camera_position: &Vector3) {
        // TODO!!: determine if shader+material already active to reduce work...

        if self.material.double_sided {
            gl::Disable(gl::CULL_FACE);
        } else {
            gl::Enable(gl::CULL_FACE);
        }

        self.configure_shader(model_matrix, mvp_matrix, camera_position);

        // draw mesh
        gl::BindVertexArray(self.vao);
        if self.ebo.is_some() {
            gl::DrawElements(gl::TRIANGLES, self.num_indices as i32, gl::UNSIGNED_INT, ptr::null());
        }
        else {
            gl::DrawArrays(gl::TRIANGLES, 0, self.num_vertices as i32)
        }

        gl::BindVertexArray(0);
        gl::ActiveTexture(gl::TEXTURE0);
    }

    unsafe fn configure_shader(&self, model_matrix: &Matrix4,
        mvp_matrix: &Matrix4, camera_position: &Vector3)
    {
        // let pbr_shader = &Rc::get_mut(&mut self.pbr_shader).unwrap();
        let mat = &self.material;
        let shader = &self.pbr_shader.shader;
        let uniforms = &self.pbr_shader.uniforms;
        self.pbr_shader.shader.use_program();

        // camera params
        shader.set_mat4(uniforms.u_ModelMatrix, model_matrix);
        shader.set_mat4(uniforms.u_MVPMatrix, mvp_matrix);
        shader.set_vector3(uniforms.u_Camera, camera_position);

        // NOTE: for sampler numbers, see also PbrShader constructor
        shader.set_vector4(uniforms.u_BaseColorFactor, &mat.base_color_factor);
        if let Some(ref base_color_texture) = mat.base_color_texture {
            gl::ActiveTexture(gl::TEXTURE0);
            gl::BindTexture(gl::TEXTURE_2D, base_color_texture.id);
        }
        if let Some(ref normal_texture) = mat.normal_texture {
            gl::ActiveTexture(gl::TEXTURE1);
            gl::BindTexture(gl::TEXTURE_2D, normal_texture.id);
        }
        if let Some(ref emissive_texture) = mat.emissive_texture {
            gl::ActiveTexture(gl::TEXTURE2);
            gl::BindTexture(gl::TEXTURE_2D, emissive_texture.id);

            shader.set_vector3(uniforms.u_EmissiveFactor, &mat.emissive_factor);
        }

        if let Some(ref mr_texture) = mat.metallic_roughness_texture {
            gl::ActiveTexture(gl::TEXTURE3);
            gl::BindTexture(gl::TEXTURE_2D, mr_texture.id);
        }
        shader.set_vec2(uniforms.u_MetallicRoughnessValues,
            mat.metallic_factor, mat.roughness_factor);

        if let Some(ref occlusion_texture) = mat.occlusion_texture {
            gl::ActiveTexture(gl::TEXTURE4);
            gl::BindTexture(gl::TEXTURE_2D, occlusion_texture.id);

            shader.set_float(uniforms.u_OcclusionSampler, mat.occlusion_strength);
        }
    }

    unsafe fn setup_primitive(&mut self, vertices: Vec<Vertex>, indices: Option<Vec<u32>>) {
        // create buffers/arrays
        gl::GenVertexArrays(1, &mut self.vao);
        gl::GenBuffers(1, &mut self.vbo);
        if indices.is_some() {
            let mut ebo = 0;
            gl::GenBuffers(1, &mut ebo);
            self.ebo = Some(ebo);
        }

        gl::BindVertexArray(self.vao);
        // load data into vertex buffers
        gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
        let size = (vertices.len() * size_of::<Vertex>()) as isize;
        let data = &vertices[0] as *const Vertex as *const c_void;
        gl::BufferData(gl::ARRAY_BUFFER, size, data, gl::STATIC_DRAW);

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

        // set the vertex attribute pointers
        let size = size_of::<Vertex>() as i32;
        // POSITION
        gl::EnableVertexAttribArray(0);
        gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, position) as *const c_void);
        // NORMAL
        gl::EnableVertexAttribArray(1);
        gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, normal) as *const c_void);
        // TANGENT
        gl::EnableVertexAttribArray(2);
        gl::VertexAttribPointer(2, 4, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tangent) as *const c_void);
        // TEXCOORD_0
        gl::EnableVertexAttribArray(3);
        gl::VertexAttribPointer(3, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tex_coord_0) as *const c_void);
        // TEXCOORD_1
        gl::EnableVertexAttribArray(4);
        gl::VertexAttribPointer(4, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tex_coord_1) as *const c_void);
        // COLOR_0
        gl::EnableVertexAttribArray(5);
        gl::VertexAttribPointer(5, 4, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, color_0) as *const c_void);

        gl::BindVertexArray(0);
    }
}
<commit_msg>Primitive: handle joints, weights (WIP)<commit_after>use std::mem::size_of;
use std::os::raw::c_void;
use std::path::Path;
use std::ptr;
use std::rc::Rc;

use gl;
use gltf;
use gltf::json::mesh::Mode;
use gltf_importer;
use gltf_utils::PrimitiveIterators;

// use camera::Camera;
use render::math::*;
use render::{Material, Scene};
use shader::*;

#[derive(Debug)]
pub struct Vertex {
    pub position: Vector3,
    pub normal: Vector3,
    pub tangent: Vector4,
    pub tex_coord_0: Vector2,
    pub tex_coord_1: Vector2,
    pub color_0: Vector4,
    pub joints_0: [u16; 4],
    pub weights_0: Vector4,
}

impl Default for Vertex {
    fn default() -> Self {
        Vertex {
            position: Vector3::zero(),
            normal: Vector3::zero(),
            tangent: Vector4::zero(),
            tex_coord_0: Vector2::zero(),
            tex_coord_1: Vector2::zero(),
            color_0: Vector4::zero(),
            joints_0: [0; 4],
            weights_0: Vector4::zero(),
        }
    }
}

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

pub struct Primitive {
    pub bounds: Bounds,

    vao: u32,
    vbo: u32,
    num_vertices: u32,

    ebo: Option<u32>,
    num_indices: u32,

    material: Rc<Material>,

    pbr_shader: Rc<PbrShader>,

    // TODO!: mode, targets
}

impl Primitive {
    pub fn new(
        bounds: Bounds,
        vertices: Vec<Vertex>,
        indices: Option<Vec<u32>>,
        material: Rc<Material>,
        shader: Rc<PbrShader>,
    ) -> Primitive {
        let num_indices = indices.as_ref().map(|i| i.len()).unwrap_or(0);
        let mut prim = Primitive {
            bounds,
            num_vertices: vertices.len() as u32,
            num_indices: num_indices as u32,
            vao: 0, vbo: 0, ebo: None,
            material,
            pbr_shader: shader,
        };

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

    pub fn from_gltf(
        g_primitive: gltf::Primitive,
        primitive_index: usize,
        mesh_index: usize,
        scene: &mut Scene,
        buffers: &gltf_importer::Buffers,
        base_path: &Path) -> Primitive
    {
        // positions
        let positions = g_primitive.positions(buffers)
            .expect(&format!("primitives must have the POSITION attribute (mesh: {}, primitive: {})",
                mesh_index, primitive_index));

        let bounds = g_primitive.position_bounds()
            .unwrap(); // can't fail if validated "minimally"
        let mut vertices: Vec<Vertex> = positions
            .map(|position| {
                Vertex {
                    position: Vector3::from(position),
                    ..Vertex::default()
                }
            }).collect();

        let mut shader_flags = ShaderFlags::empty();

        // normals
        if let Some(normals) = g_primitive.normals(buffers) {
            for (i, normal) in normals.enumerate() {
                vertices[i].normal = Vector3::from(normal);
            }
            shader_flags |= HAS_NORMALS;
        }
        else {
            debug!("Found no NORMALs for primitive {} of mesh {} \
                   (flat normal calculation not implemented yet)", primitive_index, mesh_index);
        }

        // tangents
        if let Some(tangents) = g_primitive.tangents(buffers) {
            for (i, tangent) in tangents.enumerate() {
                vertices[i].tangent = Vector4::from(tangent);
            }
            shader_flags |= HAS_TANGENTS;
        }
        else {
            debug!("Found no TANGENTS for primitive {} of mesh {} \
                   (tangent calculation not implemented yet)", primitive_index, mesh_index);
        }

        // texture coordinates
        let mut tex_coord_set = 0;
        while let Some(tex_coords) = g_primitive.tex_coords_f32(tex_coord_set, buffers) {
            if tex_coord_set > 1 {
                warn!("Ignoring texture coordinate set {}, \
                        only supporting 2 sets at the moment. (mesh: {}, primitive: {})",
                        tex_coord_set, mesh_index, primitive_index);
                tex_coord_set += 1;
                continue;
            }
            for (i, tex_coord) in tex_coords.enumerate() {
                match tex_coord_set {
                    0 => vertices[i].tex_coord_0 = Vector2::from(tex_coord),
                    1 => vertices[i].tex_coord_1 = Vector2::from(tex_coord),
                    _ => unreachable!()
                }
            }
            shader_flags |= HAS_UV;
            tex_coord_set += 1;
        }

        // colors
        if let Some(colors) = g_primitive.colors_rgba_f32(0, 1.0, buffers) {
            for (i, c) in colors.enumerate() {
                vertices[i].color_0 = c.into();
            }
            shader_flags |= HAS_COLORS;
        }
        if g_primitive.colors_rgba_f32(1, 1.0, buffers).is_some() {
            warn!("Ignoring further color attributes, only supporting COLOR_0. (mesh: {}, primitive: {})",
                mesh_index, primitive_index);
        }

        if let Some(joints) = g_primitive.joints_u16(0, buffers) {
            for (i, joint) in joints.enumerate() {
                vertices[i].joints_0 = joint;
            }
            println!("has joints");
        }
        if g_primitive.joints_u16(1, buffers).is_some() {
            warn!("Ignoring further joint attributes, only supporting JOINTS_0. (mesh: {}, primitive: {})",
                mesh_index, primitive_index);
        }

        if let Some(weights) = g_primitive.weights_f32(0, buffers) {
            for (i, weights) in weights.enumerate() {
                vertices[i].weights_0 = weights.into();
            }
            println!("has weights");
        }
        if g_primitive.weights_f32(1, buffers).is_some() {
            warn!("Ignoring further weight attributes, only supporting WEIGHTS_0. (mesh: {}, primitive: {})",
                mesh_index, primitive_index);
        }

        let indices: Option<Vec<u32>> = g_primitive.indices_u32(buffers).map(|indices| indices.collect());

        assert_eq!(g_primitive.mode(), Mode::Triangles, "not yet implemented: primitive mode must be Triangles.");

        let g_material = g_primitive.material();

        let mut material = None;
        if let Some(mat) = scene.materials.iter().find(|m| (***m).index == g_material.index()) {
            material = Rc::clone(mat).into()
        }

        if material.is_none() { // no else due to borrow checker madness
            let mat = Rc::new(Material::from_gltf(&g_material, scene, buffers, base_path));
            scene.materials.push(Rc::clone(&mat));
            material = Some(mat);
        };
        let material = material.unwrap();
        shader_flags |= material.shader_flags();

        let mut new_shader = false; // borrow checker workaround
        let shader =
            if let Some(shader) = scene.shaders.get(&shader_flags) {
                Rc::clone(shader)
            }
            else {
                new_shader = true;
                PbrShader::new(shader_flags).into()

            };
        if new_shader {
            scene.shaders.insert(shader_flags, Rc::clone(&shader));
        }

        Primitive::new(bounds.into(), vertices, indices, material, shader)
    }

    /// render the mesh
    pub unsafe fn draw(&self, model_matrix: &Matrix4, mvp_matrix: &Matrix4, camera_position: &Vector3) {
        // TODO!!: determine if shader+material already active to reduce work...

        if self.material.double_sided {
            gl::Disable(gl::CULL_FACE);
        } else {
            gl::Enable(gl::CULL_FACE);
        }

        self.configure_shader(model_matrix, mvp_matrix, camera_position);

        // draw mesh
        gl::BindVertexArray(self.vao);
        if self.ebo.is_some() {
            gl::DrawElements(gl::TRIANGLES, self.num_indices as i32, gl::UNSIGNED_INT, ptr::null());
        }
        else {
            gl::DrawArrays(gl::TRIANGLES, 0, self.num_vertices as i32)
        }

        gl::BindVertexArray(0);
        gl::ActiveTexture(gl::TEXTURE0);
    }

    unsafe fn configure_shader(&self, model_matrix: &Matrix4,
        mvp_matrix: &Matrix4, camera_position: &Vector3)
    {
        // let pbr_shader = &Rc::get_mut(&mut self.pbr_shader).unwrap();
        let mat = &self.material;
        let shader = &self.pbr_shader.shader;
        let uniforms = &self.pbr_shader.uniforms;
        self.pbr_shader.shader.use_program();

        // camera params
        shader.set_mat4(uniforms.u_ModelMatrix, model_matrix);
        shader.set_mat4(uniforms.u_MVPMatrix, mvp_matrix);
        shader.set_vector3(uniforms.u_Camera, camera_position);

        // NOTE: for sampler numbers, see also PbrShader constructor
        shader.set_vector4(uniforms.u_BaseColorFactor, &mat.base_color_factor);
        if let Some(ref base_color_texture) = mat.base_color_texture {
            gl::ActiveTexture(gl::TEXTURE0);
            gl::BindTexture(gl::TEXTURE_2D, base_color_texture.id);
        }
        if let Some(ref normal_texture) = mat.normal_texture {
            gl::ActiveTexture(gl::TEXTURE1);
            gl::BindTexture(gl::TEXTURE_2D, normal_texture.id);
        }
        if let Some(ref emissive_texture) = mat.emissive_texture {
            gl::ActiveTexture(gl::TEXTURE2);
            gl::BindTexture(gl::TEXTURE_2D, emissive_texture.id);

            shader.set_vector3(uniforms.u_EmissiveFactor, &mat.emissive_factor);
        }

        if let Some(ref mr_texture) = mat.metallic_roughness_texture {
            gl::ActiveTexture(gl::TEXTURE3);
            gl::BindTexture(gl::TEXTURE_2D, mr_texture.id);
        }
        shader.set_vec2(uniforms.u_MetallicRoughnessValues,
            mat.metallic_factor, mat.roughness_factor);

        if let Some(ref occlusion_texture) = mat.occlusion_texture {
            gl::ActiveTexture(gl::TEXTURE4);
            gl::BindTexture(gl::TEXTURE_2D, occlusion_texture.id);

            shader.set_float(uniforms.u_OcclusionSampler, mat.occlusion_strength);
        }
    }

    unsafe fn setup_primitive(&mut self, vertices: Vec<Vertex>, indices: Option<Vec<u32>>) {
        // create buffers/arrays
        gl::GenVertexArrays(1, &mut self.vao);
        gl::GenBuffers(1, &mut self.vbo);
        if indices.is_some() {
            let mut ebo = 0;
            gl::GenBuffers(1, &mut ebo);
            self.ebo = Some(ebo);
        }

        gl::BindVertexArray(self.vao);
        // load data into vertex buffers
        gl::BindBuffer(gl::ARRAY_BUFFER, self.vbo);
        let size = (vertices.len() * size_of::<Vertex>()) as isize;
        let data = &vertices[0] as *const Vertex as *const c_void;
        gl::BufferData(gl::ARRAY_BUFFER, size, data, gl::STATIC_DRAW);

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

        // set the vertex attribute pointers
        let size = size_of::<Vertex>() as i32;
        // POSITION
        gl::EnableVertexAttribArray(0);
        gl::VertexAttribPointer(0, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, position) as *const c_void);
        // NORMAL
        gl::EnableVertexAttribArray(1);
        gl::VertexAttribPointer(1, 3, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, normal) as *const c_void);
        // TANGENT
        gl::EnableVertexAttribArray(2);
        gl::VertexAttribPointer(2, 4, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tangent) as *const c_void);
        // TEXCOORD_0
        gl::EnableVertexAttribArray(3);
        gl::VertexAttribPointer(3, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tex_coord_0) as *const c_void);
        // TEXCOORD_1
        gl::EnableVertexAttribArray(4);
        gl::VertexAttribPointer(4, 2, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, tex_coord_1) as *const c_void);
        // COLOR_0
        gl::EnableVertexAttribArray(5);
        gl::VertexAttribPointer(5, 4, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, color_0) as *const c_void);
        // JOINTS_0
        gl::EnableVertexAttribArray(6);
        // TODO: normalization?
        gl::VertexAttribPointer(6, 4, gl::UNSIGNED_SHORT, gl::FALSE, size, offset_of!(Vertex, joints_0) as *const c_void);
        // WEIGHTS_0
        gl::EnableVertexAttribArray(7);
        gl::VertexAttribPointer(7, 4, gl::FLOAT, gl::FALSE, size, offset_of!(Vertex, weights_0) as *const c_void);

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