<commit_before>//! An example of using syntect for testing syntax definitions.
//! Basically exactly the same as what Sublime Text can do,
//! but without needing ST installed
// To run tests only for a particular package, while showing the operations, you could use:
// cargo run --example syntest -- --debug testdata/Packages/Makefile/
// to specify that the syntax definitions should be parsed instead of loaded from the dump file,
// you can tell it where to parse them from - the following will execute only 1 syntax test after
// parsing the sublime-syntax files in the JavaScript folder:
// cargo run --example syntest testdata/Packages/JavaScript/syntax_test_json.json testdata/Packages/JavaScript/
extern crate syntect;
extern crate walkdir;
#[macro_use]
extern crate lazy_static;
extern crate regex;
//extern crate onig;
use syntect::parsing::{SyntaxSet, ParseState, ScopeStack, Scope};
use syntect::highlighting::ScopeSelectors;
use syntect::easy::{ScopeRegionIterator};

use std::path::Path;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::cmp::{min, max};
use std::time::Instant;
use walkdir::{DirEntry, WalkDir};
use std::str::FromStr;
use regex::Regex;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SyntaxTestHeaderError {
    MalformedHeader,
    SyntaxDefinitionNotFound,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SyntaxTestFileResult {
    FailedAssertions(usize, usize),
    Success(usize),
}

lazy_static! {
    pub static ref SYNTAX_TEST_HEADER_PATTERN: Regex = Regex::new(r#"(?xm)
            ^(?P<testtoken_start>\s*\S+)
            \s+SYNTAX\sTEST\s+
            "(?P<syntax_file>[^"]+)"
            \s*(?P<testtoken_end>\S+)?$
        "#).unwrap();
    pub static ref SYNTAX_TEST_ASSERTION_PATTERN: Regex = Regex::new(r#"(?xm)
        \s*(?:
            (?P<begin_of_token><-)|(?P<range>\^+)
        )(.*)$"#).unwrap();
}

#[derive(Debug)]
struct AssertionRange<'a> {
    begin_char: usize,
    end_char: usize,
    scope_selector_text: &'a str,
    is_pure_assertion_line: bool,
}

#[derive(Debug)]
struct ScopedText {
    scope: Vec<Scope>,
    char_start: usize,
    text_len: usize,
}

#[derive(Debug)]
struct RangeTestResult {
    column_begin: usize,
    column_end: usize,
    success: bool,
}

fn get_line_assertion_details<'a>(testtoken_start: &str, testtoken_end: Option<&str>, line: &'a str) -> Option<AssertionRange<'a>> {
    // if the test start token specified in the test file's header is on the line
    if let Some(index) = line.find(testtoken_start) {
        let (before_token_start, token_and_rest_of_line) = line.split_at(index);

        if let Some(captures) = SYNTAX_TEST_ASSERTION_PATTERN.captures(&token_and_rest_of_line[testtoken_start.len()..]) {
            let mut sst = captures.get(3).unwrap().as_str(); // get the scope selector text
            let mut only_whitespace_after_token_end = true;

            if let Some(token) = testtoken_end { // if there is an end token defined in the test file header
                if let Some(end_token_pos) = sst.find(token) { // and there is an end token in the line
                    let (ss, after_token_end) = sst.split_at(end_token_pos); // the scope selector text ends at the end token
                    sst = &ss;
                    only_whitespace_after_token_end = after_token_end.trim_right().is_empty();
                }
            }
            return Some(AssertionRange {
                begin_char: index + if captures.get(2).is_some() { testtoken_start.len() + captures.get(2).unwrap().start() } else { 0 },
                end_char: index + if captures.get(2).is_some() { testtoken_start.len() + captures.get(2).unwrap().end() } else { 1 },
                scope_selector_text: sst,
                is_pure_assertion_line: before_token_start.trim_left().is_empty() && only_whitespace_after_token_end, // if only whitespace surrounds the test tokens on the line, then it is a pure assertion line
            });
        }
    }
    None
}

fn process_assertions(assertion: &AssertionRange, test_against_line_scopes: &Vec<ScopedText>) -> Vec<RangeTestResult> {
    // format the scope selector to include a space at the beginning, because, currently, ScopeSelector expects excludes to begin with " -"
    // and they are sometimes in the syntax test as ^^^-comment, for example
    let selector = ScopeSelectors::from_str(&format!(" {}", &assertion.scope_selector_text)).unwrap();
    // find the scope at the specified start column, and start matching the selector through the rest of the tokens on the line from there until the end column is reached
    let mut results = Vec::new();
    for scoped_text in test_against_line_scopes.iter().skip_while(|s|s.char_start + s.text_len <= assertion.begin_char).take_while(|s|s.char_start < assertion.end_char) {
        let match_value = selector.does_match(scoped_text.scope.as_slice());
        let result = RangeTestResult {
            column_begin: max(scoped_text.char_start, assertion.begin_char),
            column_end: min(scoped_text.char_start + scoped_text.text_len, assertion.end_char),
            success: match_value.is_some()
        };
        results.push(result);
    }
    // don't ignore assertions after the newline, they should be treated as though they are asserting against the newline
    let last = test_against_line_scopes.last().unwrap();
    if last.char_start + last.text_len < assertion.end_char {
        let match_value = selector.does_match(last.scope.as_slice());
        let result = RangeTestResult {
            column_begin: max(last.char_start + last.text_len, assertion.begin_char),
            column_end: assertion.end_char,
            success: match_value.is_some()
        };
        results.push(result);
    }
    results
}

/// If `parse_test_lines` is `false` then lines that only contain assertions are not parsed
fn test_file(ss: &SyntaxSet, path: &Path, parse_test_lines: bool, debug: bool) -> Result<SyntaxTestFileResult, SyntaxTestHeaderError> {
    use syntect::util::debug_print_ops;
    let f = File::open(path).unwrap();
    let mut reader = BufReader::new(f);
    let mut line = String::new();

    // read the first line from the file - if we have reached EOF already, it's an invalid file
    if reader.read_line(&mut line).unwrap() == 0 {
        return Err(SyntaxTestHeaderError::MalformedHeader);
    }

    line = line.replace("\r", &"");

    // parse the syntax test header in the first line of the file
    let header_line = line.clone();
    let search_result = SYNTAX_TEST_HEADER_PATTERN.captures(&header_line);
    let captures = search_result.ok_or(SyntaxTestHeaderError::MalformedHeader)?;

    let testtoken_start = captures.name("testtoken_start").unwrap().as_str();
    let testtoken_end = captures.name("testtoken_end").map_or(None, |c|Some(c.as_str()));
    let syntax_file = captures.name("syntax_file").unwrap().as_str();

    // find the relevant syntax definition to parse the file with - case is important!
    println!("The test file references syntax definition file: {}", syntax_file);
    let syntax = ss.find_syntax_by_path(syntax_file).ok_or(SyntaxTestHeaderError::SyntaxDefinitionNotFound)?;

    // iterate over the lines of the file, testing them
    let mut state = ParseState::new(syntax);
    let mut stack = ScopeStack::new();

    let mut current_line_number = 1;
    let mut test_against_line_number = 1;
    let mut scopes_on_line_being_tested = Vec::new();
    let mut previous_non_assertion_line = line.to_string();

    let mut assertion_failures: usize = 0;
    let mut total_assertions: usize = 0;

    loop { // over lines of file, starting with the header line
        let mut line_only_has_assertion = false;
        let mut line_has_assertion = false;
        if let Some(assertion) = get_line_assertion_details(testtoken_start, testtoken_end, &line) {
            let result = process_assertions(&assertion, &scopes_on_line_being_tested);
            total_assertions += &assertion.end_char - &assertion.begin_char;
            for failure in result.iter().filter(|r|!r.success) {
                let length = failure.column_end - failure.column_begin;
                let text: String = previous_non_assertion_line.chars().skip(failure.column_begin).take(length).collect();
                println!("  Assertion selector {:?} \
                    from line {:?} failed against line {:?}, column range {:?}-{:?} \
                    (with text {:?}) \
                    has scope {:?}",
                    assertion.scope_selector_text.trim(),
                    current_line_number, test_against_line_number, failure.column_begin, failure.column_end,
                    text,
                    scopes_on_line_being_tested.iter().skip_while(|s|s.char_start + s.text_len <= failure.column_begin).next().unwrap_or(scopes_on_line_being_tested.last().unwrap()).scope
                );
                assertion_failures += failure.column_end - failure.column_begin;
            }
            line_only_has_assertion = assertion.is_pure_assertion_line;
            line_has_assertion = true;
        }
        if !line_only_has_assertion || parse_test_lines {
            if !line_has_assertion { // ST seems to ignore lines that have assertions when calculating which line the assertion tests against
                scopes_on_line_being_tested.clear();
                test_against_line_number = current_line_number;
                previous_non_assertion_line = line.to_string();
            }
            if debug && !line_only_has_assertion {
                println!("-- debugging line {} -- scope stack: {:?}", current_line_number, stack);
            }
            let ops = state.parse_line(&line);
            if debug && !line_only_has_assertion {
                if ops.is_empty() && !line.is_empty() {
                    println!("no operations for this line...");
                } else {
                    debug_print_ops(&line, &ops);
                }
            }
            let mut col: usize = 0;
            for (s, op) in ScopeRegionIterator::new(&ops, &line) {
                stack.apply(op);
                if s.is_empty() { // in this case we don't care about blank tokens
                    continue;
                }
                if !line_has_assertion {
                    // if the line has no assertions on it, remember the scopes on the line so we can test against them later
                    let len = s.chars().count();
                    scopes_on_line_being_tested.push(
                        ScopedText {
                            char_start: col,
                            text_len: len,
                            scope: stack.as_slice().to_vec()
                        }
                    );
                    // TODO: warn when there are duplicate adjacent (non-meta?) scopes, as it is almost always undesired
                    col += len;
                }
            }
        }

        line.clear();
        current_line_number += 1;
        if reader.read_line(&mut line).unwrap() == 0 {
            break;
        }
        line = line.replace("\r", &"");
    }
    if assertion_failures > 0 {
        Ok(SyntaxTestFileResult::FailedAssertions(assertion_failures, total_assertions))
    } else {
        Ok(SyntaxTestFileResult::Success(total_assertions))
    }
}

fn main() {
    let mut args: Vec<String> = std::env::args().collect();
    let debug_arg = args.iter().position(|s| s == "--debug");
    if debug_arg.is_some() {
        args.remove(debug_arg.unwrap());
    }

    let time_arg = args.iter().position(|s| s == "--time");
    if time_arg.is_some() {
        args.remove(time_arg.unwrap());
    }

    let tests_path = if args.len() < 2 {
        "."
    } else {
        &args[1]
    };
    let syntaxes_path = if args.len() == 3 {
        &args[2]
    } else {
        ""
    };

    // load the syntaxes from disk if told to
    // (as opposed to from the binary dumps)
    // this helps to ensure that a recompile isn't needed
    // when using this for syntax development
    let mut ss = if syntaxes_path.is_empty() {
        SyntaxSet::load_defaults_newlines() // note we load the version with newlines
    } else {
        SyntaxSet::new()
    };
    if !syntaxes_path.is_empty() {
        println!("loading syntax definitions from {}", syntaxes_path);
        ss.load_syntaxes(&syntaxes_path, true).unwrap(); // note that we load the version with newlines
        ss.link_syntaxes();
    }

    let exit_code = recursive_walk(&ss, &tests_path, debug_arg.is_some(), time_arg.is_some());
    println!("exiting with code {}", exit_code);
    std::process::exit(exit_code);

}

fn recursive_walk(ss: &SyntaxSet, path: &str, debug: bool, time: bool) -> i32 {
    let mut exit_code: i32 = 0; // exit with code 0 by default, if all tests pass
    let walker = WalkDir::new(path).into_iter();
    for entry in walker.filter_entry(|e|e.file_type().is_dir() || is_a_syntax_test_file(e)) {
        let entry = entry.unwrap();
        if entry.file_type().is_file() {
            println!("Testing file {}", entry.path().display());
            let start = Instant::now();
            let result = test_file(&ss, entry.path(), true, debug);
            let elapsed = start.elapsed();
            println!("{:?}", result);
            if time {
                let ms = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
                println!("{} ms for file {}", ms, entry.path().display());
            }
            if exit_code != 2 { // leave exit code 2 if there was an error
                if let Err(_) = result { // set exit code 2 if there was an error
                    exit_code = 2;
                } else if let Ok(ok) = result {
                    if let SyntaxTestFileResult::FailedAssertions(_, _) = ok {
                        exit_code = 1; // otherwise, if there were failures, exit with code 1
                    }
                }
            }
        }
    }
    exit_code
}

fn is_a_syntax_test_file(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("syntax_test_"))
         .unwrap_or(false)
}
<commit_msg>Switch syntest parsing to getopts<commit_after>//! An example of using syntect for testing syntax definitions.
//! Basically exactly the same as what Sublime Text can do,
//! but without needing ST installed
// To run tests only for a particular package, while showing the operations, you could use:
// cargo run --example syntest -- --debug testdata/Packages/Makefile/
// to specify that the syntax definitions should be parsed instead of loaded from the dump file,
// you can tell it where to parse them from - the following will execute only 1 syntax test after
// parsing the sublime-syntax files in the JavaScript folder:
// cargo run --example syntest testdata/Packages/JavaScript/syntax_test_json.json testdata/Packages/JavaScript/
extern crate syntect;
extern crate walkdir;
#[macro_use]
extern crate lazy_static;
extern crate regex;
extern crate getopts;

//extern crate onig;
use syntect::parsing::{SyntaxSet, ParseState, ScopeStack, Scope};
use syntect::highlighting::ScopeSelectors;
use syntect::easy::{ScopeRegionIterator};

use std::path::Path;
use std::io::{BufRead, BufReader};
use std::fs::File;
use std::cmp::{min, max};
use std::time::Instant;
use std::str::FromStr;

use getopts::Options;
use regex::Regex;
use walkdir::{DirEntry, WalkDir};

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SyntaxTestHeaderError {
    MalformedHeader,
    SyntaxDefinitionNotFound,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SyntaxTestFileResult {
    FailedAssertions(usize, usize),
    Success(usize),
}

lazy_static! {
    pub static ref SYNTAX_TEST_HEADER_PATTERN: Regex = Regex::new(r#"(?xm)
            ^(?P<testtoken_start>\s*\S+)
            \s+SYNTAX\sTEST\s+
            "(?P<syntax_file>[^"]+)"
            \s*(?P<testtoken_end>\S+)?$
        "#).unwrap();
    pub static ref SYNTAX_TEST_ASSERTION_PATTERN: Regex = Regex::new(r#"(?xm)
        \s*(?:
            (?P<begin_of_token><-)|(?P<range>\^+)
        )(.*)$"#).unwrap();
}

#[derive(Debug)]
struct AssertionRange<'a> {
    begin_char: usize,
    end_char: usize,
    scope_selector_text: &'a str,
    is_pure_assertion_line: bool,
}

#[derive(Debug)]
struct ScopedText {
    scope: Vec<Scope>,
    char_start: usize,
    text_len: usize,
}

#[derive(Debug)]
struct RangeTestResult {
    column_begin: usize,
    column_end: usize,
    success: bool,
}

fn get_line_assertion_details<'a>(testtoken_start: &str, testtoken_end: Option<&str>, line: &'a str) -> Option<AssertionRange<'a>> {
    // if the test start token specified in the test file's header is on the line
    if let Some(index) = line.find(testtoken_start) {
        let (before_token_start, token_and_rest_of_line) = line.split_at(index);

        if let Some(captures) = SYNTAX_TEST_ASSERTION_PATTERN.captures(&token_and_rest_of_line[testtoken_start.len()..]) {
            let mut sst = captures.get(3).unwrap().as_str(); // get the scope selector text
            let mut only_whitespace_after_token_end = true;

            if let Some(token) = testtoken_end { // if there is an end token defined in the test file header
                if let Some(end_token_pos) = sst.find(token) { // and there is an end token in the line
                    let (ss, after_token_end) = sst.split_at(end_token_pos); // the scope selector text ends at the end token
                    sst = &ss;
                    only_whitespace_after_token_end = after_token_end.trim_right().is_empty();
                }
            }
            return Some(AssertionRange {
                begin_char: index + if captures.get(2).is_some() { testtoken_start.len() + captures.get(2).unwrap().start() } else { 0 },
                end_char: index + if captures.get(2).is_some() { testtoken_start.len() + captures.get(2).unwrap().end() } else { 1 },
                scope_selector_text: sst,
                is_pure_assertion_line: before_token_start.trim_left().is_empty() && only_whitespace_after_token_end, // if only whitespace surrounds the test tokens on the line, then it is a pure assertion line
            });
        }
    }
    None
}

fn process_assertions(assertion: &AssertionRange, test_against_line_scopes: &Vec<ScopedText>) -> Vec<RangeTestResult> {
    // format the scope selector to include a space at the beginning, because, currently, ScopeSelector expects excludes to begin with " -"
    // and they are sometimes in the syntax test as ^^^-comment, for example
    let selector = ScopeSelectors::from_str(&format!(" {}", &assertion.scope_selector_text)).unwrap();
    // find the scope at the specified start column, and start matching the selector through the rest of the tokens on the line from there until the end column is reached
    let mut results = Vec::new();
    for scoped_text in test_against_line_scopes.iter().skip_while(|s|s.char_start + s.text_len <= assertion.begin_char).take_while(|s|s.char_start < assertion.end_char) {
        let match_value = selector.does_match(scoped_text.scope.as_slice());
        let result = RangeTestResult {
            column_begin: max(scoped_text.char_start, assertion.begin_char),
            column_end: min(scoped_text.char_start + scoped_text.text_len, assertion.end_char),
            success: match_value.is_some()
        };
        results.push(result);
    }
    // don't ignore assertions after the newline, they should be treated as though they are asserting against the newline
    let last = test_against_line_scopes.last().unwrap();
    if last.char_start + last.text_len < assertion.end_char {
        let match_value = selector.does_match(last.scope.as_slice());
        let result = RangeTestResult {
            column_begin: max(last.char_start + last.text_len, assertion.begin_char),
            column_end: assertion.end_char,
            success: match_value.is_some()
        };
        results.push(result);
    }
    results
}

/// If `parse_test_lines` is `false` then lines that only contain assertions are not parsed
fn test_file(ss: &SyntaxSet, path: &Path, parse_test_lines: bool, debug: bool) -> Result<SyntaxTestFileResult, SyntaxTestHeaderError> {
    use syntect::util::debug_print_ops;
    let f = File::open(path).unwrap();
    let mut reader = BufReader::new(f);
    let mut line = String::new();

    // read the first line from the file - if we have reached EOF already, it's an invalid file
    if reader.read_line(&mut line).unwrap() == 0 {
        return Err(SyntaxTestHeaderError::MalformedHeader);
    }

    line = line.replace("\r", &"");

    // parse the syntax test header in the first line of the file
    let header_line = line.clone();
    let search_result = SYNTAX_TEST_HEADER_PATTERN.captures(&header_line);
    let captures = search_result.ok_or(SyntaxTestHeaderError::MalformedHeader)?;

    let testtoken_start = captures.name("testtoken_start").unwrap().as_str();
    let testtoken_end = captures.name("testtoken_end").map_or(None, |c|Some(c.as_str()));
    let syntax_file = captures.name("syntax_file").unwrap().as_str();

    // find the relevant syntax definition to parse the file with - case is important!
    println!("The test file references syntax definition file: {}", syntax_file);
    let syntax = ss.find_syntax_by_path(syntax_file).ok_or(SyntaxTestHeaderError::SyntaxDefinitionNotFound)?;

    // iterate over the lines of the file, testing them
    let mut state = ParseState::new(syntax);
    let mut stack = ScopeStack::new();

    let mut current_line_number = 1;
    let mut test_against_line_number = 1;
    let mut scopes_on_line_being_tested = Vec::new();
    let mut previous_non_assertion_line = line.to_string();

    let mut assertion_failures: usize = 0;
    let mut total_assertions: usize = 0;

    loop { // over lines of file, starting with the header line
        let mut line_only_has_assertion = false;
        let mut line_has_assertion = false;
        if let Some(assertion) = get_line_assertion_details(testtoken_start, testtoken_end, &line) {
            let result = process_assertions(&assertion, &scopes_on_line_being_tested);
            total_assertions += &assertion.end_char - &assertion.begin_char;
            for failure in result.iter().filter(|r|!r.success) {
                let length = failure.column_end - failure.column_begin;
                let text: String = previous_non_assertion_line.chars().skip(failure.column_begin).take(length).collect();
                println!("  Assertion selector {:?} \
                    from line {:?} failed against line {:?}, column range {:?}-{:?} \
                    (with text {:?}) \
                    has scope {:?}",
                    assertion.scope_selector_text.trim(),
                    current_line_number, test_against_line_number, failure.column_begin, failure.column_end,
                    text,
                    scopes_on_line_being_tested.iter().skip_while(|s|s.char_start + s.text_len <= failure.column_begin).next().unwrap_or(scopes_on_line_being_tested.last().unwrap()).scope
                );
                assertion_failures += failure.column_end - failure.column_begin;
            }
            line_only_has_assertion = assertion.is_pure_assertion_line;
            line_has_assertion = true;
        }
        if !line_only_has_assertion || parse_test_lines {
            if !line_has_assertion { // ST seems to ignore lines that have assertions when calculating which line the assertion tests against
                scopes_on_line_being_tested.clear();
                test_against_line_number = current_line_number;
                previous_non_assertion_line = line.to_string();
            }
            if debug && !line_only_has_assertion {
                println!("-- debugging line {} -- scope stack: {:?}", current_line_number, stack);
            }
            let ops = state.parse_line(&line);
            if debug && !line_only_has_assertion {
                if ops.is_empty() && !line.is_empty() {
                    println!("no operations for this line...");
                } else {
                    debug_print_ops(&line, &ops);
                }
            }
            let mut col: usize = 0;
            for (s, op) in ScopeRegionIterator::new(&ops, &line) {
                stack.apply(op);
                if s.is_empty() { // in this case we don't care about blank tokens
                    continue;
                }
                if !line_has_assertion {
                    // if the line has no assertions on it, remember the scopes on the line so we can test against them later
                    let len = s.chars().count();
                    scopes_on_line_being_tested.push(
                        ScopedText {
                            char_start: col,
                            text_len: len,
                            scope: stack.as_slice().to_vec()
                        }
                    );
                    // TODO: warn when there are duplicate adjacent (non-meta?) scopes, as it is almost always undesired
                    col += len;
                }
            }
        }

        line.clear();
        current_line_number += 1;
        if reader.read_line(&mut line).unwrap() == 0 {
            break;
        }
        line = line.replace("\r", &"");
    }
    if assertion_failures > 0 {
        Ok(SyntaxTestFileResult::FailedAssertions(assertion_failures, total_assertions))
    } else {
        Ok(SyntaxTestFileResult::Success(total_assertions))
    }
}

fn main() {
    let args: Vec<String> = std::env::args().collect();
    let mut opts = Options::new();
    opts.optflag("d", "debug", "Show parsing results for each test line");
    opts.optflag("t", "time", "Time execution as a more broad-ranging benchmark");

    let matches = match opts.parse(&args[1..]) {
        Ok(m) => { m }
        Err(f) => { panic!(f.to_string()) }
    };

    let tests_path = if matches.free.len() < 1 {
        "."
    } else {
        &args[1]
    };

    let syntaxes_path = if matches.free.len() < 2 {
        ""
    } else {
        &args[2]
    };

    // load the syntaxes from disk if told to
    // (as opposed to from the binary dumps)
    // this helps to ensure that a recompile isn't needed
    // when using this for syntax development
    let mut ss = if syntaxes_path.is_empty() {
        SyntaxSet::load_defaults_newlines() // note we load the version with newlines
    } else {
        SyntaxSet::new()
    };
    if !syntaxes_path.is_empty() {
        println!("loading syntax definitions from {}", syntaxes_path);
        ss.load_syntaxes(&syntaxes_path, true).unwrap(); // note that we load the version with newlines
        ss.link_syntaxes();
    }

    let exit_code = recursive_walk(&ss, &tests_path, matches.opt_present("debug"), matches.opt_present("time"));
    println!("exiting with code {}", exit_code);
    std::process::exit(exit_code);

}

fn recursive_walk(ss: &SyntaxSet, path: &str, debug: bool, time: bool) -> i32 {
    let mut exit_code: i32 = 0; // exit with code 0 by default, if all tests pass
    let walker = WalkDir::new(path).into_iter();
    for entry in walker.filter_entry(|e|e.file_type().is_dir() || is_a_syntax_test_file(e)) {
        let entry = entry.unwrap();
        if entry.file_type().is_file() {
            println!("Testing file {}", entry.path().display());
            let start = Instant::now();
            let result = test_file(&ss, entry.path(), true, debug);
            let elapsed = start.elapsed();
            println!("{:?}", result);
            if time {
                let ms = (elapsed.as_secs() * 1_000) + (elapsed.subsec_nanos() / 1_000_000) as u64;
                println!("{} ms for file {}", ms, entry.path().display());
            }
            if exit_code != 2 { // leave exit code 2 if there was an error
                if let Err(_) = result { // set exit code 2 if there was an error
                    exit_code = 2;
                } else if let Ok(ok) = result {
                    if let SyntaxTestFileResult::FailedAssertions(_, _) = ok {
                        exit_code = 1; // otherwise, if there were failures, exit with code 1
                    }
                }
            }
        }
    }
    exit_code
}

fn is_a_syntax_test_file(entry: &DirEntry) -> bool {
    entry.file_name()
         .to_str()
         .map(|s| s.starts_with("syntax_test_"))
         .unwrap_or(false)
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::env;
use hyper::Client;
use hyper::header::Connection;
use std::collections::BTreeMap;
use rustc_serialize::json;
use std::fs::File;

static BASE_URL:    &'static str = "https://www.googleapis.com/youtube/v3";
static MAX_RESULTS: i32          = 50;
lazy_static! {
    static ref API_KEY: String = {
        let opt_key = env::var("YOUTUBE_API_KEY");
        match opt_key {
            Ok(key) => key,
            Err(_) => {
                let mut f = File::open("youtube.txt").unwrap();
                let mut s = String::new();
                let _ = f.read_to_string(&mut s);
                s
            }
        }
    };
}

pub trait HasThumbnail {
    fn get_thumbnails(&self) -> BTreeMap<String, Thumbnail>;
    fn get_thumbnail_url(&self) -> Option<String> {
        let thumbs = self.get_thumbnails();
        thumbs.get(         "default").map(|t| t.url.to_string())
            .or(thumbs.get("medium"  ).map(|t| t.url.to_string()))
            .or(thumbs.get("high"    ).map(|t| t.url.to_string()))
            .or(thumbs.get("standard").map(|t| t.url.to_string()))
            .or(thumbs.get("maxres"  ).map(|t| t.url.to_string()))
    }
    fn get_artwork_url(&self) -> Option<String> {
        let thumbs = self.get_thumbnails();
        thumbs.get(          "maxres").map(|t| t.url.to_string())
            .or(thumbs.get("standard").map(|t| t.url.to_string()))
            .or(thumbs.get("high"    ).map(|t| t.url.to_string()))
            .or(thumbs.get("medium"  ).map(|t| t.url.to_string()))
            .or(thumbs.get("default" ).map(|t| t.url.to_string()))
    }
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Thumbnail {
    pub url:    String,
    pub width:  i32,
    pub height: i32
}

impl PartialEq for Thumbnail {
    fn eq(&self, t: &Thumbnail) -> bool {
        return self.url == t.url;
    }
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct PlaylistItemResponse {
    pub kind:          String,
    pub etag:          String,
    pub nextPageToken: Option<String>,
    pub pageInfo:      BTreeMap<String, i32>,
    pub items:         Vec<PlaylistItem>,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct PlaylistItem {
    pub kind:    String,
    pub etag:    String,
    pub id:      String,
    pub snippet: PlaylistItemSnippet,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct PlaylistItemSnippet {
    pub title:         String,
    pub description:   String,
    pub publishedAt:   String,
    pub channelId:     String,
    pub channelTitle:  String,
    pub thumbnails:    Option<BTreeMap<String, Thumbnail>>,
    pub position:      i32,
    pub playlistId:    String,
    pub resourceId:    BTreeMap<String, String>
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct VideoResponse {
    pub kind:          String,
    pub etag:          String,
    pub pageInfo:      BTreeMap<String, i32>,
    pub items:         Vec<Video>,
}

#[allow(non_snake_case)]
#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Video {
    pub kind:    String,
    pub etag:    String,
    pub id:      String,
    pub snippet: VideoSnippet,
}

#[allow(non_snake_case)]
#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct VideoSnippet {
    pub title:                String,
    pub description:          String,
    pub publishedAt:          String,
    pub channelId:            String,
    pub channelTitle:         String,
    pub thumbnails:           Option<BTreeMap<String, Thumbnail>>,
    pub tags:                 Option<Vec<String>>,
    pub categoryId:           String,
    pub liveBroadcastContent: String,
}

impl HasThumbnail for PlaylistItemSnippet {
    fn get_thumbnails(&self) -> BTreeMap<String, Thumbnail> {
        self.thumbnails.clone().unwrap_or(BTreeMap::new())
    }
}

impl HasThumbnail for VideoSnippet {
    fn get_thumbnails(&self) -> BTreeMap<String, Thumbnail> {
        self.thumbnails.clone().unwrap_or(BTreeMap::new())
    }
}

pub fn fetch_playlist(id: &str) -> json::DecodeResult<PlaylistItemResponse> {
    let params = format!("key={}&part=snippet&playlistId={}&maxResults={}",
                         *API_KEY,
                         id,
                         MAX_RESULTS);
    let url    = format!("{}/{}?{}", BASE_URL, "playlistItems", params);
    let client = Client::new();
    let mut res = client.get(&url)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    json::decode::<PlaylistItemResponse>(&body)
}

pub fn fetch_video(id: &str) -> json::DecodeResult<Video> {
    let params = format!("key={}&part=snippet&id={}", *API_KEY, id);
    let url    = format!("{}/{}?{}", BASE_URL, "videos", params);
    let client = Client::new();
    let mut res = client.get(&url)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let res = try!(json::decode::<VideoResponse>(&body));
    if res.items.len() > 0 {
        return Ok(res.items[0].clone());
    }
    Err(json::DecoderError::ApplicationError("track not found".to_string()))
}
<commit_msg>Get youtube playlist snippet<commit_after>use std::io::Read;
use std::env;
use hyper::Client;
use hyper::header::Connection;
use std::collections::BTreeMap;
use rustc_serialize::json;
use std::fs::File;

static BASE_URL:    &'static str = "https://www.googleapis.com/youtube/v3";
static MAX_RESULTS: i32          = 50;
lazy_static! {
    static ref API_KEY: String = {
        let opt_key = env::var("YOUTUBE_API_KEY");
        match opt_key {
            Ok(key) => key,
            Err(_) => {
                let mut f = File::open("youtube.txt").unwrap();
                let mut s = String::new();
                let _ = f.read_to_string(&mut s);
                s
            }
        }
    };
}

pub trait HasThumbnail {
    fn get_thumbnails(&self) -> BTreeMap<String, Thumbnail>;
    fn get_thumbnail_url(&self) -> Option<String> {
        let thumbs = self.get_thumbnails();
        thumbs.get(         "default").map(|t| t.url.to_string())
            .or(thumbs.get("medium"  ).map(|t| t.url.to_string()))
            .or(thumbs.get("high"    ).map(|t| t.url.to_string()))
            .or(thumbs.get("standard").map(|t| t.url.to_string()))
            .or(thumbs.get("maxres"  ).map(|t| t.url.to_string()))
    }
    fn get_artwork_url(&self) -> Option<String> {
        let thumbs = self.get_thumbnails();
        thumbs.get(          "maxres").map(|t| t.url.to_string())
            .or(thumbs.get("standard").map(|t| t.url.to_string()))
            .or(thumbs.get("high"    ).map(|t| t.url.to_string()))
            .or(thumbs.get("medium"  ).map(|t| t.url.to_string()))
            .or(thumbs.get("default" ).map(|t| t.url.to_string()))
    }
}

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Thumbnail {
    pub url:    String,
    pub width:  i32,
    pub height: i32
}

impl PartialEq for Thumbnail {
    fn eq(&self, t: &Thumbnail) -> bool {
        return self.url == t.url;
    }
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct PlaylistResponse {
    pub kind:          String,
    pub etag:          String,
    pub nextPageToken: Option<String>,
    pub pageInfo:      BTreeMap<String, i32>,
    pub items:         Vec<Playlist>,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Playlist {
    pub kind:    String,
    pub etag:    String,
    pub id:      String,
    pub snippet: PlaylistSnippet,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct PlaylistSnippet {
    pub title:         String,
    pub description:   String,
    pub publishedAt:   String,
    pub channelId:     String,
    pub channelTitle:  String,
    pub thumbnails:    Option<BTreeMap<String, Thumbnail>>,
    pub tags:          Option<Vec<String>>,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct PlaylistItemResponse {
    pub kind:          String,
    pub etag:          String,
    pub nextPageToken: Option<String>,
    pub pageInfo:      BTreeMap<String, i32>,
    pub items:         Vec<PlaylistItem>,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct PlaylistItem {
    pub kind:    String,
    pub etag:    String,
    pub id:      String,
    pub snippet: PlaylistItemSnippet,
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct PlaylistItemSnippet {
    pub title:         String,
    pub description:   String,
    pub publishedAt:   String,
    pub channelId:     String,
    pub channelTitle:  String,
    pub thumbnails:    Option<BTreeMap<String, Thumbnail>>,
    pub position:      i32,
    pub playlistId:    String,
    pub resourceId:    BTreeMap<String, String>
}

#[allow(non_snake_case)]
#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct VideoResponse {
    pub kind:          String,
    pub etag:          String,
    pub pageInfo:      BTreeMap<String, i32>,
    pub items:         Vec<Video>,
}

#[allow(non_snake_case)]
#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Video {
    pub kind:    String,
    pub etag:    String,
    pub id:      String,
    pub snippet: VideoSnippet,
}

#[allow(non_snake_case)]
#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct VideoSnippet {
    pub title:                String,
    pub description:          String,
    pub publishedAt:          String,
    pub channelId:            String,
    pub channelTitle:         String,
    pub thumbnails:           Option<BTreeMap<String, Thumbnail>>,
    pub tags:                 Option<Vec<String>>,
    pub categoryId:           String,
    pub liveBroadcastContent: String,
}

impl HasThumbnail for PlaylistSnippet {
    fn get_thumbnails(&self) -> BTreeMap<String, Thumbnail> {
        self.thumbnails.clone().unwrap_or(BTreeMap::new())
    }
}

impl HasThumbnail for PlaylistItemSnippet {
    fn get_thumbnails(&self) -> BTreeMap<String, Thumbnail> {
        self.thumbnails.clone().unwrap_or(BTreeMap::new())
    }
}

impl HasThumbnail for VideoSnippet {
    fn get_thumbnails(&self) -> BTreeMap<String, Thumbnail> {
        self.thumbnails.clone().unwrap_or(BTreeMap::new())
    }
}

pub fn fetch_playlist(id: &str) -> json::DecodeResult<PlaylistResponse> {
    let params = format!("key={}&part=snippet&id={}&maxResults={}",
                         *API_KEY,
                         id,
                         MAX_RESULTS);
    let url    = format!("{}/{}?{}", BASE_URL, "playlists", params);
    let client = Client::new();
    let mut res = client.get(&url)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    json::decode::<PlaylistResponse>(&body)
}

pub fn fetch_playlist_items(id: &str) -> json::DecodeResult<PlaylistItemResponse> {
    let params = format!("key={}&part=snippet&playlistId={}&maxResults={}",
                         *API_KEY,
                         id,
                         MAX_RESULTS);
    let url    = format!("{}/{}?{}", BASE_URL, "playlistItems", params);
    let client = Client::new();
    let mut res = client.get(&url)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    json::decode::<PlaylistItemResponse>(&body)
}

pub fn fetch_video(id: &str) -> json::DecodeResult<Video> {
    let params = format!("key={}&part=snippet&id={}", *API_KEY, id);
    let url    = format!("{}/{}?{}", BASE_URL, "videos", params);
    let client = Client::new();
    let mut res = client.get(&url)
                        .header(Connection::close())
                        .send().unwrap();
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();
    let res = try!(json::decode::<VideoResponse>(&body));
    if res.items.len() > 0 {
        return Ok(res.items[0].clone());
    }
    Err(json::DecoderError::ApplicationError("track not found".to_string()))
}
<|endoftext|>


<commit_before>//! Function interfaces for VST 2.4 API.

#![doc(hidden)]

use std::{mem, slice};

use std::os::raw::{c_char, c_void};

use buffer::AudioBuffer;
use api::consts::*;
use api::{self, AEffect, ChannelProperties};
use editor::{Rect, KeyCode, Key, KnobMode};
use host::Host;

/// Deprecated process function.
pub fn process_deprecated(
    _effect: *mut AEffect,
    _raw_inputs: *const *const f32,
    _raw_outputs: *mut *mut f32,
    _samples: i32,
) {
}

/// VST2.4 replacing function.
pub fn process_replacing(
    effect: *mut AEffect,
    raw_inputs: *const *const f32,
    raw_outputs: *mut *mut f32,
    samples: i32,
) {
    // Handle to the vst
    let plugin = unsafe { (*effect).get_plugin() };
    let cache = unsafe { (*effect).get_cache() };
    let info = &mut cache.info;
    let (input_count, output_count) = (info.inputs as usize, info.outputs as usize);
    let mut buffer = unsafe {
        AudioBuffer::from_raw(
            input_count,
            output_count,
            raw_inputs,
            raw_outputs,
            samples as usize,
        )
    };
    plugin.process(&mut buffer);
}

/// VST2.4 replacing function with `f64` values.
pub fn process_replacing_f64(
    effect: *mut AEffect,
    raw_inputs: *const *const f64,
    raw_outputs: *mut *mut f64,
    samples: i32,
) {
    let plugin = unsafe { (*effect).get_plugin() };
    let cache = unsafe { (*effect).get_cache() };
    let info = &mut cache.info;
    let (input_count, output_count) = (info.inputs as usize, info.outputs as usize);
    let mut buffer = unsafe {
        AudioBuffer::from_raw(
            input_count,
            output_count,
            raw_inputs,
            raw_outputs,
            samples as usize,
        )
    };
    plugin.process_f64(&mut buffer);
}

/// VST2.4 set parameter function.
pub fn set_parameter(effect: *mut AEffect, index: i32, value: f32) {
    unsafe { (*effect).get_plugin() }.set_parameter(index, value);
}

/// VST2.4 get parameter function.
pub fn get_parameter(effect: *mut AEffect, index: i32) -> f32 {
    unsafe { (*effect).get_plugin() }.get_parameter(index)
}

/// Copy a string into a destination buffer.
///
/// String will be cut at `max` characters.
fn copy_string(dst: *mut c_void, src: &str, max: usize) -> isize {
    unsafe {
        use std::cmp::min;
        use libc::{c_void, memset, memcpy};

        let dst = dst as *mut c_void;
        memset(dst, 0, max);
        memcpy(dst, src.as_ptr() as *const c_void, min(max, src.len()));
    }

    1 // Success
}

/// VST2.4 dispatch function. This function handles dispatching all opcodes to the vst plugin.
pub fn dispatch(
    effect: *mut AEffect,
    opcode: i32,
    index: i32,
    value: isize,
    ptr: *mut c_void,
    opt: f32,
) -> isize {
    use plugin::{CanDo, OpCode};

    // Convert passed in opcode to enum
    let opcode = OpCode::from(opcode);
    // Plugin handle
    let plugin = unsafe { (*effect).get_plugin() };

    match opcode {
        OpCode::Initialize => plugin.init(),
        OpCode::Shutdown => unsafe {
            (*effect).drop_plugin();
            drop(mem::transmute::<*mut AEffect, Box<AEffect>>(effect));
        },

        OpCode::ChangePreset => plugin.change_preset(value as i32),
        OpCode::GetCurrentPresetNum => return plugin.get_preset_num() as isize,
        OpCode::SetCurrentPresetName => plugin.set_preset_name(read_string(ptr)),
        OpCode::GetCurrentPresetName => {
            let num = plugin.get_preset_num();
            return copy_string(ptr, &plugin.get_preset_name(num), MAX_PRESET_NAME_LEN);
        }

        OpCode::GetParameterLabel => {
            return copy_string(ptr, &plugin.get_parameter_label(index), MAX_PARAM_STR_LEN)
        }
        OpCode::GetParameterDisplay => {
            return copy_string(ptr, &plugin.get_parameter_text(index), MAX_PARAM_STR_LEN)
        }
        OpCode::GetParameterName => {
            return copy_string(ptr, &plugin.get_parameter_name(index), MAX_PARAM_STR_LEN)
        }

        OpCode::SetSampleRate => plugin.set_sample_rate(opt),
        OpCode::SetBlockSize => plugin.set_block_size(value as i64),
        OpCode::StateChanged => {
            if value == 1 {
                plugin.resume();
            } else {
                plugin.suspend();
            }
        }

        OpCode::EditorGetRect => {
            if let Some(editor) = plugin.get_editor() {
                let size = editor.size();
                let pos = editor.position();

                unsafe {
                    // Given a Rect** structure
                    // TODO: Investigate whether we are given a valid Rect** pointer already
                    *(ptr as *mut *mut c_void) = Box::into_raw(Box::new(Rect {
                        left: pos.0 as i16, // x coord of position
                        top: pos.1 as i16, // y coord of position
                        right: (pos.0 + size.0) as i16, // x coord of pos + x coord of size
                        bottom: (pos.1 + size.1) as i16, // y coord of pos + y coord of size
                    })) as *mut _; // TODO: free memory
                }
            }
        }
        OpCode::EditorOpen => {
            if let Some(editor) = plugin.get_editor() {
                editor.open(ptr); //ptr is raw window handle, eg HWND* on windows
            }
        }
        OpCode::EditorClose => {
            if let Some(editor) = plugin.get_editor() {
                editor.close();
            }
        }

        OpCode::EditorIdle => {
            if let Some(editor) = plugin.get_editor() {
                editor.idle();
            }
        }

        OpCode::GetData => {
            let mut chunks = if index == 0 {
                plugin.get_bank_data()
            } else {
                plugin.get_preset_data()
            };

            chunks.shrink_to_fit();
            let len = chunks.len() as isize; // eventually we should be using ffi::size_t

            unsafe {
                *(ptr as *mut *mut c_void) = chunks.as_ptr() as *mut c_void;
            }

            mem::forget(chunks);
            return len;
        }
        OpCode::SetData => {
            let chunks = unsafe { slice::from_raw_parts(ptr as *mut u8, value as usize) };

            if index == 0 {
                plugin.load_bank_data(chunks);
            } else {
                plugin.load_preset_data(chunks);
            }
        }

        OpCode::ProcessEvents => {
            plugin.process_events(unsafe { &*(ptr as *const api::Events) });
        }
        OpCode::CanBeAutomated => return plugin.can_be_automated(index) as isize,
        OpCode::StringToParameter => {
            return plugin.string_to_parameter(index, read_string(ptr)) as isize
        }

        OpCode::GetPresetName => {
            return copy_string(ptr, &plugin.get_preset_name(index), MAX_PRESET_NAME_LEN)
        }

        OpCode::GetInputInfo => {
            if index >= 0 && index < plugin.get_info().inputs {
                unsafe {
                    let ptr = mem::transmute::<_, *mut ChannelProperties>(ptr);
                    *ptr = plugin.get_input_info(index).into();
                }
            }
        }
        OpCode::GetOutputInfo => {
            if index >= 0 && index < plugin.get_info().outputs {
                unsafe {
                    let ptr = mem::transmute::<_, *mut ChannelProperties>(ptr);
                    *ptr = plugin.get_output_info(index).into();
                }
            }
        }
        OpCode::GetCategory => {
            return plugin.get_info().category.into();
        }

        OpCode::GetVendorName => {
            return copy_string(ptr, &plugin.get_info().vendor, MAX_VENDOR_STR_LEN)
        }
        OpCode::GetProductName => {
            return copy_string(ptr, &plugin.get_info().name, MAX_PRODUCT_STR_LEN)
        }
        OpCode::GetVendorVersion => return plugin.get_info().version as isize,
        OpCode::VendorSpecific => return plugin.vendor_specific(index, value, ptr, opt),
        OpCode::CanDo => {
            let can_do: CanDo = match read_string(ptr).parse() {
                Ok(c) => c,
                Err(e) => {
                    warn!("{}", e);
                    return 0;
                }
            };
            return plugin.can_do(can_do).into();
        }
        OpCode::GetTailSize => {
            if plugin.get_tail_size() == 0 {
                return 1;
            } else {
                return plugin.get_tail_size();
            }
        }

        //OpCode::GetParamInfo => { /*TODO*/ }
        OpCode::GetApiVersion => return 2400,

        OpCode::EditorKeyDown => {
            if let Some(editor) = plugin.get_editor() {
                editor.key_down(KeyCode {
                    character: index as u8 as char,
                    key: Key::from(value),
                    modifier: unsafe { mem::transmute::<f32, i32>(opt) } as u8,
                });
            }
        }
        OpCode::EditorKeyUp => {
            if let Some(editor) = plugin.get_editor() {
                editor.key_up(KeyCode {
                    character: index as u8 as char,
                    key: Key::from(value),
                    modifier: unsafe { mem::transmute::<f32, i32>(opt) } as u8,
                });
            }
        }
        OpCode::EditorSetKnobMode => {
            if let Some(editor) = plugin.get_editor() {
                editor.set_knob_mode(KnobMode::from(value));
            }
        }

        _ => {
            warn!("Unimplemented opcode ({:?})", opcode);
            trace!(
                "Arguments; index: {}, value: {}, ptr: {:?}, opt: {}",
                index,
                value,
                ptr,
                opt
            );
        }
    }

    0
}

pub fn host_dispatch(
    host: &mut Host,
    effect: *mut AEffect,
    opcode: i32,
    index: i32,
    value: isize,
    ptr: *mut c_void,
    opt: f32,
) -> isize {
    use host::OpCode;

    match OpCode::from(opcode) {
        OpCode::Version => return 2400,
        OpCode::Automate => host.automate(index, opt),

        OpCode::Idle => host.idle(),

        // ...
        OpCode::CanDo => {
            info!("Plugin is asking if host can: {}.", read_string(ptr));
        }

        OpCode::GetVendorVersion => return host.get_info().0,
        OpCode::GetVendorString => return copy_string(ptr, &host.get_info().1, MAX_VENDOR_STR_LEN),
        OpCode::GetProductString => {
            return copy_string(ptr, &host.get_info().2, MAX_PRODUCT_STR_LEN)
        }
        OpCode::ProcessEvents => {
            host.process_events(unsafe { &*(ptr as *const api::Events) });
        }

        unimplemented => {
            trace!("VST: Got unimplemented host opcode ({:?})", unimplemented);
            trace!(
                "Arguments; effect: {:?}, index: {}, value: {}, ptr: {:?}, opt: {}",
                effect,
                index,
                value,
                ptr,
                opt
            );
        }
    }
    0
}

// Read a string from the `ptr` buffer
fn read_string(ptr: *mut c_void) -> String {
    use std::ffi::CStr;

    String::from_utf8_lossy(unsafe { CStr::from_ptr(ptr as *mut c_char).to_bytes() }).into_owned()
}
<commit_msg>Fixing comments to be consistent<commit_after>//! Function interfaces for VST 2.4 API.

#![doc(hidden)]

use std::{mem, slice};

use std::os::raw::{c_char, c_void};

use buffer::AudioBuffer;
use api::consts::*;
use api::{self, AEffect, ChannelProperties};
use editor::{Rect, KeyCode, Key, KnobMode};
use host::Host;

/// Deprecated process function.
pub fn process_deprecated(
    _effect: *mut AEffect,
    _raw_inputs: *const *const f32,
    _raw_outputs: *mut *mut f32,
    _samples: i32,
) {
}

/// VST2.4 replacing function.
pub fn process_replacing(
    effect: *mut AEffect,
    raw_inputs: *const *const f32,
    raw_outputs: *mut *mut f32,
    samples: i32,
) {
    // Handle to the VST
    let plugin = unsafe { (*effect).get_plugin() };
    let cache = unsafe { (*effect).get_cache() };
    let info = &mut cache.info;
    let (input_count, output_count) = (info.inputs as usize, info.outputs as usize);
    let mut buffer = unsafe {
        AudioBuffer::from_raw(
            input_count,
            output_count,
            raw_inputs,
            raw_outputs,
            samples as usize,
        )
    };
    plugin.process(&mut buffer);
}

/// VST2.4 replacing function with `f64` values.
pub fn process_replacing_f64(
    effect: *mut AEffect,
    raw_inputs: *const *const f64,
    raw_outputs: *mut *mut f64,
    samples: i32,
) {
    let plugin = unsafe { (*effect).get_plugin() };
    let cache = unsafe { (*effect).get_cache() };
    let info = &mut cache.info;
    let (input_count, output_count) = (info.inputs as usize, info.outputs as usize);
    let mut buffer = unsafe {
        AudioBuffer::from_raw(
            input_count,
            output_count,
            raw_inputs,
            raw_outputs,
            samples as usize,
        )
    };
    plugin.process_f64(&mut buffer);
}

/// VST2.4 set parameter function.
pub fn set_parameter(effect: *mut AEffect, index: i32, value: f32) {
    unsafe { (*effect).get_plugin() }.set_parameter(index, value);
}

/// VST2.4 get parameter function.
pub fn get_parameter(effect: *mut AEffect, index: i32) -> f32 {
    unsafe { (*effect).get_plugin() }.get_parameter(index)
}

/// Copy a string into a destination buffer.
///
/// String will be cut at `max` characters.
fn copy_string(dst: *mut c_void, src: &str, max: usize) -> isize {
    unsafe {
        use std::cmp::min;
        use libc::{c_void, memset, memcpy};

        let dst = dst as *mut c_void;
        memset(dst, 0, max);
        memcpy(dst, src.as_ptr() as *const c_void, min(max, src.len()));
    }

    1 // Success
}

/// VST2.4 dispatch function. This function handles dispatching all opcodes to the VST plugin.
pub fn dispatch(
    effect: *mut AEffect,
    opcode: i32,
    index: i32,
    value: isize,
    ptr: *mut c_void,
    opt: f32,
) -> isize {
    use plugin::{CanDo, OpCode};

    // Convert passed in opcode to enum
    let opcode = OpCode::from(opcode);
    // Plugin handle
    let plugin = unsafe { (*effect).get_plugin() };

    match opcode {
        OpCode::Initialize => plugin.init(),
        OpCode::Shutdown => unsafe {
            (*effect).drop_plugin();
            drop(mem::transmute::<*mut AEffect, Box<AEffect>>(effect));
        },

        OpCode::ChangePreset => plugin.change_preset(value as i32),
        OpCode::GetCurrentPresetNum => return plugin.get_preset_num() as isize,
        OpCode::SetCurrentPresetName => plugin.set_preset_name(read_string(ptr)),
        OpCode::GetCurrentPresetName => {
            let num = plugin.get_preset_num();
            return copy_string(ptr, &plugin.get_preset_name(num), MAX_PRESET_NAME_LEN);
        }

        OpCode::GetParameterLabel => {
            return copy_string(ptr, &plugin.get_parameter_label(index), MAX_PARAM_STR_LEN)
        }
        OpCode::GetParameterDisplay => {
            return copy_string(ptr, &plugin.get_parameter_text(index), MAX_PARAM_STR_LEN)
        }
        OpCode::GetParameterName => {
            return copy_string(ptr, &plugin.get_parameter_name(index), MAX_PARAM_STR_LEN)
        }

        OpCode::SetSampleRate => plugin.set_sample_rate(opt),
        OpCode::SetBlockSize => plugin.set_block_size(value as i64),
        OpCode::StateChanged => {
            if value == 1 {
                plugin.resume();
            } else {
                plugin.suspend();
            }
        }

        OpCode::EditorGetRect => {
            if let Some(editor) = plugin.get_editor() {
                let size = editor.size();
                let pos = editor.position();

                unsafe {
                    // Given a Rect** structure
                    // TODO: Investigate whether we are given a valid Rect** pointer already
                    *(ptr as *mut *mut c_void) = Box::into_raw(Box::new(Rect {
                        left: pos.0 as i16, // x coord of position
                        top: pos.1 as i16, // y coord of position
                        right: (pos.0 + size.0) as i16, // x coord of pos + x coord of size
                        bottom: (pos.1 + size.1) as i16, // y coord of pos + y coord of size
                    })) as *mut _; // TODO: free memory
                }
            }
        }
        OpCode::EditorOpen => {
            if let Some(editor) = plugin.get_editor() {
                editor.open(ptr); //ptr is raw window handle, eg HWND* on windows
            }
        }
        OpCode::EditorClose => {
            if let Some(editor) = plugin.get_editor() {
                editor.close();
            }
        }

        OpCode::EditorIdle => {
            if let Some(editor) = plugin.get_editor() {
                editor.idle();
            }
        }

        OpCode::GetData => {
            let mut chunks = if index == 0 {
                plugin.get_bank_data()
            } else {
                plugin.get_preset_data()
            };

            chunks.shrink_to_fit();
            let len = chunks.len() as isize; // eventually we should be using ffi::size_t

            unsafe {
                *(ptr as *mut *mut c_void) = chunks.as_ptr() as *mut c_void;
            }

            mem::forget(chunks);
            return len;
        }
        OpCode::SetData => {
            let chunks = unsafe { slice::from_raw_parts(ptr as *mut u8, value as usize) };

            if index == 0 {
                plugin.load_bank_data(chunks);
            } else {
                plugin.load_preset_data(chunks);
            }
        }

        OpCode::ProcessEvents => {
            plugin.process_events(unsafe { &*(ptr as *const api::Events) });
        }
        OpCode::CanBeAutomated => return plugin.can_be_automated(index) as isize,
        OpCode::StringToParameter => {
            return plugin.string_to_parameter(index, read_string(ptr)) as isize
        }

        OpCode::GetPresetName => {
            return copy_string(ptr, &plugin.get_preset_name(index), MAX_PRESET_NAME_LEN)
        }

        OpCode::GetInputInfo => {
            if index >= 0 && index < plugin.get_info().inputs {
                unsafe {
                    let ptr = mem::transmute::<_, *mut ChannelProperties>(ptr);
                    *ptr = plugin.get_input_info(index).into();
                }
            }
        }
        OpCode::GetOutputInfo => {
            if index >= 0 && index < plugin.get_info().outputs {
                unsafe {
                    let ptr = mem::transmute::<_, *mut ChannelProperties>(ptr);
                    *ptr = plugin.get_output_info(index).into();
                }
            }
        }
        OpCode::GetCategory => {
            return plugin.get_info().category.into();
        }

        OpCode::GetVendorName => {
            return copy_string(ptr, &plugin.get_info().vendor, MAX_VENDOR_STR_LEN)
        }
        OpCode::GetProductName => {
            return copy_string(ptr, &plugin.get_info().name, MAX_PRODUCT_STR_LEN)
        }
        OpCode::GetVendorVersion => return plugin.get_info().version as isize,
        OpCode::VendorSpecific => return plugin.vendor_specific(index, value, ptr, opt),
        OpCode::CanDo => {
            let can_do: CanDo = match read_string(ptr).parse() {
                Ok(c) => c,
                Err(e) => {
                    warn!("{}", e);
                    return 0;
                }
            };
            return plugin.can_do(can_do).into();
        }
        OpCode::GetTailSize => {
            if plugin.get_tail_size() == 0 {
                return 1;
            } else {
                return plugin.get_tail_size();
            }
        }

        //OpCode::GetParamInfo => { /*TODO*/ }
        OpCode::GetApiVersion => return 2400,

        OpCode::EditorKeyDown => {
            if let Some(editor) = plugin.get_editor() {
                editor.key_down(KeyCode {
                    character: index as u8 as char,
                    key: Key::from(value),
                    modifier: unsafe { mem::transmute::<f32, i32>(opt) } as u8,
                });
            }
        }
        OpCode::EditorKeyUp => {
            if let Some(editor) = plugin.get_editor() {
                editor.key_up(KeyCode {
                    character: index as u8 as char,
                    key: Key::from(value),
                    modifier: unsafe { mem::transmute::<f32, i32>(opt) } as u8,
                });
            }
        }
        OpCode::EditorSetKnobMode => {
            if let Some(editor) = plugin.get_editor() {
                editor.set_knob_mode(KnobMode::from(value));
            }
        }

        _ => {
            warn!("Unimplemented opcode ({:?})", opcode);
            trace!(
                "Arguments; index: {}, value: {}, ptr: {:?}, opt: {}",
                index,
                value,
                ptr,
                opt
            );
        }
    }

    0
}

pub fn host_dispatch(
    host: &mut Host,
    effect: *mut AEffect,
    opcode: i32,
    index: i32,
    value: isize,
    ptr: *mut c_void,
    opt: f32,
) -> isize {
    use host::OpCode;

    match OpCode::from(opcode) {
        OpCode::Version => return 2400,
        OpCode::Automate => host.automate(index, opt),

        OpCode::Idle => host.idle(),

        // ...
        OpCode::CanDo => {
            info!("Plugin is asking if host can: {}.", read_string(ptr));
        }

        OpCode::GetVendorVersion => return host.get_info().0,
        OpCode::GetVendorString => return copy_string(ptr, &host.get_info().1, MAX_VENDOR_STR_LEN),
        OpCode::GetProductString => {
            return copy_string(ptr, &host.get_info().2, MAX_PRODUCT_STR_LEN)
        }
        OpCode::ProcessEvents => {
            host.process_events(unsafe { &*(ptr as *const api::Events) });
        }

        unimplemented => {
            trace!("VST: Got unimplemented host opcode ({:?})", unimplemented);
            trace!(
                "Arguments; effect: {:?}, index: {}, value: {}, ptr: {:?}, opt: {}",
                effect,
                index,
                value,
                ptr,
                opt
            );
        }
    }
    0
}

// Read a string from the `ptr` buffer
fn read_string(ptr: *mut c_void) -> String {
    use std::ffi::CStr;

    String::from_utf8_lossy(unsafe { CStr::from_ptr(ptr as *mut c_char).to_bytes() }).into_owned()
}
<|endoftext|>


<commit_before>use js::function::{NativeFunction, NativeFunc};
use js::value::{Value, ResultValue, VFunction, VUndefined, VObject, to_value, from_value};
use collections::treemap::TreeMap;
use std::gc::Gc;
use std::cell::RefCell;
use std::iter::FromIterator;
use time::{now, strftime};
/// Print a javascript value to stdout
pub fn log(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let args : Vec<~str> = FromIterator::from_iter(args.iter().map(|x|from_value::<~str>(*x).unwrap()));
	println!("{}: {}", strftime("%X", &now()), args.connect(" "));
	return Ok(Gc::new(VUndefined));
}
/// Create a new 'console' object
pub fn _create() -> Value {
	let mut console = TreeMap::new();
	console.insert(~"log", to_value(log));
	to_value(console)
}<commit_msg>Add console.error and console.exception<commit_after>use js::function::{NativeFunction, NativeFunc};
use js::value::{Value, ResultValue, VFunction, VUndefined, VObject, to_value, from_value};
use collections::treemap::TreeMap;
use std::gc::Gc;
use std::cell::RefCell;
use std::iter::FromIterator;
use std::io::stdio::stderr;
use std::io::Writer;
use time::{now, strftime};
/// Print a javascript value to stdout
pub fn log(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let args : Vec<~str> = FromIterator::from_iter(args.iter().map(|x|from_value::<~str>(*x).unwrap()));
	println!("{}: {}", strftime("%X", &now()), args.connect(" "));
	return Ok(Gc::new(VUndefined));
}
/// Print a javascript value to stderr
pub fn error(_:Value, _:Value, args:Vec<Value>) -> ResultValue {
	let args : Vec<~str> = FromIterator::from_iter(args.iter().map(|x|from_value::<~str>(*x).unwrap()));
	match writeln!(&mut stderr().unwrap(), "{}: {}", strftime("%X", &now()), args.connect(" ")) {
		Ok(_) => Ok(Gc::new(VUndefined)),
		Err(io_error) => Err(to_value(io_error.to_str()))
	}
}
/// Create a new 'console' object
pub fn _create() -> Value {
	let mut console = TreeMap::new();
	console.insert(~"log", to_value(log));
	console.insert(~"error", to_value(error));
	console.insert(~"exception", to_value(error));
	to_value(console)
}<|endoftext|>


<commit_before>use crate::Endianness;
use crate::VInt;
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::fmt;
use std::io;
use std::io::Read;
use std::io::Write;

/// Trait for a simple binary serialization.
pub trait BinarySerializable: fmt::Debug + Sized {
    /// Serialize
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()>;
    /// Deserialize
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self>;
}

pub trait DeserializeFrom<T: BinarySerializable> {
    fn deserialize(&mut self) -> io::Result<T>;
}

/// Implement deserialize from &[u8] for all types which implement BinarySerializable.
///
/// TryFrom would actually be preferrable, but not possible because of the orphan
/// rules (not completely sure if this could be resolved)
impl<T: BinarySerializable> DeserializeFrom<T> for &[u8] {
    fn deserialize(&mut self) -> io::Result<T> {
        T::deserialize(self)
    }
}

/// `FixedSize` marks a `BinarySerializable` as
/// always serializing to the same size.
pub trait FixedSize: BinarySerializable {
    const SIZE_IN_BYTES: usize;
}

impl BinarySerializable for () {
    fn serialize<W: Write>(&self, _: &mut W) -> io::Result<()> {
        Ok(())
    }
    fn deserialize<R: Read>(_: &mut R) -> io::Result<Self> {
        Ok(())
    }
}

impl FixedSize for () {
    const SIZE_IN_BYTES: usize = 0;
}

impl<T: BinarySerializable> BinarySerializable for Vec<T> {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        VInt(self.len() as u64).serialize(writer)?;
        for it in self {
            it.serialize(writer)?;
        }
        Ok(())
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Vec<T>> {
        let num_items = VInt::deserialize(reader)?.val();
        let mut items: Vec<T> = Vec::with_capacity(num_items as usize);
        for _ in 0..num_items {
            let item = T::deserialize(reader)?;
            items.push(item);
        }
        Ok(items)
    }
}

impl<Left: BinarySerializable, Right: BinarySerializable> BinarySerializable for (Left, Right) {
    fn serialize<W: Write>(&self, write: &mut W) -> io::Result<()> {
        self.0.serialize(write)?;
        self.1.serialize(write)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        Ok((Left::deserialize(reader)?, Right::deserialize(reader)?))
    }
}
impl<Left: BinarySerializable + FixedSize, Right: BinarySerializable + FixedSize> FixedSize
    for (Left, Right)
{
    const SIZE_IN_BYTES: usize = Left::SIZE_IN_BYTES + Right::SIZE_IN_BYTES;
}

impl BinarySerializable for u32 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u32::<Endianness>(*self)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<u32> {
        reader.read_u32::<Endianness>()
    }
}

impl FixedSize for u32 {
    const SIZE_IN_BYTES: usize = 4;
}

impl BinarySerializable for u64 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u64::<Endianness>(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        reader.read_u64::<Endianness>()
    }
}

impl FixedSize for u64 {
    const SIZE_IN_BYTES: usize = 8;
}

impl BinarySerializable for f32 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_f32::<Endianness>(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        reader.read_f32::<Endianness>()
    }
}

impl FixedSize for f32 {
    const SIZE_IN_BYTES: usize = 4;
}

impl BinarySerializable for i64 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_i64::<Endianness>(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        reader.read_i64::<Endianness>()
    }
}

impl FixedSize for i64 {
    const SIZE_IN_BYTES: usize = 8;
}

impl BinarySerializable for f64 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_f64::<Endianness>(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        reader.read_f64::<Endianness>()
    }
}

impl FixedSize for f64 {
    const SIZE_IN_BYTES: usize = 8;
}

impl BinarySerializable for u8 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u8(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<u8> {
        reader.read_u8()
    }
}

impl FixedSize for u8 {
    const SIZE_IN_BYTES: usize = 1;
}

impl BinarySerializable for String {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        let data: &[u8] = self.as_bytes();
        VInt(data.len() as u64).serialize(writer)?;
        writer.write_all(data)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<String> {
        let string_length = VInt::deserialize(reader)?.val() as usize;
        let mut result = String::with_capacity(string_length);
        reader
            .take(string_length as u64)
            .read_to_string(&mut result)?;
        Ok(result)
    }
}

#[cfg(test)]
pub mod test {

    use super::VInt;
    use super::*;
    use crate::serialize::BinarySerializable;
    pub fn fixed_size_test<O: BinarySerializable + FixedSize + Default>() {
        let mut buffer = Vec::new();
        O::default().serialize(&mut buffer).unwrap();
        assert_eq!(buffer.len(), O::SIZE_IN_BYTES);
    }

    fn serialize_test<T: BinarySerializable + Eq>(v: T) -> usize {
        let mut buffer: Vec<u8> = Vec::new();
        v.serialize(&mut buffer).unwrap();
        let num_bytes = buffer.len();
        let mut cursor = &buffer[..];
        let deser = T::deserialize(&mut cursor).unwrap();
        assert_eq!(deser, v);
        num_bytes
    }

    #[test]
    fn test_serialize_u8() {
        fixed_size_test::<u8>();
    }

    #[test]
    fn test_serialize_u32() {
        fixed_size_test::<u32>();
        assert_eq!(4, serialize_test(3u32));
        assert_eq!(4, serialize_test(5u32));
        assert_eq!(4, serialize_test(u32::max_value()));
    }

    #[test]
    fn test_serialize_i64() {
        fixed_size_test::<i64>();
    }

    #[test]
    fn test_serialize_f64() {
        fixed_size_test::<f64>();
    }

    #[test]
    fn test_serialize_u64() {
        fixed_size_test::<u64>();
    }

    #[test]
    fn test_serialize_string() {
        assert_eq!(serialize_test(String::from("")), 1);
        assert_eq!(serialize_test(String::from("ぽよぽよ")), 1 + 3 * 4);
        assert_eq!(serialize_test(String::from("富士さん見える。")), 1 + 3 * 8);
    }

    #[test]
    fn test_serialize_vec() {
        assert_eq!(serialize_test(Vec::<u8>::new()), 1);
        assert_eq!(serialize_test(vec![1u32, 3u32]), 1 + 4 * 2);
    }

    #[test]
    fn test_serialize_vint() {
        for i in 0..10_000 {
            serialize_test(VInt(i as u64));
        }
        assert_eq!(serialize_test(VInt(7u64)), 1);
        assert_eq!(serialize_test(VInt(127u64)), 1);
        assert_eq!(serialize_test(VInt(128u64)), 2);
        assert_eq!(serialize_test(VInt(129u64)), 2);
        assert_eq!(serialize_test(VInt(1234u64)), 2);
        assert_eq!(serialize_test(VInt(16_383u64)), 2);
        assert_eq!(serialize_test(VInt(16_384u64)), 3);
        assert_eq!(serialize_test(VInt(u64::max_value())), 10);
    }
}
<commit_msg>add serialize for bool<commit_after>use crate::Endianness;
use crate::VInt;
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::fmt;
use std::io;
use std::io::Read;
use std::io::Write;

/// Trait for a simple binary serialization.
pub trait BinarySerializable: fmt::Debug + Sized {
    /// Serialize
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()>;
    /// Deserialize
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self>;
}

pub trait DeserializeFrom<T: BinarySerializable> {
    fn deserialize(&mut self) -> io::Result<T>;
}

/// Implement deserialize from &[u8] for all types which implement BinarySerializable.
///
/// TryFrom would actually be preferrable, but not possible because of the orphan
/// rules (not completely sure if this could be resolved)
impl<T: BinarySerializable> DeserializeFrom<T> for &[u8] {
    fn deserialize(&mut self) -> io::Result<T> {
        T::deserialize(self)
    }
}

/// `FixedSize` marks a `BinarySerializable` as
/// always serializing to the same size.
pub trait FixedSize: BinarySerializable {
    const SIZE_IN_BYTES: usize;
}

impl BinarySerializable for () {
    fn serialize<W: Write>(&self, _: &mut W) -> io::Result<()> {
        Ok(())
    }
    fn deserialize<R: Read>(_: &mut R) -> io::Result<Self> {
        Ok(())
    }
}

impl FixedSize for () {
    const SIZE_IN_BYTES: usize = 0;
}

impl<T: BinarySerializable> BinarySerializable for Vec<T> {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        VInt(self.len() as u64).serialize(writer)?;
        for it in self {
            it.serialize(writer)?;
        }
        Ok(())
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Vec<T>> {
        let num_items = VInt::deserialize(reader)?.val();
        let mut items: Vec<T> = Vec::with_capacity(num_items as usize);
        for _ in 0..num_items {
            let item = T::deserialize(reader)?;
            items.push(item);
        }
        Ok(items)
    }
}

impl<Left: BinarySerializable, Right: BinarySerializable> BinarySerializable for (Left, Right) {
    fn serialize<W: Write>(&self, write: &mut W) -> io::Result<()> {
        self.0.serialize(write)?;
        self.1.serialize(write)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        Ok((Left::deserialize(reader)?, Right::deserialize(reader)?))
    }
}
impl<Left: BinarySerializable + FixedSize, Right: BinarySerializable + FixedSize> FixedSize
    for (Left, Right)
{
    const SIZE_IN_BYTES: usize = Left::SIZE_IN_BYTES + Right::SIZE_IN_BYTES;
}

impl BinarySerializable for u32 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u32::<Endianness>(*self)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<u32> {
        reader.read_u32::<Endianness>()
    }
}

impl FixedSize for u32 {
    const SIZE_IN_BYTES: usize = 4;
}

impl BinarySerializable for u64 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u64::<Endianness>(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        reader.read_u64::<Endianness>()
    }
}

impl FixedSize for u64 {
    const SIZE_IN_BYTES: usize = 8;
}

impl BinarySerializable for f32 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_f32::<Endianness>(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        reader.read_f32::<Endianness>()
    }
}

impl FixedSize for f32 {
    const SIZE_IN_BYTES: usize = 4;
}

impl BinarySerializable for i64 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_i64::<Endianness>(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        reader.read_i64::<Endianness>()
    }
}

impl FixedSize for i64 {
    const SIZE_IN_BYTES: usize = 8;
}

impl BinarySerializable for f64 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_f64::<Endianness>(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<Self> {
        reader.read_f64::<Endianness>()
    }
}

impl FixedSize for f64 {
    const SIZE_IN_BYTES: usize = 8;
}

impl BinarySerializable for u8 {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        writer.write_u8(*self)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<u8> {
        reader.read_u8()
    }
}

impl FixedSize for u8 {
    const SIZE_IN_BYTES: usize = 1;
}

impl BinarySerializable for bool {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        let val = if *self { 1 } else { 0 };
        writer.write_u8(val)
    }
    fn deserialize<R: Read>(reader: &mut R) -> io::Result<bool> {
        let val = reader.read_u8()?;
        match val {
            0 => Ok(false),
            1 => Ok(true),
            _ => Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "invalid bool value on deserialization, data corrupted",
            )),
        }
    }
}

impl FixedSize for bool {
    const SIZE_IN_BYTES: usize = 1;
}

impl BinarySerializable for String {
    fn serialize<W: Write>(&self, writer: &mut W) -> io::Result<()> {
        let data: &[u8] = self.as_bytes();
        VInt(data.len() as u64).serialize(writer)?;
        writer.write_all(data)
    }

    fn deserialize<R: Read>(reader: &mut R) -> io::Result<String> {
        let string_length = VInt::deserialize(reader)?.val() as usize;
        let mut result = String::with_capacity(string_length);
        reader
            .take(string_length as u64)
            .read_to_string(&mut result)?;
        Ok(result)
    }
}

#[cfg(test)]
pub mod test {

    use super::VInt;
    use super::*;
    use crate::serialize::BinarySerializable;
    pub fn fixed_size_test<O: BinarySerializable + FixedSize + Default>() {
        let mut buffer = Vec::new();
        O::default().serialize(&mut buffer).unwrap();
        assert_eq!(buffer.len(), O::SIZE_IN_BYTES);
    }

    fn serialize_test<T: BinarySerializable + Eq>(v: T) -> usize {
        let mut buffer: Vec<u8> = Vec::new();
        v.serialize(&mut buffer).unwrap();
        let num_bytes = buffer.len();
        let mut cursor = &buffer[..];
        let deser = T::deserialize(&mut cursor).unwrap();
        assert_eq!(deser, v);
        num_bytes
    }

    #[test]
    fn test_serialize_u8() {
        fixed_size_test::<u8>();
    }

    #[test]
    fn test_serialize_u32() {
        fixed_size_test::<u32>();
        assert_eq!(4, serialize_test(3u32));
        assert_eq!(4, serialize_test(5u32));
        assert_eq!(4, serialize_test(u32::max_value()));
    }

    #[test]
    fn test_serialize_i64() {
        fixed_size_test::<i64>();
    }

    #[test]
    fn test_serialize_f64() {
        fixed_size_test::<f64>();
    }

    #[test]
    fn test_serialize_u64() {
        fixed_size_test::<u64>();
    }

    #[test]
    fn test_serialize_string() {
        assert_eq!(serialize_test(String::from("")), 1);
        assert_eq!(serialize_test(String::from("ぽよぽよ")), 1 + 3 * 4);
        assert_eq!(serialize_test(String::from("富士さん見える。")), 1 + 3 * 8);
    }

    #[test]
    fn test_serialize_vec() {
        assert_eq!(serialize_test(Vec::<u8>::new()), 1);
        assert_eq!(serialize_test(vec![1u32, 3u32]), 1 + 4 * 2);
    }

    #[test]
    fn test_serialize_vint() {
        for i in 0..10_000 {
            serialize_test(VInt(i as u64));
        }
        assert_eq!(serialize_test(VInt(7u64)), 1);
        assert_eq!(serialize_test(VInt(127u64)), 1);
        assert_eq!(serialize_test(VInt(128u64)), 2);
        assert_eq!(serialize_test(VInt(129u64)), 2);
        assert_eq!(serialize_test(VInt(1234u64)), 2);
        assert_eq!(serialize_test(VInt(16_383u64)), 2);
        assert_eq!(serialize_test(VInt(16_384u64)), 3);
        assert_eq!(serialize_test(VInt(u64::max_value())), 10);
    }
}
<|endoftext|>


<commit_before>#![feature(try_trait)]

use serde::Deserialize;

#[derive(Deserialize)]
struct Versions {
    stable: Option<String>,
    bottle: bool,
}

#[derive(Deserialize)]
struct Bottle {
    stable: Option<BottleStable>,
}

#[derive(Deserialize)]
struct BottleStable {
    rebuild: u64,
    files: serde_json::Value,
}

#[derive(Deserialize)]
struct Formula {
    name: String,
    versions: Versions,
    bottle: Bottle,
    revision: u64,
}

#[derive(Deserialize)]
struct Formulae(Vec<Formula>);

#[derive(Deserialize)]
struct BottleInfo {
    url: String,
    sha256: String,
}

fn d(f: &Formula) -> Option<()> {
    let revision = f.revision;
    let revision = if revision == 0 { "".to_string() } else { format!("_{}", revision) };
    if f.versions.bottle {
        let name = &f.name;
        let version = f.versions.stable.as_ref()?;
        let bs = f.bottle.stable.as_ref()?;
        let rebuild = bs.rebuild;
        let rebuild = if rebuild == 0 { "".to_string() } else { format!(".{}", rebuild) };
        for (platform, v) in bs.files.as_object()?.iter() {
            if let Ok(bi) = serde_json::from_value::<BottleInfo>(v.clone()) {
                println!(
                    "{} {} {}-{}{}.{}.bottle{}.tar.gz",
                    bi.sha256, bi.url, name, version, revision, platform, rebuild
                );
            }
        }
    }
    Some(())
}

fn main() {
    let f: Formulae = serde_json::from_reader(std::io::stdin()).unwrap();
    for f in f.0 {
        d(&f);
    }
}
<commit_msg>homebrew-bottles: refactor<commit_after>#![feature(try_trait)]

use serde::Deserialize;

#[derive(Deserialize)]
struct Versions {
    stable: Option<String>,
    bottle: bool,
}

#[derive(Deserialize)]
struct Bottle {
    stable: Option<BottleStable>,
}

#[derive(Deserialize)]
struct BottleStable {
    rebuild: u64,
    files: serde_json::Value,
}

#[derive(Deserialize)]
struct Formula {
    name: String,
    versions: Versions,
    bottle: Bottle,
    revision: u64,
}

#[derive(Deserialize)]
struct Formulae(Vec<Formula>);

#[derive(Deserialize)]
struct BottleInfo {
    url: String,
    sha256: String,
}

fn d(f: &Formula) -> Option<()> {
    if f.versions.bottle {
        let bs = f.bottle.stable.as_ref()?;
        for (platform, v) in bs.files.as_object()?.iter() {
            if let Ok(bi) = serde_json::from_value::<BottleInfo>(v.clone()) {
                println!(
                    "{sha256} {url} {name}-{version}{revision}.{platform}.bottle{rebuild}.tar.gz",
                    sha256 = bi.sha256,
                    url = bi.url,
                    name = f.name,
                    version = f.versions.stable.as_ref()?,
                    revision = if f.revision == 0 { "".to_owned() } else { format!("_{}", f.revision) },
                    platform = platform,
                    rebuild = if bs.rebuild == 0 { "".to_owned() } else { format!(".{}", bs.rebuild) },
                );
            }
        }
    }
    Some(())
}

fn main() {
    let f: Formulae = serde_json::from_reader(std::io::stdin()).unwrap();
    for f in f.0 {
        d(&f);
    }
}
<|endoftext|>


<commit_before>//! An example that displays RDTSC frequency.
extern crate raw_cpuid;
extern crate x86;

use std::time;
use x86::time::rdtscp;

const MHZ_TO_HZ: u64 = 1000000;
const KHZ_TO_HZ: u64 = 1000;

fn main() {
    let cpuid = raw_cpuid::CpuId::new();
    let has_tsc = cpuid
        .get_feature_info()
        .map_or(false, |finfo| finfo.has_tsc());

    let has_invariant_tsc = cpuid
        .get_extended_function_info()
        .map_or(false, |efinfo| efinfo.has_invariant_tsc());

    let tsc_frequency_hz = cpuid.get_tsc_info().map(|tinfo| {
        if tinfo.nominal_frequency() != 0 {
            Some(tinfo.tsc_frequency())
        } else if tinfo.numerator() != 0 && tinfo.denominator() != 0 {
            // Skylake and Kabylake don't report the crystal clock, approximate with base frequency:
            cpuid
                .get_processor_frequency_info()
                .map(|pinfo| pinfo.processor_base_frequency() as u64 * MHZ_TO_HZ)
                .map(|cpu_base_freq_hz| {
                    let crystal_hz =
                        cpu_base_freq_hz * tinfo.denominator() as u64 / tinfo.numerator() as u64;
                    crystal_hz * tinfo.numerator() as u64 / tinfo.denominator() as u64
                })
        } else {
            None
        }
    });

    if has_tsc {
        println!(
            "TSC Frequency is: {} ({})",
            match tsc_frequency_hz {
                Some(x) => format!("{} Hz", x.unwrap_or(0)),
                None => String::from("unknown"),
            },
            if has_invariant_tsc {
                "invariant"
            } else {
                "TSC frequency varies with speed-stepping"
            }
        );
    }

    cpuid.get_hypervisor_info().map(|hv| {
        hv.tsc_frequency().map(|tsc_khz| {
            let virtual_tsc_frequency_hz = tsc_khz as u64 * KHZ_TO_HZ;
            println!(
                "Hypervisor reports TSC Frequency at: {} Hz",
                virtual_tsc_frequency_hz
            );
        })
    });

    let one_second = time::Duration::from_secs(1);
    let now = time::Instant::now();
    let start = unsafe { rdtscp() };
    loop {
        if now.elapsed() >= one_second {
            break;
        }
    }
    let end = unsafe { rdtscp() };
    println!("Empirical measurement of TSC was: {} Hz", (end - start));
}
<commit_msg>Change reporting.<commit_after>//! An example that displays RDTSC frequency.
extern crate raw_cpuid;
extern crate x86;

use std::time;
use x86::time::rdtscp;

const MHZ_TO_HZ: u64 = 1000000;
const KHZ_TO_HZ: u64 = 1000;

fn main() {
    let cpuid = raw_cpuid::CpuId::new();
    let has_tsc = cpuid
        .get_feature_info()
        .map_or(false, |finfo| finfo.has_tsc());

    let has_invariant_tsc = cpuid
        .get_extended_function_info()
        .map_or(false, |efinfo| efinfo.has_invariant_tsc());

    let tsc_frequency_hz = cpuid.get_tsc_info().map(|tinfo| {
        if tinfo.nominal_frequency() != 0 {
            Some(tinfo.tsc_frequency())
        } else if tinfo.numerator() != 0 && tinfo.denominator() != 0 {
            // Skylake and Kabylake don't report the crystal clock, approximate with base frequency:
            cpuid
                .get_processor_frequency_info()
                .map(|pinfo| pinfo.processor_base_frequency() as u64 * MHZ_TO_HZ)
                .map(|cpu_base_freq_hz| {
                    let crystal_hz =
                        cpu_base_freq_hz * tinfo.denominator() as u64 / tinfo.numerator() as u64;
                    crystal_hz * tinfo.numerator() as u64 / tinfo.denominator() as u64
                })
        } else {
            None
        }
    });

    if has_tsc {
        println!(
            "TSC Frequency is: {} ({})",
            match tsc_frequency_hz {
                Some(x) => format!("{} Hz", x.unwrap_or(0)),
                None => String::from("unknown"),
            },
            if has_invariant_tsc {
                "invariant"
            } else {
                "TSC frequency varies with speed-stepping"
            }
        );
    }

    cpuid.get_hypervisor_info().map(|hv| {
        hv.tsc_frequency().map(|tsc_khz| {
            let virtual_tsc_frequency_hz = tsc_khz as u64 * KHZ_TO_HZ;
            println!(
                "Hypervisor reports TSC Frequency at: {} Hz",
                virtual_tsc_frequency_hz
            );
        })
    });

    let one_second = time::Duration::from_secs(1);
    let now = time::Instant::now();
    let start = unsafe { rdtscp() };
    loop {
        if now.elapsed() >= one_second {
            break;
        }
    }
    let end = unsafe { rdtscp() };
    println!(
        "Empirical measurement of TSC frequency was: {} Hz",
        (end - start)
    );
}
<|endoftext|>


<commit_before><commit_msg>Removed unused imports.<commit_after><|endoftext|>


<commit_before>use super::{AggregatePublicKey, Signature};
use bls_aggregates::{
    AggregatePublicKey as RawAggregatePublicKey, AggregateSignature as RawAggregateSignature,
};
use serde::ser::{Serialize, Serializer};
use ssz::{
    decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash,
};

/// A BLS aggregate signature.
///
/// This struct is a wrapper upon a base type and provides helper functions (e.g., SSZ
/// serialization).
#[derive(Debug, PartialEq, Clone, Default, Eq)]
pub struct AggregateSignature(RawAggregateSignature);

impl AggregateSignature {
    /// Instantiate a new AggregateSignature.
    pub fn new() -> Self {
        AggregateSignature(RawAggregateSignature::new())
    }

    /// Add (aggregate) a signature to the `AggregateSignature`.
    pub fn add(&mut self, signature: &Signature) {
        self.0.add(signature.as_raw())
    }

    /// Verify the `AggregateSignature` against an `AggregatePublicKey`.
    ///
    /// Only returns `true` if the set of keys in the `AggregatePublicKey` match the set of keys
    /// that signed the `AggregateSignature`.
    pub fn verify(
        &self,
        msg: &[u8],
        domain: u64,
        aggregate_public_key: &AggregatePublicKey,
    ) -> bool {
        self.0.verify(msg, domain, aggregate_public_key.as_raw())
    }

    /// Verify this AggregateSignature against multiple AggregatePublickeys with multiple Messages.
    ///
    ///  All PublicKeys related to a Message should be aggregated into one AggregatePublicKey.
    ///  Each AggregatePublicKey has a 1:1 ratio with a 32 byte Message.
    pub fn verify_multiple(
        &self,
        messages: &[&[u8]],
        domain: u64,
        aggregate_public_keys: &[&AggregatePublicKey],
    ) -> bool {
        let aggregate_public_keys: Vec<&RawAggregatePublicKey> = aggregate_public_keys
            .iter()
            .map(|pk| pk.as_raw())
            .collect();

        // Messages are concatenated into one long message.
        let mut msg: Vec<u8> = vec![];
        for message in messages {
            msg.extend_from_slice(message);
        }

        self.0
            .verify_multiple(&msg[..], domain, &aggregate_public_keys[..])
    }
}

impl Encodable for AggregateSignature {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_vec(&self.0.as_bytes());
    }
}

impl Decodable for AggregateSignature {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (sig_bytes, i) = decode_ssz_list(bytes, i)?;
        let raw_sig =
            RawAggregateSignature::from_bytes(&sig_bytes).map_err(|_| DecodeError::TooShort)?;
        Ok((AggregateSignature(raw_sig), i))
    }
}

impl Serialize for AggregateSignature {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_bytes(&ssz_encode(self))
    }
}

impl TreeHash for AggregateSignature {
    fn hash_tree_root_internal(&self) -> Vec<u8> {
        hash(&self.0.as_bytes())
    }
}

#[cfg(test)]
mod tests {
    use super::super::{Keypair, Signature};
    use super::*;
    use ssz::ssz_encode;

    #[test]
    pub fn test_ssz_round_trip() {
        let keypair = Keypair::random();

        let mut original = AggregateSignature::new();
        original.add(&Signature::new(&[42, 42], 0, &keypair.sk));

        let bytes = ssz_encode(&original);
        let (decoded, _) = AggregateSignature::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }
}
<commit_msg>Run rustfmt<commit_after>use super::{AggregatePublicKey, Signature};
use bls_aggregates::{
    AggregatePublicKey as RawAggregatePublicKey, AggregateSignature as RawAggregateSignature,
};
use serde::ser::{Serialize, Serializer};
use ssz::{
    decode_ssz_list, hash, ssz_encode, Decodable, DecodeError, Encodable, SszStream, TreeHash,
};

/// A BLS aggregate signature.
///
/// This struct is a wrapper upon a base type and provides helper functions (e.g., SSZ
/// serialization).
#[derive(Debug, PartialEq, Clone, Default, Eq)]
pub struct AggregateSignature(RawAggregateSignature);

impl AggregateSignature {
    /// Instantiate a new AggregateSignature.
    pub fn new() -> Self {
        AggregateSignature(RawAggregateSignature::new())
    }

    /// Add (aggregate) a signature to the `AggregateSignature`.
    pub fn add(&mut self, signature: &Signature) {
        self.0.add(signature.as_raw())
    }

    /// Verify the `AggregateSignature` against an `AggregatePublicKey`.
    ///
    /// Only returns `true` if the set of keys in the `AggregatePublicKey` match the set of keys
    /// that signed the `AggregateSignature`.
    pub fn verify(
        &self,
        msg: &[u8],
        domain: u64,
        aggregate_public_key: &AggregatePublicKey,
    ) -> bool {
        self.0.verify(msg, domain, aggregate_public_key.as_raw())
    }

    /// Verify this AggregateSignature against multiple AggregatePublickeys with multiple Messages.
    ///
    ///  All PublicKeys related to a Message should be aggregated into one AggregatePublicKey.
    ///  Each AggregatePublicKey has a 1:1 ratio with a 32 byte Message.
    pub fn verify_multiple(
        &self,
        messages: &[&[u8]],
        domain: u64,
        aggregate_public_keys: &[&AggregatePublicKey],
    ) -> bool {
        let aggregate_public_keys: Vec<&RawAggregatePublicKey> =
            aggregate_public_keys.iter().map(|pk| pk.as_raw()).collect();

        // Messages are concatenated into one long message.
        let mut msg: Vec<u8> = vec![];
        for message in messages {
            msg.extend_from_slice(message);
        }

        self.0
            .verify_multiple(&msg[..], domain, &aggregate_public_keys[..])
    }
}

impl Encodable for AggregateSignature {
    fn ssz_append(&self, s: &mut SszStream) {
        s.append_vec(&self.0.as_bytes());
    }
}

impl Decodable for AggregateSignature {
    fn ssz_decode(bytes: &[u8], i: usize) -> Result<(Self, usize), DecodeError> {
        let (sig_bytes, i) = decode_ssz_list(bytes, i)?;
        let raw_sig =
            RawAggregateSignature::from_bytes(&sig_bytes).map_err(|_| DecodeError::TooShort)?;
        Ok((AggregateSignature(raw_sig), i))
    }
}

impl Serialize for AggregateSignature {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_bytes(&ssz_encode(self))
    }
}

impl TreeHash for AggregateSignature {
    fn hash_tree_root_internal(&self) -> Vec<u8> {
        hash(&self.0.as_bytes())
    }
}

#[cfg(test)]
mod tests {
    use super::super::{Keypair, Signature};
    use super::*;
    use ssz::ssz_encode;

    #[test]
    pub fn test_ssz_round_trip() {
        let keypair = Keypair::random();

        let mut original = AggregateSignature::new();
        original.add(&Signature::new(&[42, 42], 0, &keypair.sk));

        let bytes = ssz_encode(&original);
        let (decoded, _) = AggregateSignature::ssz_decode(&bytes, 0).unwrap();

        assert_eq!(original, decoded);
    }
}
<|endoftext|>