<commit_before>//imports
use std::collections::HashMap;
use std::collections::TreeMap;
use std::io::BufferedReader;
use std::io::File;

///rust all this set's challenges
fn main(){
	println!("set one ::");
	//challenge_one();
	//challenge_two();
	challenge_three();
	challenge_four();
	//challenge_five();
	//challenge_six();
	//challenge_seven();
	//challenge_eight();
}

//challenges
/// solution for challenge one
fn challenge_one(){
	//println!("challenge one ::");
	//params
	let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
	let desired = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t";
	//get result
	let result = hexstr_tob64str( input);
	//print info
	//println!("input: {}", input);
	println!("\tresult: {}", result);
	println!("\tresult == desired: {}", result.as_slice() == desired);}

/// solution for challenge two
fn challenge_two(){
	println!("challenge two ::");
	//params
	let input_a = "1c0111001f010100061a024b53535009181c";
	let input_b = "686974207468652062756c6c277320657965";
	let desired = "746865206b696420646f6e277420706c6179";
	//convert to bytes
	let a_bytes = hexstr_tobytes( input_a);
	let b_bytes = hexstr_tobytes( input_b);
	//apply xor
	let result_bytes = xor_bytes(
		a_bytes.as_slice(), b_bytes.as_slice());
	//convert to string
	let result = bytes_tohexstr( result_bytes.as_slice());
	//print info
	println!("\tresult: {}", result);
	println!("\tresult == desired: {}", result.as_slice() == desired);}

/// solution for challenge three
fn challenge_three(){
	println!("challenge three ::");
	//params
	let input =
		"1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736";
	let extractions = crack_xor_cipher( input);
	print!("extractions:");
	print!("cipher :: message :: rating");
	for ( &cipher, ( message, rating)) in extractions.iter() {
		print!("{:02x} :: {} :: {:.2f}", cipher, message, rating);}}

/// solution for challenge four
fn challenge_four(){
	let lines = read_lines( "data/4.txt");
	println!("challenge four ::");}

/// solution for challenge five
fn challenge_five(){
	println!("challenge five ::");}

/// solution for challenge six
fn challenge_six(){
	println!("challenge six ::");}

/// solution for challenge seven
fn challenge_seven(){
	println!("challenge seven ::");}

/// solution for challenge eight
fn challenge_eight(){
	println!("challenge eight ::");}

//conversion functions
/// convert a hex string into base64
fn hexstr_tob64str( input: &str) -> String {
	//vars
	let bytes = hexstr_tobytes( input);
	let b64_codes : Vec<u8> = bytes_tob64codes( bytes.as_slice());
	return b64codes_tob64str( b64_codes.as_slice());
	}

/// convert a hex string into a byte vector
fn hexstr_tobytes( input: &str) -> Vec<u8> {
	let mut i = 0;
	let mut bytes : Vec<u8> = Vec::new();
	//parse bytes
	while i < input.len() {
		//current byte we're parsing
		let mut byte = 0u8;
		//parse first half
		byte += hex_toi( input.char_at( i));
		byte <<= 4;
		i += 1;
		//break if byte is \nincomplete
		if i == input.len() {
			bytes.push( byte);
			break;}
		//parse second half
		byte += hex_toi( input.char_at( i));
		//add byte
		bytes.push( byte);
		i += 1;}
	return bytes;}

fn bytes_tohexstr( bytes : &[u8]) -> String {
	let mut result = String::new();
	for &byte in bytes.iter() {
		let half1 = ( byte >> 4) & 0b1111;
		let half2 = byte & 0b1111;
		result.push_char( hexcode_tochar( half1));
		result.push_char( hexcode_tochar( half2));}
	return result;}

/// convert a byte string into b64 codes
fn bytes_tob64codes( bytes : &[u8]) -> Vec<u8> {
	let mut codes : Vec<u8> = Vec::new();
	//write bytes into b64 codes
	let mut leftover: u8 = 0;
	for i in range( 0, bytes.len()) {
		let byte = bytes[ i];
		match i % 3 {
			0 => {
				codes.push( ( byte >> 2));
				leftover = byte & 0b11;}
			1 => {
				codes.push( ( (leftover << 4) + (byte >> 4)));
				leftover = byte & 0b1111;}
			_ => {
				codes.push( ( (leftover << 2) + (byte >> 6)));
				codes.push( ( byte & 0b111111));}}}
	return codes;}

fn b64codes_tob64str( codes : &[u8]) -> String {
	let mut result = String::new();
	//convert b64 codes into string
	for i in range( 0, codes.len()) {
		result.push_char( b64code_tochar( codes[ i]));}
	return result;}

/// convert a hex char its corresponding int
fn hex_toi( character : char) -> u8 {
	match character {
		'0'..'9' => (character as u8) - ('0' as u8) + 0,
		'a'..'f' => (character as u8) - ('a' as u8) + 10,
		_ => fail!("error: input contained non-hex chars")}}

/// convert a base64 code into its corresponding char
fn b64code_tochar( code : u8) -> char {
	match code {
		00..25 => ( code - 00 + ('A' as u8)) as char,
		26..51 => ( code - 26 + ('a' as u8)) as char,
		52..61 => ( code - 52 + ('0' as u8)) as char,
		62 => '+',
		63 => '/',
		_ => fail!("error: code out of range")}}

/// convert a hec
fn hexcode_tochar( code : u8) -> char {
	match code {
		00..09 => ( code - 00 + ('0' as u8)) as char,
		10..15 => ( code - 10 + ('a' as u8)) as char,
		_ => fail!("error: code out of range")}}

//utilities
/// xor two byte arrays
fn xor_bytes( a : &[u8], b : &[u8]) -> Vec<u8> {
	let size = std::cmp::min( a.len(), b.len());
	let mut result = Vec::new();
	for i in range( 0, size) {
		result.push( a[i] ^ b[i]);}
	return result;}

fn score_bytes( bytes : &[u8]) -> TreeMap<u8, u8> {
	let mut table : TreeMap<u8, u8> = TreeMap::new();
	for &byte in bytes.iter() {
		let new_count =
			match table.find( &byte) {
				Some( count) => count + 1,
				None => 1};
		table.insert( byte, new_count);}
	return table;}

/// single byte xor cipher
fn byte_cipher( original : &[u8], cipher : u8) -> Vec<u8> {
	let mut result = Vec::new();
	for &byte in original.iter() {
		result.push( byte ^ cipher);}
	return result;}

fn crack_xor_cipher( input : &str) -> HashMap< u8, ( String, f32)> {
	//convert input to bytes
	let input_bytes = hexstr_tobytes( input);
	//create score table
	let input_scores = score_bytes( input_bytes.as_slice());
	println!("score table: {}", input_scores);
	//find top scores
	let mut top_scores : Vec<u8> = Vec::new();
	let scores_cap = 3;
	for &value in input_scores.values() {
		top_scores.push( value);}
	top_scores.sort();
	top_scores.reverse();
	let top_scores = top_scores.slice_to( scores_cap);
	println!("top {} scores: {}", scores_cap, top_scores);
	//find bytes that match top scores
	let mut common_bytes : Vec<u8> = Vec::new();
	for ( &byte, score) in input_scores.iter() {
		if top_scores.contains( score) {
			common_bytes.push( byte);}}
	//result of above:
	//  most common bytes in input_bytes: { 120: 6, 55: 5, 54: 3 }
	let common_bytes = common_bytes.as_slice();
	println!("common bytes: {}", common_bytes);
	//let common_chars = [' ','e','t','a','o','i','n','s','h','r','d','l','u'];
	let common_chars = [' ', 'e', 't', 'a', 'o', 'i'];
	let mut extractions : HashMap< u8, ( String, f32)> = HashMap::new();
	let rating_cap : f32 = 0.8;
	for &common_byte in common_bytes.iter() {
		for &common_char in common_chars.iter() {
			let common_char_byte = common_char.to_ascii().to_byte();
			let cipher_byte = common_char_byte ^ common_byte;
			if extractions.contains_key( &cipher_byte) {
				continue;}
			//create attempt
			let attempt_bytes = byte_cipher( input_bytes.as_slice(), cipher_byte);
			let attempt_ascii = attempt_bytes.as_slice().to_ascii();
			let attempt = attempt_ascii.as_str_ascii();
			//try to filter attempt
			let rating  = rate_attempt( attempt);
			if rating > rating_cap {
				extractions.insert(
					cipher_byte, ( String::from_str( attempt), rating));
				println!("{:02x}, '{}' :: {} :: {}",
					common_byte, common_char, attempt, rating);}}}
	return extractions;}

/// rate the likelihood a string is a good decoding attempt
fn rate_attempt( attempt : &str) -> f32 {
	let good_chars = "abcdefghijklmnopqrstuvwxyz ,.?!\'\"";
	let neut_chars = "()[]{}<>-=_+:;/@#$%^&*~`";
	let mut positive : f32 = 0.0;
	let mut negative : f32 = 0.0;
	let count = attempt.len();
	//count good and (probably) bad chars
	for attempt_char in attempt.chars() {
		let char_lower = attempt_char.to_lowercase();
		if good_chars.contains_char( char_lower) {
			positive += 1.0;}
		else if ! neut_chars.contains_char( char_lower) {
			negative += 1.0;}}
	let numerator = positive.powi( 2) - negative.powi( 2);
	let denominator = count.to_f32().unwrap().powi( 2);
	return numerator / denominator;}

fn read_lines( filename : &str) -> Vec<String> {
	// Create a path to the desired file
	let path = Path::new( filename);
	let file = File::open( &path);
	let mut reader = BufferedReader::new( file);

	let mut result : Vec<String> = Vec::new();
	for line_result in reader.lines() {
		if ! line_result.is_ok() {
			fail!( "reading a line failed");}
		let line = line_result.unwrap();
		let line_stripped = line.as_slice().trim_chars('\n');
		result.push( String::from_str( line_stripped));}
	return result;}
<commit_msg>finished challenge four<commit_after>//imports
use std::collections::TreeMap;
use std::io::BufferedReader;
use std::io::File;

///rust all this set's challenges
fn main(){
	println!("set one ::");
	//challenge_one();
	//challenge_two();
	//challenge_three();
	challenge_four();
	//challenge_five();
	//challenge_six();
	//challenge_seven();
	//challenge_eight();
}

//challenges
/// solution for challenge one
fn challenge_one(){
	//println!("challenge one ::");
	//params
	let input = "49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d";
	let desired = "SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t";
	//get result
	let result = hexstr_tob64str( input);
	//print info
	//println!("input: {}", input);
	println!("\tresult: {}", result);
	println!("\tresult == desired: {}", result.as_slice() == desired);}

/// solution for challenge two
fn challenge_two(){
	println!("challenge two ::");
	//params
	let input_a = "1c0111001f010100061a024b53535009181c";
	let input_b = "686974207468652062756c6c277320657965";
	let desired = "746865206b696420646f6e277420706c6179";
	//convert to bytes
	let a_bytes = hexstr_tobytes( input_a);
	let b_bytes = hexstr_tobytes( input_b);
	//apply xor
	let result_bytes = xor_bytes(
		a_bytes.as_slice(), b_bytes.as_slice());
	//convert to string
	let result = bytes_tohexstr( result_bytes.as_slice());
	//print info
	println!("\tresult: {}", result);
	println!("\tresult == desired: {}", result.as_slice() == desired);}

/// solution for challenge three
fn challenge_three(){
	println!("challenge three ::");
	//params
	let input =
		"1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736";
	let extractions = crack_xor_cipher( input);
	println!("extractions:");
	println!("cipher :: message :: rating");
	for ( &cipher, &( ref message, ref rating)) in extractions.iter() {
		println!("{:02x} :: {} :: {:.2f}", cipher, message, *rating);}}

/// solution for challenge four
fn challenge_four(){
	println!("challenge four ::");
	let lines = read_lines( "data/4.txt");
	let mut i : int = 0;
	for ref line in lines.iter() {
		let extractions = crack_xor_cipher( line.as_slice());
		if ! extractions.is_empty() {
			println!("extractions for line {}:", i);
			for ( &cipher, &( ref message, ref rating)) in extractions.iter() {
				println!("{:02x} :: {} :: {:.2f}\n", cipher, message, *rating);}}
		i += 1;}}

/// solution for challenge five
fn challenge_five(){
	println!("challenge five ::");}

/// solution for challenge six
fn challenge_six(){
	println!("challenge six ::");}

/// solution for challenge seven
fn challenge_seven(){
	println!("challenge seven ::");}

/// solution for challenge eight
fn challenge_eight(){
	println!("challenge eight ::");}

//conversion functions
/// convert a hex string into base64
fn hexstr_tob64str( input: &str) -> String {
	//vars
	let bytes = hexstr_tobytes( input);
	let b64_codes : Vec<u8> = bytes_tob64codes( bytes.as_slice());
	return b64codes_tob64str( b64_codes.as_slice());
	}

/// convert a hex string into a byte vector
fn hexstr_tobytes( input: &str) -> Vec<u8> {
	let mut i = 0;
	let mut bytes : Vec<u8> = Vec::new();
	//parse bytes
	while i < input.len() {
		//current byte we're parsing
		let mut byte = 0u8;
		//parse first half
		byte += hex_toi( input.char_at( i));
		byte <<= 4;
		i += 1;
		//break if byte is \nincomplete
		if i == input.len() {
			bytes.push( byte);
			break;}
		//parse second half
		byte += hex_toi( input.char_at( i));
		//add byte
		bytes.push( byte);
		i += 1;}
	return bytes;}

fn bytes_tohexstr( bytes : &[u8]) -> String {
	let mut result = String::new();
	for &byte in bytes.iter() {
		let half1 = ( byte >> 4) & 0b1111;
		let half2 = byte & 0b1111;
		result.push_char( hexcode_tochar( half1));
		result.push_char( hexcode_tochar( half2));}
	return result;}

/// convert a byte string into b64 codes
fn bytes_tob64codes( bytes : &[u8]) -> Vec<u8> {
	let mut codes : Vec<u8> = Vec::new();
	//write bytes into b64 codes
	let mut leftover: u8 = 0;
	for i in range( 0, bytes.len()) {
		let byte = bytes[ i];
		match i % 3 {
			0 => {
				codes.push( ( byte >> 2));
				leftover = byte & 0b11;}
			1 => {
				codes.push( ( (leftover << 4) + (byte >> 4)));
				leftover = byte & 0b1111;}
			_ => {
				codes.push( ( (leftover << 2) + (byte >> 6)));
				codes.push( ( byte & 0b111111));}}}
	return codes;}

fn b64codes_tob64str( codes : &[u8]) -> String {
	let mut result = String::new();
	//convert b64 codes into string
	for i in range( 0, codes.len()) {
		result.push_char( b64code_tochar( codes[ i]));}
	return result;}

/// convert a hex char its corresponding int
fn hex_toi( character : char) -> u8 {
	match character {
		'0'..'9' => (character as u8) - ('0' as u8) + 0,
		'a'..'f' => (character as u8) - ('a' as u8) + 10,
		_ => fail!("error: input contained non-hex chars")}}

/// convert a base64 code into its corresponding char
fn b64code_tochar( code : u8) -> char {
	match code {
		00..25 => ( code - 00 + ('A' as u8)) as char,
		26..51 => ( code - 26 + ('a' as u8)) as char,
		52..61 => ( code - 52 + ('0' as u8)) as char,
		62 => '+',
		63 => '/',
		_ => fail!("error: code out of range")}}

/// convert a hec
fn hexcode_tochar( code : u8) -> char {
	match code {
		00..09 => ( code - 00 + ('0' as u8)) as char,
		10..15 => ( code - 10 + ('a' as u8)) as char,
		_ => fail!("error: code out of range")}}

//utilities
/// xor two byte arrays
fn xor_bytes( a : &[u8], b : &[u8]) -> Vec<u8> {
	let size = std::cmp::min( a.len(), b.len());
	let mut result = Vec::new();
	for i in range( 0, size) {
		result.push( a[i] ^ b[i]);}
	return result;}

fn score_bytes( bytes : &[u8]) -> TreeMap<u8, u8> {
	let mut table : TreeMap<u8, u8> = TreeMap::new();
	for &byte in bytes.iter() {
		let new_count =
			match table.find( &byte) {
				Some( count) => count + 1,
				None => 1};
		table.insert( byte, new_count);}
	return table;}

/// single byte xor cipher
fn byte_cipher( original : &[u8], cipher : u8) -> Vec<u8> {
	let mut result = Vec::new();
	for &byte in original.iter() {
		result.push( byte ^ cipher);}
	return result;}

fn crack_xor_cipher( input : &str) -> TreeMap< u8, (String, f32)> {
	//convert input to bytes
	let input_bytes = hexstr_tobytes( input);
	//create score table
	let input_scores = score_bytes( input_bytes.as_slice());
	//println!("score table: {}", input_scores);
	//find top scores
	let mut top_scores : Vec<u8> = Vec::new();
	let scores_cap = 3;
	for &value in input_scores.values() {
		top_scores.push( value);}
	top_scores.sort();
	top_scores.reverse();
	let top_scores = top_scores.slice_to( scores_cap);
	//println!("top {} scores: {}", scores_cap, top_scores);
	//find bytes that match top scores
	let mut common_bytes : Vec<u8> = Vec::new();
	for ( &byte, score) in input_scores.iter() {
		if top_scores.contains( score) {
			common_bytes.push( byte);}}
	//result of above:
	//  most common bytes in input_bytes: { 120: 6, 55: 5, 54: 3 }
	let common_bytes = common_bytes.as_slice();
	//println!("common bytes: {}", common_bytes);
	//let common_chars = [' ','e','t','a','o','i','n','s','h','r','d','l','u'];
	let common_chars = [' ', 'e', 't', 'a', 'o', 'i'];
	let mut extractions : TreeMap< u8, (String, f32)> = TreeMap::new();
	let rating_cap : f32 = 0.8;
	for &common_byte in common_bytes.iter() {
		for &common_char in common_chars.iter() {
			let common_char_byte = common_char.to_ascii().to_byte();
			let cipher_byte = common_char_byte ^ common_byte;
			if extractions.contains_key( &cipher_byte) {
				continue;}
			//create attempt
			let attempt_bytes = byte_cipher( input_bytes.as_slice(), cipher_byte);
			let attempt_slice = attempt_bytes.as_slice();
			if ! attempt_slice.is_ascii() {
				continue;}
			let attempt_ascii = attempt_slice.to_ascii();
			let attempt = attempt_ascii.as_str_ascii();
			for &trimchar in ['\n',' ','\t'].iter() {
				attempt.trim_chars( trimchar);}
			//try to filter attempt
			let rating  = rate_attempt( attempt);
			if rating > rating_cap {
				extractions.insert(
					cipher_byte, ( String::from_str( attempt), rating));}}}
	return extractions;}

/// rate the likelihood a string is a good decoding attempt
fn rate_attempt( attempt : &str) -> f32 {
	let good_chars = "abcdefghijklmnopqrstuvwxyz ,.?!\'\"";
	let neut_chars = "()[]{}<>-=_+:;/@#$%^&*~`";
	let mut positive : f32 = 0.0;
	let mut negative : f32 = 0.0;
	let count = attempt.len();
	//count good and (probably) bad chars
	for attempt_char in attempt.chars() {
		let char_lower = attempt_char.to_lowercase();
		if good_chars.contains_char( char_lower) {
			positive += 1.0;}
		else if ! neut_chars.contains_char( char_lower) {
			negative += 1.0;}}
	let numerator = positive.powi( 2) - negative.powi( 2);
	let denominator = count.to_f32().unwrap().powi( 2);
	return numerator / denominator;}

fn read_lines( filename : &str) -> Vec<String> {
	// Create a path to the desired file
	let path = Path::new( filename);
	let file = File::open( &path);
	let mut reader = BufferedReader::new( file);

	let mut result : Vec<String> = Vec::new();
	for line_result in reader.lines() {
		if ! line_result.is_ok() {
			fail!( "reading a line failed");}
		let line = line_result.unwrap();
		let line_stripped = line.as_slice().trim_chars('\n');
		result.push( String::from_str( line_stripped));}
	return result;}
<|endoftext|>


<commit_before>#![feature(plugin, custom_derive, custom_attribute)]
#![plugin(rocket_codegen)]
extern crate rocket;
extern crate serde;
extern crate itertools;

#[macro_use]
extern crate serde_derive;
extern crate rocket_contrib;

#[cfg(test)]
extern crate serde_json;

use rocket_contrib::Json;

use std::io;
use std::path::{Path, PathBuf};

use rocket::response::NamedFile;

mod automata;
use automata::{Dfa, Nfa, Unsanitary};

#[get("/")]
fn index() -> io::Result<NamedFile> {
    NamedFile::open("../frontend/build/index.html")
}

#[get("/<file..>")]
fn files(file: PathBuf) -> Option<NamedFile> {
    NamedFile::open(Path::new("../frontend/build/").join(file)).ok()
}

#[post("/submit", format = "application/json", data = "<data>")]
fn submit_nfa(data: Json<Nfa<Unsanitary>>) -> Json<Dfa> {
    Json(data.into_inner().check().unwrap().make_deterministic())
}

fn rocket() -> rocket::Rocket {
    rocket::ignite().mount("/", routes![index, submit_nfa, files])
}

fn main() {
    rocket().launch();
}

#[cfg(test)]
mod test {
    use super::rocket;
    use rocket::local::Client;
    use rocket::http::Status;
    use rocket::http::ContentType;

    use serde_json;
    use automata::*;

    /// Test home page ("/" or "/index.html")
    #[test]
    fn test_index() {
        let rocket = rocket();
        let client = Client::new(rocket).expect("valid rocket instance");
        let mut response = client.get("/").dispatch();

        assert_eq!(response.status(), Status::Ok);
        assert_eq!(response.content_type(), Some(ContentType::HTML));
        assert!(
            response
                .body_string()
                .unwrap()
                .contains("You need to enable JavaScript to run this app.")
        );
        //assert!(response.headers().get_one("X-Special").is_some());

        let response = client.get("/index.html").dispatch();
        assert_eq!(response.status(), Status::Ok);
        assert_eq!(response.content_type(), Some(ContentType::HTML));
    }

    #[test]
    fn test_not_found() {
        let rocket = rocket();
        let client = Client::new(rocket).expect("valid rocket instance");
        let response = client.get("/asdfasdfasdf").dispatch();
        assert_eq!(response.status(), Status::NotFound);
    }

    /// Test POSTing of NFA in JSON
    #[test]
    fn test_submit_nfa() {
        let rocket = rocket();
        let client = Client::new(rocket).expect("valid rocket instance");

        //Test good JSON
        let input = r#"{
            "start": "1",
            "alphabet": ["a", "b"],
            "nodes": {
                "1": {
                    "a": ["1", "2"],
                    "b": ["1"]
                },
                "2": {
                    "a": ["3"],
                    "b": ["3"]
                },
                "3": {
                    "a": ["1"],
                    "b": ["2"]
                }
            },
            "final_states": ["3"]
        }"#;

        let mut response = client
            .post("/submit")
            .body(input)
            .header(ContentType::JSON)
            .dispatch();

        assert_eq!(response.status(), Status::Ok);

        //Convert JSON to DFA
        let body_string: &str = &(response.body_string()).unwrap();
        let dfa_thing: Dfa = serde_json::from_str(body_string).unwrap();
    }

    #[test]
    fn test_empty_nfa() {
        let rocket = rocket();
        let client = Client::new(rocket).expect("valid rocket instance");
        let response = client
            .post("/submit")
            .body("{}")
            .header(ContentType::JSON)
            .dispatch();

        assert_eq!(response.status(), Status::BadRequest);
    }

}
<commit_msg>minimise output<commit_after>#![feature(plugin, custom_derive, custom_attribute)]
#![plugin(rocket_codegen)]
extern crate rocket;
extern crate serde;
extern crate itertools;

#[macro_use]
extern crate serde_derive;
extern crate rocket_contrib;

#[cfg(test)]
extern crate serde_json;

use rocket_contrib::Json;

use std::io;
use std::path::{Path, PathBuf};

use rocket::response::NamedFile;

mod automata;
use automata::{Dfa, Nfa, Unsanitary};

#[get("/")]
fn index() -> io::Result<NamedFile> {
    NamedFile::open("../frontend/build/index.html")
}

#[get("/<file..>")]
fn files(file: PathBuf) -> Option<NamedFile> {
    NamedFile::open(Path::new("../frontend/build/").join(file)).ok()
}

#[post("/submit", format = "application/json", data = "<data>")]
fn submit_nfa(data: Json<Nfa<Unsanitary>>) -> Json<Dfa> {
    Json(data.into_inner().check().unwrap().make_deterministic().minimise())
}

fn rocket() -> rocket::Rocket {
    rocket::ignite().mount("/", routes![index, submit_nfa, files])
}

fn main() {
    rocket().launch();
}

#[cfg(test)]
mod test {
    use super::rocket;
    use rocket::local::Client;
    use rocket::http::Status;
    use rocket::http::ContentType;

    use serde_json;
    use automata::*;

    /// Test home page ("/" or "/index.html")
    #[test]
    fn test_index() {
        let rocket = rocket();
        let client = Client::new(rocket).expect("valid rocket instance");
        let mut response = client.get("/").dispatch();

        assert_eq!(response.status(), Status::Ok);
        assert_eq!(response.content_type(), Some(ContentType::HTML));
        assert!(
            response
                .body_string()
                .unwrap()
                .contains("You need to enable JavaScript to run this app.")
        );
        //assert!(response.headers().get_one("X-Special").is_some());

        let response = client.get("/index.html").dispatch();
        assert_eq!(response.status(), Status::Ok);
        assert_eq!(response.content_type(), Some(ContentType::HTML));
    }

    #[test]
    fn test_not_found() {
        let rocket = rocket();
        let client = Client::new(rocket).expect("valid rocket instance");
        let response = client.get("/asdfasdfasdf").dispatch();
        assert_eq!(response.status(), Status::NotFound);
    }

    /// Test POSTing of NFA in JSON
    #[test]
    fn test_submit_nfa() {
        let rocket = rocket();
        let client = Client::new(rocket).expect("valid rocket instance");

        //Test good JSON
        let input = r#"{
            "start": "1",
            "alphabet": ["a", "b"],
            "nodes": {
                "1": {
                    "a": ["1", "2"],
                    "b": ["1"]
                },
                "2": {
                    "a": ["3"],
                    "b": ["3"]
                },
                "3": {
                    "a": ["1"],
                    "b": ["2"]
                }
            },
            "final_states": ["3"]
        }"#;

        let mut response = client
            .post("/submit")
            .body(input)
            .header(ContentType::JSON)
            .dispatch();

        assert_eq!(response.status(), Status::Ok);

        //Convert JSON to DFA
        let body_string: &str = &(response.body_string()).unwrap();
        let dfa_thing: Dfa = serde_json::from_str(body_string).unwrap();
    }

    #[test]
    fn test_empty_nfa() {
        let rocket = rocket();
        let client = Client::new(rocket).expect("valid rocket instance");
        let response = client
            .post("/submit")
            .body("{}")
            .header(ContentType::JSON)
            .dispatch();

        assert_eq!(response.status(), Status::BadRequest);
    }

}
<|endoftext|>


<commit_before>extern crate crypto;

use std::fs::File;
use std::io::{BufReader, BufRead};

use crypto::aessafe::AesSafe128Encryptor;
use crypto::symmetriccipher::BlockEncryptor;

fn hex_to_u8(a: u8) -> u8 {
    match a {
        b'0'...b'9' => a - b'0',
        b'a'...b'h' => a - b'a' + 10,
        _           => 0
    }
}

fn u8_to_hex(a: u8) -> u8 {
    match a {
        0...9   => a + b'0',
        10...15 => a + b'a' - 10,
        _       => 0
    }
}

fn vec_u8_from_hex_string(s: &String) -> Vec<u8> {
    s.as_bytes().chunks(2).map(|a| hex_to_u8(a[0]) * 16 + hex_to_u8(a[1])).collect()
}

fn vec_u8_to_hex_string(v: &Vec<u8>) -> String {
    v.iter().map(|u| [u8_to_hex(u / 16), u8_to_hex(u % 16)])
        .fold(String::from(""), |mut acc, item| {acc.push(item[0] as char); acc.push(item[1] as char); acc})
}

fn u8_slice_inc(v: &mut [u8]) {
    let mut inc = 1;

    for i in (0..v.len()).rev() {
        if v[i] == 0xff && inc == 1 {
            v[i] = 0;
            inc = 1;
        } else {
            v[i] += inc;
            inc = 0;
        }
    }
}

fn ctr_crypt(key: &[u8], iv: &[u8], msg: &[u8]) -> Vec<u8> {
    let mut v = Vec::with_capacity(msg.len());
    // TODO: find better way to copy arrays
    let mut prev = &mut [0; 16];

    for i in 0..16 {
        prev[i] = iv[i];
    }

    let mut m_i = &mut [0; 16];
    let encryptor = AesSafe128Encryptor::new(key);

    for c_i in msg.chunks(16) {
        encryptor.encrypt_block(prev, &mut m_i[..]);

        for i in 0..c_i.len() {
            v.push(c_i[i] ^ m_i[i]);
        }

        u8_slice_inc(prev);
    }

    v
}

fn ctr_decrypt(key: &Vec<u8>, msg: &Vec<u8>) -> Vec<u8> {
    let (iv, msg) = msg.split_at(16);
    ctr_crypt(&key[..], iv, &msg[..])
}

fn ctr_encrypt(key: &Vec<u8>, iv: &Vec<u8>, msg: &Vec<u8>) -> Vec<u8> {
    let mut v = Vec::with_capacity(iv.len() + msg.len());
    v.extend(iv.iter().cloned());
    v.extend(ctr_crypt(&key[..], &iv[..], &msg[..]));
    v
}

fn main() {
    // decode
    let input_file = File::open("in.txt").unwrap();
    let input = BufReader::new(input_file);
    let input: Vec<_> = input.lines().filter_map(|res| res.ok())
        .filter(|s| s.len() > 0)
        .map(|s| vec_u8_from_hex_string(&s))
        .collect();
    let input: Vec<_> = input.chunks(2).collect();

    for v in input {
        println!("key: {:?}", v[0]);
        println!("cpt: {:?}", v[1]);

        let msg = ctr_decrypt(&v[0], &v[1]);
        println!("msg: {:?}", msg);

        let pt = String::from_utf8(msg).unwrap();
        println!("pt: {:?}", pt);

        println!("");
    }

    // encode
    let input_file = File::open("in_clear.txt").unwrap();
    let input = BufReader::new(input_file);
    let input: Vec<_> = input.lines().filter_map(|res| res.ok())
        .filter(|s| s.len() > 0)
        .collect();
    let input: Vec<_> = input.chunks(3).collect();

    for v in input {
        let key = vec_u8_from_hex_string(&v[0]);
        let iv = vec_u8_from_hex_string(&v[1]);
        let pt = &v[2];

        println!("key: {:?}", key);
        println!("IV: {:?}", iv);
        println!("pt: {:?}", pt);

        let ct = ctr_encrypt(&key, &iv, &pt.as_bytes().iter().cloned().collect());
        println!("msg: {:?}", ct);

        let hex = vec_u8_to_hex_string(&ct);
        println!("ct: {:?}", hex);

        println!("");
    }
}

<commit_msg>use clone_from_slice (unstable)<commit_after>#![feature(clone_from_slice)]

extern crate crypto;

use std::fs::File;
use std::io::{BufReader, BufRead};

use crypto::aessafe::AesSafe128Encryptor;
use crypto::symmetriccipher::BlockEncryptor;

fn hex_to_u8(a: u8) -> u8 {
    match a {
        b'0'...b'9' => a - b'0',
        b'a'...b'h' => a - b'a' + 10,
        _           => 0
    }
}

fn u8_to_hex(a: u8) -> u8 {
    match a {
        0...9   => a + b'0',
        10...15 => a + b'a' - 10,
        _       => 0
    }
}

fn vec_u8_from_hex_string(s: &String) -> Vec<u8> {
    s.as_bytes().chunks(2).map(|a| hex_to_u8(a[0]) * 16 + hex_to_u8(a[1])).collect()
}

fn vec_u8_to_hex_string(v: &Vec<u8>) -> String {
    v.iter().map(|u| [u8_to_hex(u / 16), u8_to_hex(u % 16)])
        .fold(String::from(""), |mut acc, item| {acc.push(item[0] as char); acc.push(item[1] as char); acc})
}

fn u8_slice_inc(v: &mut [u8]) {
    let mut inc = 1;

    for i in (0..v.len()).rev() {
        if v[i] == 0xff && inc == 1 {
            v[i] = 0;
            inc = 1;
        } else {
            v[i] += inc;
            inc = 0;
        }
    }
}

fn ctr_crypt(key: &[u8], iv: &[u8], msg: &[u8]) -> Vec<u8> {
    let mut v = Vec::with_capacity(msg.len());
    // TODO: find better way to copy arrays
    let mut prev = &mut [0; 16];
    prev.clone_from_slice(iv);

    let mut m_i = &mut [0; 16];
    let encryptor = AesSafe128Encryptor::new(key);

    for c_i in msg.chunks(16) {
        encryptor.encrypt_block(prev, &mut m_i[..]);

        for i in 0..c_i.len() {
            v.push(c_i[i] ^ m_i[i]);
        }

        u8_slice_inc(prev);
    }

    v
}

fn ctr_decrypt(key: &Vec<u8>, msg: &Vec<u8>) -> Vec<u8> {
    let (iv, msg) = msg.split_at(16);
    ctr_crypt(&key[..], iv, &msg[..])
}

fn ctr_encrypt(key: &Vec<u8>, iv: &Vec<u8>, msg: &Vec<u8>) -> Vec<u8> {
    let mut v = Vec::with_capacity(iv.len() + msg.len());
    v.extend(iv.iter().cloned());
    v.extend(ctr_crypt(&key[..], &iv[..], &msg[..]));
    v
}

fn main() {
    // decode
    let input_file = File::open("in.txt").unwrap();
    let input = BufReader::new(input_file);
    let input: Vec<_> = input.lines().filter_map(|res| res.ok())
        .filter(|s| s.len() > 0)
        .map(|s| vec_u8_from_hex_string(&s))
        .collect();
    let input: Vec<_> = input.chunks(2).collect();

    for v in input {
        println!("key: {:?}", v[0]);
        println!("cpt: {:?}", v[1]);

        let msg = ctr_decrypt(&v[0], &v[1]);
        println!("msg: {:?}", msg);

        let pt = String::from_utf8(msg).unwrap();
        println!("pt: {:?}", pt);

        println!("");
    }

    // encode
    let input_file = File::open("in_clear.txt").unwrap();
    let input = BufReader::new(input_file);
    let input: Vec<_> = input.lines().filter_map(|res| res.ok())
        .filter(|s| s.len() > 0)
        .collect();
    let input: Vec<_> = input.chunks(3).collect();

    for v in input {
        let key = vec_u8_from_hex_string(&v[0]);
        let iv = vec_u8_from_hex_string(&v[1]);
        let pt = &v[2];

        println!("key: {:?}", key);
        println!("IV: {:?}", iv);
        println!("pt: {:?}", pt);

        let ct = ctr_encrypt(&key, &iv, &pt.as_bytes().iter().cloned().collect());
        println!("msg: {:?}", ct);

        let hex = vec_u8_to_hex_string(&ct);
        println!("ct: {:?}", hex);

        println!("");
    }
}

<|endoftext|>


<commit_before>use crate::*;
use futures::future::join;
use serde::Serialize;
use std::fs;
use std::process::Command;
use structopt::StructOpt;

#[derive(Serialize, Debug, Clone, StructOpt)]
pub struct NetworkConfig {
    /// Delay in milliseconds
    #[structopt(long, default_value = "0")]
    pub delay: u64,
    /// Jitter in milliseconds
    #[structopt(long, default_value = "0")]
    pub jitter: u64,
    /// Delay correlation percentage (range: [0.0-100.0])
    #[structopt(long, default_value = "0")]
    pub delay_correlation: f32,
    /// Independent chance of packet loss (range: [0.0-100.0])
    #[structopt(long, default_value = "0")]
    pub random_loss: f32,
    /// Random packet loss correlation (range: [0.0-100.0])
    #[structopt(long, default_value = "0")]
    pub random_loss_correlation: f32,
    /// Network loopback interface.
    #[structopt(long, default_value = "lo")]
    #[serde(skip)]
    pub interface: String,
    /// Rate limit of simulated wire. Defaults to 1Gigabit.
    #[structopt(long, default_value = "1073741824")]
    pub rate_limit_kbps: usize,
    #[structopt(long, default_value = "1000")]
    pub packet_limit: usize,
}

impl Default for NetworkConfig {
    fn default() -> Self {
        Self {
            delay: 0,
            jitter: 0,
            delay_correlation: 0.0,
            random_loss: 0.0,
            random_loss_correlation: 0.0,
            interface: String::from("lo"),
            rate_limit_kbps: 1073741824,
            packet_limit: 1000,
        }
    }
}

impl NetworkConfig {
    fn reset(&self) {
        Command::new("tc")
            .args(&["qdisc", "del", "dev", self.interface.as_str(), "root"])
            .output()
            .expect("resetting network loopback interface");
    }

    fn apply(&self) {
        let output = Command::new("tc")
            .args(&[
                "qdisc",
                "add",
                "dev",
                &self.interface,
                "root",
                "netem",
                "delay",
                &format!("{}", self.delay / 2 * 1000),
                &format!("{}", self.jitter / 2 * 1000),
                &format!("{}", self.delay_correlation),
                "loss",
                "random",
                &format!("{}%", self.random_loss / 2.),
                &format!("{}%", self.random_loss_correlation),
                "rate",
                &format!("{}kbit", self.rate_limit_kbps),
                "limit",
                &format!("{}", self.packet_limit / 2),
            ])
            .output()
            .expect("applying delay");
        assert_eq!(
            output.status.code(),
            Some(0),
            "Failure apllying: {:#?}",
            output
        )
    }
}

#[derive(StructOpt)]
pub struct Options {
    #[structopt(flatten)]
    pub network_config: NetworkConfig,
    #[structopt(flatten)]
    pub client_options: client::Options,
    /// Whether to launch a server in this process at the client's expected
    /// server address.
    #[structopt(long)]
    pub start_server: bool,
    #[structopt(long, short = "o")]
    pub output: Option<String>,
}

async fn run_client(options: &Options) -> Result<client::Summary> {
    client::client_main(options.client_options.clone()).await
}

async fn run(options: &Options) -> Result<client::Summary> {
    let server_options = server::Options {
        address: options.client_options.address,
        protocol: options.client_options.protocol,
    };

    let (results, server_result) =
        join(run_client(&options), server::server_main(server_options)).await;

    server_result.and_then(|_| results)
}

pub async fn runner_main(options: Options) -> Result<client::Summary> {
    options.network_config.reset();
    options.network_config.apply();

    let results = run(&options).await;

    options.network_config.reset();

    let results = results?;

    if let Some(output) = options.output {
        let writer = fs::File::create(output)?;
        let mut writer = csv::Writer::from_writer(writer);

        for report in &results.trip_reports {
            writer.serialize(report)?;
        }
    }

    Ok(results)
}
<commit_msg>Respect `start_server`<commit_after>use crate::*;
use futures::future::join;
use serde::Serialize;
use std::fs;
use std::process::Command;
use structopt::StructOpt;

#[derive(Serialize, Debug, Clone, StructOpt)]
pub struct NetworkConfig {
    /// Delay in milliseconds
    #[structopt(long, default_value = "0")]
    pub delay: u64,
    /// Jitter in milliseconds
    #[structopt(long, default_value = "0")]
    pub jitter: u64,
    /// Delay correlation percentage (range: [0.0-100.0])
    #[structopt(long, default_value = "0")]
    pub delay_correlation: f32,
    /// Independent chance of packet loss (range: [0.0-100.0])
    #[structopt(long, default_value = "0")]
    pub random_loss: f32,
    /// Random packet loss correlation (range: [0.0-100.0])
    #[structopt(long, default_value = "0")]
    pub random_loss_correlation: f32,
    /// Network loopback interface.
    #[structopt(long, default_value = "lo")]
    #[serde(skip)]
    pub interface: String,
    /// Rate limit of simulated wire. Defaults to 1Gigabit.
    #[structopt(long, default_value = "1073741824")]
    pub rate_limit_kbps: usize,
    #[structopt(long, default_value = "1000")]
    pub packet_limit: usize,
}

impl Default for NetworkConfig {
    fn default() -> Self {
        Self {
            delay: 0,
            jitter: 0,
            delay_correlation: 0.0,
            random_loss: 0.0,
            random_loss_correlation: 0.0,
            interface: String::from("lo"),
            rate_limit_kbps: 1073741824,
            packet_limit: 1000,
        }
    }
}

impl NetworkConfig {
    fn reset(&self) {
        Command::new("tc")
            .args(&["qdisc", "del", "dev", self.interface.as_str(), "root"])
            .output()
            .expect("resetting network loopback interface");
    }

    fn apply(&self) {
        let output = Command::new("tc")
            .args(&[
                "qdisc",
                "add",
                "dev",
                &self.interface,
                "root",
                "netem",
                "delay",
                &format!("{}", self.delay / 2 * 1000),
                &format!("{}", self.jitter / 2 * 1000),
                &format!("{}", self.delay_correlation),
                "loss",
                "random",
                &format!("{}%", self.random_loss / 2.),
                &format!("{}%", self.random_loss_correlation),
                "rate",
                &format!("{}kbit", self.rate_limit_kbps),
                "limit",
                &format!("{}", self.packet_limit / 2),
            ])
            .output()
            .expect("applying delay");
        assert_eq!(
            output.status.code(),
            Some(0),
            "Failure apllying: {:#?}",
            output
        )
    }
}

#[derive(StructOpt)]
pub struct Options {
    #[structopt(flatten)]
    pub network_config: NetworkConfig,
    #[structopt(flatten)]
    pub client_options: client::Options,
    /// Whether to launch a server in this process at the client's expected
    /// server address.
    #[structopt(long)]
    pub start_server: bool,
    #[structopt(long, short = "o")]
    pub output: Option<String>,
}

async fn run_client(options: &Options) -> Result<client::Summary> {
    client::client_main(options.client_options.clone()).await
}

async fn run(options: &Options) -> Result<client::Summary> {
    let server_options = server::Options {
        address: options.client_options.address,
        protocol: options.client_options.protocol,
    };

    let run_server = async move {
        if options.start_server {
            return server::server_main(server_options).await;
        }

        Ok(())
    };

    let (results, server_result) =
        join(run_client(&options), run_server).await;

    server_result.and_then(|_| results)
}

pub async fn runner_main(options: Options) -> Result<client::Summary> {
    options.network_config.reset();
    options.network_config.apply();

    let results = run(&options).await;

    options.network_config.reset();

    let results = results?;

    if let Some(output) = options.output {
        let writer = fs::File::create(output)?;
        let mut writer = csv::Writer::from_writer(writer);

        for report in &results.trip_reports {
            writer.serialize(report)?;
        }
    }

    Ok(results)
}
<|endoftext|>


<commit_before>extern crate bootstrap_rs as bootstrap;
extern crate fiber;
#[macro_use]
extern crate lazy_static;

use fiber::FiberId;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
use std::mem;
use std::sync::Mutex;
use std::time::{Duration, Instant};

thread_local! {
    static CONTEXT: RefCell<Context> = RefCell::new(Context { stack: Vec::new() });
}

lazy_static! {
    static ref CONTEXT_MAP: Mutex<HashMap<FiberId, Context>> = Mutex::new(HashMap::with_capacity(1024));
}

/// Swaps the currently tracked execution context with the specified context.
pub fn switch_context(old: FiberId, new: FiberId) {
    let mut context_map = CONTEXT_MAP.lock().expect("Unable to acquire lock on context map");

    let new_context = context_map.remove(&new).unwrap_or(Context { stack: Vec::new() });
    let old_context = with_context(move |context| {
        let mut new_context = new_context;
        mem::swap(context, &mut new_context);
        new_context
    });

    context_map.insert(old, old_context);
}

pub struct Stopwatch {
    name: &'static str,
}

impl Stopwatch {
    pub fn new(name: &'static str) -> Stopwatch {
        let data = StopwatchData {
            name: name,
            start_time: Instant::now(),
            budget: None,
            children: Vec::new(),
        };

        with_context(move |context| context.push(data));

        Stopwatch {
            name: name,
        }
    }

    pub fn with_budget(name: &'static str, budget: Duration) -> Stopwatch {
        let data = StopwatchData {
            name: name,
            start_time: Instant::now(),
            budget: Some(budget),
            children: Vec::new(),
        };

        with_context(move |context| context.push(data));

        Stopwatch {
            name: name,
        }
    }
}

impl Drop for Stopwatch {
    fn drop(&mut self) {
        with_context(|context| context.pop(self));
    }
}

#[derive(Debug)]
struct Context {
    stack: Vec<StopwatchData>,
}

impl Context {
    fn push(&mut self, data: StopwatchData) {
        self.stack.push(data);
    }

    fn pop(&mut self, current: &Stopwatch) {
        let end_time = Instant::now();

        let data = self.stack
            .pop()
            .unwrap_or_else(|| panic!("Stopwatch stack corrupted, no stopwatches left to pop, trying to pop \"{}\"", current.name));
        assert_eq!(data.name, current.name, "Stopwatch stack corrupted, mismatched stopwatch popped");

        let record = StopwatchRecord {
            name: data.name,
            start_time: data.start_time,
            end_time: end_time,
            budget: data.budget,
            children: data.children,
        };

        // If the budget was exceeded, then log record and its child hierarchy.
        if let Some(budget) = record.budget {
            assert!(record.duration().as_secs() == 0, "TODO: Support durations greater than 1 second");

            if record.duration() > budget {
                // TODO: What's a better way for stopwatch to handle logging? We don't want to
                // print to stdout, but we don't necessarily know what logging method a client
                // crate would want to use.
                println!(
                    "Budget for {} exceeded: Budget was {:?}, actual was {:?} (exceeded by {:?})",
                    record.name,
                    PrettyDuration(budget),
                    PrettyDuration(record.duration()),
                    PrettyDuration(record.duration() - budget));

                log_timing_hierarchy(&record, 1, record.duration());
            }
        }

        // Add record to parent's list of children if necessary.
        if let Some(parent) = self.stack.last_mut() {
            parent.children.push(record);
        }
    }
}

#[derive(Debug)]
struct StopwatchData {
    name: &'static str,
    start_time: Instant,
    budget: Option<Duration>,
    children: Vec<StopwatchRecord>,
}

#[derive(Debug)]
struct StopwatchRecord {
    name: &'static str,
    start_time: Instant,
    end_time: Instant,
    budget: Option<Duration>,
    children: Vec<StopwatchRecord>,
}

impl StopwatchRecord {
    fn duration(&self) -> Duration {
        self.end_time - self.start_time
    }
}

fn with_context<F, T>(func: F) -> T
    where F: FnOnce(&mut Context) -> T
{
    CONTEXT.with(move |context_cell| {
        let mut context = context_cell.borrow_mut();
        func(&mut *context)
    })
}

fn log_timing_hierarchy(record: &StopwatchRecord, depth: usize, root_time: Duration) {
    let record_time = record.duration();

    let record_percent = (record_time.subsec_nanos() as f32 / root_time.subsec_nanos() as f32) * 100.0;

    // Calculate self time.
    let child_time = record.children
        .iter()
        .fold(Duration::from_millis(0), |total, child| total + child.duration());
    let self_time = record_time - child_time;
    let self_percent = (self_time.subsec_nanos() as f32 / root_time.subsec_nanos() as f32) * 100.0;

    // Left-pad current record.
    // TODO: Use http://www.leftpad.io/ for this so that we don't have to maintain our own
    // left-pad implementation.
    for _ in 0..depth {
        print!("  ");
    }

    // Print current record.
    println!("{}: {:?} ({:.1}%)", record.name, PrettyDuration(record_time), record_percent);

    if record.children.len() > 0 {
        // Left-pad "self" entry
        for _ in 0..depth + 1 {
            print!("  ");
        }

        println!("Self: {:?} ({:.1}%)", PrettyDuration(self_time), self_percent);

        // Log children recursively.
        for child in &record.children {
            log_timing_hierarchy(child, depth + 1, root_time);
        }
    }
}

pub struct PrettyDuration(pub Duration);

impl Debug for PrettyDuration {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        let millis = (self.0.subsec_nanos() / 1_000_000) % 1_000;
        let micros = (self.0.subsec_nanos() / 1_000) % 1_000;
        write!(formatter, "{}ms {}μs", millis, micros)
    }
}
<commit_msg>Teach PrettyDuration to handle durations longer than 1 second<commit_after>extern crate bootstrap_rs as bootstrap;
extern crate fiber;
#[macro_use]
extern crate lazy_static;

use fiber::FiberId;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::{self, Debug, Formatter};
use std::mem;
use std::sync::Mutex;
use std::time::{Duration, Instant};

thread_local! {
    static CONTEXT: RefCell<Context> = RefCell::new(Context { stack: Vec::new() });
}

lazy_static! {
    static ref CONTEXT_MAP: Mutex<HashMap<FiberId, Context>> = Mutex::new(HashMap::with_capacity(1024));
}

/// Swaps the currently tracked execution context with the specified context.
pub fn switch_context(old: FiberId, new: FiberId) {
    let mut context_map = CONTEXT_MAP.lock().expect("Unable to acquire lock on context map");

    let new_context = context_map.remove(&new).unwrap_or(Context { stack: Vec::new() });
    let old_context = with_context(move |context| {
        let mut new_context = new_context;
        mem::swap(context, &mut new_context);
        new_context
    });

    context_map.insert(old, old_context);
}

pub struct Stopwatch {
    name: &'static str,
}

impl Stopwatch {
    pub fn new(name: &'static str) -> Stopwatch {
        let data = StopwatchData {
            name: name,
            start_time: Instant::now(),
            budget: None,
            children: Vec::new(),
        };

        with_context(move |context| context.push(data));

        Stopwatch {
            name: name,
        }
    }

    pub fn with_budget(name: &'static str, budget: Duration) -> Stopwatch {
        let data = StopwatchData {
            name: name,
            start_time: Instant::now(),
            budget: Some(budget),
            children: Vec::new(),
        };

        with_context(move |context| context.push(data));

        Stopwatch {
            name: name,
        }
    }
}

impl Drop for Stopwatch {
    fn drop(&mut self) {
        with_context(|context| context.pop(self));
    }
}

#[derive(Debug)]
struct Context {
    stack: Vec<StopwatchData>,
}

impl Context {
    fn push(&mut self, data: StopwatchData) {
        self.stack.push(data);
    }

    fn pop(&mut self, current: &Stopwatch) {
        let end_time = Instant::now();

        let data = self.stack
            .pop()
            .unwrap_or_else(|| panic!("Stopwatch stack corrupted, no stopwatches left to pop, trying to pop \"{}\"", current.name));
        assert_eq!(data.name, current.name, "Stopwatch stack corrupted, mismatched stopwatch popped");

        let record = StopwatchRecord {
            name: data.name,
            start_time: data.start_time,
            end_time: end_time,
            budget: data.budget,
            children: data.children,
        };

        // If the budget was exceeded, then log record and its child hierarchy.
        if let Some(budget) = record.budget {
            if record.duration() > budget {
                // TODO: What's a better way for stopwatch to handle logging? We don't want to
                // print to stdout, but we don't necessarily know what logging method a client
                // crate would want to use.
                println!(
                    "Budget for {} exceeded: Budget was {:?}, actual was {:?} (exceeded by {:?})",
                    record.name,
                    PrettyDuration(budget),
                    PrettyDuration(record.duration()),
                    PrettyDuration(record.duration() - budget));

                log_timing_hierarchy(&record, 1, record.duration());
            }
        }

        // Add record to parent's list of children if necessary.
        if let Some(parent) = self.stack.last_mut() {
            parent.children.push(record);
        }
    }
}

#[derive(Debug)]
struct StopwatchData {
    name: &'static str,
    start_time: Instant,
    budget: Option<Duration>,
    children: Vec<StopwatchRecord>,
}

#[derive(Debug)]
struct StopwatchRecord {
    name: &'static str,
    start_time: Instant,
    end_time: Instant,
    budget: Option<Duration>,
    children: Vec<StopwatchRecord>,
}

impl StopwatchRecord {
    fn duration(&self) -> Duration {
        self.end_time - self.start_time
    }
}

fn with_context<F, T>(func: F) -> T
    where F: FnOnce(&mut Context) -> T
{
    CONTEXT.with(move |context_cell| {
        let mut context = context_cell.borrow_mut();
        func(&mut *context)
    })
}

fn log_timing_hierarchy(record: &StopwatchRecord, depth: usize, root_time: Duration) {
    let record_time = record.duration();

    let record_percent = (record_time.subsec_nanos() as f32 / root_time.subsec_nanos() as f32) * 100.0;

    // Calculate self time.
    let child_time = record.children
        .iter()
        .fold(Duration::from_millis(0), |total, child| total + child.duration());
    let self_time = record_time - child_time;
    let self_percent = (self_time.subsec_nanos() as f32 / root_time.subsec_nanos() as f32) * 100.0;

    // Left-pad current record.
    // TODO: Use http://www.leftpad.io/ for this so that we don't have to maintain our own
    // left-pad implementation.
    for _ in 0..depth {
        print!("  ");
    }

    // Print current record.
    println!("{}: {:?} ({:.1}%)", record.name, PrettyDuration(record_time), record_percent);

    if record.children.len() > 0 {
        // Left-pad "self" entry
        for _ in 0..depth + 1 {
            print!("  ");
        }

        println!("Self: {:?} ({:.1}%)", PrettyDuration(self_time), self_percent);

        // Log children recursively.
        for child in &record.children {
            log_timing_hierarchy(child, depth + 1, root_time);
        }
    }
}

pub struct PrettyDuration(pub Duration);

impl Debug for PrettyDuration {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        let secs = self.0.as_secs();
        let millis = (self.0.subsec_nanos() / 1_000_000) % 1_000;
        let micros = (self.0.subsec_nanos() / 1_000) % 1_000;
        if secs > 0 {
            write!(formatter, "{}s {}ms {}μs", secs, millis, micros)
        } else {
            write!(formatter, "{}ms {}μs", millis, micros)
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Data needed to style a Gecko document.

use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
use gecko_bindings::structs::{StyleSheetInfo, ServoStyleSheetInner};
use gecko_bindings::structs::nsIDocument;
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use malloc_size_of::MallocSizeOfOps;
use media_queries::{Device, MediaList};
use properties::ComputedValues;
use servo_arc::Arc;
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use stylesheets::{StylesheetContents, StylesheetInDocument};
use stylist::Stylist;

/// Little wrapper to a Gecko style sheet.
#[derive(Debug, Eq, PartialEq)]
pub struct GeckoStyleSheet(*const ServoStyleSheet);

impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
    fn to_media_list_key(&self) -> MediaListKey {
        use std::mem;
        unsafe {
            MediaListKey::from_raw(mem::transmute(self.0))
        }
    }
}

impl GeckoStyleSheet {
    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer.
    #[inline]
    pub unsafe fn new(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        bindings::Gecko_StyleSheet_AddRef(s);
        Self::from_addrefed(s)
    }

    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer that
    /// already holds a strong reference.
    #[inline]
    pub unsafe fn from_addrefed(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        GeckoStyleSheet(s)
    }

    /// Get the raw `ServoStyleSheet` that we're wrapping.
    pub fn raw(&self) -> &ServoStyleSheet {
        unsafe { &*self.0 }
    }

    fn inner(&self) -> &ServoStyleSheetInner {
        unsafe {
            &*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner)
        }
    }
}

impl Drop for GeckoStyleSheet {
    fn drop(&mut self) {
        unsafe { bindings::Gecko_StyleSheet_Release(self.0) };
    }
}

impl Clone for GeckoStyleSheet {
    fn clone(&self) -> Self {
        unsafe { bindings::Gecko_StyleSheet_AddRef(self.0) };
        GeckoStyleSheet(self.0)
    }
}

impl StylesheetInDocument for GeckoStyleSheet {
    fn contents(&self, _: &SharedRwLockReadGuard) -> &StylesheetContents {
        debug_assert!(!self.inner().mContents.mRawPtr.is_null());
        unsafe {
            let contents =
                (&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _;
            &*contents
        }
    }

    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
        use gecko_bindings::structs::ServoMediaList;
        use std::mem;

        unsafe {
            let servo_media_list =
                self.raw()._base.mMedia.mRawPtr as *const ServoMediaList;
            if servo_media_list.is_null() {
                return None;
            }
            let raw_list = &*(*servo_media_list).mRawList.mRawPtr;
            let list = Locked::<MediaList>::as_arc(mem::transmute(&raw_list));
            Some(list.read_with(guard))
        }
    }

    // All the stylesheets Servo knows about are enabled, because that state is
    // handled externally by Gecko.
    fn enabled(&self) -> bool {
        true
    }
}

/// The container for data that a Servo-backed Gecko document needs to style
/// itself.
pub struct PerDocumentStyleDataImpl {
    /// Rule processor.
    pub stylist: Stylist,
}

/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
/// and unexpected races while trying to mutate it.
pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);

impl PerDocumentStyleData {
    /// Create a dummy `PerDocumentStyleData`.
    pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
        let device = Device::new(pres_context);

        // FIXME(emilio, tlin): How is this supposed to work with XBL? This is
        // right now not always honored, see bug 1405543...
        //
        // Should we just force XBL Stylists to be NoQuirks?
        let quirks_mode = unsafe {
            (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode
        };

        PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
            stylist: Stylist::new(device, quirks_mode.into()),
        }))
    }

    /// Get an immutable reference to this style data.
    pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
        self.0.borrow()
    }

    /// Get an mutable reference to this style data.
    pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
        self.0.borrow_mut()
    }
}

impl PerDocumentStyleDataImpl {
    /// Recreate the style data if the stylesheets have changed.
    pub fn flush_stylesheets<E>(
        &mut self,
        guard: &SharedRwLockReadGuard,
        document_element: Option<E>,
    ) -> bool
    where
        E: TElement,
    {
        self.stylist.flush(
            &StylesheetGuards::same(guard),
            document_element,
        )
    }

    /// Returns whether private browsing is enabled.
    pub fn is_private_browsing_enabled(&self) -> bool {
        let doc =
            self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();
        unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
    }

    /// Get the default computed values for this document.
    pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
        self.stylist.device().default_computed_values_arc()
    }

    /// Returns whether visited links are enabled.
    fn visited_links_enabled(&self) -> bool {
        unsafe { bindings::Gecko_AreVisitedLinksEnabled() }
    }
    /// Returns whether visited styles are enabled.
    pub fn visited_styles_enabled(&self) -> bool {
        self.visited_links_enabled() && !self.is_private_browsing_enabled()
    }

    /// Measure heap usage.
    pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
        self.stylist.add_size_of(ops, sizes);
    }
}

unsafe impl HasFFI for PerDocumentStyleData {
    type FFIType = RawServoStyleSet;
}
unsafe impl HasSimpleFFI for PerDocumentStyleData {}
unsafe impl HasBoxFFI for PerDocumentStyleData {}
<commit_msg>style: Read visited links pref directly.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Data needed to style a Gecko document.

use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
use gecko_bindings::structs::{StyleSheetInfo, ServoStyleSheetInner, nsIDocument, self};
use gecko_bindings::sugar::ownership::{HasArcFFI, HasBoxFFI, HasFFI, HasSimpleFFI};
use invalidation::media_queries::{MediaListKey, ToMediaListKey};
use malloc_size_of::MallocSizeOfOps;
use media_queries::{Device, MediaList};
use properties::ComputedValues;
use servo_arc::Arc;
use shared_lock::{Locked, StylesheetGuards, SharedRwLockReadGuard};
use stylesheets::{StylesheetContents, StylesheetInDocument};
use stylist::Stylist;

/// Little wrapper to a Gecko style sheet.
#[derive(Debug, Eq, PartialEq)]
pub struct GeckoStyleSheet(*const ServoStyleSheet);

impl ToMediaListKey for ::gecko::data::GeckoStyleSheet {
    fn to_media_list_key(&self) -> MediaListKey {
        use std::mem;
        unsafe {
            MediaListKey::from_raw(mem::transmute(self.0))
        }
    }
}

impl GeckoStyleSheet {
    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer.
    #[inline]
    pub unsafe fn new(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        bindings::Gecko_StyleSheet_AddRef(s);
        Self::from_addrefed(s)
    }

    /// Create a `GeckoStyleSheet` from a raw `ServoStyleSheet` pointer that
    /// already holds a strong reference.
    #[inline]
    pub unsafe fn from_addrefed(s: *const ServoStyleSheet) -> Self {
        debug_assert!(!s.is_null());
        GeckoStyleSheet(s)
    }

    /// Get the raw `ServoStyleSheet` that we're wrapping.
    pub fn raw(&self) -> &ServoStyleSheet {
        unsafe { &*self.0 }
    }

    fn inner(&self) -> &ServoStyleSheetInner {
        unsafe {
            &*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner)
        }
    }
}

impl Drop for GeckoStyleSheet {
    fn drop(&mut self) {
        unsafe { bindings::Gecko_StyleSheet_Release(self.0) };
    }
}

impl Clone for GeckoStyleSheet {
    fn clone(&self) -> Self {
        unsafe { bindings::Gecko_StyleSheet_AddRef(self.0) };
        GeckoStyleSheet(self.0)
    }
}

impl StylesheetInDocument for GeckoStyleSheet {
    fn contents(&self, _: &SharedRwLockReadGuard) -> &StylesheetContents {
        debug_assert!(!self.inner().mContents.mRawPtr.is_null());
        unsafe {
            let contents =
                (&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _;
            &*contents
        }
    }

    fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
        use gecko_bindings::structs::ServoMediaList;
        use std::mem;

        unsafe {
            let servo_media_list =
                self.raw()._base.mMedia.mRawPtr as *const ServoMediaList;
            if servo_media_list.is_null() {
                return None;
            }
            let raw_list = &*(*servo_media_list).mRawList.mRawPtr;
            let list = Locked::<MediaList>::as_arc(mem::transmute(&raw_list));
            Some(list.read_with(guard))
        }
    }

    // All the stylesheets Servo knows about are enabled, because that state is
    // handled externally by Gecko.
    fn enabled(&self) -> bool {
        true
    }
}

/// The container for data that a Servo-backed Gecko document needs to style
/// itself.
pub struct PerDocumentStyleDataImpl {
    /// Rule processor.
    pub stylist: Stylist,
}

/// The data itself is an `AtomicRefCell`, which guarantees the proper semantics
/// and unexpected races while trying to mutate it.
pub struct PerDocumentStyleData(AtomicRefCell<PerDocumentStyleDataImpl>);

impl PerDocumentStyleData {
    /// Create a dummy `PerDocumentStyleData`.
    pub fn new(pres_context: RawGeckoPresContextOwned) -> Self {
        let device = Device::new(pres_context);

        // FIXME(emilio, tlin): How is this supposed to work with XBL? This is
        // right now not always honored, see bug 1405543...
        //
        // Should we just force XBL Stylists to be NoQuirks?
        let quirks_mode = unsafe {
            (*device.pres_context().mDocument.raw::<nsIDocument>()).mCompatMode
        };

        PerDocumentStyleData(AtomicRefCell::new(PerDocumentStyleDataImpl {
            stylist: Stylist::new(device, quirks_mode.into()),
        }))
    }

    /// Get an immutable reference to this style data.
    pub fn borrow(&self) -> AtomicRef<PerDocumentStyleDataImpl> {
        self.0.borrow()
    }

    /// Get an mutable reference to this style data.
    pub fn borrow_mut(&self) -> AtomicRefMut<PerDocumentStyleDataImpl> {
        self.0.borrow_mut()
    }
}

impl PerDocumentStyleDataImpl {
    /// Recreate the style data if the stylesheets have changed.
    pub fn flush_stylesheets<E>(
        &mut self,
        guard: &SharedRwLockReadGuard,
        document_element: Option<E>,
    ) -> bool
    where
        E: TElement,
    {
        self.stylist.flush(
            &StylesheetGuards::same(guard),
            document_element,
        )
    }

    /// Returns whether private browsing is enabled.
    pub fn is_private_browsing_enabled(&self) -> bool {
        let doc =
            self.stylist.device().pres_context().mDocument.raw::<nsIDocument>();
        unsafe { bindings::Gecko_IsPrivateBrowsingEnabled(doc) }
    }

    /// Get the default computed values for this document.
    pub fn default_computed_values(&self) -> &Arc<ComputedValues> {
        self.stylist.device().default_computed_values_arc()
    }

    /// Returns whether visited links are enabled.
    fn visited_links_enabled(&self) -> bool {
        unsafe { structs::StylePrefs_sVisitedLinksEnabled }
    }
    /// Returns whether visited styles are enabled.
    pub fn visited_styles_enabled(&self) -> bool {
        self.visited_links_enabled() && !self.is_private_browsing_enabled()
    }

    /// Measure heap usage.
    pub fn add_size_of(&self, ops: &mut MallocSizeOfOps, sizes: &mut ServoStyleSetSizes) {
        self.stylist.add_size_of(ops, sizes);
    }
}

unsafe impl HasFFI for PerDocumentStyleData {
    type FFIType = RawServoStyleSet;
}
unsafe impl HasSimpleFFI for PerDocumentStyleData {}
unsafe impl HasBoxFFI for PerDocumentStyleData {}
<|endoftext|>


<commit_before>use std::io::fs::File;

use gl;
use gl::types::GLuint;
use libc::c_void;

use image;
use image::Image;

use graphics::ImageSize;

/// Wraps OpenGL texture data.
/// The texture gets deleted when running out of scope.
pub struct Texture {
    id: GLuint,
    width: u32,
    height: u32,
}

impl Texture {
    /// Creates a new texture.
    #[inline(always)]
    pub fn new(id: GLuint, width: u32, height: u32) -> Texture {
        Texture {
            id: id,
            width: width,
            height: height,
        }
    }

    /// Gets the OpenGL id of the texture.
    #[inline(always)]
    pub fn get_id(&self) -> GLuint {
        self.id
    }

    /// Loads image from memory, the format is 8-bit greyscale.
    pub fn from_memory_alpha(buf: &[u8], width: u32, height: u32) -> Result<Texture, String> {
        let mut pixels = Vec::new();
        for alpha in buf.iter() {
            pixels.push(255);
            pixels.push(255);
            pixels.push(255);
            pixels.push(*alpha);
        }

        let mut id: GLuint = 0;
        unsafe {
            gl::GenTextures(1, &mut id);
            gl::BindTexture(gl::TEXTURE_2D, id);
            gl::TexParameteri(
                gl::TEXTURE_2D,
                gl::TEXTURE_MIN_FILTER,
                gl::LINEAR as i32
            );
            gl::TexParameteri(
                gl::TEXTURE_2D,
                gl::TEXTURE_MAG_FILTER,
                gl::LINEAR as i32
            );
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RGBA as i32,
                width as i32,
                height as i32,
                0,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                pixels.as_ptr() as *c_void
            );
        }

        Ok(Texture::new(id, width, height))
    }

    /// Loads image by relative file name to the asset root.
    pub fn from_path(path: &Path) -> Result<Texture, String> {
        let fin = File::open(path).unwrap();

        let img = match Image::load(fin, image::PNG) {
            Ok(img) => img,
            Err(e)  => return Err(format!("Could not load '{}': {}",
                path.filename_str().unwrap(), e)),
        };

        match img.colortype() {
            image::RGBA(8) => {},
            c => fail!("Unsupported color type {} in png", c),
        };

        let (width, height) = img.dimensions();

        let mut id: GLuint = 0;
        unsafe {
            gl::GenTextures(1, &mut id);
            gl::BindTexture(gl::TEXTURE_2D, id);
            gl::TexParameteri(
                gl::TEXTURE_2D,
                gl::TEXTURE_MIN_FILTER,
                gl::LINEAR as i32
            );
            gl::TexParameteri(
                gl::TEXTURE_2D,
                gl::TEXTURE_MAG_FILTER,
                gl::LINEAR as i32
            );
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RGBA as i32,
                width as i32,
                height as i32,
                0,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                img.raw_pixels().as_ptr() as *c_void
            );
        }

        Ok(Texture::new(id, width, height))
    }
}

impl Drop for Texture {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, [self.id].as_ptr());
        }
    }
}

impl ImageSize for Texture {
    fn get_size(&self) -> (u32, u32) {
        (self.width, self.height)
    }
}
<commit_msg>Upgraded to latest Rust<commit_after>use std::io::fs::File;

use gl;
use gl::types::GLuint;
use libc::c_void;

use image;
use image::Image;

use graphics::ImageSize;

/// Wraps OpenGL texture data.
/// The texture gets deleted when running out of scope.
pub struct Texture {
    id: GLuint,
    width: u32,
    height: u32,
}

impl Texture {
    /// Creates a new texture.
    #[inline(always)]
    pub fn new(id: GLuint, width: u32, height: u32) -> Texture {
        Texture {
            id: id,
            width: width,
            height: height,
        }
    }

    /// Gets the OpenGL id of the texture.
    #[inline(always)]
    pub fn get_id(&self) -> GLuint {
        self.id
    }

    /// Loads image from memory, the format is 8-bit greyscale.
    pub fn from_memory_alpha(buf: &[u8], width: u32, height: u32) -> Result<Texture, String> {
        let mut pixels = Vec::new();
        for alpha in buf.iter() {
            pixels.push(255);
            pixels.push(255);
            pixels.push(255);
            pixels.push(*alpha);
        }

        let mut id: GLuint = 0;
        unsafe {
            gl::GenTextures(1, &mut id);
            gl::BindTexture(gl::TEXTURE_2D, id);
            gl::TexParameteri(
                gl::TEXTURE_2D,
                gl::TEXTURE_MIN_FILTER,
                gl::LINEAR as i32
            );
            gl::TexParameteri(
                gl::TEXTURE_2D,
                gl::TEXTURE_MAG_FILTER,
                gl::LINEAR as i32
            );
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RGBA as i32,
                width as i32,
                height as i32,
                0,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                pixels.as_ptr() as *const c_void
            );
        }

        Ok(Texture::new(id, width, height))
    }

    /// Loads image by relative file name to the asset root.
    pub fn from_path(path: &Path) -> Result<Texture, String> {
        let fin = File::open(path).unwrap();

        let img = match Image::load(fin, image::PNG) {
            Ok(img) => img,
            Err(e)  => return Err(format!("Could not load '{}': {}",
                path.filename_str().unwrap(), e)),
        };

        match img.colortype() {
            image::RGBA(8) => {},
            c => fail!("Unsupported color type {} in png", c),
        };

        let (width, height) = img.dimensions();

        let mut id: GLuint = 0;
        unsafe {
            gl::GenTextures(1, &mut id);
            gl::BindTexture(gl::TEXTURE_2D, id);
            gl::TexParameteri(
                gl::TEXTURE_2D,
                gl::TEXTURE_MIN_FILTER,
                gl::LINEAR as i32
            );
            gl::TexParameteri(
                gl::TEXTURE_2D,
                gl::TEXTURE_MAG_FILTER,
                gl::LINEAR as i32
            );
            gl::TexImage2D(
                gl::TEXTURE_2D,
                0,
                gl::RGBA as i32,
                width as i32,
                height as i32,
                0,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                img.raw_pixels().as_ptr() as *const c_void
            );
        }

        Ok(Texture::new(id, width, height))
    }
}

impl Drop for Texture {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteTextures(1, [self.id].as_ptr());
        }
    }
}

impl ImageSize for Texture {
    fn get_size(&self) -> (u32, u32) {
        (self.width, self.height)
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Jerome Rasky <jerome@rasky.co>
//
// Licensed under the Apache License, version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     <http://www.apache.org/licenses/LICENSE-2.0>
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the
// License for the specific language concerning governing permissions and
// limitations under the License.
use std::io::prelude::*;

use std::io::BufReader;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::sync::atomic::{AtomicBool, Ordering};
use std::fs::File;
use std::iter::FromIterator;
use std::borrow::Borrow;
use std::thread::JoinHandle;
use std::collections::HashMap;

use std::env;
use std::io;
use std::thread;

use flx::{SearchBase, LineInfo};
use error::{StrError, StrResult};
use bis_c;

use types::*;
use constants::*;

pub fn start_threads(emit: Sender<Event>)
                     -> StrResult<(JoinHandle<()>, Arc<AtomicBool>)> {
    // mask sigint
    trys!(bis_c::mask_sigint(), "Failed to mask SIGINT");

    // start the sigint thread
    let signal_emit = emit.clone();
    thread::spawn(move || {
        read_signals(signal_emit);
    });

    // start reading history
    let history_emit = emit.clone();
    thread::spawn(move || {
        read_history(history_emit);
    });

    // start the input thread
    let input_stop = Arc::new(AtomicBool::new(false));
    let stop = input_stop.clone();
    let input_thread = thread::spawn(|| {
        read_input(emit, stop)
    });

    Ok((input_thread, input_stop))
}

fn read_history(emit: Sender<Event>) {
    let history_path = trysp!(env::var("HISTFILE"), "Failed to get bash history file");
    let input_file = BufReader::new(trysp!(File::open(history_path), "Cauld not open history file"));
    let mut count = -1.0;
    let base = SearchBase::from_iter(input_file.lines().map(|maybe| {
        count += 1.0;
        trace!("New line with count {}", count);
        LineInfo::new(maybe.expect("Failed to read line from file"), count)
    }));
    // if this fails, we can't search anything
    trysp!(emit.send(Event::SearchReady(base)), "Failed to emit search ready signal");
}

fn read_input(emit: Sender<Event>, stop: Arc<AtomicBool>) {
    // this thread is joined on quit, so none of its sends should fail
    let mut escape = None;

    // escape sequence tree, assume ANSI
    let mut control: HashMap<String, Option<Event>> = HashMap::default();
    control.insert(format!("["), None);
    control.insert(format!("[A"), Some(Event::KeyUp));
    control.insert(format!("[B"), Some(Event::KeyDown));

    // read characters
    for maybe_chr in io::stdin().chars() {
        match maybe_chr {
            Err(_) => {
                error!("Failed to read input, quitting");
                trysp!(emit.send(Event::Quit(false)), "Failed to emit quit signal");
                break;
            },
            Ok(ESC) => {
                escape = Some(String::default());
                trace!("Begin escape sequence");
            }
            Ok(chr) => {
                match escape {
                    None => {
                        if chr.is_control() {
                            match chr {
                                EOT => {
                                    // stop
                                    trysp!(emit.send(Event::Quit(false)),
                                           "Failed to send quit event");
                                },
                                CTRL_U => {
                                    // clear query
                                    trysp!(emit.send(Event::Clear),
                                           "Failed to send clear event");
                                },
                                '\n' => {
                                    // exit
                                    trysp!(emit.send(Event::Quit(true)),
                                           "Failed to send quit signal");
                                },
                                ESC => {
                                    // escape sequence
                                    escape = Some(format!(""));
                                }
                                _ => {
                                    // unknown control character
                                    trysp!(emit.send(Event::Bell),
                                           "Failed to send bell event");
                                }
                            }
                        } else {
                            trysp!(emit.send(Event::Input(chr)),
                                   "Failed to send character");
                        }
                    },
                    Some(mut seq) => {
                        seq.push(chr);
                        match control.get(&seq) {
                            None => {
                                // no possible escape sequence like this
                                trysp!(emit.send(Event::Bell),
                                       "Failed to send bell event");
                                trysp!(emit.send(Event::Input(chr)),
                                       "Failed to send character");
                                escape = None;
                            },
                            Some(&None) => {
                                // keep going
                                escape = Some(seq);
                            },
                            Some(&Some(ref event)) => {
                                // send the appropriate event
                                let cloned = trysp!(
                                    event.maybe_clone()
                                        .ok_or(StrError::new(
                                            "Event {:?} could not be cloned", None)),
                                    "Failed to create event");
                                trysp!(emit.send(cloned),
                                       "Failed to send escape event");
                                escape = None;
                            }
                        }
                    }
                }
            }
        }

        // check for requested stop
        if stop.load(Ordering::Relaxed) {
            debug!("Input thread exiting");
            break;
        }
    }
}

fn read_signals(emit: Sender<Event>) {
    // wait for a sigint
    trysp!(bis_c::wait_sigint(), "Failed to wait for sigint");

    debug!("Caught sigint");

    // send a quit signal
    let _ = emit.send(Event::Quit(false));
    // might happen after events is closed, so don't fail
}

pub fn start_query(emit: Sender<Event>, base: Arc<SearchBase>, query: Arc<String>) {
    let result = base.query::<&String>(query.borrow(), MATCH_NUMBER);
    let _ = emit.send(Event::Match(result, query)).and_then(|_| {
        trace!("Finished query");
        Ok(())
    });
    // don't panic on fail send, events might be already closed
}
<commit_msg>Add default history file path<commit_after>// Copyright 2015 Jerome Rasky <jerome@rasky.co>
//
// Licensed under the Apache License, version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//     <http://www.apache.org/licenses/LICENSE-2.0>
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied. See the
// License for the specific language concerning governing permissions and
// limitations under the License.
use std::io::prelude::*;

use std::io::BufReader;
use std::sync::Arc;
use std::sync::mpsc::Sender;
use std::sync::atomic::{AtomicBool, Ordering};
use std::fs::File;
use std::iter::FromIterator;
use std::borrow::Borrow;
use std::thread::JoinHandle;
use std::collections::HashMap;

use std::env;
use std::io;
use std::thread;

use flx::{SearchBase, LineInfo};
use error::{StrError, StrResult};
use bis_c;

use types::*;
use constants::*;

pub fn start_threads(emit: Sender<Event>)
                     -> StrResult<(JoinHandle<()>, Arc<AtomicBool>)> {
    // mask sigint
    trys!(bis_c::mask_sigint(), "Failed to mask SIGINT");

    // start the sigint thread
    let signal_emit = emit.clone();
    thread::spawn(move || {
        read_signals(signal_emit);
    });

    // start reading history
    let history_emit = emit.clone();
    thread::spawn(move || {
        read_history(history_emit);
    });

    // start the input thread
    let input_stop = Arc::new(AtomicBool::new(false));
    let stop = input_stop.clone();
    let input_thread = thread::spawn(|| {
        read_input(emit, stop)
    });

    Ok((input_thread, input_stop))
}

fn read_history(emit: Sender<Event>) {
    let history_path = match env::var("HISTFILE") {
        Ok(path) => path,
        Err(env::VarError::NotPresent) => {
            debug!("History file not found, defaulting to ~/.bash_history");
            "~/.bash_history".into()
        },
        Err(e) => {
            panic!("Failed to get history file path: {}", e);
        }
    };
    let input_file = BufReader::new(trysp!(File::open(history_path), "Cauld not open history file"));
    let mut count = -1.0;
    let base = SearchBase::from_iter(input_file.lines().map(|maybe| {
        count += 1.0;
        trace!("New line with count {}", count);
        LineInfo::new(maybe.expect("Failed to read line from file"), count)
    }));
    // if this fails, we can't search anything
    trysp!(emit.send(Event::SearchReady(base)), "Failed to emit search ready signal");
}

fn read_input(emit: Sender<Event>, stop: Arc<AtomicBool>) {
    // this thread is joined on quit, so none of its sends should fail
    let mut escape = None;

    // escape sequence tree, assume ANSI
    let mut control: HashMap<String, Option<Event>> = HashMap::default();
    control.insert(format!("["), None);
    control.insert(format!("[A"), Some(Event::KeyUp));
    control.insert(format!("[B"), Some(Event::KeyDown));

    // read characters
    for maybe_chr in io::stdin().chars() {
        match maybe_chr {
            Err(_) => {
                error!("Failed to read input, quitting");
                trysp!(emit.send(Event::Quit(false)), "Failed to emit quit signal");
                break;
            },
            Ok(ESC) => {
                escape = Some(String::default());
                trace!("Begin escape sequence");
            }
            Ok(chr) => {
                match escape {
                    None => {
                        if chr.is_control() {
                            match chr {
                                EOT => {
                                    // stop
                                    trysp!(emit.send(Event::Quit(false)),
                                           "Failed to send quit event");
                                },
                                CTRL_U => {
                                    // clear query
                                    trysp!(emit.send(Event::Clear),
                                           "Failed to send clear event");
                                },
                                '\n' => {
                                    // exit
                                    trysp!(emit.send(Event::Quit(true)),
                                           "Failed to send quit signal");
                                },
                                ESC => {
                                    // escape sequence
                                    escape = Some(format!(""));
                                }
                                _ => {
                                    // unknown control character
                                    trysp!(emit.send(Event::Bell),
                                           "Failed to send bell event");
                                }
                            }
                        } else {
                            trysp!(emit.send(Event::Input(chr)),
                                   "Failed to send character");
                        }
                    },
                    Some(mut seq) => {
                        seq.push(chr);
                        match control.get(&seq) {
                            None => {
                                // no possible escape sequence like this
                                trysp!(emit.send(Event::Bell),
                                       "Failed to send bell event");
                                trysp!(emit.send(Event::Input(chr)),
                                       "Failed to send character");
                                escape = None;
                            },
                            Some(&None) => {
                                // keep going
                                escape = Some(seq);
                            },
                            Some(&Some(ref event)) => {
                                // send the appropriate event
                                let cloned = trysp!(
                                    event.maybe_clone()
                                        .ok_or(StrError::new(
                                            "Event {:?} could not be cloned", None)),
                                    "Failed to create event");
                                trysp!(emit.send(cloned),
                                       "Failed to send escape event");
                                escape = None;
                            }
                        }
                    }
                }
            }
        }

        // check for requested stop
        if stop.load(Ordering::Relaxed) {
            debug!("Input thread exiting");
            break;
        }
    }
}

fn read_signals(emit: Sender<Event>) {
    // wait for a sigint
    trysp!(bis_c::wait_sigint(), "Failed to wait for sigint");

    debug!("Caught sigint");

    // send a quit signal
    let _ = emit.send(Event::Quit(false));
    // might happen after events is closed, so don't fail
}

pub fn start_query(emit: Sender<Event>, base: Arc<SearchBase>, query: Arc<String>) {
    let result = base.query::<&String>(query.borrow(), MATCH_NUMBER);
    let _ = emit.send(Event::Match(result, query)).and_then(|_| {
        trace!("Finished query");
        Ok(())
    });
    // don't panic on fail send, events might be already closed
}
<|endoftext|>