<commit_before>#![allow(dead_code)]
#![allow(non_upper_case_globals)]
//#![allow(unused_assignments)]
#![allow(unused_imports)]
//#![allow(unused_variables)]

use std::env;
use std::ffi::OsStr;
use std::fmt::Display;
use std::fs;
use std::fs::File;
use std::io::{ BufReader, BufWriter, };
use std::io::prelude::*;
use std::os::unix::net::UnixStream;
use std::os::unix::process::CommandExt;
use std::path::{ Path, PathBuf, };
use std::process::{ Command, exit, };

use jsonrpc_lite;
use jsonrpc_lite::JsonRpc;

use serde_json;
use serde_json::Value;

type JsonRpcId = i64;

fn make_lsp_json_str(id: JsonRpcId, method: &str, params: &Value) -> Result<String, serde_json::error::Error> {
    let msg = json!({
        "jsonrpc": "2.0",
        "id": id,
        "method": method,
        "params": params,
    });
    let request = serde_json::to_string(&msg)?;
    Ok(format!("Content-Length: {}\r\n\r\n{}", request.len(), request))
}

#[derive(Debug, PartialEq)]
/// A message header, as described in the Language Server Protocol specification.
enum LspHeader {
    ContentType,
    ContentLength(usize),
}

/// Given a reference to a reader, attempts to read a Language Server Protocol message,
/// blocking until a message is received.
fn read_message<B: BufRead>(reader: &mut B) -> Value {
    let mut buffer = String::new();
    let mut content_length: Option<usize> = None;

    // read in headers.
    loop {
            buffer.clear();
            reader.read_line(&mut buffer).unwrap();
            match &buffer {
                s if s.trim().is_empty() => { break }, // empty line is end of headers
                s => {
                    match parse_header(s) {
                        LspHeader::ContentLength(len) => content_length = Some(len),
                        LspHeader::ContentType => (), // utf-8 only currently allowed value
                    };
                }
            };
        }

    let content_length = content_length.ok_or_else(|| format!("missing content-length header: {}", buffer)).unwrap();
    // message body isn't newline terminated, so we read content_length bytes
    let mut body_buffer = vec![0; content_length];
    reader.read_exact(&mut body_buffer).unwrap();
    let body = String::from_utf8(body_buffer).unwrap();
    serde_json::from_str::<Value>(&body).unwrap()
}

const HEADER_CONTENT_LENGTH: &str = "content-length";
const HEADER_CONTENT_TYPE: &str = "content-type";

/// Given a header string, attempts to extract and validate the name and value parts.
fn parse_header(s: &str) -> LspHeader {
    let split: Vec<String> = s.split(": ").map(|s| s.trim().to_lowercase()).collect();
    if split.len() != 2 { panic!(format!("malformed header: {}", s)) }
    match split[0].as_ref() {
        HEADER_CONTENT_TYPE   => LspHeader::ContentType,
        HEADER_CONTENT_LENGTH => LspHeader::ContentLength(usize::from_str_radix(&split[1], 10).unwrap()),
        _ => panic!(format!("Unknown header: {}", s)),
    }
}

fn handle_msg_quietly<B: BufRead>(mut reader: B) {
    match serde_json::from_value(read_message(&mut reader)).unwrap() {
        JsonRpc::Request(obj)    => eprintln!("client received unexpected request: {:?}", obj),
        JsonRpc::Notification(_) => (),
        JsonRpc::Success(_)      => (),
        JsonRpc::Error(obj)      => println!("recv error: {:?}", obj),
    }
}

fn handle_msg<B: BufRead>(mut reader: B) {
    match serde_json::from_value(read_message(&mut reader)).unwrap() {
        JsonRpc::Request(obj)      => eprintln!("client received unexpected request: {:?}", obj),
        JsonRpc::Notification(obj) => println!("recv notification: {:?}", obj),
        JsonRpc::Success(obj)      => println!("recv success: {:?}", obj),
        JsonRpc::Error(obj)        => println!("recv error: {:?}", obj),
    }
}

enum ExitCode { Success, Failure }

fn handle_msg_to_exit_code<B: BufRead>(mut reader: B, id: JsonRpcId) -> ExitCode {
    let mut done = false;
    let mut success = false;
    let mut failure = false;

    loop {
        let json_rpc: JsonRpc = serde_json::from_value(read_message(&mut reader)).unwrap();
        match json_rpc {
            JsonRpc::Request(ref obj)      => eprintln!("client received unexpected request: {:?}", obj),
            JsonRpc::Success(ref obj)      => {
                let json_id = json_rpc.get_id().unwrap();
                let id_str = match json_id {
                    jsonrpc_lite::Id::Num(n)   => n.to_string(),
                    jsonrpc_lite::Id::Str(s)   => s,
                    jsonrpc_lite::Id::None(()) => "".to_string(),
                };
                if id_str == id.to_string() {
                    let result = json_rpc.get_result().unwrap();
                    println!("json_rpc: {:?}", json_rpc);
                    return ExitCode::Success
                } else {
                    println!("recv success: {:?}", obj)
                }
            },
            JsonRpc::Error(ref obj)        => {
                let json_id = json_rpc.get_id().unwrap();
                let id_str = match json_id {
                    jsonrpc_lite::Id::Num(n)   => n.to_string(),
                    jsonrpc_lite::Id::Str(s)   => s,
                    jsonrpc_lite::Id::None(()) => "".to_string(),
                };
                if id_str == id.to_string() {
                    let error = json_rpc.get_error().unwrap();
                    eprintln!("[error] {}", error);
                    return ExitCode::Failure
                } else {
                    println!("recv error: {:?}", obj)
                }
            },
            JsonRpc::Notification(ref obj) => {
                match json_rpc.get_method() {
                    Some("window/logMessage") => {
                        let params0 = json_rpc.get_params().unwrap();
                        let params = match params0 {
                            jsonrpc_lite::Params::Array(_) => panic!("not expecting array"),
                            jsonrpc_lite::Params::None(()) => panic!("not expecting none"),
                            jsonrpc_lite::Params::Map(kvs) => kvs,
                        };
                        let lvl = params["type"].as_i64().unwrap();
                        let msg = params["message"].as_str().unwrap();
                        println!("{}", msg);
                        if msg == "Exited with code 0" { success = true }
                        if msg == "Done" { done = true }
                        if lvl == 1 { failure = true }
                    },
                    Some("textDocument/publishDiagnostics") => {
                        let params0 = json_rpc.get_params().unwrap();
                        let params = match params0 {
                            jsonrpc_lite::Params::Array(_) => panic!("not expecting array"),
                            jsonrpc_lite::Params::None(()) => panic!("not expecting none"),
                            jsonrpc_lite::Params::Map(kvs) => kvs,
                        };
                        let uri = params["uri"].as_str().unwrap();
                        let diagnostics = params["diagnostics"].as_array().unwrap();
                        for diagnostic in diagnostics {
                            println!("{}: {}", uri, diagnostic);
                        }
                    },
                    Some(_) | _ => println!("recv notification: {:?}", obj),
                }
            },
        }

        // val Error = 1L
        // val Warning = 2L
        // val Info = 3L
        // val Log = 4L

        // 'runMain t.Main'     reports "[log] Exited with code 0" and then "[log] Done"
        // 'runMain t.BadMain'  reports "[log] Done"               and then "[error] Nonzero exit code: 1"
        // 'compile' w/ error   reports "[error] Compilation failed"
        // 'compile' w/o errors reports "[log] Done", but we can't distinguish that from BadMain's "[log] Done"...

        if success && done { return ExitCode::Success }
        if failure { return ExitCode::Failure }
    }
}

pub fn talk_to_client(port_file: File) {
    let json: serde_json::Value = serde_json::from_reader(port_file).unwrap();
    let uri = json["uri"].as_str().unwrap();
    // TODO: Use a less idiotic way to get the path from the URI
    let socket_file_path = &uri[8..];

    match UnixStream::connect(socket_file_path) {
        Ok(stream) => talk_to_client_impl(socket_file_path, stream),
        Err(_)     => {
            fs::remove_file("project/target/active.json").expect("Failed to delete port file");
            ::main()
        },
    }
}

fn talk_to_client_impl<P: AsRef<Path>>(socket_file_path: P, mut stream: UnixStream) {
    let json_str = make_lsp_json_str(1, "initialize", &json!({})).unwrap();
    stream.write_all(json_str.as_bytes()).unwrap();
    stream.flush().unwrap();

    let mut reader = BufReader::new(stream);
    handle_msg_quietly(&mut reader);

    let mut args = env::args().skip(1); // skip the path of the executable
    let command_line = args.nth(0).expect("at least one argument to sbt when server already running");
    let json_str2 = make_lsp_json_str(2, "sbt/exec", &json!({"commandLine": command_line})).unwrap();
    let mut stream2 = UnixStream::connect(socket_file_path).unwrap();
    stream2.write_all(json_str2.as_bytes()).unwrap();
    stream2.flush().unwrap();

    let reader2 = BufReader::new(stream2);
    match handle_msg_to_exit_code(reader2, 2) {
        ExitCode::Failure => exit(1),
        ExitCode::Success => exit(0),
    }
}

#[cfg(test)]
mod tests {
    use jsonrpc_lite::JsonRpc;
    use serde_json;
    use super::*;

    #[test]
    fn decode_ok() {
        let msg = r#"{"jsonrpc":"2.0","result":{"commandQueue":["collectAnalyses","shell"],"exitCode":0,"status":"Done"},"id":null}"#;
        let json = serde_json::from_str::<serde_json::Value>(&msg).unwrap();
        let json_rpc: JsonRpc = serde_json::from_value(json).expect("is JSON RPC");
    }

    #[test]
    #[should_panic(expected = "data did not match any variant of untagged enum JsonRpc")]
    fn decode_ko() {
        let msg = r#"{"jsonrpc":"2.0","result":{"commandQueue":["collectAnalyses","shell"],"exitCode":0,"status":"Done"}}"#;
        let json = serde_json::from_str::<serde_json::Value>(&msg).unwrap();
        let json_rpc: JsonRpc = serde_json::from_value(json).expect("is JSON RPC");
    }
}
<commit_msg>Drop unused success result<commit_after>#![allow(dead_code)]
#![allow(non_upper_case_globals)]
//#![allow(unused_assignments)]
#![allow(unused_imports)]
//#![allow(unused_variables)]

use std::env;
use std::ffi::OsStr;
use std::fmt::Display;
use std::fs;
use std::fs::File;
use std::io::{ BufReader, BufWriter, };
use std::io::prelude::*;
use std::os::unix::net::UnixStream;
use std::os::unix::process::CommandExt;
use std::path::{ Path, PathBuf, };
use std::process::{ Command, exit, };

use jsonrpc_lite;
use jsonrpc_lite::JsonRpc;

use serde_json;
use serde_json::Value;

type JsonRpcId = i64;

fn make_lsp_json_str(id: JsonRpcId, method: &str, params: &Value) -> Result<String, serde_json::error::Error> {
    let msg = json!({
        "jsonrpc": "2.0",
        "id": id,
        "method": method,
        "params": params,
    });
    let request = serde_json::to_string(&msg)?;
    Ok(format!("Content-Length: {}\r\n\r\n{}", request.len(), request))
}

#[derive(Debug, PartialEq)]
/// A message header, as described in the Language Server Protocol specification.
enum LspHeader {
    ContentType,
    ContentLength(usize),
}

/// Given a reference to a reader, attempts to read a Language Server Protocol message,
/// blocking until a message is received.
fn read_message<B: BufRead>(reader: &mut B) -> Value {
    let mut buffer = String::new();
    let mut content_length: Option<usize> = None;

    // read in headers.
    loop {
            buffer.clear();
            reader.read_line(&mut buffer).unwrap();
            match &buffer {
                s if s.trim().is_empty() => { break }, // empty line is end of headers
                s => {
                    match parse_header(s) {
                        LspHeader::ContentLength(len) => content_length = Some(len),
                        LspHeader::ContentType => (), // utf-8 only currently allowed value
                    };
                }
            };
        }

    let content_length = content_length.ok_or_else(|| format!("missing content-length header: {}", buffer)).unwrap();
    // message body isn't newline terminated, so we read content_length bytes
    let mut body_buffer = vec![0; content_length];
    reader.read_exact(&mut body_buffer).unwrap();
    let body = String::from_utf8(body_buffer).unwrap();
    serde_json::from_str::<Value>(&body).unwrap()
}

const HEADER_CONTENT_LENGTH: &str = "content-length";
const HEADER_CONTENT_TYPE: &str = "content-type";

/// Given a header string, attempts to extract and validate the name and value parts.
fn parse_header(s: &str) -> LspHeader {
    let split: Vec<String> = s.split(": ").map(|s| s.trim().to_lowercase()).collect();
    if split.len() != 2 { panic!(format!("malformed header: {}", s)) }
    match split[0].as_ref() {
        HEADER_CONTENT_TYPE   => LspHeader::ContentType,
        HEADER_CONTENT_LENGTH => LspHeader::ContentLength(usize::from_str_radix(&split[1], 10).unwrap()),
        _ => panic!(format!("Unknown header: {}", s)),
    }
}

fn handle_msg_quietly<B: BufRead>(mut reader: B) {
    match serde_json::from_value(read_message(&mut reader)).unwrap() {
        JsonRpc::Request(obj)    => eprintln!("client received unexpected request: {:?}", obj),
        JsonRpc::Notification(_) => (),
        JsonRpc::Success(_)      => (),
        JsonRpc::Error(obj)      => println!("recv error: {:?}", obj),
    }
}

fn handle_msg<B: BufRead>(mut reader: B) {
    match serde_json::from_value(read_message(&mut reader)).unwrap() {
        JsonRpc::Request(obj)      => eprintln!("client received unexpected request: {:?}", obj),
        JsonRpc::Notification(obj) => println!("recv notification: {:?}", obj),
        JsonRpc::Success(obj)      => println!("recv success: {:?}", obj),
        JsonRpc::Error(obj)        => println!("recv error: {:?}", obj),
    }
}

enum ExitCode { Success, Failure }

fn handle_msg_to_exit_code<B: BufRead>(mut reader: B, id: JsonRpcId) -> ExitCode {
    let mut done = false;
    let mut success = false;
    let mut failure = false;

    loop {
        let json_rpc: JsonRpc = serde_json::from_value(read_message(&mut reader)).unwrap();
        match json_rpc {
            JsonRpc::Request(ref obj)      => eprintln!("client received unexpected request: {:?}", obj),
            JsonRpc::Success(ref obj)      => {
                let json_id = json_rpc.get_id().unwrap();
                let id_str = match json_id {
                    jsonrpc_lite::Id::Num(n)   => n.to_string(),
                    jsonrpc_lite::Id::Str(s)   => s,
                    jsonrpc_lite::Id::None(()) => "".to_string(),
                };
                if id_str == id.to_string() {
                    return ExitCode::Success
                } else {
                    println!("recv success: {:?}", obj)
                }
            },
            JsonRpc::Error(ref obj)        => {
                let json_id = json_rpc.get_id().unwrap();
                let id_str = match json_id {
                    jsonrpc_lite::Id::Num(n)   => n.to_string(),
                    jsonrpc_lite::Id::Str(s)   => s,
                    jsonrpc_lite::Id::None(()) => "".to_string(),
                };
                if id_str == id.to_string() {
                    let error = json_rpc.get_error().unwrap();
                    eprintln!("[error] {}", error);
                    return ExitCode::Failure
                } else {
                    println!("recv error: {:?}", obj)
                }
            },
            JsonRpc::Notification(ref obj) => {
                match json_rpc.get_method() {
                    Some("window/logMessage") => {
                        let params0 = json_rpc.get_params().unwrap();
                        let params = match params0 {
                            jsonrpc_lite::Params::Array(_) => panic!("not expecting array"),
                            jsonrpc_lite::Params::None(()) => panic!("not expecting none"),
                            jsonrpc_lite::Params::Map(kvs) => kvs,
                        };
                        let lvl = params["type"].as_i64().unwrap();
                        let msg = params["message"].as_str().unwrap();
                        println!("{}", msg);
                        if msg == "Exited with code 0" { success = true }
                        if msg == "Done" { done = true }
                        if lvl == 1 { failure = true }
                    },
                    Some("textDocument/publishDiagnostics") => {
                        let params0 = json_rpc.get_params().unwrap();
                        let params = match params0 {
                            jsonrpc_lite::Params::Array(_) => panic!("not expecting array"),
                            jsonrpc_lite::Params::None(()) => panic!("not expecting none"),
                            jsonrpc_lite::Params::Map(kvs) => kvs,
                        };
                        let uri = params["uri"].as_str().unwrap();
                        let diagnostics = params["diagnostics"].as_array().unwrap();
                        for diagnostic in diagnostics {
                            println!("{}: {}", uri, diagnostic);
                        }
                    },
                    Some(_) | _ => println!("recv notification: {:?}", obj),
                }
            },
        }

        // val Error = 1L
        // val Warning = 2L
        // val Info = 3L
        // val Log = 4L

        // 'runMain t.Main'     reports "[log] Exited with code 0" and then "[log] Done"
        // 'runMain t.BadMain'  reports "[log] Done"               and then "[error] Nonzero exit code: 1"
        // 'compile' w/ error   reports "[error] Compilation failed"
        // 'compile' w/o errors reports "[log] Done", but we can't distinguish that from BadMain's "[log] Done"...

        if success && done { return ExitCode::Success }
        if failure { return ExitCode::Failure }
    }
}

pub fn talk_to_client(port_file: File) {
    let json: serde_json::Value = serde_json::from_reader(port_file).unwrap();
    let uri = json["uri"].as_str().unwrap();
    // TODO: Use a less idiotic way to get the path from the URI
    let socket_file_path = &uri[8..];

    match UnixStream::connect(socket_file_path) {
        Ok(stream) => talk_to_client_impl(socket_file_path, stream),
        Err(_)     => {
            fs::remove_file("project/target/active.json").expect("Failed to delete port file");
            ::main()
        },
    }
}

fn talk_to_client_impl<P: AsRef<Path>>(socket_file_path: P, mut stream: UnixStream) {
    let json_str = make_lsp_json_str(1, "initialize", &json!({})).unwrap();
    stream.write_all(json_str.as_bytes()).unwrap();
    stream.flush().unwrap();

    let mut reader = BufReader::new(stream);
    handle_msg_quietly(&mut reader);

    let mut args = env::args().skip(1); // skip the path of the executable
    let command_line = args.nth(0).expect("at least one argument to sbt when server already running");
    let json_str2 = make_lsp_json_str(2, "sbt/exec", &json!({"commandLine": command_line})).unwrap();
    let mut stream2 = UnixStream::connect(socket_file_path).unwrap();
    stream2.write_all(json_str2.as_bytes()).unwrap();
    stream2.flush().unwrap();

    let reader2 = BufReader::new(stream2);
    match handle_msg_to_exit_code(reader2, 2) {
        ExitCode::Failure => exit(1),
        ExitCode::Success => exit(0),
    }
}

#[cfg(test)]
mod tests {
    use jsonrpc_lite::JsonRpc;
    use serde_json;
    use super::*;

    #[test]
    fn decode_ok() {
        let msg = r#"{"jsonrpc":"2.0","result":{"commandQueue":["collectAnalyses","shell"],"exitCode":0,"status":"Done"},"id":null}"#;
        let json = serde_json::from_str::<serde_json::Value>(&msg).unwrap();
        let json_rpc: JsonRpc = serde_json::from_value(json).expect("is JSON RPC");
    }

    #[test]
    #[should_panic(expected = "data did not match any variant of untagged enum JsonRpc")]
    fn decode_ko() {
        let msg = r#"{"jsonrpc":"2.0","result":{"commandQueue":["collectAnalyses","shell"],"exitCode":0,"status":"Done"}}"#;
        let json = serde_json::from_str::<serde_json::Value>(&msg).unwrap();
        let json_rpc: JsonRpc = serde_json::from_value(json).expect("is JSON RPC");
    }
}
<|endoftext|>


<commit_before>use Endpoint;
use PageableEndpoint;
use Pager;
use error;
use reqwest;
use reqwest::header;
use serde_json;
use serde_urlencoded;
use std;
use std::env;
use std::fmt;
use std::io::Read;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use std::time;

const API_BASE_PATH: &str = "http://proxer.me/api/v1/";

#[derive(Debug, Clone)]
pub struct ClientConfig {
	pub cooldown: time::Duration,
}

impl Default for ClientConfig {
	/// Default ClientConfig:
	/// - No cooldown

	fn default() -> Self {
		Self {
			cooldown: time::Duration::new(0, 0),
		}
	}
}

/// Client that holds the api key and sends requests
#[derive(Debug, Clone)]
pub struct Client {
	api_key: String,
	base_uri: String,
	user_agent: String,
	config: ClientConfig,
	last_request: Arc<Mutex<Option<time::Instant>>>,
}

#[allow(unused)]
impl Client {
	/// Create a new api client with a given api key
	pub fn new(api_key: String) -> Self {
		let crates_name = env::var("CARGO_PKG_NAME").unwrap_or("unknown".to_string());

		let crates_version = &env::var("CARGO_PKG_VERSION").unwrap_or("unknown".to_string());
		let ua = format!("libproxer-rust({}/v{})", crates_name, crates_version);

		Self {
			api_key: api_key,
			base_uri: API_BASE_PATH.to_string(),
			user_agent: ua,
			config: ClientConfig::default(),
			last_request: Arc::new(Mutex::new(None)),
		}
	}

	/// load api key from an environment variable
	pub fn with_env_key(env_key: &str) -> Option<Client> {
		match env::var_os(env_key) {
			Some(r) => Some(Client::new(r.into_string().unwrap())),
			None => None,
		}
	}

	pub fn cooldown_time(&mut self, time: time::Duration) {
		self.config.cooldown = time;
	}

	/// execute a request that satisfies [`Endpoint`](../trait.Endpoint.html)
	pub fn execute<T>(&mut self, mut endpoint: T) -> Result<T::ResponseType, error::Error>
	where
		T: super::Endpoint + Clone + fmt::Debug,
	{
		let uristring = self.base_uri.to_string() + T::URL;

		header!{(ProxerApiKey, "Proxer-Api-Key") => [String]}

		let mut headers = reqwest::header::Headers::new();

		headers.set(header::UserAgent::new(self.user_agent.to_string()));
		headers.set(header::Host::new("proxer.me", None));
		headers.set(header::ContentType::form_url_encoded());
		headers.set(ProxerApiKey(self.api_key.clone()));

		let mut http_req = reqwest::Request::new(reqwest::Method::Post, uristring.parse().unwrap());

		// add our headers to the request
		http_req.headers_mut().extend(headers.iter());

		match serde_urlencoded::to_string(endpoint.clone()) {
			Ok(body) => {
				debug!("post data: {}", body);
				*http_req.body_mut() = Some(body.into());
			}
			Err(err) => panic!("can't serialize form parameters"),
		}

		debug!("creating reqwest client");
		let client = reqwest::Client::new();

		self.waiting_for_cooldown();
		debug!("sending request");

		let response = client.execute(http_req);
		debug!("response received");
		self.reset_cooldown();

		// This section needs some rewriting. maybe... later
		match response {
			Err(e) => return Err(error::Error::Http),
			Ok(mut res) => {
				debug!("http response code: {}", res.status());

				let mut json_string = String::new();
				res.read_to_string(&mut json_string);

				debug!("http response length: {}kb", json_string.len() * 1000);

				match serde_json::from_str::<ApiResponse<T::ResponseType>>(&json_string) {
					Err(e) => return Err(error::Error::Json(e)),
					Ok(r) => {
						if r.error != 0 {
							Err(error::Error::Api(error::api::Api::new(
								r.code.unwrap(),
								r.message,
							)))
						}
						else {
							Ok(r.data.unwrap())
						}
					}
				}
			}
		}
	}

	fn remaining_cooldown_time(&self) -> time::Duration {
		match *self.last_request.lock().unwrap() {
			None => self.config.cooldown,
			Some(time) => time.elapsed().clone(),
		}
	}

	fn reset_cooldown(&mut self) {
		*self.last_request.lock().unwrap() = Some(time::Instant::now());
	}

	// vlocking till we can create a new request
	fn waiting_for_cooldown(&mut self) {
		let conf_cooldown = self.config.cooldown;
		let since_last = self.remaining_cooldown_time();

		debug!(
			"configurated cooldown {:2}.{}s",
			conf_cooldown.as_secs(),
			conf_cooldown.subsec_nanos()
		);
		debug!(
			"last request {:2}.{}s ago",
			since_last.as_secs(),
			since_last.subsec_nanos()
		);

		if since_last >= conf_cooldown {
			return;
		}

		let wait = self.config.cooldown - self.remaining_cooldown_time();
		debug!(
			"waiting for cooldown: {:2}.{}s",
			wait.as_secs(),
			wait.subsec_nanos()
		);

		thread::sleep(wait);
	}

	pub fn pager<T>(self, mut endpoint: T) -> Pager<T>
	where
		T: Endpoint + PageableEndpoint + Clone + fmt::Debug,
		<T as Endpoint>::ResponseType: IntoIterator + Clone + fmt::Debug,
		<<T as Endpoint>::ResponseType as std::iter::IntoIterator>::Item: Clone + fmt::Debug,
	{
		Pager::new(self, endpoint, None, None)
	}
}

/// responses are parsed into ApiRequest
#[derive(Debug, Clone, Deserialize)]
pub struct ApiResponse<T> {
	/// api error
	pub error: i64,
	/// api message
	pub message: String,
	/// actual data
	pub data: Option<T>,
	/// optional error code
	/// in case of an error this contains the error code
	pub code: Option<i64>,
}
<commit_msg>check received http statuscode<commit_after>use Endpoint;
use error;
use PageableEndpoint;
use Pager;
use reqwest;
use reqwest::StatusCode;
use reqwest::header;
use serde_json;
use serde_urlencoded;
use std;
use std::env;
use std::fmt;
use std::io::Read;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use std::time;

const API_BASE_PATH: &str = "http://proxer.me/api/v1/";

#[derive(Debug, Clone)]
pub struct ClientConfig {
	pub cooldown: time::Duration,
}

impl Default for ClientConfig {
	/// Default ClientConfig:
	/// - No cooldown

	fn default() -> Self {
		Self {
			cooldown: time::Duration::new(0, 0),
		}
	}
}

/// Client that holds the api key and sends requests
#[derive(Debug, Clone)]
pub struct Client {
	api_key: String,
	base_uri: String,
	user_agent: String,
	config: ClientConfig,
	last_request: Arc<Mutex<Option<time::Instant>>>,
}

#[allow(unused)]
impl Client {
	/// Create a new api client with a given api key
	pub fn new(api_key: String) -> Self {
		let crates_name = env::var("CARGO_PKG_NAME").unwrap_or("unknown".to_string());

		let crates_version = &env::var("CARGO_PKG_VERSION").unwrap_or("unknown".to_string());
		let ua = format!("libproxer-rust({}/v{})", crates_name, crates_version);

		Self {
			api_key: api_key,
			base_uri: API_BASE_PATH.to_string(),
			user_agent: ua,
			config: ClientConfig::default(),
			last_request: Arc::new(Mutex::new(None)),
		}
	}

	/// load api key from an environment variable
	pub fn with_env_key(env_key: &str) -> Option<Client> {
		match env::var_os(env_key) {
			Some(r) => Some(Client::new(r.into_string().unwrap())),
			None => None,
		}
	}

	pub fn cooldown_time(&mut self, time: time::Duration) {
		self.config.cooldown = time;
	}

	/// execute a request that satisfies [`Endpoint`](../trait.Endpoint.html)
	pub fn execute<T>(&mut self, mut endpoint: T) -> Result<T::ResponseType, error::Error>
	where
		T: super::Endpoint + Clone + fmt::Debug,
	{
		let uristring = self.base_uri.to_string() + T::URL;

		header!{(ProxerApiKey, "Proxer-Api-Key") => [String]}

		let mut headers = reqwest::header::Headers::new();

		headers.set(header::UserAgent::new(self.user_agent.to_string()));
		headers.set(header::Host::new("proxer.me", None));
		headers.set(header::ContentType::form_url_encoded());
		headers.set(ProxerApiKey(self.api_key.clone()));

		let mut http_req = reqwest::Request::new(reqwest::Method::Post, uristring.parse().unwrap());

		// add our headers to the request
		http_req.headers_mut().extend(headers.iter());

		match serde_urlencoded::to_string(endpoint.clone()) {
			Ok(body) => {
				debug!("post data: {}", body);
				*http_req.body_mut() = Some(body.into());
			}
			Err(err) => panic!("can't serialize form parameters"),
		}

		debug!("creating reqwest client");
		let client = reqwest::Client::new();

		self.waiting_for_cooldown();
		debug!("sending request");

		let response = client.execute(http_req);
		debug!("response received");
		self.reset_cooldown();

		// This section needs some rewriting. maybe... later
		match response {
			Err(e) => return Err(error::Error::Unknown),
			Ok(mut res) => {
				debug!("http response code: {}", res.status());

				if res.status() != StatusCode::Ok {
					return Err(error::Error::Http)
				}

				let mut json_string = String::new();
				res.read_to_string(&mut json_string);

				debug!("http response length: {}kb", json_string.len() * 1000);

				match serde_json::from_str::<ApiResponse<T::ResponseType>>(&json_string) {
					Err(e) => return Err(error::Error::Json(e)),
					Ok(r) => {
						if r.error != 0 {
							Err(error::Error::Api(error::api::Api::new(
								r.code.unwrap(),
								r.message,
							)))
						}
						else {
							Ok(r.data.unwrap())
						}
					}
				}
			}
		}
	}

	fn remaining_cooldown_time(&self) -> time::Duration {
		match *self.last_request.lock().unwrap() {
			None => self.config.cooldown,
			Some(time) => time.elapsed().clone(),
		}
	}

	fn reset_cooldown(&mut self) {
		*self.last_request.lock().unwrap() = Some(time::Instant::now());
	}

	// vlocking till we can create a new request
	fn waiting_for_cooldown(&mut self) {
		let conf_cooldown = self.config.cooldown;
		let since_last = self.remaining_cooldown_time();

		debug!(
			"configurated cooldown {:2}.{}s",
			conf_cooldown.as_secs(),
			conf_cooldown.subsec_nanos()
		);
		debug!(
			"last request {:2}.{}s ago",
			since_last.as_secs(),
			since_last.subsec_nanos()
		);

		if since_last >= conf_cooldown {
			return;
		}

		let wait = self.config.cooldown - self.remaining_cooldown_time();
		debug!(
			"waiting for cooldown: {:2}.{}s",
			wait.as_secs(),
			wait.subsec_nanos()
		);

		thread::sleep(wait);
	}

	pub fn pager<T>(self, mut endpoint: T) -> Pager<T>
	where
		T: Endpoint + PageableEndpoint + Clone + fmt::Debug,
		<T as Endpoint>::ResponseType: IntoIterator + Clone + fmt::Debug,
		<<T as Endpoint>::ResponseType as std::iter::IntoIterator>::Item: Clone + fmt::Debug,
	{
		Pager::new(self, endpoint, None, None)
	}
}

/// responses are parsed into ApiRequest
#[derive(Debug, Clone, Deserialize)]
pub struct ApiResponse<T> {
	/// api error
	pub error: i64,
	/// api message
	pub message: String,
	/// actual data
	pub data: Option<T>,
	/// optional error code
	/// in case of an error this contains the error code
	pub code: Option<i64>,
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate syntax;
extern crate toml;

use std::{env, fs};
use std::cell::Cell;
use std::default::Default;
use std::fs::File;
use std::io::{Error, ErrorKind, Read};
use std::path::{Path, PathBuf};

#[macro_use]
mod config_type;
#[macro_use]
mod options;

pub mod file_lines;
pub mod lists;
pub mod summary;

use config_type::ConfigType;
use file_lines::FileLines;
pub use lists::*;
pub use options::*;
use summary::Summary;

/// This macro defines configuration options used in rustfmt. Each option
/// is defined as follows:
///
/// `name: value type, default value, is stable, description;`
create_config! {
    // Fundamental stuff
    max_width: usize, 100, true, "Maximum width of each line";
    hard_tabs: bool, false, true, "Use tab characters for indentation, spaces for alignment";
    tab_spaces: usize, 4, true, "Number of spaces per tab";
    newline_style: NewlineStyle, NewlineStyle::Unix, true, "Unix or Windows line endings";
    indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items.";
    use_small_heuristics: bool, true, false, "Whether to use different formatting for items and\
        expressions if they satisfy a heuristic notion of 'small'.";

    // strings and comments
    format_strings: bool, false, false, "Format string literals where necessary";
    wrap_comments: bool, false, true, "Break comments to fit on the line";
    comment_width: usize, 80, false,
        "Maximum length of comments. No effect unless wrap_comments = true";
    normalize_comments: bool, false, true, "Convert /* */ comments to // comments where possible";

    // Single line expressions and items.
    empty_item_single_line: bool, true, false,
        "Put empty-body functions and impls on a single line";
    struct_lit_single_line: bool, true, false,
        "Put small struct literals on a single line";
    fn_single_line: bool, false, false, "Put single-expression functions on a single line";
    where_single_line: bool, false, false, "To force single line where layout";

    // Imports
    imports_indent: IndentStyle, IndentStyle::Visual, false, "Indent of imports";
    imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block";

    // Ordering
    reorder_extern_crates: bool, true, false, "Reorder extern crate statements alphabetically";
    reorder_extern_crates_in_group: bool, true, false, "Reorder extern crate statements in group";
    reorder_imports: bool, false, false, "Reorder import statements alphabetically";
    reorder_imports_in_group: bool, false, false, "Reorder import statements in group";
    reorder_imported_names: bool, true, false,
        "Reorder lists of names in import statements alphabetically";
    reorder_modules: bool, false, false, "Reorder module statemtents alphabetically in group";

    // Spaces around punctuation
    binop_separator: SeparatorPlace, SeparatorPlace::Front, false,
        "Where to put a binary operator when a binary expression goes multiline.";
    type_punctuation_density: TypeDensity, TypeDensity::Wide, false,
        "Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
    space_before_colon: bool, false, false, "Leave a space before the colon";
    space_after_colon: bool, true, false, "Leave a space after the colon";
    spaces_around_ranges: bool, false, false, "Put spaces around the  .. and ... range operators";
    spaces_within_parens_and_brackets: bool, false, false,
        "Put spaces within non-empty parentheses or brackets";

    // Misc.
    combine_control_expr: bool, true, false, "Combine control expressions with function calls.";
    struct_field_align_threshold: usize, 0, false, "Align struct fields if their diffs fits within \
                                             threshold.";
    remove_blank_lines_at_start_or_end_of_block: bool, true, false,
        "Remove blank lines at start or end of a block";
    match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \
        the same line with the pattern of arms";
    force_multiline_blocks: bool, false, false,
        "Force multiline closure bodies and match arms to be wrapped in a block";
    fn_args_density: Density, Density::Tall, false, "Argument density in functions";
    brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
    control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
        "Brace style for control flow constructs";
    trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
        "How to handle trailing commas for lists";
    trailing_semicolon: bool, true, false,
        "Add trailing semicolon after break, continue and return";
    match_block_trailing_comma: bool, false, false,
        "Put a trailing comma after a block based match arm (non-block arms are not affected)";
    blank_lines_upper_bound: usize, 1, false,
        "Maximum number of blank lines which can be put between items.";
    blank_lines_lower_bound: usize, 0, false,
        "Minimum number of blank lines which must be put between items.";

    // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
    merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
    use_try_shorthand: bool, false, false, "Replace uses of the try! macro by the ? shorthand";
    condense_wildcard_suffixes: bool, false, false, "Replace strings of _ wildcards by a single .. \
                                              in tuple patterns";
    force_explicit_abi: bool, true, true, "Always print the abi for extern items";
    use_field_init_shorthand: bool, false, false, "Use field initialization shorthand if possible";

    // Control options (changes the operation of rustfmt, rather than the formatting)
    write_mode: WriteMode, WriteMode::Overwrite, false,
        "What Write Mode to use when none is supplied: \
         Replace, Overwrite, Display, Plain, Diff, Coverage";
    color: Color, Color::Auto, false,
        "What Color option to use when none is supplied: Always, Never, Auto";
    required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
        "Require a specific version of rustfmt.";
    unstable_features: bool, false, true,
            "Enables unstable features. Only available on nightly channel";
    disable_all_formatting: bool, false, false, "Don't reformat anything";
    skip_children: bool, false, false, "Don't reformat out of line modules";
    hide_parse_errors: bool, false, false, "Hide errors from the parser";
    error_on_line_overflow: bool, true, false, "Error if unable to get all lines within max_width";
    error_on_unformatted: bool, false, false,
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces";
    report_todo: ReportTactic, ReportTactic::Never, false,
        "Report all, none or unnumbered occurrences of TODO in source file comments";
    report_fixme: ReportTactic, ReportTactic::Never, false,
        "Report all, none or unnumbered occurrences of FIXME in source file comments";

    // Not user-facing.
    verbose: bool, false, false, "Use verbose output";
    file_lines: FileLines, FileLines::all(), false,
        "Lines to format; this is not supported in rustfmt.toml, and can only be specified \
         via the --file-lines option";
    width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
        "'small' heuristic values";
}

/// Check for the presence of known config file names (`rustfmt.toml, `.rustfmt.toml`) in `dir`
///
/// Return the path if a config file exists, empty if no file exists, and Error for IO errors
pub fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
    const CONFIG_FILE_NAMES: [&str; 2] = [".rustfmt.toml", "rustfmt.toml"];
    for config_file_name in &CONFIG_FILE_NAMES {
        let config_file = dir.join(config_file_name);
        match fs::metadata(&config_file) {
            // Only return if it's a file to handle the unlikely situation of a directory named
            // `rustfmt.toml`.
            Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
            // Return the error if it's something other than `NotFound`; otherwise we didn't
            // find the project file yet, and continue searching.
            Err(e) => {
                if e.kind() != ErrorKind::NotFound {
                    return Err(e);
                }
            }
            _ => {}
        }
    }
    Ok(None)
}

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

    #[test]
    fn test_config_set() {
        let mut config = Config::default();
        config.set().verbose(false);
        assert_eq!(config.verbose(), false);
        config.set().verbose(true);
        assert_eq!(config.verbose(), true);
    }

    #[test]
    fn test_config_used_to_toml() {
        let config = Config::default();

        let merge_derives = config.merge_derives();
        let skip_children = config.skip_children();

        let used_options = config.used_options();
        let toml = used_options.to_toml().unwrap();
        assert_eq!(
            toml,
            format!(
                "merge_derives = {}\nskip_children = {}\n",
                merge_derives, skip_children,
            )
        );
    }

    #[test]
    fn test_was_set() {
        let config = Config::from_toml("hard_tabs = true").unwrap();

        assert_eq!(config.was_set().hard_tabs(), true);
        assert_eq!(config.was_set().verbose(), false);
    }

    // FIXME(#2183) these tests cannot be run in parallel because they use env vars
    // #[test]
    // fn test_as_not_nightly_channel() {
    //     let mut config = Config::default();
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     config.set().unstable_features(true);
    //     assert_eq!(config.was_set().unstable_features(), false);
    // }

    // #[test]
    // fn test_as_nightly_channel() {
    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
    //     let mut config = Config::default();
    //     config.set().unstable_features(true);
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     config.set().unstable_features(true);
    //     assert_eq!(config.unstable_features(), true);
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
    // }

    // #[test]
    // fn test_unstable_from_toml() {
    //     let mut config = Config::from_toml("unstable_features = true").unwrap();
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
    //     config = Config::from_toml("unstable_features = true").unwrap();
    //     assert_eq!(config.was_set().unstable_features(), true);
    //     assert_eq!(config.unstable_features(), true);
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
    // }
}
<commit_msg>Fixed small typo in configuration help<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate syntax;
extern crate toml;

use std::{env, fs};
use std::cell::Cell;
use std::default::Default;
use std::fs::File;
use std::io::{Error, ErrorKind, Read};
use std::path::{Path, PathBuf};

#[macro_use]
mod config_type;
#[macro_use]
mod options;

pub mod file_lines;
pub mod lists;
pub mod summary;

use config_type::ConfigType;
use file_lines::FileLines;
pub use lists::*;
pub use options::*;
use summary::Summary;

/// This macro defines configuration options used in rustfmt. Each option
/// is defined as follows:
///
/// `name: value type, default value, is stable, description;`
create_config! {
    // Fundamental stuff
    max_width: usize, 100, true, "Maximum width of each line";
    hard_tabs: bool, false, true, "Use tab characters for indentation, spaces for alignment";
    tab_spaces: usize, 4, true, "Number of spaces per tab";
    newline_style: NewlineStyle, NewlineStyle::Unix, true, "Unix or Windows line endings";
    indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items.";
    use_small_heuristics: bool, true, false, "Whether to use different formatting for items and \
        expressions if they satisfy a heuristic notion of 'small'.";

    // strings and comments
    format_strings: bool, false, false, "Format string literals where necessary";
    wrap_comments: bool, false, true, "Break comments to fit on the line";
    comment_width: usize, 80, false,
        "Maximum length of comments. No effect unless wrap_comments = true";
    normalize_comments: bool, false, true, "Convert /* */ comments to // comments where possible";

    // Single line expressions and items.
    empty_item_single_line: bool, true, false,
        "Put empty-body functions and impls on a single line";
    struct_lit_single_line: bool, true, false,
        "Put small struct literals on a single line";
    fn_single_line: bool, false, false, "Put single-expression functions on a single line";
    where_single_line: bool, false, false, "To force single line where layout";

    // Imports
    imports_indent: IndentStyle, IndentStyle::Visual, false, "Indent of imports";
    imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block";

    // Ordering
    reorder_extern_crates: bool, true, false, "Reorder extern crate statements alphabetically";
    reorder_extern_crates_in_group: bool, true, false, "Reorder extern crate statements in group";
    reorder_imports: bool, false, false, "Reorder import statements alphabetically";
    reorder_imports_in_group: bool, false, false, "Reorder import statements in group";
    reorder_imported_names: bool, true, false,
        "Reorder lists of names in import statements alphabetically";
    reorder_modules: bool, false, false, "Reorder module statemtents alphabetically in group";

    // Spaces around punctuation
    binop_separator: SeparatorPlace, SeparatorPlace::Front, false,
        "Where to put a binary operator when a binary expression goes multiline.";
    type_punctuation_density: TypeDensity, TypeDensity::Wide, false,
        "Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
    space_before_colon: bool, false, false, "Leave a space before the colon";
    space_after_colon: bool, true, false, "Leave a space after the colon";
    spaces_around_ranges: bool, false, false, "Put spaces around the  .. and ... range operators";
    spaces_within_parens_and_brackets: bool, false, false,
        "Put spaces within non-empty parentheses or brackets";

    // Misc.
    combine_control_expr: bool, true, false, "Combine control expressions with function calls.";
    struct_field_align_threshold: usize, 0, false, "Align struct fields if their diffs fits within \
                                             threshold.";
    remove_blank_lines_at_start_or_end_of_block: bool, true, false,
        "Remove blank lines at start or end of a block";
    match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \
        the same line with the pattern of arms";
    force_multiline_blocks: bool, false, false,
        "Force multiline closure bodies and match arms to be wrapped in a block";
    fn_args_density: Density, Density::Tall, false, "Argument density in functions";
    brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
    control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
        "Brace style for control flow constructs";
    trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
        "How to handle trailing commas for lists";
    trailing_semicolon: bool, true, false,
        "Add trailing semicolon after break, continue and return";
    match_block_trailing_comma: bool, false, false,
        "Put a trailing comma after a block based match arm (non-block arms are not affected)";
    blank_lines_upper_bound: usize, 1, false,
        "Maximum number of blank lines which can be put between items.";
    blank_lines_lower_bound: usize, 0, false,
        "Minimum number of blank lines which must be put between items.";

    // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
    merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
    use_try_shorthand: bool, false, false, "Replace uses of the try! macro by the ? shorthand";
    condense_wildcard_suffixes: bool, false, false, "Replace strings of _ wildcards by a single .. \
                                              in tuple patterns";
    force_explicit_abi: bool, true, true, "Always print the abi for extern items";
    use_field_init_shorthand: bool, false, false, "Use field initialization shorthand if possible";

    // Control options (changes the operation of rustfmt, rather than the formatting)
    write_mode: WriteMode, WriteMode::Overwrite, false,
        "What Write Mode to use when none is supplied: \
         Replace, Overwrite, Display, Plain, Diff, Coverage";
    color: Color, Color::Auto, false,
        "What Color option to use when none is supplied: Always, Never, Auto";
    required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
        "Require a specific version of rustfmt.";
    unstable_features: bool, false, true,
            "Enables unstable features. Only available on nightly channel";
    disable_all_formatting: bool, false, false, "Don't reformat anything";
    skip_children: bool, false, false, "Don't reformat out of line modules";
    hide_parse_errors: bool, false, false, "Hide errors from the parser";
    error_on_line_overflow: bool, true, false, "Error if unable to get all lines within max_width";
    error_on_unformatted: bool, false, false,
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces";
    report_todo: ReportTactic, ReportTactic::Never, false,
        "Report all, none or unnumbered occurrences of TODO in source file comments";
    report_fixme: ReportTactic, ReportTactic::Never, false,
        "Report all, none or unnumbered occurrences of FIXME in source file comments";

    // Not user-facing.
    verbose: bool, false, false, "Use verbose output";
    file_lines: FileLines, FileLines::all(), false,
        "Lines to format; this is not supported in rustfmt.toml, and can only be specified \
         via the --file-lines option";
    width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
        "'small' heuristic values";
}

/// Check for the presence of known config file names (`rustfmt.toml, `.rustfmt.toml`) in `dir`
///
/// Return the path if a config file exists, empty if no file exists, and Error for IO errors
pub fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
    const CONFIG_FILE_NAMES: [&str; 2] = [".rustfmt.toml", "rustfmt.toml"];
    for config_file_name in &CONFIG_FILE_NAMES {
        let config_file = dir.join(config_file_name);
        match fs::metadata(&config_file) {
            // Only return if it's a file to handle the unlikely situation of a directory named
            // `rustfmt.toml`.
            Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
            // Return the error if it's something other than `NotFound`; otherwise we didn't
            // find the project file yet, and continue searching.
            Err(e) => {
                if e.kind() != ErrorKind::NotFound {
                    return Err(e);
                }
            }
            _ => {}
        }
    }
    Ok(None)
}

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

    #[test]
    fn test_config_set() {
        let mut config = Config::default();
        config.set().verbose(false);
        assert_eq!(config.verbose(), false);
        config.set().verbose(true);
        assert_eq!(config.verbose(), true);
    }

    #[test]
    fn test_config_used_to_toml() {
        let config = Config::default();

        let merge_derives = config.merge_derives();
        let skip_children = config.skip_children();

        let used_options = config.used_options();
        let toml = used_options.to_toml().unwrap();
        assert_eq!(
            toml,
            format!(
                "merge_derives = {}\nskip_children = {}\n",
                merge_derives, skip_children,
            )
        );
    }

    #[test]
    fn test_was_set() {
        let config = Config::from_toml("hard_tabs = true").unwrap();

        assert_eq!(config.was_set().hard_tabs(), true);
        assert_eq!(config.was_set().verbose(), false);
    }

    // FIXME(#2183) these tests cannot be run in parallel because they use env vars
    // #[test]
    // fn test_as_not_nightly_channel() {
    //     let mut config = Config::default();
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     config.set().unstable_features(true);
    //     assert_eq!(config.was_set().unstable_features(), false);
    // }

    // #[test]
    // fn test_as_nightly_channel() {
    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
    //     let mut config = Config::default();
    //     config.set().unstable_features(true);
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     config.set().unstable_features(true);
    //     assert_eq!(config.unstable_features(), true);
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
    // }

    // #[test]
    // fn test_unstable_from_toml() {
    //     let mut config = Config::from_toml("unstable_features = true").unwrap();
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
    //     config = Config::from_toml("unstable_features = true").unwrap();
    //     assert_eq!(config.was_set().unstable_features(), true);
    //     assert_eq!(config.unstable_features(), true);
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
    // }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;

use std::hash::Hash;
use test::{black_box, Bencher};

use hashbrown::HashMap;
//use rustc_hash::FxHashMap as HashMap;
//use std::collections::HashMap;

fn new_map<K: Eq + Hash, V>() -> HashMap<K, V> {
    HashMap::default()
}

#[bench]
fn insert_i32(b: &mut Bencher) {
    b.iter(|| {
        let mut m: HashMap<i32, i32> = new_map();
        for i in 1..1001 {
            m.insert(i, i);
        }
        black_box(m);
    })
}

#[bench]
fn insert_i64(b: &mut Bencher) {
    b.iter(|| {
        let mut m: HashMap<i64, i64> = new_map();
        for i in 1..1001 {
            m.insert(i, i);
        }
        black_box(m);
    })
}

#[bench]
fn insert_erase_i32(b: &mut Bencher) {
    b.iter(|| {
        let mut m: HashMap<i32, i32> = new_map();
        for i in 1..1001 {
            m.insert(i, i);
        }
        black_box(&mut m);
        for i in 1..1001 {
            m.remove(&i);
        }
        black_box(m);
    })
}

#[bench]
fn insert_erase_i64(b: &mut Bencher) {
    b.iter(|| {
        let mut m: HashMap<i64, i64> = new_map();
        for i in 1..1001 {
            m.insert(i, i);
        }
        black_box(&mut m);
        for i in 1..1001 {
            m.remove(&i);
        }
        black_box(m);
    })
}

#[bench]
fn lookup_i32(b: &mut Bencher) {
    let mut m: HashMap<i32, i32> = new_map();
    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in 1..1001 {
            black_box(m.get(&i));
        }
    })
}

#[bench]
fn lookup_i64(b: &mut Bencher) {
    let mut m: HashMap<i64, i64> = new_map();
    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in 1..1001 {
            black_box(m.get(&i));
        }
    })
}

#[bench]
fn lookup_fail_i32(b: &mut Bencher) {
    let mut m: HashMap<i32, i32> = new_map();
    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in 1001..2001 {
            black_box(m.get(&i));
        }
    })
}

#[bench]
fn lookup_fail_i64(b: &mut Bencher) {
    let mut m: HashMap<i64, i64> = new_map();
    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in 1001..2001 {
            black_box(m.get(&i));
        }
    })
}

#[bench]
fn iter_i32(b: &mut Bencher) {
    let mut m: HashMap<i32, i32> = new_map();
    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in &m {
            black_box(i);
        }
    })
}

#[bench]
fn iter_i64(b: &mut Bencher) {
    let mut m: HashMap<i64, i64> = new_map();
    for i in 1..1001 {
        m.insert(i, i);
    }

    b.iter(|| {
        for i in &m {
            black_box(i);
        }
    })
}
<commit_msg>Add the std hasher and different key distributions to benchmarks.<commit_after>// This benchmark suite contains some benchmarks along a set of dimensions:
//   Hasher: std default (SipHash) and crate default (FxHash).
//   Int key distribution: low bit heavy, top bit heavy, and random.
//   Task: basic functionality: insert, insert_erase, lookup, lookup_fail, iter
#![feature(test)]

extern crate test;

use test::{black_box, Bencher};

use hashbrown::HashMap;
use hashbrown::hash_map::DefaultHashBuilder;
use std::collections::hash_map::RandomState;

const SIZE: usize = 1000;

// The default hashmap when using this crate directly.
type FxHashMap<K, V> = HashMap<K, V, DefaultHashBuilder>;
// This uses the hashmap from this crate with the default hasher of the stdlib.
type StdHashMap<K, V> = HashMap<K, V, RandomState>;

// A random key iterator.
#[derive(Clone, Copy)]
struct RandomKeys {
    remaining: usize,
    state: usize,
}

impl RandomKeys {
    fn new(size: usize) -> Self {
        RandomKeys{
            remaining: size,
            state: 1,
        }
    }

    // Produce a different set of random values.
    fn new2(size: usize) -> Self {
        RandomKeys{
            remaining: size,
            state: 2,
        }
    }
}

impl Iterator for RandomKeys {
    type Item = usize;
    fn next(&mut self) -> Option<usize> {
        if self.remaining == 0 {
            None
        } else {
            self.remaining -= 1;
            // Multiply by some 32 bit prime.
            self.state = self.state.wrapping_mul(3787392781);
            // Mix in to the bottom bits which are constant mod powers of 2.
            Some(self.state ^ (self.state >> 4))
        }
    }
}

macro_rules! bench_insert {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            b.iter(|| {
                let mut m = $maptype::default();
                for i in $keydist {
                    m.insert(i, i);
                }
                black_box(m);
            })
        }
    }
}

bench_insert!(insert_fx_serial, FxHashMap, 0..SIZE);
bench_insert!(insert_std_serial, StdHashMap, 0..SIZE);
bench_insert!(insert_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes));
bench_insert!(insert_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes));
bench_insert!(insert_fx_random, FxHashMap, RandomKeys::new(SIZE));
bench_insert!(insert_std_random, StdHashMap, RandomKeys::new(SIZE));

macro_rules! bench_insert_erase {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            b.iter(|| {
                let mut m = $maptype::default();
                for i in $keydist {
                    m.insert(i, i);
                }
                black_box(&mut m);
                for i in $keydist {
                    m.remove(&i);
                }
                black_box(m);
            })
        }
    }
}

bench_insert_erase!(insert_erase_fx_serial, FxHashMap, 0..SIZE);
bench_insert_erase!(insert_erase_std_serial, StdHashMap, 0..SIZE);
bench_insert_erase!(insert_erase_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes));
bench_insert_erase!(insert_erase_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes));
bench_insert_erase!(insert_erase_fx_random, FxHashMap, RandomKeys::new(SIZE));
bench_insert_erase!(insert_erase_std_random, StdHashMap, RandomKeys::new(SIZE));

macro_rules! bench_lookup {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            for i in $keydist {
                m.insert(i, i);
            }

            b.iter(|| {
                for i in $keydist {
                    black_box(m.get(&i));
                }
            })
        }
    }
}

bench_lookup!(lookup_fx_serial, FxHashMap, 0..SIZE);
bench_lookup!(lookup_std_serial, StdHashMap, 0..SIZE);
bench_lookup!(lookup_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes));
bench_lookup!(lookup_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes));
bench_lookup!(lookup_fx_random, FxHashMap, RandomKeys::new(SIZE));
bench_lookup!(lookup_std_random, StdHashMap, RandomKeys::new(SIZE));

macro_rules! bench_lookup_fail {
    ($name:ident, $maptype:ident, $keydist:expr, $keydist2:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            for i in $keydist {
                m.insert(i, i);
            }

            b.iter(|| {
                for i in $keydist2 {
                    black_box(m.get(&i));
                }
            })
        }
    }
}

bench_lookup_fail!(lookup_fail_fx_serial, FxHashMap, 0..SIZE, SIZE..SIZE*2);
bench_lookup_fail!(lookup_fail_std_serial, StdHashMap, 0..SIZE, SIZE..SIZE*2);
bench_lookup_fail!(lookup_fail_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes),
              (SIZE..SIZE*2).map(usize::swap_bytes));
bench_lookup_fail!(lookup_fail_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes),
              (SIZE..SIZE*2).map(usize::swap_bytes));
bench_lookup_fail!(lookup_fail_fx_random, FxHashMap, RandomKeys::new(SIZE), RandomKeys::new2(SIZE));
bench_lookup_fail!(lookup_fail_std_random, StdHashMap, RandomKeys::new(SIZE), RandomKeys::new2(SIZE));

macro_rules! bench_iter {
    ($name:ident, $maptype:ident, $keydist:expr) => {
        #[bench]
        fn $name(b: &mut Bencher) {
            let mut m = $maptype::default();
            for i in $keydist {
                m.insert(i, i);
            }

            b.iter(|| {
                for i in &m {
                    black_box(i);
                }
            })
        }
    }
}

bench_iter!(iter_fx_serial, FxHashMap, 0..SIZE);
bench_iter!(iter_std_serial, StdHashMap, 0..SIZE);
bench_iter!(iter_fx_highbits, FxHashMap, (0..SIZE).map(usize::swap_bytes));
bench_iter!(iter_std_highbits, StdHashMap, (0..SIZE).map(usize::swap_bytes));
bench_iter!(iter_fx_random, FxHashMap, RandomKeys::new(SIZE));
bench_iter!(iter_std_random, StdHashMap, RandomKeys::new(SIZE));
<|endoftext|>


<commit_before>extern crate test;
extern crate postgres;

use test::Bencher;

use postgres::{Connection, SslMode};

#[bench]
fn bench_naiive_execute(b: &mut test::Bencher) {
    let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
    conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]).unwrap();

    b.iter(|| {
        let stmt = conn.prepare("UPDATE foo SET id = 1").unwrap();
        let out = stmt.execute(&[]).unwrap();
        stmt.finish().unwrap();
        out
    });
}

#[bench]
fn bench_execute(b: &mut test::Bencher) {
    let conn = Connection::connect("postgres://postgres@localhost", &SslMode::None).unwrap();
    conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]).unwrap();

    b.iter(|| {
        conn.execute("UPDATE foo SET id = 1", &[]).unwrap()
    });
}
<commit_msg>Update benchmark<commit_after>#![feature(test)]
extern crate test;
extern crate postgres;

use postgres::{Connection, TlsMode};

#[bench]
fn bench_naiive_execute(b: &mut test::Bencher) {
    let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
    conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]).unwrap();

    b.iter(|| {
        let stmt = conn.prepare("UPDATE foo SET id = 1").unwrap();
        let out = stmt.execute(&[]).unwrap();
        stmt.finish().unwrap();
        out
    });
}

#[bench]
fn bench_execute(b: &mut test::Bencher) {
    let conn = Connection::connect("postgres://postgres@localhost", TlsMode::None).unwrap();
    conn.execute("CREATE TEMPORARY TABLE foo (id INT)", &[]).unwrap();

    b.iter(|| {
        conn.execute("UPDATE foo SET id = 1", &[]).unwrap()
    });
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate crossbeam;
extern crate ipc_channel;
extern crate test;

use ipc_channel::platform;

use std::sync::{mpsc, Mutex};

/// Allows doing multiple inner iterations per bench.iter() run.
///
/// This is mostly to amortise the overhead of spawning a thread in the benchmark
/// when sending larger messages (that might be fragmented).
///
/// Note that you need to compensate the displayed results
/// for the proportionally longer runs yourself,
/// as the benchmark framework doesn't know about the inner iterations...
const ITERATIONS: usize = 1;

#[bench]
fn create_channel(b: &mut test::Bencher) {
    b.iter(|| {
        for _ in 0..ITERATIONS {
            platform::channel().unwrap();
        }
    });
}

fn bench_size(b: &mut test::Bencher, size: usize) {
    let data: Vec<u8> = (0..size).map(|i| (i % 251) as u8).collect();
    let (tx, rx) = platform::channel().unwrap();

    let (wait_tx, wait_rx) = mpsc::channel();
    let wait_rx = Mutex::new(wait_rx);

    if size > platform::OsIpcSender::get_max_fragment_size() {
        b.iter(|| {
            crossbeam::scope(|scope| {
                let tx = tx.clone();
                scope.spawn(|| {
                    let wait_rx = wait_rx.lock().unwrap();
                    let tx = tx;
                    for _ in 0..ITERATIONS {
                        tx.send(&data, vec![], vec![]).unwrap();
                        if ITERATIONS > 1 {
                            // Prevent beginning of the next send
                            // from overlapping with receive of last fragment,
                            // as otherwise results of runs with a large tail fragment
                            // are significantly skewed.
                            wait_rx.recv().unwrap();
                        }
                    }
                });
                for _ in 0..ITERATIONS {
                    rx.recv().unwrap();
                    if ITERATIONS > 1 {
                        wait_tx.send(()).unwrap();
                    }
                }
                // For reasons mysterious to me,
                // not returning a value *from every branch*
                // adds some 100 ns or so of overhead to all results --
                // which is quite significant for very short tests...
                0
            })
        });
    } else {
        b.iter(|| {
            for _ in 0..ITERATIONS {
                tx.send(&data, vec![], vec![]).unwrap();
                rx.recv().unwrap();
            }
            0
        });
    }
}

#[bench]
fn size_00_1(b: &mut test::Bencher) {
    bench_size(b, 1);
}
#[bench]
fn size_01_2(b: &mut test::Bencher) {
    bench_size(b, 2);
}
#[bench]
fn size_02_4(b: &mut test::Bencher) {
    bench_size(b, 4);
}
#[bench]
fn size_03_8(b: &mut test::Bencher) {
    bench_size(b, 8);
}
#[bench]
fn size_04_16(b: &mut test::Bencher) {
    bench_size(b, 16);
}
#[bench]
fn size_05_32(b: &mut test::Bencher) {
    bench_size(b, 32);
}
#[bench]
fn size_06_64(b: &mut test::Bencher) {
    bench_size(b, 64);
}
#[bench]
fn size_07_128(b: &mut test::Bencher) {
    bench_size(b, 128);
}
#[bench]
fn size_08_256(b: &mut test::Bencher) {
    bench_size(b, 256);
}
#[bench]
fn size_09_512(b: &mut test::Bencher) {
    bench_size(b, 512);
}
#[bench]
fn size_10_1k(b: &mut test::Bencher) {
    bench_size(b, 1 * 1024);
}
#[bench]
fn size_11_2k(b: &mut test::Bencher) {
    bench_size(b, 2 * 1024);
}
#[bench]
fn size_12_4k(b: &mut test::Bencher) {
    bench_size(b, 4 * 1024);
}
#[bench]
fn size_13_8k(b: &mut test::Bencher) {
    bench_size(b, 8 * 1024);
}
#[bench]
fn size_14_16k(b: &mut test::Bencher) {
    bench_size(b, 16 * 1024);
}
#[bench]
fn size_15_32k(b: &mut test::Bencher) {
    bench_size(b, 32 * 1024);
}
#[bench]
fn size_16_64k(b: &mut test::Bencher) {
    bench_size(b, 64 * 1024);
}
#[bench]
fn size_17_128k(b: &mut test::Bencher) {
    bench_size(b, 128 * 1024);
}
#[bench]
fn size_18_256k(b: &mut test::Bencher) {
    bench_size(b, 256 * 1024);
}
#[bench]
fn size_19_512k(b: &mut test::Bencher) {
    bench_size(b, 512 * 1024);
}
#[bench]
fn size_20_1m(b: &mut test::Bencher) {
    bench_size(b, 1 * 1024 * 1024);
}
#[bench]
fn size_21_2m(b: &mut test::Bencher) {
    bench_size(b, 2 * 1024 * 1024);
}
#[bench]
fn size_22_4m(b: &mut test::Bencher) {
    bench_size(b, 4 * 1024 * 1024);
}
#[bench]
fn size_23_8m(b: &mut test::Bencher) {
    bench_size(b, 8 * 1024 * 1024);
}

mod receiver_set {
    use ipc_channel::ipc::{self, IpcReceiverSet};
    use test;

    fn gen_select_test(b: &mut test::Bencher, to_send: usize, n: usize) -> () {
        let mut active = Vec::with_capacity(to_send);
        let mut dormant = Vec::with_capacity(n - to_send);
        let mut rx_set = IpcReceiverSet::new().unwrap();
        for _ in 0..to_send {
            let (tx, rx) = ipc::channel().unwrap();
            rx_set.add(rx).unwrap();
            active.push(tx);
        }
        for _ in to_send..n {
            let (tx, rx) = ipc::channel::<()>().unwrap();
            rx_set.add(rx).unwrap();
            dormant.push(tx);
        }
        b.iter(|| {
            for tx in active.iter() {
                tx.send(()).unwrap();
            }
            let mut received = 0;
            while received < to_send {
                for result in rx_set.select().unwrap().into_iter() {
                    let (_, _) = result.unwrap();
                    received += 1;
                }
            }
        });
    }

    fn create_empty_set() -> Result<IpcReceiverSet, ()> {
        Ok(IpcReceiverSet::new().unwrap())
    }

    fn add_n_rxs(rx_set: &mut IpcReceiverSet, n: usize) -> () {
        for _ in 0..n {
            let (_, rx) = ipc::channel::<()>().unwrap();
            rx_set.add(rx).unwrap();
        }
    }

    #[bench]
    fn send_on_1_of_1(b: &mut test::Bencher) -> () {
        gen_select_test(b, 1, 1);
    }

    #[bench]
    fn send_on_1_of_5(b: &mut test::Bencher) -> () {
        gen_select_test(b, 1, 5);
    }

    #[bench]
    fn send_on_2_of_5(b: &mut test::Bencher) -> () {
        gen_select_test(b, 2, 5);
    }

    #[bench]
    fn send_on_5_of_5(b: &mut test::Bencher) -> () {
        gen_select_test(b, 5, 5);
    }

    #[bench]
    fn send_on_1_of_20(b: &mut test::Bencher) -> () {
        gen_select_test(b, 1, 20);
    }

    #[bench]
    fn send_on_5_of_20(b: &mut test::Bencher) -> () {
        gen_select_test(b, 5, 20);
    }

    #[bench]
    fn send_on_20_of_20(b: &mut test::Bencher) -> () {
        gen_select_test(b, 20, 20);
    }

    #[bench]
    fn send_on_1_of_100(b: &mut test::Bencher) -> () {
        gen_select_test(b, 1, 100);
    }

    #[bench]
    fn send_on_5_of_100(b: &mut test::Bencher) -> () {
        gen_select_test(b, 5, 100);
    }
    #[bench]
    fn send_on_20_of_100(b: &mut test::Bencher) -> () {
        gen_select_test(b, 20, 100);
    }

    #[bench]
    fn send_on_100_of_100(b: &mut test::Bencher) -> () {
        gen_select_test(b, 100, 100);
    }

    #[bench]
    fn create_and_destroy_empty_set(b: &mut test::Bencher) -> () {
        b.iter(|| {
            create_empty_set().unwrap();
        });
    }

    #[bench]
    fn create_and_destroy_set_of_10(b: &mut test::Bencher) -> () {
        b.iter(|| {
            let mut rx_set = IpcReceiverSet::new().unwrap();
            add_n_rxs(&mut rx_set, 10);
        });
    }

    #[bench]
    fn create_and_destroy_set_of_5(b: &mut test::Bencher) -> () {
        b.iter(|| {
            let mut rx_set = IpcReceiverSet::new().unwrap();
            add_n_rxs(&mut rx_set, 5);
        });
    }

    #[bench]
    // Benchmark adding and removing closed receivers from the set
    fn add_and_remove_closed_receivers(b: &mut test::Bencher) -> () {
        b.iter(|| {
            let mut rx_set = IpcReceiverSet::new().unwrap();
            {
                {
                    let (_, rx) = ipc::channel::<()>().unwrap();
                    rx_set.add(rx).unwrap();
                }
                // On select Receivers with a "ClosedChannel" event
                // will be closed
                rx_set.select().unwrap();
                let (_, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
            }
        });
    }
}
<commit_msg>Benchmarks: Separate platform and high-level tests into submodules<commit_after>#![feature(test)]

extern crate ipc_channel;
extern crate test;

/// Allows doing multiple inner iterations per bench.iter() run.
///
/// This is mostly to amortise the overhead of spawning a thread in the benchmark
/// when sending larger messages (that might be fragmented).
///
/// Note that you need to compensate the displayed results
/// for the proportionally longer runs yourself,
/// as the benchmark framework doesn't know about the inner iterations...
const ITERATIONS: usize = 1;

mod platform {
    extern crate crossbeam;

    use ipc_channel::platform;
    use ITERATIONS;

    use std::sync::{mpsc, Mutex};
    use test;

    #[bench]
    fn create_channel(b: &mut test::Bencher) {
        b.iter(|| {
            for _ in 0..ITERATIONS {
                platform::channel().unwrap();
            }
        });
    }

    fn bench_transfer_data(b: &mut test::Bencher, size: usize) {
        let data: Vec<u8> = (0..size).map(|i| (i % 251) as u8).collect();
        let (tx, rx) = platform::channel().unwrap();

        let (wait_tx, wait_rx) = mpsc::channel();
        let wait_rx = Mutex::new(wait_rx);

        if size > platform::OsIpcSender::get_max_fragment_size() {
            b.iter(|| {
                crossbeam::scope(|scope| {
                    let tx = tx.clone();
                    scope.spawn(|| {
                        let wait_rx = wait_rx.lock().unwrap();
                        let tx = tx;
                        for _ in 0..ITERATIONS {
                            tx.send(&data, vec![], vec![]).unwrap();
                            if ITERATIONS > 1 {
                                // Prevent beginning of the next send
                                // from overlapping with receive of last fragment,
                                // as otherwise results of runs with a large tail fragment
                                // are significantly skewed.
                                wait_rx.recv().unwrap();
                            }
                        }
                    });
                    for _ in 0..ITERATIONS {
                        rx.recv().unwrap();
                        if ITERATIONS > 1 {
                            wait_tx.send(()).unwrap();
                        }
                    }
                    // For reasons mysterious to me,
                    // not returning a value *from every branch*
                    // adds some 100 ns or so of overhead to all results --
                    // which is quite significant for very short tests...
                    0
                })
            });
        } else {
            b.iter(|| {
                for _ in 0..ITERATIONS {
                    tx.send(&data, vec![], vec![]).unwrap();
                    rx.recv().unwrap();
                }
                0
            });
        }
    }

    #[bench]
    fn transfer_data_00_1(b: &mut test::Bencher) {
        bench_transfer_data(b, 1);
    }
    #[bench]
    fn transfer_data_01_2(b: &mut test::Bencher) {
        bench_transfer_data(b, 2);
    }
    #[bench]
    fn transfer_data_02_4(b: &mut test::Bencher) {
        bench_transfer_data(b, 4);
    }
    #[bench]
    fn transfer_data_03_8(b: &mut test::Bencher) {
        bench_transfer_data(b, 8);
    }
    #[bench]
    fn transfer_data_04_16(b: &mut test::Bencher) {
        bench_transfer_data(b, 16);
    }
    #[bench]
    fn transfer_data_05_32(b: &mut test::Bencher) {
        bench_transfer_data(b, 32);
    }
    #[bench]
    fn transfer_data_06_64(b: &mut test::Bencher) {
        bench_transfer_data(b, 64);
    }
    #[bench]
    fn transfer_data_07_128(b: &mut test::Bencher) {
        bench_transfer_data(b, 128);
    }
    #[bench]
    fn transfer_data_08_256(b: &mut test::Bencher) {
        bench_transfer_data(b, 256);
    }
    #[bench]
    fn transfer_data_09_512(b: &mut test::Bencher) {
        bench_transfer_data(b, 512);
    }
    #[bench]
    fn transfer_data_10_1k(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024);
    }
    #[bench]
    fn transfer_data_11_2k(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024);
    }
    #[bench]
    fn transfer_data_12_4k(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024);
    }
    #[bench]
    fn transfer_data_13_8k(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024);
    }
    #[bench]
    fn transfer_data_14_16k(b: &mut test::Bencher) {
        bench_transfer_data(b, 16 * 1024);
    }
    #[bench]
    fn transfer_data_15_32k(b: &mut test::Bencher) {
        bench_transfer_data(b, 32 * 1024);
    }
    #[bench]
    fn transfer_data_16_64k(b: &mut test::Bencher) {
        bench_transfer_data(b, 64 * 1024);
    }
    #[bench]
    fn transfer_data_17_128k(b: &mut test::Bencher) {
        bench_transfer_data(b, 128 * 1024);
    }
    #[bench]
    fn transfer_data_18_256k(b: &mut test::Bencher) {
        bench_transfer_data(b, 256 * 1024);
    }
    #[bench]
    fn transfer_data_19_512k(b: &mut test::Bencher) {
        bench_transfer_data(b, 512 * 1024);
    }
    #[bench]
    fn transfer_data_20_1m(b: &mut test::Bencher) {
        bench_transfer_data(b, 1 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_21_2m(b: &mut test::Bencher) {
        bench_transfer_data(b, 2 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_22_4m(b: &mut test::Bencher) {
        bench_transfer_data(b, 4 * 1024 * 1024);
    }
    #[bench]
    fn transfer_data_23_8m(b: &mut test::Bencher) {
        bench_transfer_data(b, 8 * 1024 * 1024);
    }
}

mod ipc {
    mod receiver_set {
        use ipc_channel::ipc::{self, IpcReceiverSet};
        use test;

        fn gen_select_test(b: &mut test::Bencher, to_send: usize, n: usize) -> () {
            let mut active = Vec::with_capacity(to_send);
            let mut dormant = Vec::with_capacity(n - to_send);
            let mut rx_set = IpcReceiverSet::new().unwrap();
            for _ in 0..to_send {
                let (tx, rx) = ipc::channel().unwrap();
                rx_set.add(rx).unwrap();
                active.push(tx);
            }
            for _ in to_send..n {
                let (tx, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
                dormant.push(tx);
            }
            b.iter(|| {
                for tx in active.iter() {
                    tx.send(()).unwrap();
                }
                let mut received = 0;
                while received < to_send {
                    for result in rx_set.select().unwrap().into_iter() {
                        let (_, _) = result.unwrap();
                        received += 1;
                    }
                }
            });
        }

        fn create_empty_set() -> Result<IpcReceiverSet, ()> {
            Ok(IpcReceiverSet::new().unwrap())
        }

        fn add_n_rxs(rx_set: &mut IpcReceiverSet, n: usize) -> () {
            for _ in 0..n {
                let (_, rx) = ipc::channel::<()>().unwrap();
                rx_set.add(rx).unwrap();
            }
        }

        #[bench]
        fn send_on_1_of_1(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 1);
        }

        #[bench]
        fn send_on_1_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 5);
        }

        #[bench]
        fn send_on_2_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 2, 5);
        }

        #[bench]
        fn send_on_5_of_5(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 5);
        }

        #[bench]
        fn send_on_1_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 20);
        }

        #[bench]
        fn send_on_5_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 20);
        }

        #[bench]
        fn send_on_20_of_20(b: &mut test::Bencher) -> () {
            gen_select_test(b, 20, 20);
        }

        #[bench]
        fn send_on_1_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 1, 100);
        }

        #[bench]
        fn send_on_5_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 5, 100);
        }
        #[bench]
        fn send_on_20_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 20, 100);
        }

        #[bench]
        fn send_on_100_of_100(b: &mut test::Bencher) -> () {
            gen_select_test(b, 100, 100);
        }

        #[bench]
        fn create_and_destroy_empty_set(b: &mut test::Bencher) -> () {
            b.iter(|| {
                create_empty_set().unwrap();
            });
        }

        #[bench]
        fn create_and_destroy_set_of_10(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                add_n_rxs(&mut rx_set, 10);
            });
        }

        #[bench]
        fn create_and_destroy_set_of_5(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                add_n_rxs(&mut rx_set, 5);
            });
        }

        #[bench]
        // Benchmark adding and removing closed receivers from the set
        fn add_and_remove_closed_receivers(b: &mut test::Bencher) -> () {
            b.iter(|| {
                let mut rx_set = IpcReceiverSet::new().unwrap();
                {
                    {
                        let (_, rx) = ipc::channel::<()>().unwrap();
                        rx_set.add(rx).unwrap();
                    }
                    // On select Receivers with a "ClosedChannel" event
                    // will be closed
                    rx_set.select().unwrap();
                    let (_, rx) = ipc::channel::<()>().unwrap();
                    rx_set.add(rx).unwrap();
                }
            });
        }
    }
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate robots;
extern crate test;

use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender};

use robots::actors::{Actor, ActorSystem, ActorCell, ActorContext, Arguments, Props};

use test::Bencher;

#[derive(Copy, Clone, PartialEq)]
enum BenchMessage {
    Nothing,
    Over,
}

struct InternalState {
    sender: Arc<Mutex<Sender<()>>>,
}

impl Actor<BenchMessage> for InternalState {
    fn receive<Args: Arguments>(&self, message: BenchMessage, _context: ActorCell<Args, BenchMessage, InternalState>) {
        if message == BenchMessage::Over {
            let _ = self.sender.lock().unwrap().send(());
        }
    }
}

impl InternalState {
    fn new(sender: Arc<Mutex<Sender<()>>>) -> InternalState {
        InternalState {
            sender: sender,
        }
    }
}

#[bench]
fn send_1000_messages(b: &mut Bencher) {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(2);

    let (tx, rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(InternalState::new), tx);
    let actor_ref_1 = actor_system.actor_of(props.clone(), "sender".to_owned());
    let actor_ref_2 = actor_system.actor_of(props.clone(), "receiver".to_owned());

    b.iter(|| {
        for _ in 0..1_000 {
            actor_ref_1.tell_to(actor_ref_2.clone(), BenchMessage::Nothing);
        }
        actor_ref_1.tell_to(actor_ref_2.clone(), BenchMessage::Over);
        let _ = rx.recv();
    });

    actor_system.shutdown();
}
<commit_msg>Add actor creation bench.<commit_after>#![feature(test)]

extern crate robots;
extern crate test;

use std::sync::{Arc, Mutex};
use std::sync::mpsc::{channel, Sender};

use robots::actors::{Actor, ActorSystem, ActorCell, ActorContext, Arguments, Props};

use test::Bencher;

#[derive(Copy, Clone, PartialEq)]
enum BenchMessage {
    Nothing,
    Over,
}

struct InternalState {
    sender: Arc<Mutex<Sender<()>>>,
}

impl Actor<BenchMessage> for InternalState {
    fn receive<Args: Arguments>(&self,
                                message: BenchMessage,
                                _context: ActorCell<Args, BenchMessage, InternalState>) {
        if message == BenchMessage::Over {
            let _ = self.sender.lock().unwrap().send(());
        }
    }
}

impl InternalState {
    fn new(sender: Arc<Mutex<Sender<()>>>) -> InternalState {
        InternalState { sender: sender }
    }
}

#[bench]
fn send_1000_messages(b: &mut Bencher) {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(1);

    let (tx, rx) = channel();
    let tx = Arc::new(Mutex::new(tx));

    let props = Props::new(Arc::new(InternalState::new), tx);
    let actor_ref_1 = actor_system.actor_of(props.clone(), "sender".to_owned());
    let actor_ref_2 = actor_system.actor_of(props.clone(), "receiver".to_owned());

    b.iter(|| {
        for _ in 0..1_000 {
            actor_ref_1.tell_to(actor_ref_2.clone(), BenchMessage::Nothing);
        }
        actor_ref_1.tell_to(actor_ref_2.clone(), BenchMessage::Over);
        let _ = rx.recv();
    });

    actor_system.shutdown();
}

struct Dummy;

impl Actor<()> for Dummy {
    fn receive<Args: Arguments>(&self, _message: (), _context: ActorCell<Args, (), Dummy>) {}
}

impl Dummy {
    fn new(_: ()) -> Dummy {
        Dummy
    }
}

#[bench]
fn create_1000_actors(b: &mut Bencher) {
    let actor_system = ActorSystem::new("test".to_owned());
    actor_system.spawn_threads(1);

    let props = Props::new(Arc::new(Dummy::new), ());

    b.iter(|| {
        for i in 0..1_000 {
            actor_system.actor_of(props.clone(), format!("{}", i));
        }
    });

    actor_system.shutdown();
}
<|endoftext|>