<commit_before>
use protos::{LogFileEntry, StudyQuestion, StudyQuestions, StudyQuestionAnswer};
use std::error::Error;

extern crate regex;
use self::regex::Regex;

pub struct UserStudyQuestions {
    pub replay_filename: String,
    pub answer_lines: Vec<String>,
}
impl UserStudyQuestions {
    #[allow(unused_assignments)]
    pub fn get_questions(&mut self) -> Result<Option<StudyQuestions>, Box<Error>> {
        use scaii_core;
        use std::fs::File;
        use std::io::prelude::*;
        use std::io::BufReader;
        println!("Looking for question file for replay {}", self.replay_filename);
        let mut questionfile_path = scaii_core::get_default_replay_dir()?;
        let question_filename_root = get_question_filename_root_for_replay(&self.replay_filename);
        println!("question_filename root is {}", question_filename_root);
        let question_filename = get_filename_for_root(question_filename_root)?;
        let mut user_id = "".to_string();
        let mut treatment_id = "".to_string();
        let mut answer_filename = "".to_string();
        match question_filename  {
            None => { return Ok(None); },
            Some(ref filename)  => {
                user_id = get_field_from_filename(filename, 2 as u32);
                treatment_id = get_field_from_filename(filename, 3 as u32);
                answer_filename = filename.replace("question", "answer");
                let result = str::replace("Hello World!", "!", "?");
println!("{}", result); // => "Hello World!"
                println!("user_id {} ", user_id);
                println!("treatment_id {}", treatment_id);
            },
        }
        questionfile_path.push(question_filename.unwrap().as_str());
        println!("path is {:?}", questionfile_path);
        let f = File::open(questionfile_path)?;
        let reader = BufReader::new(f);

        let mut questions_vec: Vec<StudyQuestion> = Vec::new();
        let mut line_num: u8 = 0;
        for line in reader.lines() {
            line_num = line_num + 1;
            let question_string = line.unwrap();
            if check_line(&question_string, &line_num) {
                println!("STUDY QUESTION: {}", question_string);
                let question: StudyQuestion = self.get_study_question(&question_string, &line_num)?;
                questions_vec.push(question);
            }else {
                continue;   // If something in the line is invalid, print error to
                            // terminal and continue loop.
            }
        }
        let study_questions = StudyQuestions {
            user_id: user_id,
            treatment_id: treatment_id,
            study_questions: questions_vec,
            answer_filename: answer_filename,
        };
        Ok(Some(study_questions))
    }

    fn get_study_question(&mut self, line : &String, line_num : &u8) -> Result<StudyQuestion, Box<Error>> {
        use super::ReplayError;
        let line_parts_iterator = line.split(";");
        let vec: Vec<&str> = line_parts_iterator.collect();
        if vec.len() < 3 {
            return Err(Box::new(ReplayError::new(&format!("study question line needs at least three fields: <step>;<questionIndex>;<question>;<answer1>..."))));
        }

        let step: String = vec[0].to_string();
        check_regex("^[0-9]+$|^summary$".to_string(), "STEP REGEX FAIL".to_string(), &step, &line_num);

        let question_index: String = vec[1].to_string();
        check_regex("^[0-9]+$".to_string(), "INDEX REGEX FAIL".to_string(), &question_index, &line_num);

        let question_type: String = vec[2].to_string();
        check_regex("^plain:NA:NA$|^waitForClick:(gameboard_|rewardBar_|saliencyMap_){0, 2}(gameboard|rewardBar|saliencyMap){0, 1}:.+".to_string(), "QUESTION TYPE REGEX FAIL".to_string(), &question_type, &line_num);

        let question : String = vec[3].to_string();
        // println!("\t{:?} Question: {:?}", line_num, question);

        let mut answer_vec : Vec<String> = Vec::new();
        for x in 4..vec.len() {
            answer_vec.push(vec[x].to_string());
        }

        Ok(StudyQuestion {
            step: step,
            question: question,
            answers: answer_vec,
            question_id_for_step: question_index,
            question_type: question_type,
        })
    }

    pub fn persist_log_entry_incremental(&mut self, lfe: LogFileEntry) -> Result<(), Box<Error>> {
        use std::fs::{File, OpenOptions,remove_file};
        use std::io::Write;
        use scaii_core;
        println!("{:?}", &lfe);
        let output_line = lfe.entry;

        let mut answerfile_path = scaii_core::get_default_replay_dir()?;
        let filename = lfe.filename;
        answerfile_path.push(filename);

        if !answerfile_path.exists(){
            File::create(&answerfile_path)?;
        }
        let mut file = OpenOptions::new().append(true).open(answerfile_path).unwrap();
        file.write_all(output_line.as_bytes())?;
        file.write_all("\n".to_string().as_bytes())?;
        Ok(())
    }
    pub fn persist_log_entry(&mut self, lfe: LogFileEntry) -> Result<(), Box<Error>> {
        use std::fs::{File, OpenOptions,remove_file};
        use std::io::Write;
        use scaii_core;
        println!("{:?}", &lfe);
        let output_line = lfe.entry;
        self.answer_lines.push(output_line);

        if lfe.is_last_line {
            let mut answerfile_path = scaii_core::get_default_replay_dir()?;
            // append to file called replayX_answers_userID_treatmentID.txt
            // or ??? replayX_answers_userID_sessionID_treatmentID.txt
            let filename = lfe.filename;
            answerfile_path.push(filename);
            if answerfile_path.exists(){
                remove_file(&answerfile_path)?;
            }
            println!("answerfile_path is {:?}", answerfile_path);
            File::create(&answerfile_path)?;
            let mut file = OpenOptions::new().append(true).open(answerfile_path).unwrap();
            for line in &self.answer_lines {
                file.write_all(line.as_bytes())?;
                file.write_all("\n".to_string().as_bytes())?;
                //writeln!(file, format!("{}",line))?;
            }
        }

        Ok(())
    }

    pub fn persist_study_question_answer(&mut self, sqa: StudyQuestionAnswer) -> Result<(), Box<Error>> {
        use std::fs::{File, OpenOptions,remove_file};
        use std::io::Write;
        use scaii_core;
        println!("{:?}", &sqa);
        let user_id = sqa.user_id;
        let treatment_id = sqa.treatment_id;
        let answer = sqa.answer;
        let question = sqa.question;
        let question_number = sqa.question_number;
        let step = sqa.step;
        let output_line = format!("{};{};{};{}", question_number, step, question, answer);
        self.answer_lines.push(output_line);

        if step == "summary".to_string() {
            let mut answerfile_path = scaii_core::get_default_replay_dir()?;
            // append to file called replayX_answers_userID_treatmentID.txt
            // or ??? replayX_answers_userID_sessionID_treatmentID.txt
            let filename = get_answer_filename(&self.replay_filename, &user_id, &treatment_id);
            answerfile_path.push(filename);
            if answerfile_path.exists(){
                remove_file(&answerfile_path)?;
            }
            println!("answerfile_path is {:?}", answerfile_path);
            File::create(&answerfile_path)?;
            let mut file = OpenOptions::new().append(true).open(answerfile_path).unwrap();
            for line in &self.answer_lines {
                file.write_all(line.as_bytes())?;
                file.write_all("\n".to_string().as_bytes())?;
                //writeln!(file, format!("{}",line))?;
            }
        }

        Ok(())
    }
}

fn get_field_from_filename(filename : &String, index : u32) -> String {
    let filename_parts_iterator = filename.split(".");
    let vec: Vec<&str> = filename_parts_iterator.collect();
    let root = vec[0];
    let root_parts_iterator = root.split("_");
    let vec:Vec<&str> = root_parts_iterator.collect();
    vec[index as usize].to_string()
}

fn get_filename_for_root(root: String) -> Result<Option<String>, Box<Error>>  {
    use scaii_core;
    use std::fs;
    let questionfile_path = scaii_core::get_default_replay_dir()?;
    for entry in fs::read_dir(questionfile_path)? {
        let entry = entry?;
        let path = entry.path();
        if !path.is_dir() {
            let filename = path.file_name().unwrap().to_str().unwrap().to_string();
            if filename.starts_with(root.as_str()) {
                println!("filename found was {}", filename);
                return Ok(Some(filename));
            }
        }
    }
    Ok(None)
}

fn get_question_filename_root_for_replay(filename : &String) -> String {
    let filename_parts_iterator = filename.split(".");
    let vec: Vec<&str> = filename_parts_iterator.collect();
    format!("{}_questions", vec[0])
}

// replayX_answers_userID_treatmentID.txt
fn get_answer_filename(filename : &String, user_id: &String, treatment_id: &String) -> String {
    let filename_parts_iterator = filename.split(".");
    let vec: Vec<&str> = filename_parts_iterator.collect();
    format!("{}_answers_{}_{}.txt", vec[0], user_id, treatment_id)
}

fn check_line(line: &String, line_num: &u8) -> bool {
    let line_arr: Vec<char> = line.chars().collect();
    if line_arr.len() == 0 {      // Check for newline
        // println!("LINE\t{:?}\tWARNING: Newline/Empty line", line_num);
        return false;
    }

    if line_arr[0] == '#' {         // Check for comments
        println!("LINE\t{:?}\t{:?}", line_num, line);
        return false;
    }

    if line.chars().filter(|&c| c == ';').count() < 3 {
        panic!("\n\tERROR: line {:?}\t Missing \';\' delimiter.", line_num);
    }
    true
}

fn check_regex(regex: String, msg: String, line: &String, line_num: &u8) {
    let step_reg = Regex::new(&regex).unwrap();
    if !step_reg.is_match(&line) {                      // on Regex no match, panic
        panic!("LINE\t{:?}\t{:?}", line_num, msg);
    }
}

#[test]
fn test_regex() {
    use std::panic;

    let result = panic::catch_unwind(|| {
        check_regex("^[0-9]+$|^summary$".to_string(), "STEP REGEX FAIL".to_string(), &";;;".to_string(), &0);
    });
    assert!(result.is_err());

}<commit_msg>rewrote error checking for better test<commit_after>
use protos::{LogFileEntry, StudyQuestion, StudyQuestions, StudyQuestionAnswer};
use std::error::Error;
use std::path::PathBuf;
extern crate regex;
use self::regex::Regex;

pub struct UserStudyQuestions {
    pub replay_filename: String,
    pub answer_lines: Vec<String>,
}
impl UserStudyQuestions {
    #[allow(unused_assignments)]
    pub fn get_questions(&mut self) -> Result<Option<StudyQuestions>, Box<Error>> {
        use scaii_core;
        use std::fs::File;
        use std::io::prelude::*;
        use std::io::BufReader;
        println!("Looking for question file for replay {}", self.replay_filename);
        let mut questionfile_path = scaii_core::get_default_replay_dir()?;
        let question_filename_root = get_question_filename_root_for_replay(&self.replay_filename);
        println!("question_filename root is {}", question_filename_root);
        let question_filename = get_filename_for_root(question_filename_root)?;
        let mut user_id = "".to_string();
        let mut treatment_id = "".to_string();
        let mut answer_filename = "".to_string();
        match question_filename  {
            None => { return Ok(None); },
            Some(ref filename)  => {
                user_id = get_field_from_filename(filename, 2 as u32);
                treatment_id = get_field_from_filename(filename, 3 as u32);
                answer_filename = filename.replace("question", "answer");
                let result = str::replace("Hello World!", "!", "?");
println!("{}", result); // => "Hello World!"
                println!("user_id {} ", user_id);
                println!("treatment_id {}", treatment_id);
            },
        }
        let q_file = question_filename.clone();
        questionfile_path.push(&question_filename.unwrap().as_str());
        println!("path is {:?}", questionfile_path);

        if check_file(questionfile_path.clone()).len() != 0 {
            panic!();
        }

        let f = File::open(questionfile_path)?;
        let reader = BufReader::new(f);

        let mut questions_vec: Vec<StudyQuestion> = Vec::new();
        for line in reader.lines() {
            let question_string = line.unwrap();
            println!("STUDY QUESTION: {}", question_string);
            let question: StudyQuestion = self.get_study_question(&question_string)?;
            questions_vec.push(question);
        }
        let study_questions = StudyQuestions {
            user_id: user_id,
            treatment_id: treatment_id,
            study_questions: questions_vec,
            answer_filename: answer_filename,
        };
        Ok(Some(study_questions))
    }

    fn get_study_question(&mut self, line : &String) -> Result<StudyQuestion, Box<Error>> {
        use super::ReplayError;
        let line_parts_iterator = line.split(";");
        let vec: Vec<&str> = line_parts_iterator.collect();

        let step: String = vec[0].to_string();

        let question_index: String = vec[1].to_string();

        let question_type: String = vec[2].to_string();

        let question : String = vec[3].to_string();

        let mut answer_vec : Vec<String> = Vec::new();
        for x in 4..vec.len() {
            answer_vec.push(vec[x].to_string());
        }

        Ok(StudyQuestion {
            step: step,
            question: question,
            answers: answer_vec,
            question_id_for_step: question_index,
            question_type: question_type,
        })
    }

    pub fn persist_log_entry_incremental(&mut self, lfe: LogFileEntry) -> Result<(), Box<Error>> {
        use std::fs::{File, OpenOptions,remove_file};
        use std::io::Write;
        use scaii_core;
        println!("{:?}", &lfe);
        let output_line = lfe.entry;

        let mut answerfile_path = scaii_core::get_default_replay_dir()?;
        let filename = lfe.filename;
        answerfile_path.push(filename);

        if !answerfile_path.exists(){
            File::create(&answerfile_path)?;
        }
        let mut file = OpenOptions::new().append(true).open(answerfile_path).unwrap();
        file.write_all(output_line.as_bytes())?;
        file.write_all("\n".to_string().as_bytes())?;
        Ok(())
    }
    pub fn persist_log_entry(&mut self, lfe: LogFileEntry) -> Result<(), Box<Error>> {
        use std::fs::{File, OpenOptions,remove_file};
        use std::io::Write;
        use scaii_core;
        println!("{:?}", &lfe);
        let output_line = lfe.entry;
        self.answer_lines.push(output_line);

        if lfe.is_last_line {
            let mut answerfile_path = scaii_core::get_default_replay_dir()?;
            // append to file called replayX_answers_userID_treatmentID.txt
            // or ??? replayX_answers_userID_sessionID_treatmentID.txt
            let filename = lfe.filename;
            answerfile_path.push(filename);
            if answerfile_path.exists(){
                remove_file(&answerfile_path)?;
            }
            println!("answerfile_path is {:?}", answerfile_path);
            File::create(&answerfile_path)?;
            let mut file = OpenOptions::new().append(true).open(answerfile_path).unwrap();
            for line in &self.answer_lines {
                file.write_all(line.as_bytes())?;
                file.write_all("\n".to_string().as_bytes())?;
                //writeln!(file, format!("{}",line))?;
            }
        }

        Ok(())
    }

    pub fn persist_study_question_answer(&mut self, sqa: StudyQuestionAnswer) -> Result<(), Box<Error>> {
        use std::fs::{File, OpenOptions,remove_file};
        use std::io::Write;
        use scaii_core;
        println!("{:?}", &sqa);
        let user_id = sqa.user_id;
        let treatment_id = sqa.treatment_id;
        let answer = sqa.answer;
        let question = sqa.question;
        let question_number = sqa.question_number;
        let step = sqa.step;
        let output_line = format!("{};{};{};{}", question_number, step, question, answer);
        self.answer_lines.push(output_line);

        if step == "summary".to_string() {
            let mut answerfile_path = scaii_core::get_default_replay_dir()?;
            // append to file called replayX_answers_userID_treatmentID.txt
            // or ??? replayX_answers_userID_sessionID_treatmentID.txt
            let filename = get_answer_filename(&self.replay_filename, &user_id, &treatment_id);
            answerfile_path.push(filename);
            if answerfile_path.exists(){
                remove_file(&answerfile_path)?;
            }
            println!("answerfile_path is {:?}", answerfile_path);
            File::create(&answerfile_path)?;
            let mut file = OpenOptions::new().append(true).open(answerfile_path).unwrap();
            for line in &self.answer_lines {
                file.write_all(line.as_bytes())?;
                file.write_all("\n".to_string().as_bytes())?;
                //writeln!(file, format!("{}",line))?;
            }
        }

        Ok(())
    }
}

fn get_field_from_filename(filename : &String, index : u32) -> String {
    let filename_parts_iterator = filename.split(".");
    let vec: Vec<&str> = filename_parts_iterator.collect();
    let root = vec[0];
    let root_parts_iterator = root.split("_");
    let vec:Vec<&str> = root_parts_iterator.collect();
    vec[index as usize].to_string()
}

fn get_filename_for_root(root: String) -> Result<Option<String>, Box<Error>>  {
    use scaii_core;
    use std::fs;
    let questionfile_path = scaii_core::get_default_replay_dir()?;
    for entry in fs::read_dir(questionfile_path)? {
        let entry = entry?;
        let path = entry.path();
        if !path.is_dir() {
            let filename = path.file_name().unwrap().to_str().unwrap().to_string();
            if filename.starts_with(root.as_str()) {
                println!("filename found was {}", filename);
                return Ok(Some(filename));
            }
        }
    }
    Ok(None)
}

fn get_question_filename_root_for_replay(filename : &String) -> String {
    let filename_parts_iterator = filename.split(".");
    let vec: Vec<&str> = filename_parts_iterator.collect();
    format!("{}_questions", vec[0])
}

// replayX_answers_userID_treatmentID.txt
fn get_answer_filename(filename : &String, user_id: &String, treatment_id: &String) -> String {
    let filename_parts_iterator = filename.split(".");
    let vec: Vec<&str> = filename_parts_iterator.collect();
    format!("{}_answers_{}_{}.txt", vec[0], user_id, treatment_id)
}

fn check_file(file: PathBuf) -> Vec<u8> {
    use std::io::{BufRead, BufReader};
    use std::fs::File;
    let f = File::open(&file).expect("Unable to open file");
    let f = BufReader::new(f);

    let mut errors: Vec<u8> = Vec::new();
    let mut line_num: u8 = 0;

    for line in f.lines() {
        line_num = line_num + 1;
        let q_string = line.unwrap();

        if check_comments_or_nl(&q_string, &line_num, &file.to_str().unwrap()) {
            let temp = check_question(&q_string, &line_num, &file.to_str().unwrap());
            if temp != 0 {
                errors.push(temp);
            }
        }
    }
    errors
}

#[allow(dead_code)]
fn check_comments_or_nl(line: &String, line_num: &u8, fname: &str) -> bool {
    let line_arr: Vec<char> = line.chars().collect();
    if line_arr.len() == 0 {      // Check for newline
        // println!("LINE\t{:?}\tWARNING: Newline/Empty line", line_num);
        return false;
    }

    if line_arr[0] == '#' {         // Check for comments
        //println!("LINE\t{:?}\t{:?}", line_num, line);
        return false;
    }
    true
}

fn check_question(line: &String, line_num: &u8, fname: &str) ->u8{
    let line_copy = line.clone();
    let line_parts_iterator = line_copy.split(";");
    let vec: Vec<&str> = line_parts_iterator.collect();

    let field0: String = vec[0].to_string();

    let mut temp:u8 = 0;

    if line.chars().filter(|&c| c == ';').count() < 3 {
        println!("\nERROR (1): Missing \';\' delimiter.\n--> {:?}:{:?}\n\t|\n Line {:?} | {:?}\n\t|\n", fname, line_num, line_num, line);
        return 1;
    }

    temp = check_regex(02, "^[0-9]*|^summary$".to_string(), "Invalid entry for step number in Field 0.".to_string(), &field0, &line, &line_num, &fname);
    if temp != 0 { return temp; }

    let field1: String = vec[1].to_string();
    temp = check_regex(03, "^[0-9]*".to_string(), "Invalid entry for question index Field 1.".to_string(), &field1, &line, &line_num, &fname);

    let field2: String = vec[2].to_string();
    let f2vec: Vec<&str> = field2.split(":").collect();
    if temp != 0 { return temp; }

    if f2vec.len() > 0 {
        if f2vec[0] == "plain" {
            temp = check_regex(04, "plain:NA:NA".to_string(), "Invalid entry for question type in Field 2. When question type is specified as plain, subfields 1 and 2 must be 'NA'. ".to_string(), &field2, &line, &line_num, &fname);
            if temp != 0 { return temp; }
        }else{
            temp = check_regex(05, "^waitForClick".to_string(), "Invalid entry for question type in Field 2. Question type must be [ plain | waitForClick ]".to_string(), &f2vec[0].to_string(), &line, &line_num, &fname);
            if temp != 0 { return temp; }
            if f2vec.len() > 2  && !f2vec.contains(&""){
                temp = check_regex(06, "^(gameboard_?|rewardBar_?|saliencyMap_?){0,3}$".to_string(), "Invalid entry for question type in Field 2, subfield 1. Valid entries are {gameboard, rewardBar, saliencyMap}, deliminated by _.".to_string(), &f2vec[1].to_string(), &line, &line_num, &fname);
                if temp != 0 { return temp; }
            }else{
                temp = check_regex(07, "$^".to_string(), "Invalid entry for question type in Field 2. Question type waitForClick cannot have blank subfields.".to_string(), &field2, &line, &line_num, &fname);
                if temp != 0 { return temp; }
            }
        }
    }else {
        temp = check_regex(08, "$^".to_string(), "Invalid entry for question type in Field 2.".to_string(), &field2, &line, &line_num, &fname);
        if temp != 0 { return temp; }
    }

    return 0;
}

/*
check_regex args:
1. error code (0 means no error)
2. regex expression, if string does not pass it then this is an error
3. message explaining what the error is
4. reference to the substring to check
5. the full parent string
6. line number the substring is from
7. the filename the substring is from
*/
fn check_regex(error_code: u8, regex: String, msg: String, str_to_check: &String, full_line: &String, line_num: &u8, fname: &str) -> u8 {
    let step_reg = Regex::new(&regex).unwrap();
    if !step_reg.is_match(&str_to_check) {
        println!("\nERROR ({}): {}\n\t--> {}:{}\n\t|\n Line {} | {}\n\t|\n\tInvalid substring: {:?}\n", error_code, msg, fname, line_num, line_num, full_line, str_to_check);
        return error_code;
    }
    0
}
<|endoftext|>


<commit_before>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

pub struct Stream {
  info: StreamInfo,
  pub metadata: Vec<Metadata>,
  pub frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
        output: Vec::new(),
        frame_index: 0,
      }
    }
  )
);

impl Stream {
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  pub fn info(&self) -> StreamInfo {
    self.info
  }

  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer<P>(producer: &mut P, error_str: &str)
                             -> io::Result<Stream>
   where P: StreamProducer {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                         => break,
        Err(ErrorKind::EndOfInput)    => break,
        Err(ErrorKind::Consumed(_))   => continue,
        Err(ErrorKind::Incomplete(_)) => continue,
        Err(_)                        => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream.info.channels as usize;
      let block_size  = stream.info.max_block_size as usize;
      let output_size = block_size * channels;

      stream.output.reserve_exact(output_size);

      unsafe { stream.output.set_len(output_size) }

      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  pub fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata::block(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  pub fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                                   -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

pub struct Iter<'a> {
  stream: &'a mut Stream,
  channel: usize,
  frame_index: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a> Iter<'a> {
  pub fn new(stream: &'a mut Stream) -> Iter<'a> {
    let samples_left = stream.info.total_samples;

    Iter {
      stream: stream,
      channel: 0,
      frame_index: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }
}

impl<'a> Iterator for Iter<'a> {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.block_size == 0 || self.sample_index == self.block_size {
      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[self.frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel      += 1;
    self.samples_left -= 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a change that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}
<commit_msg>Add a method for converting into `Iter`<commit_after>use nom;
use nom::{Err, IResult};

use metadata;
use frame;
use subframe;

use metadata::{Metadata, StreamInfo, metadata_parser};
use frame::{frame_parser, Frame};
use utility::{ErrorKind, ByteStream, ReadStream, StreamProducer};

use std::io;
use std::usize;
use std::fs::File;

enum ParserState {
  Marker,
  Metadata,
  Frame,
}

pub struct Stream {
  info: StreamInfo,
  pub metadata: Vec<Metadata>,
  pub frames: Vec<Frame>,
  state: ParserState,
  output: Vec<i32>,
  frame_index: usize,
}

named!(pub stream_parser <&[u8], Stream>,
  chain!(
    blocks: metadata_parser ~
    frames: many1!(apply!(frame_parser, &blocks.0)),
    move|| {
      Stream {
        info: blocks.0,
        metadata: blocks.1,
        frames: frames,
        state: ParserState::Marker,
        output: Vec::new(),
        frame_index: 0,
      }
    }
  )
);

impl Stream {
  pub fn new() -> Stream {
    Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    }
  }

  pub fn info(&self) -> StreamInfo {
    self.info
  }

  pub fn from_file(filename: &str) -> io::Result<Stream> {
    File::open(filename).and_then(|file| {
      let mut producer = ReadStream::new(file);
      let error_str    = format!("parser: couldn't parse the given file {}",
                                 filename);

      Stream::from_stream_producer(&mut producer, &error_str)
    })
  }

  pub fn from_buffer(buffer: &[u8]) -> io::Result<Stream> {
    let mut producer = ByteStream::new(buffer);
    let error_str    = "parser: couldn't parse the buffer";

    Stream::from_stream_producer(&mut producer, error_str)
  }

  fn from_stream_producer<P>(producer: &mut P, error_str: &str)
                             -> io::Result<Stream>
   where P: StreamProducer {
    let mut is_error = false;
    let mut stream   = Stream {
      info: StreamInfo::new(),
      metadata: Vec::new(),
      frames: Vec::new(),
      state: ParserState::Marker,
      output: Vec::new(),
      frame_index: 0,
    };

    loop {
      match stream.handle(producer) {
        Ok(_)                         => break,
        Err(ErrorKind::EndOfInput)    => break,
        Err(ErrorKind::Consumed(_))   => continue,
        Err(ErrorKind::Incomplete(_)) => continue,
        Err(_)                        => {
          is_error = true;

          break;
        }
      }
    }

    if !is_error {
      let channels    = stream.info.channels as usize;
      let block_size  = stream.info.max_block_size as usize;
      let output_size = block_size * channels;

      stream.output.reserve_exact(output_size);

      unsafe { stream.output.set_len(output_size) }

      Ok(stream)
    } else {
      Err(io::Error::new(io::ErrorKind::InvalidData, error_str))
    }
  }

  pub fn iter(&mut self) -> Iter {
    Iter::new(self)
  }

  pub fn next_frame<'a>(&'a mut self) -> Option<&'a [i32]> {
    if self.frames.is_empty() || self.frame_index >= self.frames.len() {
      None
    } else {
      let frame       = &self.frames[self.frame_index];
      let channels    = frame.header.channels as usize;
      let block_size  = frame.header.block_size as usize;
      let mut channel = 0;

      for subframe in &frame.subframes[0..channels] {
        let start  = channel * block_size;
        let end    = (channel + 1) * block_size;
        let output = &mut self.output[start..end];

        subframe::decode(&subframe, output);

        channel += 1;
      }

      frame::decode(frame.header.channel_assignment, &mut self.output);

      self.frame_index += 1;

      Some(&self.output[0..(block_size * channels)])
    }
  }

  fn handle_marker<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(0);

    match tag!(input, "fLaC") {
      IResult::Done(i, _)    => {
        self.state = ParserState::Metadata;

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_metadata<'a>(&mut self, input: &'a [u8])
                         -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(1);

    match metadata::block(input) {
      IResult::Done(i, block) => {
        let is_last = block.is_last;

        if let metadata::Data::StreamInfo(info) = block.data {
          self.info = info;
        } else {
          self.metadata.push(block);
        }

        if is_last {
          self.state = ParserState::Frame;
        }

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  fn handle_frame<'a>(&mut self, input: &'a [u8]) -> IResult<&'a [u8], ()> {
    let kind = nom::ErrorKind::Custom(2);

    match frame_parser(input, &self.info) {
      IResult::Done(i, frame) => {
        self.frames.push(frame);

        IResult::Error(Err::Position(kind, i))
      }
      IResult::Error(_)      => IResult::Error(Err::Code(kind)),
      IResult::Incomplete(n) => IResult::Incomplete(n),
    }
  }

  pub fn handle<S: StreamProducer>(&mut self, stream: &mut S)
                                   -> Result<(), ErrorKind> {
    stream.parse(|input| {
      match self.state {
        ParserState::Marker   => self.handle_marker(input),
        ParserState::Metadata => self.handle_metadata(input),
        ParserState::Frame    => self.handle_frame(input),
      }
    })
  }
}

pub struct Iter<'a> {
  stream: &'a mut Stream,
  channel: usize,
  frame_index: usize,
  block_size: usize,
  sample_index: usize,
  samples_left: u64,
}

impl<'a> Iter<'a> {
  pub fn new(stream: &'a mut Stream) -> Iter<'a> {
    let samples_left = stream.info.total_samples;

    Iter {
      stream: stream,
      channel: 0,
      frame_index: 0,
      block_size: 0,
      sample_index: 0,
      samples_left: samples_left,
    }
  }
}

impl<'a> Iterator for Iter<'a> {
  type Item = i32;

  fn next(&mut self) -> Option<Self::Item> {
    if self.block_size == 0 || self.sample_index == self.block_size {
      if self.stream.next_frame().is_none() {
        return None;
      } else {
        let frame = &self.stream.frames[self.frame_index];

        self.sample_index = 0;
        self.block_size   = frame.header.block_size as usize;
      }
    }

    let channels = self.stream.info.channels as usize;
    let index    = self.sample_index + (self.channel * self.block_size);
    let sample   = self.stream.output[index];

    self.channel      += 1;
    self.samples_left -= 1;

    // Reset current channel
    if self.channel == channels {
      self.channel       = 0;
      self.sample_index += 1;
    }

    Some(sample)
  }

  fn size_hint(&self) -> (usize, Option<usize>) {
    let samples_left = self.samples_left as usize;
    let max_value    = usize::max_value() as u64;

    // There is a change that samples_left will be larger than a usize since
    // it is a u64. Make the upper bound None when it is.
    if self.samples_left > max_value {
      (samples_left, None)
    } else {
      (samples_left, Some(samples_left))
    }
  }
}
<|endoftext|>


<commit_before>/// Scoped thread.
///
/// # Examples
///
/// A basic scoped thread:
///
/// ```
/// crossbeam_utils::thread::scope(|scope| {
///     scope.spawn(|| {
///         println!("Hello from a scoped thread!");
///     });
/// });
/// ```
///
/// When writing concurrent Rust programs, you'll sometimes see a pattern like this, using
/// [`std::thread::spawn`][spawn]:
///
/// ```ignore
/// let array = [1, 2, 3];
/// let mut guards = vec![];
///
/// for i in &array {
///     let guard = std::thread::spawn(move || {
///         println!("element: {}", i);
///     });
///
///     guards.push(guard);
/// }
///
/// for guard in guards {
///     guard.join().unwrap();
/// }
/// ```
///
/// The basic pattern is:
///
/// 1. Iterate over some collection.
/// 2. Spin up a thread to operate on each part of the collection.
/// 3. Join all the threads.
///
/// However, this code actually gives an error:
///
/// ```text
/// error: `array` does not live long enough
/// for i in &array {
///           ^~~~~
/// in expansion of for loop expansion
/// note: expansion site
/// note: reference must be valid for the static lifetime...
/// note: ...but borrowed value is only valid for the block suffix following statement 0 at ...
///     let array = [1, 2, 3];
///     let mut guards = vec![];
///
///     for i in &array {
///         let guard = std::thread::spawn(move || {
///             println!("element: {}", i);
/// ...
/// error: aborting due to previous error
/// ```
///
/// Because [`std::thread::spawn`][spawn] doesn't know about this scope, it requires a
/// `'static` lifetime. One way of giving it a proper lifetime is to use an [`Arc`][arc]:
///
/// [arc]: http://doc.rust-lang.org/stable/std/sync/struct.Arc.html
/// [spawn]: https://doc.rust-lang.org/stable/std/thread/fn.spawn.html
///
/// ```
/// use std::sync::Arc;
///
/// let array = Arc::new([1, 2, 3]);
/// let mut guards = vec![];
///
/// for i in 0..array.len() {
///     let a = array.clone();
///
///     let guard = std::thread::spawn(move || {
///         println!("element: {}", a[i]);
///     });
///
///     guards.push(guard);
/// }
///
/// for guard in guards {
///     guard.join().unwrap();
/// }
/// ```
///
/// But this introduces unnecessary allocation, as `Arc<T>` puts its data on the heap, and we
/// also end up dealing with reference counts. We know that we're joining the threads before
/// our function returns, so just taking a reference _should_ be safe. Rust can't know that,
/// though.
///
/// Enter scoped threads. Here's our original example, using `spawn` from crossbeam rather
/// than from `std::thread`:
///
/// ```
/// let array = [1, 2, 3];
///
/// crossbeam_utils::thread::scope(|scope| {
///     for i in &array {
///         scope.spawn(move || {
///             println!("element: {}", i);
///         });
///     }
/// });
/// ```
///
/// Much more straightforward.

use std::cell::RefCell;
use std::fmt;
use std::marker::PhantomData;
use std::mem::{self, ManuallyDrop};
use std::ops::DerefMut;
use std::panic::{self, AssertUnwindSafe};
use std::rc::Rc;
use std::thread;
use std::io;

#[doc(hidden)]
trait FnBox<T> {
    fn call_box(self: Box<Self>) -> T;
}

impl<T, F: FnOnce() -> T> FnBox<T> for F {
    fn call_box(self: Box<Self>) -> T {
        (*self)()
    }
}

/// Like `std::thread::spawn`, but without the closure bounds.
pub unsafe fn spawn_unchecked<'a, F>(f: F) -> thread::JoinHandle<()>
where
    F: FnOnce() + Send + 'a,
{
    let builder = thread::Builder::new();
    builder_spawn_unchecked(builder, f).unwrap()
}

/// Like `std::thread::Builder::spawn`, but without the closure bounds.
pub unsafe fn builder_spawn_unchecked<'a, F>(
    builder: thread::Builder,
    f: F,
) -> io::Result<thread::JoinHandle<()>>
where
    F: FnOnce() + Send + 'a,
{
    let closure: Box<FnBox<()> + 'a> = Box::new(f);
    let closure: Box<FnBox<()> + Send> = mem::transmute(closure);
    builder.spawn(move || closure.call_box())
}

pub struct Scope<'a> {
    /// The list of the deferred functions and thread join jobs.
    dtors: RefCell<Option<DtorChain<'a, thread::Result<()>>>>,
    // !Send + !Sync
    _marker: PhantomData<*const ()>,
}

struct DtorChain<'a, T> {
    dtor: Box<FnBox<T> + 'a>,
    next: Option<Box<DtorChain<'a, T>>>,
}

impl<'a, T> DtorChain<'a, T> {
    pub fn pop(chain: &mut Option<DtorChain<'a, T>>) -> Option<Box<FnBox<T> + 'a>> {
        chain.take().map(|mut node| {
            *chain = node.next.take().map(|b| *b);
            node.dtor
        })
    }
}

struct JoinState<T> {
    join_handle: thread::JoinHandle<()>,
    result: usize,
    _marker: PhantomData<T>,
}

impl<T: Send> JoinState<T> {
    fn new(join_handle: thread::JoinHandle<()>, result: usize) -> JoinState<T> {
        JoinState {
            join_handle: join_handle,
            result: result,
            _marker: PhantomData,
        }
    }

    fn join(self) -> thread::Result<T> {
        let result = self.result;
        self.join_handle.join().map(|_| {
            unsafe { ManuallyDrop::into_inner(*Box::from_raw(result as *mut ManuallyDrop<T>))}
        })
    }
}

/// A handle to a scoped thread
pub struct ScopedJoinHandle<'a, T: 'a> {
    // !Send + !Sync
    inner: Rc<RefCell<Option<JoinState<T>>>>,
    thread: thread::Thread,
    _marker: PhantomData<&'a T>,
}

/// Create a new `Scope` for [*scoped thread spawning*](struct.Scope.html#method.spawn).
///
/// In addition, you can [register ad-hoc functions](struct.Scope.html#method.defer) that are
/// deferred to be run. No matter what happens, before the `Scope` is dropped, it is guaranteed that
/// all the unjoined spawned scoped threads are joined and the deferred functions are run.
///
/// `thread::scope()` returns `Ok(())` if all the unjoined spawned threads and the deferred
/// functions did not panic. It returns `Err(e)` if one of them panics with `e`. If many of them
/// panics, it is still guaranteed that all the threads are joined and all the functions are run,
/// and `thread::scope()` returns `Err(e)` with `e` from a panicking thread or function.
///
/// # Examples
///
/// Creating and using a scope:
///
/// ```
/// crossbeam_utils::thread::scope(|scope| {
///     scope.defer(|| println!("Exiting scope"));
///     scope.spawn(|| println!("Running child thread in scope"))
/// }).unwrap();
/// // Prints messages
/// ```
pub fn scope<'a, F, R>(f: F) -> thread::Result<R>
where
    F: FnOnce(&Scope<'a>) -> R,
{
    let mut scope = Scope {
        dtors: RefCell::new(None),
        _marker: PhantomData,
    };
    let ret = f(&scope);
    scope.drop_all()?;
    Ok(ret)
}

impl<'a> fmt::Debug for Scope<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Scope {{ ... }}")
    }
}

impl<'a, T> fmt::Debug for ScopedJoinHandle<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ScopedJoinHandle {{ ... }}")
    }
}

impl<'a> Scope<'a> {
    // This method is carefully written in a transactional style, so that it can be called directly
    // and, if any dtor panics, can be resumed in the unwinding this causes. By initially running
    // the method outside of any destructor, we avoid any leakage problems due to
    // @rust-lang/rust#14875.
    fn drop_all(&mut self) -> thread::Result<()> {
        let mut ret = Ok(());
        while let Some(dtor) = DtorChain::pop(&mut self.dtors.borrow_mut()) {
            ret = ret.and(dtor.call_box());
        }
        ret
    }

    fn defer_inner<F>(&self, f: F)
    where
        F: (FnOnce() -> thread::Result<()>) + 'a,
    {
        let mut dtors = self.dtors.borrow_mut();
        *dtors = Some(DtorChain {
            dtor: Box::new(f),
            next: dtors.take().map(Box::new),
        });
    }

    /// Schedule code to be executed when exiting the scope.
    ///
    /// This is akin to having a destructor on the stack, except that it is *guaranteed* to be
    /// run. It is guaranteed that the function is called after all the spawned threads are joined.
    pub fn defer<F>(&self, f: F)
    where
        F: FnOnce() + 'a,
    {
        self.defer_inner(move || panic::catch_unwind(AssertUnwindSafe(f)));
    }

    /// Create a scoped thread.
    ///
    /// `spawn` is similar to the [`spawn`][spawn] function in Rust's standard library. The
    /// difference is that this thread is scoped, meaning that it's guaranteed to terminate before
    /// the current stack frame goes away, allowing you to reference the parent stack frame
    /// directly. This is ensured by having the parent thread join on the child thread before the
    /// scope exits.
    ///
    /// [spawn]: http://doc.rust-lang.org/std/thread/fn.spawn.html
    pub fn spawn<'s, F, T>(&'s self, f: F) -> ScopedJoinHandle<'a, T>
    where
        'a: 's,
        F: FnOnce() -> T + Send + 'a,
        T: Send + 'a,
    {
        self.builder().spawn(f).unwrap()
    }

    /// Generates the base configuration for spawning a scoped thread, from which configuration
    /// methods can be chained.
    pub fn builder<'s>(&'s self) -> ScopedThreadBuilder<'s, 'a> {
        ScopedThreadBuilder {
            scope: self,
            builder: thread::Builder::new(),
        }
    }
}

/// Scoped thread configuration. Provides detailed control over the properties and behavior of new
/// scoped threads.
pub struct ScopedThreadBuilder<'s, 'a: 's> {
    scope: &'s Scope<'a>,
    builder: thread::Builder,
}

impl<'s, 'a: 's> ScopedThreadBuilder<'s, 'a> {
    /// Names the thread-to-be. Currently the name is used for identification only in panic
    /// messages.
    pub fn name(mut self, name: String) -> ScopedThreadBuilder<'s, 'a> {
        self.builder = self.builder.name(name);
        self
    }

    /// Sets the size of the stack for the new thread.
    pub fn stack_size(mut self, size: usize) -> ScopedThreadBuilder<'s, 'a> {
        self.builder = self.builder.stack_size(size);
        self
    }

    /// Spawns a new thread, and returns a join handle for it.
    pub fn spawn<F, T>(self, f: F) -> io::Result<ScopedJoinHandle<'a, T>>
    where
        F: FnOnce() -> T + Send + 'a,
        T: Send + 'a,
    {
        // The `Box` constructed below is written only by the spawned thread, and read by the
        // current thread only after the spawned thread is joined (`JoinState::join()`). Thus there
        // are no data races.
        let result = Box::into_raw(Box::<ManuallyDrop<T>>::new(unsafe { mem::uninitialized() })) as usize;

        let join_handle = try!(unsafe {
            builder_spawn_unchecked(self.builder, move || {
                let mut result = Box::from_raw(result as *mut ManuallyDrop<T>);
                *result = ManuallyDrop::new(f());
                mem::forget(result);
            })
        });
        let thread = join_handle.thread().clone();

        let join_state = JoinState::<T>::new(join_handle, result);
        let deferred_handle = Rc::new(RefCell::new(Some(join_state)));
        let my_handle = deferred_handle.clone();

        self.scope.defer_inner(move || {
            let state = mem::replace(deferred_handle.borrow_mut().deref_mut(), None);
            if let Some(state) = state {
                state.join().map(|_| ())
            } else {
                Ok(())
            }
        });

        Ok(ScopedJoinHandle {
            inner: my_handle,
            thread: thread,
            _marker: PhantomData,
        })
    }
}

impl<'a, T: Send + 'a> ScopedJoinHandle<'a, T> {
    /// Waits for the associated thread to finish.
    ///
    /// If the child thread panics, [`Err`] is returned with the parameter given to [`panic`].
    ///
    /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
    /// [`panic`]: https://doc.rust-lang.org/std/macro.panic.html
    ///
    /// # Panics
    ///
    /// This function may panic on some platforms if a thread attempts to join itself or otherwise
    /// may create a deadlock with joining threads.
    pub fn join(self) -> thread::Result<T> {
        let state = mem::replace(self.inner.borrow_mut().deref_mut(), None);
        state.unwrap().join()
    }

    /// Gets the underlying [`std::thread::Thread`] handle.
    ///
    /// [`std::thread::Thread`]: https://doc.rust-lang.org/std/thread/struct.Thread.html
    pub fn thread(&self) -> &thread::Thread {
        &self.thread
    }
}

impl<'a> Drop for Scope<'a> {
    fn drop(&mut self) {
        // Actually, there should be no deferred functions left to be run.
        self.drop_all().unwrap();
    }
}
<commit_msg>Return any type from spawn_unchecked (#30)<commit_after>/// Scoped thread.
///
/// # Examples
///
/// A basic scoped thread:
///
/// ```
/// crossbeam_utils::thread::scope(|scope| {
///     scope.spawn(|| {
///         println!("Hello from a scoped thread!");
///     });
/// });
/// ```
///
/// When writing concurrent Rust programs, you'll sometimes see a pattern like this, using
/// [`std::thread::spawn`][spawn]:
///
/// ```ignore
/// let array = [1, 2, 3];
/// let mut guards = vec![];
///
/// for i in &array {
///     let guard = std::thread::spawn(move || {
///         println!("element: {}", i);
///     });
///
///     guards.push(guard);
/// }
///
/// for guard in guards {
///     guard.join().unwrap();
/// }
/// ```
///
/// The basic pattern is:
///
/// 1. Iterate over some collection.
/// 2. Spin up a thread to operate on each part of the collection.
/// 3. Join all the threads.
///
/// However, this code actually gives an error:
///
/// ```text
/// error: `array` does not live long enough
/// for i in &array {
///           ^~~~~
/// in expansion of for loop expansion
/// note: expansion site
/// note: reference must be valid for the static lifetime...
/// note: ...but borrowed value is only valid for the block suffix following statement 0 at ...
///     let array = [1, 2, 3];
///     let mut guards = vec![];
///
///     for i in &array {
///         let guard = std::thread::spawn(move || {
///             println!("element: {}", i);
/// ...
/// error: aborting due to previous error
/// ```
///
/// Because [`std::thread::spawn`][spawn] doesn't know about this scope, it requires a
/// `'static` lifetime. One way of giving it a proper lifetime is to use an [`Arc`][arc]:
///
/// [arc]: http://doc.rust-lang.org/stable/std/sync/struct.Arc.html
/// [spawn]: https://doc.rust-lang.org/stable/std/thread/fn.spawn.html
///
/// ```
/// use std::sync::Arc;
///
/// let array = Arc::new([1, 2, 3]);
/// let mut guards = vec![];
///
/// for i in 0..array.len() {
///     let a = array.clone();
///
///     let guard = std::thread::spawn(move || {
///         println!("element: {}", a[i]);
///     });
///
///     guards.push(guard);
/// }
///
/// for guard in guards {
///     guard.join().unwrap();
/// }
/// ```
///
/// But this introduces unnecessary allocation, as `Arc<T>` puts its data on the heap, and we
/// also end up dealing with reference counts. We know that we're joining the threads before
/// our function returns, so just taking a reference _should_ be safe. Rust can't know that,
/// though.
///
/// Enter scoped threads. Here's our original example, using `spawn` from crossbeam rather
/// than from `std::thread`:
///
/// ```
/// let array = [1, 2, 3];
///
/// crossbeam_utils::thread::scope(|scope| {
///     for i in &array {
///         scope.spawn(move || {
///             println!("element: {}", i);
///         });
///     }
/// });
/// ```
///
/// Much more straightforward.

use std::cell::RefCell;
use std::fmt;
use std::marker::PhantomData;
use std::mem::{self, ManuallyDrop};
use std::ops::DerefMut;
use std::panic::{self, AssertUnwindSafe};
use std::rc::Rc;
use std::thread;
use std::io;

#[doc(hidden)]
trait FnBox<T> {
    fn call_box(self: Box<Self>) -> T;
}

impl<T, F: FnOnce() -> T> FnBox<T> for F {
    fn call_box(self: Box<Self>) -> T {
        (*self)()
    }
}

/// Like `std::thread::spawn`, but without lifetime bounds on the closure.
pub unsafe fn spawn_unchecked<'a, F, T>(f: F) -> thread::JoinHandle<T>
where
    F: FnOnce() -> T,
    F: Send + 'a,
    T: Send + 'static,
{
    let builder = thread::Builder::new();
    builder_spawn_unchecked(builder, f).unwrap()
}

/// Like `std::thread::Builder::spawn`, but without lifetime bounds on the closure.
pub unsafe fn builder_spawn_unchecked<'a, F, T>(
    builder: thread::Builder,
    f: F,
) -> io::Result<thread::JoinHandle<T>>
where
    F: FnOnce() -> T,
    F: Send + 'a,
    T: Send + 'static,
{
    let closure: Box<FnBox<T> + 'a> = Box::new(f);
    let closure: Box<FnBox<T> + Send> = mem::transmute(closure);
    builder.spawn(move || {
        closure.call_box()
    })
}

pub struct Scope<'a> {
    /// The list of the deferred functions and thread join jobs.
    dtors: RefCell<Option<DtorChain<'a, thread::Result<()>>>>,
    // !Send + !Sync
    _marker: PhantomData<*const ()>,
}

struct DtorChain<'a, T> {
    dtor: Box<FnBox<T> + 'a>,
    next: Option<Box<DtorChain<'a, T>>>,
}

impl<'a, T> DtorChain<'a, T> {
    pub fn pop(chain: &mut Option<DtorChain<'a, T>>) -> Option<Box<FnBox<T> + 'a>> {
        chain.take().map(|mut node| {
            *chain = node.next.take().map(|b| *b);
            node.dtor
        })
    }
}

struct JoinState<T> {
    join_handle: thread::JoinHandle<()>,
    result: usize,
    _marker: PhantomData<T>,
}

impl<T: Send> JoinState<T> {
    fn new(join_handle: thread::JoinHandle<()>, result: usize) -> JoinState<T> {
        JoinState {
            join_handle: join_handle,
            result: result,
            _marker: PhantomData,
        }
    }

    fn join(self) -> thread::Result<T> {
        let result = self.result;
        self.join_handle.join().map(|_| {
            unsafe { ManuallyDrop::into_inner(*Box::from_raw(result as *mut ManuallyDrop<T>))}
        })
    }
}

/// A handle to a scoped thread
pub struct ScopedJoinHandle<'a, T: 'a> {
    // !Send + !Sync
    inner: Rc<RefCell<Option<JoinState<T>>>>,
    thread: thread::Thread,
    _marker: PhantomData<&'a T>,
}

/// Create a new `Scope` for [*scoped thread spawning*](struct.Scope.html#method.spawn).
///
/// In addition, you can [register ad-hoc functions](struct.Scope.html#method.defer) that are
/// deferred to be run. No matter what happens, before the `Scope` is dropped, it is guaranteed that
/// all the unjoined spawned scoped threads are joined and the deferred functions are run.
///
/// `thread::scope()` returns `Ok(())` if all the unjoined spawned threads and the deferred
/// functions did not panic. It returns `Err(e)` if one of them panics with `e`. If many of them
/// panics, it is still guaranteed that all the threads are joined and all the functions are run,
/// and `thread::scope()` returns `Err(e)` with `e` from a panicking thread or function.
///
/// # Examples
///
/// Creating and using a scope:
///
/// ```
/// crossbeam_utils::thread::scope(|scope| {
///     scope.defer(|| println!("Exiting scope"));
///     scope.spawn(|| println!("Running child thread in scope"))
/// }).unwrap();
/// // Prints messages
/// ```
pub fn scope<'a, F, R>(f: F) -> thread::Result<R>
where
    F: FnOnce(&Scope<'a>) -> R,
{
    let mut scope = Scope {
        dtors: RefCell::new(None),
        _marker: PhantomData,
    };
    let ret = f(&scope);
    scope.drop_all()?;
    Ok(ret)
}

impl<'a> fmt::Debug for Scope<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Scope {{ ... }}")
    }
}

impl<'a, T> fmt::Debug for ScopedJoinHandle<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ScopedJoinHandle {{ ... }}")
    }
}

impl<'a> Scope<'a> {
    // This method is carefully written in a transactional style, so that it can be called directly
    // and, if any dtor panics, can be resumed in the unwinding this causes. By initially running
    // the method outside of any destructor, we avoid any leakage problems due to
    // @rust-lang/rust#14875.
    fn drop_all(&mut self) -> thread::Result<()> {
        let mut ret = Ok(());
        while let Some(dtor) = DtorChain::pop(&mut self.dtors.borrow_mut()) {
            ret = ret.and(dtor.call_box());
        }
        ret
    }

    fn defer_inner<F>(&self, f: F)
    where
        F: (FnOnce() -> thread::Result<()>) + 'a,
    {
        let mut dtors = self.dtors.borrow_mut();
        *dtors = Some(DtorChain {
            dtor: Box::new(f),
            next: dtors.take().map(Box::new),
        });
    }

    /// Schedule code to be executed when exiting the scope.
    ///
    /// This is akin to having a destructor on the stack, except that it is *guaranteed* to be
    /// run. It is guaranteed that the function is called after all the spawned threads are joined.
    pub fn defer<F>(&self, f: F)
    where
        F: FnOnce() + 'a,
    {
        self.defer_inner(move || panic::catch_unwind(AssertUnwindSafe(f)));
    }

    /// Create a scoped thread.
    ///
    /// `spawn` is similar to the [`spawn`][spawn] function in Rust's standard library. The
    /// difference is that this thread is scoped, meaning that it's guaranteed to terminate before
    /// the current stack frame goes away, allowing you to reference the parent stack frame
    /// directly. This is ensured by having the parent thread join on the child thread before the
    /// scope exits.
    ///
    /// [spawn]: http://doc.rust-lang.org/std/thread/fn.spawn.html
    pub fn spawn<F, T>(&self, f: F) -> ScopedJoinHandle<'a, T>
    where
        F: FnOnce() -> T,
        F: Send + 'a,
        T: Send + 'a,
    {
        self.builder().spawn(f).unwrap()
    }

    /// Generates the base configuration for spawning a scoped thread, from which configuration
    /// methods can be chained.
    pub fn builder<'s>(&'s self) -> ScopedThreadBuilder<'s, 'a> {
        ScopedThreadBuilder {
            scope: self,
            builder: thread::Builder::new(),
        }
    }
}

/// Scoped thread configuration. Provides detailed control over the properties and behavior of new
/// scoped threads.
pub struct ScopedThreadBuilder<'s, 'a: 's> {
    scope: &'s Scope<'a>,
    builder: thread::Builder,
}

impl<'s, 'a: 's> ScopedThreadBuilder<'s, 'a> {
    /// Names the thread-to-be. Currently the name is used for identification only in panic
    /// messages.
    pub fn name(mut self, name: String) -> ScopedThreadBuilder<'s, 'a> {
        self.builder = self.builder.name(name);
        self
    }

    /// Sets the size of the stack for the new thread.
    pub fn stack_size(mut self, size: usize) -> ScopedThreadBuilder<'s, 'a> {
        self.builder = self.builder.stack_size(size);
        self
    }

    /// Spawns a new thread, and returns a join handle for it.
    pub fn spawn<F, T>(self, f: F) -> io::Result<ScopedJoinHandle<'a, T>>
    where
        F: FnOnce() -> T,
        F: Send + 'a,
        T: Send + 'a,
    {
        // The `Box` constructed below is written only by the spawned thread, and read by the
        // current thread only after the spawned thread is joined (`JoinState::join()`). Thus there
        // are no data races.
        let result = Box::into_raw(Box::<ManuallyDrop<T>>::new(unsafe { mem::uninitialized() })) as usize;

        let join_handle = try!(unsafe {
            builder_spawn_unchecked(self.builder, move || {
                let mut result = Box::from_raw(result as *mut ManuallyDrop<T>);
                *result = ManuallyDrop::new(f());
                mem::forget(result);
            })
        });
        let thread = join_handle.thread().clone();

        let join_state = JoinState::<T>::new(join_handle, result);
        let deferred_handle = Rc::new(RefCell::new(Some(join_state)));
        let my_handle = deferred_handle.clone();

        self.scope.defer_inner(move || {
            let state = mem::replace(deferred_handle.borrow_mut().deref_mut(), None);
            if let Some(state) = state {
                state.join().map(|_| ())
            } else {
                Ok(())
            }
        });

        Ok(ScopedJoinHandle {
            inner: my_handle,
            thread: thread,
            _marker: PhantomData,
        })
    }
}

impl<'a, T: Send + 'a> ScopedJoinHandle<'a, T> {
    /// Waits for the associated thread to finish.
    ///
    /// If the child thread panics, [`Err`] is returned with the parameter given to [`panic`].
    ///
    /// [`Err`]: https://doc.rust-lang.org/std/result/enum.Result.html#variant.Err
    /// [`panic`]: https://doc.rust-lang.org/std/macro.panic.html
    ///
    /// # Panics
    ///
    /// This function may panic on some platforms if a thread attempts to join itself or otherwise
    /// may create a deadlock with joining threads.
    pub fn join(self) -> thread::Result<T> {
        let state = mem::replace(self.inner.borrow_mut().deref_mut(), None);
        state.unwrap().join()
    }

    /// Gets the underlying [`std::thread::Thread`] handle.
    ///
    /// [`std::thread::Thread`]: https://doc.rust-lang.org/std/thread/struct.Thread.html
    pub fn thread(&self) -> &thread::Thread {
        &self.thread
    }
}

impl<'a> Drop for Scope<'a> {
    fn drop(&mut self) {
        // Actually, there should be no deferred functions left to be run.
        self.drop_all().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::{BufRead, BufReader};
use std::path::{PathBuf, Path};
use std::fs::File;
use std::collections::HashSet;
use object::Object;
use object::File as OFile;
use memmap::{Mmap, Protection};
use gimli::*;
use regex::Regex;
use rustc_demangle::demangle;
/// So far from my tests the test executable is the first compilation unit in
/// the DWARF debug information with the future ones being libraries and rustc.
const TEST_CU_OFFSET: usize = 0;

pub type FuncLength = u64;

/// Describes a function as low_pc, high_pc and bool representing is_test.
type FuncDesc = (u64, u64, bool);

#[derive(Debug, Clone, Copy)]
pub enum LineType {
    /// Entry of function known to be a test
    TestEntry(FuncLength),
    /// Entry of function. May or may not be test
    FunctionEntry(FuncLength),
    /// Standard statement
    Statement,
    /// Condition
    Condition,
    /// Unknown type
    Unknown,
}

#[derive(Debug, Clone)]
pub struct TracerData {
    pub path: PathBuf,
    pub line: u64,
    pub address: u64,
    pub trace_type: LineType,
    pub hits: u64,
}

fn line_is_traceable(file: &PathBuf, line: u64) -> bool {
    let mut result = false;
    if line > 0 {
        // Module imports are flagged as debuggable. But are always ran so meaningless!
        let reg: Regex = Regex::new(r"(:?^|\s)mod\s+\w+;").unwrap();
        if let Ok(f) = File::open(file) {
            let reader = BufReader::new(&f);
            if let Some(Ok(l)) = reader.lines().nth((line - 1) as usize) {
                result = !reg.is_match(l.as_ref());
            }
        }
    }
    result
}

/// Finds all function entry points and returns a vector
/// This will identify definite tests, but may be prone to false negatives.
/// TODO Potential to trace all function calls from __test::main and find addresses of interest
fn get_entry_points<T: Endianity>(debug_info: &CompilationUnitHeader<T>) -> Vec<FuncDesc> {
    let mut result:Vec<FuncDesc> = Vec::new();

    result
}

fn get_line_addresses<Endian: Endianity>(project: &Path, obj: &OFile) -> Result<Vec<TracerData>>  {
    let mut result: Vec<TracerData> = Vec::new();

    let debug_info = obj.get_section(".debug_info").unwrap_or(&[]);
    let debug_info = DebugInfo::<Endian>::new(debug_info);
    let cu = debug_info.header_from_offset(DebugInfoOffset(TEST_CU_OFFSET))?;

    let addr_size = cu.address_size();
    let entries = get_entry_points(&cu);

    let debug_line = obj.get_section(".debug_line").unwrap_or(&[]);
    let debug_line = DebugLine::<Endian>::new(debug_line);

    let prog = debug_line.program(DebugLineOffset(TEST_CU_OFFSET), addr_size, None, None)?;
    let (cprog, seq) = prog.sequences()?;
    for s in &seq {
        let mut sm = cprog.resume_from(s);
        while let Ok(Some((ref header, &ln_row))) = sm.next_row() {
            if let Some(file) = ln_row.file(header) {
                let mut path = PathBuf::new();

                if let Some(dir) = file.directory(header) {
                    if let Ok(temp) = String::from_utf8(dir.to_bytes().to_vec()) {
                        path.push(temp);
                    }
                }
                // Source is part of project so we cover it.
                if path.starts_with(project) {
                    if let Some(file) = ln_row.file(header) {
                        // If we can't map to line, we can't trace it.
                        let line = ln_row.line().unwrap_or(0);
                        let file = file.path_name();
                        // We now need to filter out lines which are meaningless to trace.

                        if let Ok(file) = String::from_utf8(file.to_bytes().to_vec()) {
                            path.push(file);
                            if !line_is_traceable(&path, line) {
                                continue;
                            }
                            let data = TracerData {
                                path: path,
                                line: line,
                                address: ln_row.address(),
                                trace_type: LineType::Unknown,
                                hits: 0u64
                            };
                            result.push(data);
                        }
                    }
                }
            }
        }
    }
    // Due to rust being a higher level language multiple instructions may map
    // to the same line. This prunes these to just the first instruction address
    let mut check: HashSet<(&Path, u64)> = HashSet::new();
    let result = result.iter()
                       .filter(|x| check.insert((x.path.as_path(), x.line)))
                       .map(|x| x.clone())
                       .collect::<Vec<TracerData>>();
    Ok(result)
}

/// Generates a list of lines we want to trace the coverage of. Used to instrument the
/// traces into the test executable
pub fn generate_tracer_data(manifest: &Path, test: &Path) -> io::Result<Vec<TracerData>> {
    let file = File::open(test)?;
    let file = Mmap::open(&file, Protection::Read)?;
    if let Ok(obj) = OFile::parse(unsafe {file.as_slice() }) {

        let data = if obj.is_little_endian() {
            get_line_addresses::<LittleEndian>(manifest, &obj)
        } else {
            get_line_addresses::<BigEndian>(manifest, &obj)
        };
        data.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Error while parsing"))
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}
<commit_msg>Now identify LineTypes function and test entry.<commit_after>use std::io;
use std::io::{BufRead, BufReader};
use std::path::{PathBuf, Path};
use std::ffi::CString;
use std::ops::Deref;
use std::fs::File;
use std::collections::HashSet;
use object::Object;
use object::File as OFile;
use memmap::{Mmap, Protection};
use gimli::*;
use regex::Regex;
use rustc_demangle::demangle;
/// So far from my tests the test executable is the first compilation unit in
/// the DWARF debug information with the future ones being libraries and rustc.
const TEST_CU_OFFSET: usize = 0;

/// Describes a function as low_pc, high_pc and bool representing is_test.
type FuncDesc = (u64, u64, bool);

#[derive(Debug, Clone, Copy)]
pub enum LineType {
    /// Entry of function known to be a test
    TestEntry(u64),
    /// Entry of function. May or may not be test
    FunctionEntry(u64),
    /// Standard statement
    Statement,
    /// Condition
    Condition,
    /// Unknown type
    Unknown,
}

#[derive(Debug, Clone)]
pub struct TracerData {
    pub path: PathBuf,
    pub line: u64,
    pub address: u64,
    pub trace_type: LineType,
    pub hits: u64,
}

fn line_is_traceable(file: &PathBuf, line: u64) -> bool {
    let mut result = false;
    if line > 0 {
        // Module imports are flagged as debuggable. But are always ran so meaningless!
        let reg: Regex = Regex::new(r"(:?^|\s)mod\s+\w+;").unwrap();
        if let Ok(f) = File::open(file) {
            let reader = BufReader::new(&f);
            if let Some(Ok(l)) = reader.lines().nth((line - 1) as usize) {
                result = !reg.is_match(l.as_ref());
            }
        }
    }
    result
}

fn generate_func_desc<T: Endianity>(die: &DebuggingInformationEntry<T>,
                                    debug_str: &DebugStr<T>) -> Result<FuncDesc> {
    let mut is_test = false;
    let low = die.attr_value(DW_AT_low_pc)?;
    let high = die.attr_value(DW_AT_high_pc)?;
    let linkage = die.attr_value(DW_AT_linkage_name)?;

    // Low is a program counter address so stored in an Addr
    let low = match low {
        Some(AttributeValue::Addr(x)) => x,
        _ => 0u64,
    };
    // High is an offset from the base pc, therefore is u64 data.
    let high = match high {
        Some(AttributeValue::Udata(x)) => x,
        _ => 0u64,
    };
    if let Some(AttributeValue::DebugStrRef(offset)) = linkage {
        let empty = CString::new("").unwrap();
        let name = debug_str.get_str(offset).unwrap_or(empty.deref());
        // go from CStr to Owned String
        let name = name.to_str().unwrap_or("");
        let name = demangle(name).to_string();
        // Simplest test is whether it's in tests namespace.
        // Rust guidelines recommend all tests are in a tests module.
        is_test = name.contains("tests::");
        // May need further tests in future for completeness.
    }

    Ok((low, high, is_test))
}

/// Finds all function entry points and returns a vector
/// This will identify definite tests, but may be prone to false negatives.
/// TODO Potential to trace all function calls from __test::main and find addresses of interest
fn get_entry_points<T: Endianity>(debug_info: &CompilationUnitHeader<T>,
                                  debug_abbrev: &Abbreviations,
                                  debug_str: &DebugStr<T>) -> Vec<FuncDesc> {
    let mut result:Vec<FuncDesc> = Vec::new();
    let mut cursor = debug_info.entries(debug_abbrev);
    // skip compilation unit root.
    let _ = cursor.next_entry();
    while let Ok(Some((delta, node))) = cursor.next_dfs() {
        // Function DIE
        if node.tag() == DW_TAG_subprogram {

            if let Ok(fd) = generate_func_desc(&node, &debug_str) {
                result.push(fd);
            }
        }
    }
    result
}

fn get_line_addresses<Endian: Endianity>(project: &Path, obj: &OFile) -> Result<Vec<TracerData>>  {
    let mut result: Vec<TracerData> = Vec::new();

    let debug_info = obj.get_section(".debug_info").unwrap_or(&[]);
    let debug_info = DebugInfo::<Endian>::new(debug_info);
    let debug_abbrev = obj.get_section(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = DebugAbbrev::<Endian>::new(debug_abbrev);
    let debug_strings = obj.get_section(".debug_str").unwrap_or(&[]);
    let debug_strings = DebugStr::<Endian>::new(debug_strings);
    let cu = debug_info.header_from_offset(DebugInfoOffset(TEST_CU_OFFSET))?;

    let addr_size = cu.address_size();
    let entries = if let Ok(abbr) = cu.abbreviations(debug_abbrev) {
        get_entry_points(&cu, &abbr, &debug_strings)
            .iter()
            .map(|&(a, b, c)| {
                if c {
                    (a, LineType::TestEntry(b))
                } else {
                    (a, LineType::FunctionEntry(b))
                }
            }).collect()
    } else {
        Vec::<(u64, LineType)>::new()
    };

    let debug_line = obj.get_section(".debug_line").unwrap_or(&[]);
    let debug_line = DebugLine::<Endian>::new(debug_line);

    let prog = debug_line.program(DebugLineOffset(TEST_CU_OFFSET), addr_size, None, None)?;
    let (cprog, seq) = prog.sequences()?;
    for s in &seq {
        let mut sm = cprog.resume_from(s);
        while let Ok(Some((ref header, &ln_row))) = sm.next_row() {
            if let Some(file) = ln_row.file(header) {
                let mut path = PathBuf::new();

                if let Some(dir) = file.directory(header) {
                    if let Ok(temp) = String::from_utf8(dir.to_bytes().to_vec()) {
                        path.push(temp);
                    }
                }
                // Source is part of project so we cover it.
                if path.starts_with(project) {
                    if let Some(file) = ln_row.file(header) {
                        // If we can't map to line, we can't trace it.
                        let line = ln_row.line().unwrap_or(0);
                        let file = file.path_name();
                        // We now need to filter out lines which are meaningless to trace.

                        if let Ok(file) = String::from_utf8(file.to_bytes().to_vec()) {
                            path.push(file);
                            if !line_is_traceable(&path, line) {
                                continue;
                            }
                            let address = ln_row.address();

                            let desc = entries.iter()
                                              .filter(|&&(addr, _)| addr == address )
                                              .map(|&(a, t)| t)
                                              .nth(0)
                                              .unwrap_or(LineType::Unknown);
                            let data = TracerData {
                                path: path,
                                line: line,
                                address: address,
                                trace_type: desc,
                                hits: 0u64
                            };
                            result.push(data);
                        }
                    }
                }
            }
        }
    }
    // Due to rust being a higher level language multiple instructions may map
    // to the same line. This prunes these to just the first instruction address
    let mut check: HashSet<(&Path, u64)> = HashSet::new();
    let result = result.iter()
                       .filter(|x| check.insert((x.path.as_path(), x.line)))
                       .map(|x| x.clone())
                       .collect::<Vec<TracerData>>();
    Ok(result)
}

/// Generates a list of lines we want to trace the coverage of. Used to instrument the
/// traces into the test executable
pub fn generate_tracer_data(manifest: &Path, test: &Path) -> io::Result<Vec<TracerData>> {
    let file = File::open(test)?;
    let file = Mmap::open(&file, Protection::Read)?;
    if let Ok(obj) = OFile::parse(unsafe {file.as_slice() }) {

        let data = if obj.is_little_endian() {
            get_line_addresses::<LittleEndian>(manifest, &obj)
        } else {
            get_line_addresses::<BigEndian>(manifest, &obj)
        };
        data.map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "Error while parsing"))
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}
<|endoftext|>


<commit_before>use gl;
use std::os::raw::c_void;
use std::process::exit;
use std::sync::mpsc;

pub use glfw::{self, Action, Context, CursorMode, Key, MouseButton};

pub type Keyboard = mpsc::Receiver<(Key, Action)>;
pub type Mouse = mpsc::Receiver<(MouseButton, Action)>;
pub type MouseMove = mpsc::Receiver<[f64; 2]>;
pub type Scroll = mpsc::Receiver<[f64; 2]>;

pub fn with_window<Init: Fn(u32, u32, Keyboard, Mouse, MouseMove, Scroll) -> Result<Box<FnMut() -> bool>, String>>(dim: Option<(u32, u32)>, title: &'static str, init: Init) {
  let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

  // OpenGL hint
  glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
  glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
  glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));

  let (mut window, events, w, h) = if let Some((w, h)) = dim {
    let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed)
      .expect("Failed to create GLFW window.");

    (window, events, w, h)
  } else {
    glfw.with_primary_monitor(|glfw, monitor| {
      let monitor = monitor.unwrap();
      let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
      let (w, h) = (vmode.width, vmode.height);
      let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");

      (window, events, w, h)
    })
  };

  window.make_current();
  if cfg!(feature = "release") {
    window.set_cursor_mode(CursorMode::Disabled);
    window.set_key_polling(true);
  } else {
    window.set_cursor_pos_polling(true);
    window.set_mouse_button_polling(true);
    window.set_scroll_polling(true);
  }

  // init OpenGL
  gl::load_with(|s| window.get_proc_address(s) as *const c_void);

  info!("using resolution {}x{}", w, h);

  // create channels to stream keyboard and mouse events
  let (kbd_snd, kbd_rcv) = mpsc::channel();
  let (mouse_snd, mouse_rcv) = mpsc::channel();
  let (mouse_move_snd, mouse_move_rcv) = mpsc::channel();
  let (scroll_snd, scroll_rcv) = mpsc::channel();

  match init(w, h, kbd_rcv, mouse_rcv, mouse_move_rcv, scroll_rcv) {
    Ok(mut run) => {
      while !window.should_close() {
        glfw.poll_events();

        for (_, event) in glfw::flush_messages(&events) {
          match event {
              glfw::WindowEvent::Key(key, _, action, _) => {
                let _ = kbd_snd.send((key, action));
              },
              glfw::WindowEvent::MouseButton(button, action, _) => {
                let _ = mouse_snd.send((button, action));
              },
              glfw::WindowEvent::CursorPos(x, y) => {
                let _ = mouse_move_snd.send([x, y]);
              },
              glfw::WindowEvent::Scroll(x, y) => {
                let _ = scroll_snd.send([x, y]);
              },
              _ => {},
          }
        }

        let alive = run();
        window.swap_buffers();

        if !alive {
          window.set_should_close(true);
          break;
        }
      }
    },
    Err(e) => {
      err!("unable to initialize application");
      err!("{}", e);
      exit(1);
    }
  }
}
<commit_msg>Fixed events polling.<commit_after>use gl;
use std::os::raw::c_void;
use std::process::exit;
use std::sync::mpsc;

pub use glfw::{self, Action, Context, CursorMode, Key, MouseButton};

pub type Keyboard = mpsc::Receiver<(Key, Action)>;
pub type Mouse = mpsc::Receiver<(MouseButton, Action)>;
pub type MouseMove = mpsc::Receiver<[f64; 2]>;
pub type Scroll = mpsc::Receiver<[f64; 2]>;

pub fn with_window<Init: Fn(u32, u32, Keyboard, Mouse, MouseMove, Scroll) -> Result<Box<FnMut() -> bool>, String>>(dim: Option<(u32, u32)>, title: &'static str, init: Init) {
  let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();

  // OpenGL hint
  glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
  glfw.window_hint(glfw::WindowHint::ContextVersionMajor(3));
  glfw.window_hint(glfw::WindowHint::ContextVersionMinor(3));

  let (mut window, events, w, h) = if let Some((w, h)) = dim {
    let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::Windowed)
      .expect("Failed to create GLFW window.");

    (window, events, w, h)
  } else {
    glfw.with_primary_monitor(|glfw, monitor| {
      let monitor = monitor.unwrap();
      let vmode = monitor.get_video_mode().expect("primary monitor’s video mode");
      let (w, h) = (vmode.width, vmode.height);
      let (window, events) = glfw.create_window(w, h, title, glfw::WindowMode::FullScreen(monitor)).expect("Failed to create GLFW window.");

      (window, events, w, h)
    })
  };

  window.make_current();

  if cfg!(feature = "release") {
    window.set_cursor_mode(CursorMode::Disabled);
  }

  window.set_key_polling(true);
  window.set_cursor_pos_polling(true);
  window.set_mouse_button_polling(true);
  window.set_scroll_polling(true);

  // init OpenGL
  gl::load_with(|s| window.get_proc_address(s) as *const c_void);

  info!("using resolution {}x{}", w, h);

  // create channels to stream keyboard and mouse events
  let (kbd_snd, kbd_rcv) = mpsc::channel();
  let (mouse_snd, mouse_rcv) = mpsc::channel();
  let (mouse_move_snd, mouse_move_rcv) = mpsc::channel();
  let (scroll_snd, scroll_rcv) = mpsc::channel();

  match init(w, h, kbd_rcv, mouse_rcv, mouse_move_rcv, scroll_rcv) {
    Ok(mut run) => {
      while !window.should_close() {
        glfw.poll_events();

        for (_, event) in glfw::flush_messages(&events) {
          match event {
              glfw::WindowEvent::Key(key, _, action, _) => {
                let _ = kbd_snd.send((key, action));
              },
              glfw::WindowEvent::MouseButton(button, action, _) => {
                let _ = mouse_snd.send((button, action));
              },
              glfw::WindowEvent::CursorPos(x, y) => {
                let _ = mouse_move_snd.send([x, y]);
              },
              glfw::WindowEvent::Scroll(x, y) => {
                let _ = scroll_snd.send([x, y]);
              },
              _ => {},
          }
        }

        let alive = run();
        window.swap_buffers();

        if !alive {
          window.set_should_close(true);
          break;
        }
      }
    },
    Err(e) => {
      err!("unable to initialize application");
      err!("{}", e);
      exit(1);
    }
  }
}
<|endoftext|>