<commit_before>#[allow(default_methods)];  // For the benefit of Server. Hopefully it'll work.

extern mod extra;

use std::cell::Cell;
use std::comm::SharedChan;
use std::task::{spawn_with, spawn_supervised};
use std::rt::io::{Listener, Writer};
use std::rt::io::net::ip::IpAddr;
use std::rt::io::io_error;
use extra::time::precise_time_ns;

use std::rt::io::net::tcp::TcpListener;

use super::request::{RequestBuffer, Request};
use super::response::ResponseWriter;

// TODO: when mozilla/rust#7661 is resolved, assuming also that specifying inheritance of kinds for
// the trait works:
// - Scrap ServerUtil (including any using it into the local scope)
// - Change "trait Server" to "trait Server: Send"
// - Shift the serve_forever method into Server
pub trait Server {
	pub fn handle_request(&self, request: &Request, response: &mut ResponseWriter) -> ();

	// XXX: this could also be implemented on the serve methods
	pub fn get_config(&self) -> Config;
}

/// A temporary trait to fix current deficiencies in Rust's default methods on traits.
/// You'll need to import `ServerUtil` to be able to call `serve_forever` on a Server.
pub trait ServerUtil {
    pub fn serve_forever(self);
}

impl<T: Send + Clone + Server> ServerUtil for T {
	/**
	 * Attempt to bind to the address and port and start serving forever.
	 *
	 * This will only return if the initial connection fails or something else blows up.
	 */
    pub fn serve_forever(self) {
        let config = self.get_config();
        debug!("About to bind to %?", config.bind_address);
        let mut optlistener = TcpListener::bind(config.bind_address);
        debug!("Bind attempt completed");
        let (perf_po, perf_ch) = stream();
        let perf_ch = SharedChan::new(perf_ch);
        spawn_with(perf_po, perf_dumper);
        match optlistener {
            None => {
                debug!("listen failed :-(");
                return;
            }
            Some(ref mut listener) => {
                debug!("listening");
                loop {
                    // OK, we're sort of shadowing an IoError here. Perhaps this should be done in a
                    // separate task so that it can safely fail...
                    let mut error = None;
                    let optstream = io_error::cond.trap(|e| {
                        error = Some(e);
                    }).in(|| {
                        listener.accept()
                    });

                    let time_start = precise_time_ns();
                    if optstream.is_none() {
                        debug!("accept failed: %?", error);
                        // Question: is this the correct thing to do? We should probably be more
                        // intelligent, for there are some accept failures that are likely to be
                        // permanent, such that continuing would be a very bad idea, such as
                        // ENOBUFS/ENOMEM; and some where it should just be ignored, e.g.
                        // ECONNABORTED. TODO.
                        loop;
                    }
                    let stream = Cell::new(optstream.unwrap());
                    let child_perf_ch = perf_ch.clone();
                    let child_self = self.clone();
                    do spawn_supervised {
                        let mut time_start = time_start;
                        let mut stream = ~stream.take();
                        debug!("accepted connection, got %?", stream);
                        loop {  // A keep-alive loop, condition at end
                            let time_spawned = precise_time_ns();
                            let (request, err_status) = Request::get(~RequestBuffer::new(stream));
                            let time_request_made = precise_time_ns();
                            let mut response = ~ResponseWriter::new(stream, request);
                            let time_response_made = precise_time_ns();
                            match err_status {
                                Ok(()) => {
                                    child_self.handle_request(request, response);
                                    // Ensure that we actually do send a response:
                                    response.try_write_headers();
                                },
                                Err(status) => {
                                    // Uh oh, it's a response that I as a server cannot cope with.
                                    // No good user-agent should have caused this, so for the moment
                                    // at least I am content to send no body in the response.
                                    response.status = status;
                                    response.headers.insert(~"Content-Length", ~"0");
                                    response.write_headers();
                                },
                            }
                            // This should not be necessary, but is, because of the Drop bug
                            // apparent in BufferedWriter. When that is fixed up, then it *may* be
                            // suitable to remove flush() from here. I say "may" as it would mean
                            // that time_finished might not include writing all the response (a
                            // non-trivial time interval).
                            response.flush();
                            let time_finished = precise_time_ns();
                            child_perf_ch.send((time_start, time_spawned, time_request_made, time_response_made, time_finished));

                            // Subsequent requests on this connection have no spawn time
                            time_start = time_finished;

                            if request.close_connection {
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
}

/// The necessary configuration for an HTTP server.
///
/// At present, only the IP address and port to bind to are needed, but it's possible that other
/// options may turn up later.
pub struct Config {
	bind_address: IpAddr,
}

/* Sorry, but Rust isn't ready for this yet; SimpleServer can't be made Clone just yet. (For
 * starters, ~fn() isn't cloneable.)

/// A simple `Server`-implementing class, allowing code to be written in an imperative style.
pub struct SimpleServer {
    config: Config,
    handler: ~fn(&Request, &mut ResponseWriter),
}

impl SimpleServer {
    /// Create a new `SimpleServer` instance with the provided members.
    pub fn new(config: Config, handler: ~fn(&Request, &mut ResponseWriter)) -> SimpleServer {
        SimpleServer {
            config: config,
            handler: handler,
        }
    }
}

impl Server for SimpleServer {
    /// Handles a request by passing it on to the structure's handler function.
    #[inline]
	pub fn handle_request(&self, request: &Request, response: &mut ResponseWriter) {
        (self.handler)(request, response);
    }

    /// Returns the structure's known config.
    #[inline]
	pub fn get_config(&self) -> Config {
        self.config
    }
}

/// Create a simple server and immediately start serving forever.
///
/// This is equivalent to
///
/// ~~~ {.rust}
/// SimpleServer::new(Config { bind_address: ip_addr }, handler).serve_forever();
/// ~~~
///
/// But it's nicer this way with `do` blocks and closures:
///
/// ~~~ {.rust}
/// do serve_forever(ip_addr) |r, mut w| {
///     // Now you can handle the request here and write the wresponse.
/// }
/// ~~~
///
/// The signature of this method is liable to change if `Config` gets more members.
// Please, pretty please, don't correct the word "wresponse".
#[inline]
pub fn serve_forever(ip_addr: IpAddr, handler: ~fn(&Request, &mut ResponseWriter)) {
    SimpleServer::new(Config { bind_address: ip_addr }, handler).serve_forever();
}

/// 0.0.0.0, port 80: publicly bound to the standard HTTP port.
/// Not recommended at present as this server is not hardened against the sort of traffic you may
/// encounter on the Internet and is vulnerable to various DoS attacks. Sit it behind a gateway.
static PUBLIC: IpAddr = Ipv4(0, 0, 0, 0, 80);
*/

static PERF_DUMP_FREQUENCY : u64 = 10_000;

/// Simple function to dump out perf stats every `PERF_DUMP_FREQUENCY` requests
fn perf_dumper(perf_po: Port<(u64, u64, u64, u64, u64)>) {
    // Total durations
    let mut td_spawn = 0u64;
    let mut td_request = 0u64;
    let mut td_response = 0u64;
    let mut td_handle = 0u64;
    let mut td_total = 0u64;
    let mut i = 0u64;
    loop {
        let data = perf_po.recv();
        let (start, spawned, request_made, response_made, finished) = data;
        td_spawn += spawned - start;
        td_request += request_made - spawned;
        td_response += response_made - request_made;
        td_handle += finished - response_made;
        td_total += finished - start;
        i += 1;
        if i % PERF_DUMP_FREQUENCY == 0 {
            println("");
            println(fmt!("%? requests made thus far. Current means:", i));
            println(fmt!("- Total:               100%%, %12?", td_total / i));
            println(fmt!("- Spawn:               %3?%%, %12?", 100 * td_spawn / td_total, td_spawn / i));
            println(fmt!("- Load request:        %3?%%, %12?", 100 * td_request / td_total, td_request / i));
            println(fmt!("- Initialise response: %3?%%, %12?", 100 * td_response / td_total, td_response / i));
            println(fmt!("- Handle:              %3?%%, %12?", 100 * td_handle / td_total, td_handle / i));
        }
    }
}
<commit_msg>Omit the now-unnecessary #[allow(default_methods)].<commit_after>extern mod extra;

use std::cell::Cell;
use std::comm::SharedChan;
use std::task::{spawn_with, spawn_supervised};
use std::rt::io::{Listener, Writer};
use std::rt::io::net::ip::IpAddr;
use std::rt::io::io_error;
use extra::time::precise_time_ns;

use std::rt::io::net::tcp::TcpListener;

use super::request::{RequestBuffer, Request};
use super::response::ResponseWriter;

// TODO: when mozilla/rust#7661 is resolved, assuming also that specifying inheritance of kinds for
// the trait works:
// - Scrap ServerUtil (including any using it into the local scope)
// - Change "trait Server" to "trait Server: Send"
// - Shift the serve_forever method into Server
pub trait Server {
	pub fn handle_request(&self, request: &Request, response: &mut ResponseWriter) -> ();

	// XXX: this could also be implemented on the serve methods
	pub fn get_config(&self) -> Config;
}

/// A temporary trait to fix current deficiencies in Rust's default methods on traits.
/// You'll need to import `ServerUtil` to be able to call `serve_forever` on a Server.
pub trait ServerUtil {
    pub fn serve_forever(self);
}

impl<T: Send + Clone + Server> ServerUtil for T {
	/**
	 * Attempt to bind to the address and port and start serving forever.
	 *
	 * This will only return if the initial connection fails or something else blows up.
	 */
    pub fn serve_forever(self) {
        let config = self.get_config();
        debug!("About to bind to %?", config.bind_address);
        let mut optlistener = TcpListener::bind(config.bind_address);
        debug!("Bind attempt completed");
        let (perf_po, perf_ch) = stream();
        let perf_ch = SharedChan::new(perf_ch);
        spawn_with(perf_po, perf_dumper);
        match optlistener {
            None => {
                debug!("listen failed :-(");
                return;
            }
            Some(ref mut listener) => {
                debug!("listening");
                loop {
                    // OK, we're sort of shadowing an IoError here. Perhaps this should be done in a
                    // separate task so that it can safely fail...
                    let mut error = None;
                    let optstream = io_error::cond.trap(|e| {
                        error = Some(e);
                    }).in(|| {
                        listener.accept()
                    });

                    let time_start = precise_time_ns();
                    if optstream.is_none() {
                        debug!("accept failed: %?", error);
                        // Question: is this the correct thing to do? We should probably be more
                        // intelligent, for there are some accept failures that are likely to be
                        // permanent, such that continuing would be a very bad idea, such as
                        // ENOBUFS/ENOMEM; and some where it should just be ignored, e.g.
                        // ECONNABORTED. TODO.
                        loop;
                    }
                    let stream = Cell::new(optstream.unwrap());
                    let child_perf_ch = perf_ch.clone();
                    let child_self = self.clone();
                    do spawn_supervised {
                        let mut time_start = time_start;
                        let mut stream = ~stream.take();
                        debug!("accepted connection, got %?", stream);
                        loop {  // A keep-alive loop, condition at end
                            let time_spawned = precise_time_ns();
                            let (request, err_status) = Request::get(~RequestBuffer::new(stream));
                            let time_request_made = precise_time_ns();
                            let mut response = ~ResponseWriter::new(stream, request);
                            let time_response_made = precise_time_ns();
                            match err_status {
                                Ok(()) => {
                                    child_self.handle_request(request, response);
                                    // Ensure that we actually do send a response:
                                    response.try_write_headers();
                                },
                                Err(status) => {
                                    // Uh oh, it's a response that I as a server cannot cope with.
                                    // No good user-agent should have caused this, so for the moment
                                    // at least I am content to send no body in the response.
                                    response.status = status;
                                    response.headers.insert(~"Content-Length", ~"0");
                                    response.write_headers();
                                },
                            }
                            // This should not be necessary, but is, because of the Drop bug
                            // apparent in BufferedWriter. When that is fixed up, then it *may* be
                            // suitable to remove flush() from here. I say "may" as it would mean
                            // that time_finished might not include writing all the response (a
                            // non-trivial time interval).
                            response.flush();
                            let time_finished = precise_time_ns();
                            child_perf_ch.send((time_start, time_spawned, time_request_made, time_response_made, time_finished));

                            // Subsequent requests on this connection have no spawn time
                            time_start = time_finished;

                            if request.close_connection {
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
}

/// The necessary configuration for an HTTP server.
///
/// At present, only the IP address and port to bind to are needed, but it's possible that other
/// options may turn up later.
pub struct Config {
	bind_address: IpAddr,
}

/* Sorry, but Rust isn't ready for this yet; SimpleServer can't be made Clone just yet. (For
 * starters, ~fn() isn't cloneable.)

/// A simple `Server`-implementing class, allowing code to be written in an imperative style.
pub struct SimpleServer {
    config: Config,
    handler: ~fn(&Request, &mut ResponseWriter),
}

impl SimpleServer {
    /// Create a new `SimpleServer` instance with the provided members.
    pub fn new(config: Config, handler: ~fn(&Request, &mut ResponseWriter)) -> SimpleServer {
        SimpleServer {
            config: config,
            handler: handler,
        }
    }
}

impl Server for SimpleServer {
    /// Handles a request by passing it on to the structure's handler function.
    #[inline]
	pub fn handle_request(&self, request: &Request, response: &mut ResponseWriter) {
        (self.handler)(request, response);
    }

    /// Returns the structure's known config.
    #[inline]
	pub fn get_config(&self) -> Config {
        self.config
    }
}

/// Create a simple server and immediately start serving forever.
///
/// This is equivalent to
///
/// ~~~ {.rust}
/// SimpleServer::new(Config { bind_address: ip_addr }, handler).serve_forever();
/// ~~~
///
/// But it's nicer this way with `do` blocks and closures:
///
/// ~~~ {.rust}
/// do serve_forever(ip_addr) |r, mut w| {
///     // Now you can handle the request here and write the wresponse.
/// }
/// ~~~
///
/// The signature of this method is liable to change if `Config` gets more members.
// Please, pretty please, don't correct the word "wresponse".
#[inline]
pub fn serve_forever(ip_addr: IpAddr, handler: ~fn(&Request, &mut ResponseWriter)) {
    SimpleServer::new(Config { bind_address: ip_addr }, handler).serve_forever();
}

/// 0.0.0.0, port 80: publicly bound to the standard HTTP port.
/// Not recommended at present as this server is not hardened against the sort of traffic you may
/// encounter on the Internet and is vulnerable to various DoS attacks. Sit it behind a gateway.
static PUBLIC: IpAddr = Ipv4(0, 0, 0, 0, 80);
*/

static PERF_DUMP_FREQUENCY : u64 = 10_000;

/// Simple function to dump out perf stats every `PERF_DUMP_FREQUENCY` requests
fn perf_dumper(perf_po: Port<(u64, u64, u64, u64, u64)>) {
    // Total durations
    let mut td_spawn = 0u64;
    let mut td_request = 0u64;
    let mut td_response = 0u64;
    let mut td_handle = 0u64;
    let mut td_total = 0u64;
    let mut i = 0u64;
    loop {
        let data = perf_po.recv();
        let (start, spawned, request_made, response_made, finished) = data;
        td_spawn += spawned - start;
        td_request += request_made - spawned;
        td_response += response_made - request_made;
        td_handle += finished - response_made;
        td_total += finished - start;
        i += 1;
        if i % PERF_DUMP_FREQUENCY == 0 {
            println("");
            println(fmt!("%? requests made thus far. Current means:", i));
            println(fmt!("- Total:               100%%, %12?", td_total / i));
            println(fmt!("- Spawn:               %3?%%, %12?", 100 * td_spawn / td_total, td_spawn / i));
            println(fmt!("- Load request:        %3?%%, %12?", 100 * td_request / td_total, td_request / i));
            println(fmt!("- Initialise response: %3?%%, %12?", 100 * td_response / td_total, td_response / i));
            println(fmt!("- Handle:              %3?%%, %12?", 100 * td_handle / td_total, td_handle / i));
        }
    }
}
<|endoftext|>


<commit_before>

struct Todo {
        id: int,
        todo: ~str,
        priority: int,
        raw_todo: ~str
}

fn main () {

}
<commit_msg>a few more updates<commit_after>

struct Todo {
        id: int,
        todo: ~str,
        priority: char,
        raw_todo: ~str
}

fn create_task(todo: ~str, id: int) -> Todo {
        let task = Todo{id: id, raw_todo: todo, todo: ~"", priority: '^'};

        return task;
}

fn main () {

}
<|endoftext|>


<commit_before>use clap::{App, Arg};

fn main() {
    // Of the three argument types, flags are the most simple. Flags are simple switches which can
    // be either "on" or "off"
    //
    // clap also supports multiple occurrences of flags, the common example is "verbosity" where a
    // user could want a little information with "-v" or tons of information with "-v -v" or "-vv"
    let matches = App::new("MyApp")
        // Regular App configuration goes here...
        // We'll add a flag that represents an awesome meter...
        //
        // I'll explain each possible setting that "flags" accept. Keep in mind
        // that you DO NOT need to set each of these for every flag, only the ones
        // you want for your individual case.
        .arg(
            Arg::new("awesome")
                .about("turns up the awesome") // Displayed when showing help info
                .short('a') // Trigger this arg with "-a"
                .long("awesome") // Trigger this arg with "--awesome"
                .multiple_occurrences(true) // This flag should allow multiple
                // occurrences such as "-aaa" or "-a -a"
                .requires("config") // Says, "If the user uses -a, they MUST
                // also use this other 'config' arg too"
                // Can also specify a list using
                // requires_all(Vec<&str>)
                .conflicts_with("output"), // Opposite of requires(), says "if the
                                           // user uses -a, they CANNOT use 'output'"
                                           // also has a conflicts_with_all(Vec<&str>)
                                           // and an exclusive(true)
        )
        .arg("-c, --config=[FILE] 'sets a custom config file'")
        .arg("<output> 'sets an output file'")
        .get_matches();

    // We can find out whether or not awesome was used
    if matches.is_present("awesome") {
        println!("Awesomeness is turned on");
    }

    // If we set the multiple option of a flag we can check how many times the user specified
    //
    // Note: if we did not specify the multiple option, and the user used "awesome" we would get
    // a 1 (no matter how many times they actually used it), or a 0 if they didn't use it at all
    match matches.occurrences_of("awesome") {
        0 => println!("Nothing is awesome"),
        1 => println!("Some things are awesome"),
        2 => println!("Lots of things are awesome"),
        _ => println!("EVERYTHING is awesome!"),
    }

    // Continued program logic goes here...
}
<commit_msg>docs: update example, mentioning the `pseudo-flag` pattern<commit_after>use clap::{App, Arg};

fn main() {
    // Of the three argument types, flags are the most simple. Flags are simple switches which can
    // be either "on" or "off"
    //
    // clap also supports multiple occurrences of flags, the common example is "verbosity" where a
    // user could want a little information with "-v" or tons of information with "-v -v" or "-vv"
    let matches = App::new("MyApp")
        // Regular App configuration goes here...
        // We'll add a flag that represents an awesome meter...
        //
        // I'll explain each possible setting that "flags" accept. Keep in mind
        // that you DO NOT need to set each of these for every flag, only the ones
        // you want for your individual case.
        .arg(
            Arg::new("awesome")
                .about("turns up the awesome") // Displayed when showing help info
                .short('a') // Trigger this arg with "-a"
                .long("awesome") // Trigger this arg with "--awesome"
                .multiple_occurrences(true) // This flag should allow multiple
                // occurrences such as "-aaa" or "-a -a"
                .requires("config") // Says, "If the user uses -a, they MUST
                // also use this other 'config' arg too"
                // Can also specify a list using
                // requires_all(Vec<&str>)
                .conflicts_with("output"), // Opposite of requires(), says "if the
                                           // user uses -a, they CANNOT use 'output'"
                                           // also has a conflicts_with_all(Vec<&str>)
                                           // and an exclusive(true)
        )
        .arg(
            // Sometimes we might want to accept one of the following: `--pseudo-flag`, `--pseudo-flag=true`, `--pseudo-flag=false.`
            // The following is the `pseudo-flag` pattern stated in https://github.com/clap-rs/clap/issues/1649#issuecomment-661274943
            Arg::new("pseudo-flag") // Create a "pesudo-flag" with optional value
                .possible_values(&["true", "false"]) // Limit that value to `true` of `false`
                .long("pseudo-flag")
                .min_values(0)
                .max_values(1),
        )
        .arg("-c, --config=[FILE] 'sets a custom config file'")
        .arg("<output> 'sets an output file'")
        .get_matches();

    // We can find out whether or not awesome was used
    if matches.is_present("awesome") {
        println!("Awesomeness is turned on");
    }

    // Same thing with `pseudo-flag`
    if app.value_of("pseudo-flag") != Some("false") {
        println!("Pseudo-flag is turned on");
    }

    // If we set the multiple option of a flag we can check how many times the user specified
    //
    // Note: if we did not specify the multiple option, and the user used "awesome" we would get
    // a 1 (no matter how many times they actually used it), or a 0 if they didn't use it at all
    match matches.occurrences_of("awesome") {
        0 => println!("Nothing is awesome"),
        1 => println!("Some things are awesome"),
        2 => println!("Lots of things are awesome"),
        _ => println!("EVERYTHING is awesome!"),
    }

    // Continued program logic goes here...
}
<|endoftext|>


<commit_before>extern crate ring;
extern crate num_bigint;
extern crate num_traits;

use num_traits::{Zero, One};
use num_bigint::BigUint;
use ring::aead;
use ring::aead::{SealingKey, OpeningKey, Algorithm};
use ring::rand::{SecureRandom, SystemRandom};
static AES_GCM_MAX_NONCE_HEX: &'static [u8] = b"1000000000000000000000000";
static ALGORITHM: &'static Algorithm = &aead::AES_128_GCM;
lazy_static! {
    static ref RAND: SystemRandom = SystemRandom::new();
    static ref MAX_NONCE: BigUint = BigUint::parse_bytes(AES_GCM_MAX_NONCE_HEX, 16).unwrap();
}

pub struct Key {
    bytes: Vec<u8>,
    opening: OpeningKey,
    sealing: SealingKey,
}

impl Key {
    pub fn new(bytes: &[u8]) -> Key {
        Key {
            bytes: bytes.to_owned(),
            opening: OpeningKey::new(ALGORITHM, &bytes).unwrap(),
            sealing: SealingKey::new(ALGORITHM, &bytes).unwrap(),
        }
    }
}

impl Clone for Key {
    fn clone(&self) -> Key {
        Key::new(&self.bytes)
    }
}

/// explicitly no-Clone to avoid nonce re-use
pub struct Nonce {
    counter: BigUint,
}

impl Nonce {
    pub fn new() -> Nonce {
        Nonce { counter: BigUint::zero() }
    }

    /// TEST ONLY
    pub fn starting_from(start: BigUint) -> Nonce {
        Nonce { counter: start }
    }

    pub fn next(&mut self) -> Result<Vec<u8>, ()> {
        if &self.counter >= &MAX_NONCE {
            Err(())
        } else {
            let nonce_bytes = self.counter.to_bytes_le();
            self.counter = &self.counter + BigUint::one();

            Ok(nonce_bytes)
        }
    }
}

pub struct Handler {
    _working_nonce_buf: [u8; 32],
    _working_seal_buf: Vec<u8>,
    key: Key,
    nonce: Nonce,
}

pub fn gen_key() -> Vec<u8> {
    let mut keybytes = vec![0u8; ALGORITHM.key_len()];
    RAND.fill(&mut keybytes).unwrap();
    keybytes
}

impl Handler {
    pub fn new(key: &[u8]) -> Handler {
        debug!("👾  AEAD key len: {}", ALGORITHM.key_len());
        debug!("👾  AEAD nonce len: {}", ALGORITHM.nonce_len());
        debug!("👾  AEAD max overhead len: {}", ALGORITHM.tag_len());
        Handler {
            _working_seal_buf: vec![0u8; super::MAX_MESSAGE_SIZE],
            _working_nonce_buf: [0u8; 32],
            key: Key::new(key),
            nonce: Nonce::new(),
        }
    }

    pub fn seal(&mut self, buf: &mut [u8], len: usize) -> Result<usize, ()> {
        let nonce_len = ALGORITHM.nonce_len();
        let max_suffix_len = ALGORITHM.tag_len();

        assert!(nonce_len < u8::max_value() as usize,
                "Uh, why is the nonce size this big?");

        assert!(len <= buf.len() - max_suffix_len,
                "Buffer doesn't have enough suffix padding.");

        let mut nonce = &mut self._working_nonce_buf[..nonce_len];
        let nonce_bytes = self.nonce.next().unwrap();
        nonce[..nonce_bytes.len()].copy_from_slice(&nonce_bytes);

        let mut sealed = &mut self._working_seal_buf[..len + max_suffix_len];
        sealed[0..len].copy_from_slice(&buf[..len]);
        match aead::seal_in_place(&self.key.sealing,
                                  &nonce,
                                  &[],
                                  &mut sealed,
                                  max_suffix_len) {
            Ok(seal_len) => {
                buf[..nonce_len].copy_from_slice(&nonce[..]);
                buf[nonce_len..nonce_len+seal_len].copy_from_slice(&sealed[..seal_len]);
                Ok(nonce_len + seal_len)
            }
            Err(_) => {
                Err(())
            }
        }
    }

    pub fn open(&mut self, buf: &mut [u8]) -> Result<usize, String> {
        let nonce_len = ALGORITHM.nonce_len();

        if buf.len() < nonce_len {
            return Err("msg not long enough to contain nonce".into());
        } else if buf.len() > super::MAX_MESSAGE_SIZE {
            return Err("max message size exceeded".into());
        }

        let nonce = &mut self._working_nonce_buf[..nonce_len];
        nonce.copy_from_slice(&buf[..nonce_len]);

        aead::open_in_place(&self.key.opening, &nonce, &[], nonce_len, buf)
            .map(|buf| buf.len())
            .map_err(|_| String::from("decrypt failed"))
    }
}

// Tests for the crypto module
#[cfg(test)]
mod test {

    #[test]
    fn nonce_sanity() {
        let mut nonce = super::Nonce::new();
        let first = nonce.next().unwrap();
        let second = nonce.next().unwrap();
        assert!(first != second, "two nonces were the same! death! shame!");
    }

    #[test]
    fn nonce_overflow() {
        use num_bigint::BigUint;
        use num_traits::One;
        let mut nonce = super::Nonce::starting_from(&super::MAX_NONCE.clone() - &BigUint::one());
        if let Err(_) = nonce.next() {
            panic!("2^96 - 1 should be a valid nonce");
        }
        if let Ok(_) = nonce.next() {
            panic!("2^96 is not a valid nonce, it should overflow and fail.");
        }
    }

    #[test]
    fn raw_roundtrip() {
        use ring::aead;
        use ring::aead::{SealingKey, OpeningKey};
        use ring::rand::{SecureRandom, SystemRandom};

        let rng = SystemRandom::new();
        let mut key_bytes = vec![0u8; super::ALGORITHM.key_len()];
        let mut nonce_bytes = vec![0u8; super::ALGORITHM.nonce_len()];
        rng.fill(&mut key_bytes).unwrap();
        rng.fill(&mut nonce_bytes).unwrap();
        let key = SealingKey::new(super::ALGORITHM, &key_bytes).unwrap();

        let data = [1u8; 1350];
        let out_suffix_capacity = super::ALGORITHM.tag_len();
        let mut in_out = vec![1u8; data.len() + out_suffix_capacity];
        aead::seal_in_place(&key, &nonce_bytes, &[],
                            &mut in_out, out_suffix_capacity).unwrap();

        let opening_key = OpeningKey::new(super::ALGORITHM, &key_bytes).unwrap();
        let buf = aead::open_in_place(&opening_key, &nonce_bytes, &[],
                                      0, &mut in_out).unwrap();

        assert_eq!(buf.len(), 1350);
        assert_eq!(buf, &data[..]);
    }

    #[test]
    fn roundtrip() {
        use ::rand;
        use ::rand::distributions::{IndependentSample, Range};
        // generate some data, seal it, and then make sure it unseals to the same thing
        let mut rng = rand::thread_rng();
        let between = Range::new(10, 10000);

        let key = super::gen_key();
        let mut handler = super::Handler::new(&key);
        let data_size: usize = between.ind_sample(&mut rng);
        let mut data = vec![0u8; super::super::MAX_MESSAGE_SIZE];
        for i in 0..data_size {
            data[i] = rand::random();
        }

        let orig = data[..data_size].to_owned();

        let cipher_len = handler.seal(&mut data, data_size).unwrap();
        let decrypted_len = handler.open(&mut data[..cipher_len]).unwrap();
        assert_eq!(decrypted_len, data_size);
        assert_eq!(orig, &data[..decrypted_len], "original and decrypted don't match!");
    }

    #[test]
    fn key_sanity() {
        use std::collections::HashSet;

        let mut set: HashSet<Vec<u8>> = HashSet::with_capacity(10000);

        for _ in 0..10000 {
            let key = super::gen_key();
            assert!(set.insert(key));
        }
    }

    #[test]
    fn arc_encryption_uniqueness() {
        use core::ops::DerefMut;
        use std::sync::{Arc, Mutex};

        let key = super::gen_key();
        let handler = Arc::new(Mutex::new(super::Handler::new(&key)));
        let handler2 = handler.clone();

        let mut data = vec![0u8; super::super::MAX_MESSAGE_SIZE];

        let first = {
            let mutex = &handler;
            let mut crypto = mutex.lock().unwrap();
            let cipher_len = crypto.deref_mut().seal(&mut data, 4096).unwrap();
            data[..cipher_len].to_owned()
        };
        let second = {
            let mutex = &handler2;
            let mut crypto = mutex.lock().unwrap();
            let cipher_len = crypto.deref_mut().seal(&mut data, 4096).unwrap();
            data[..cipher_len].to_owned()
        };

        println!("{:?}", &first);
        println!("{:?}", &second);
        assert!(first != second);
    }
}

#[cfg(all(feature = "nightly", test))]
mod bench {
    extern crate test;
    const DATA_SIZE: usize = 16384;

    #[bench]
    fn bench_nonce_output(b: &mut test::Bencher) {
        let mut nonce = super::Nonce::new();
        b.bytes = 12; // kind of
        b.iter(|| {
            nonce.next()
        })
    }

    #[bench]
    fn bench_raw_seal(b: &mut test::Bencher) {
        use ring::aead;
        use ring::aead::SealingKey;
        use ring::rand::{SecureRandom, SystemRandom};

        let rng = SystemRandom::new();
        let mut key_bytes = vec![0u8; super::ALGORITHM.key_len()];
        let mut nonce_bytes = vec![0u8; super::ALGORITHM.nonce_len()];
        rng.fill(&mut key_bytes).unwrap();
        let key = SealingKey::new(super::ALGORITHM, &key_bytes).unwrap();

        let data = [1u8; DATA_SIZE];
        let out_suffix_capacity = super::ALGORITHM.tag_len();
        let mut in_out = vec![1u8; data.len() + out_suffix_capacity];

        b.bytes = DATA_SIZE as u64;
        b.iter(|| {
            rng.fill(&mut nonce_bytes).unwrap();
            aead::seal_in_place(&key, &nonce_bytes, &[], &mut in_out,
                                out_suffix_capacity).unwrap()
        })
    }

    #[bench]
    fn bench_raw_open(b: &mut test::Bencher) {
        use ring::aead;
        use ring::aead::{SealingKey, OpeningKey};
        use ring::rand::{SecureRandom, SystemRandom};

        let rng = SystemRandom::new();
        let mut key_bytes = vec![0u8; super::ALGORITHM.key_len()];
        let mut nonce_bytes = vec![0u8; super::ALGORITHM.nonce_len()];
        rng.fill(&mut key_bytes).unwrap();
        rng.fill(&mut nonce_bytes).unwrap();
        let key = SealingKey::new(super::ALGORITHM, &key_bytes).unwrap();
        let opening_key = OpeningKey::new(super::ALGORITHM, &key_bytes).unwrap();

        let data = [1u8; DATA_SIZE];
        let out_suffix_capacity = super::ALGORITHM.tag_len();
        let mut in_out = vec![1u8; data.len() + out_suffix_capacity];

        b.bytes = DATA_SIZE as u64;

        let sealed_len = aead::seal_in_place(&key, &nonce_bytes, &[], &mut in_out,
                                             out_suffix_capacity).unwrap();
        b.iter(|| { aead::open_in_place(&opening_key, &nonce_bytes, &[],
                                        0, &mut in_out[..sealed_len]).unwrap(); });
    }

    #[bench]
    fn bench_seal(b: &mut test::Bencher) {
        let key = super::gen_key();
        let mut handler = super::Handler::new(&key);
        let mut buf = vec![0u8; super::super::MAX_MESSAGE_SIZE];
        b.bytes = DATA_SIZE as u64;
        b.iter(|| handler.seal(&mut buf, DATA_SIZE))
    }

    #[bench]
    fn bench_open(b: &mut test::Bencher) {
        let key = super::gen_key();
        let mut handler = super::Handler::new(&key);
        let mut buf = vec![0u8; super::super::MAX_MESSAGE_SIZE];
        let sealed_len = handler.seal(&mut buf, DATA_SIZE).unwrap();
        b.bytes = DATA_SIZE as u64;
        b.iter(|| handler.open(&mut buf[..sealed_len]))
    }
}
<commit_msg>minimalize comments, use applicable compiler flags<commit_after>extern crate ring;
extern crate num_bigint;
extern crate num_traits;

use num_traits::{Zero, One};
use num_bigint::BigUint;
use ring::aead;
use ring::aead::{SealingKey, OpeningKey, Algorithm};
use ring::rand::{SecureRandom, SystemRandom};
static AES_GCM_MAX_NONCE_HEX: &'static [u8] = b"1000000000000000000000000";
static ALGORITHM: &'static Algorithm = &aead::AES_128_GCM;
lazy_static! {
    static ref RAND: SystemRandom = SystemRandom::new();
    static ref MAX_NONCE: BigUint = BigUint::parse_bytes(AES_GCM_MAX_NONCE_HEX, 16).unwrap();
}

pub struct Key {
    bytes: Vec<u8>,
    opening: OpeningKey,
    sealing: SealingKey,
}

impl Key {
    pub fn new(bytes: &[u8]) -> Key {
        Key {
            bytes: bytes.to_owned(),
            opening: OpeningKey::new(ALGORITHM, &bytes).unwrap(),
            sealing: SealingKey::new(ALGORITHM, &bytes).unwrap(),
        }
    }
}

impl Clone for Key {
    fn clone(&self) -> Key {
        Key::new(&self.bytes)
    }
}

pub struct Nonce {
    counter: BigUint,
}

impl Nonce {
    pub fn new() -> Nonce {
        Nonce { counter: BigUint::zero() }
    }

    #[cfg(test)]
    pub fn starting_from(start: BigUint) -> Nonce {
        Nonce { counter: start }
    }

    pub fn next(&mut self) -> Result<Vec<u8>, ()> {
        if &self.counter >= &MAX_NONCE {
            Err(())
        } else {
            let nonce_bytes = self.counter.to_bytes_le();
            self.counter = &self.counter + BigUint::one();

            Ok(nonce_bytes)
        }
    }
}

pub struct Handler {
    _working_nonce_buf: [u8; 32],
    _working_seal_buf: Vec<u8>,
    key: Key,
    nonce: Nonce,
}

pub fn gen_key() -> Vec<u8> {
    let mut keybytes = vec![0u8; ALGORITHM.key_len()];
    RAND.fill(&mut keybytes).unwrap();
    keybytes
}

impl Handler {
    pub fn new(key: &[u8]) -> Handler {
        debug!("👾  AEAD key len: {}", ALGORITHM.key_len());
        debug!("👾  AEAD nonce len: {}", ALGORITHM.nonce_len());
        debug!("👾  AEAD max overhead len: {}", ALGORITHM.tag_len());
        Handler {
            _working_seal_buf: vec![0u8; super::MAX_MESSAGE_SIZE],
            _working_nonce_buf: [0u8; 32],
            key: Key::new(key),
            nonce: Nonce::new(),
        }
    }

    pub fn seal(&mut self, buf: &mut [u8], len: usize) -> Result<usize, ()> {
        let nonce_len = ALGORITHM.nonce_len();
        let max_suffix_len = ALGORITHM.tag_len();

        assert!(nonce_len < u8::max_value() as usize,
                "Uh, why is the nonce size this big?");

        assert!(len <= buf.len() - max_suffix_len,
                "Buffer doesn't have enough suffix padding.");

        let mut nonce = &mut self._working_nonce_buf[..nonce_len];
        let nonce_bytes = self.nonce.next().unwrap();
        nonce[..nonce_bytes.len()].copy_from_slice(&nonce_bytes);

        let mut sealed = &mut self._working_seal_buf[..len + max_suffix_len];
        sealed[0..len].copy_from_slice(&buf[..len]);
        match aead::seal_in_place(&self.key.sealing,
                                  &nonce,
                                  &[],
                                  &mut sealed,
                                  max_suffix_len) {
            Ok(seal_len) => {
                buf[..nonce_len].copy_from_slice(&nonce[..]);
                buf[nonce_len..nonce_len+seal_len].copy_from_slice(&sealed[..seal_len]);
                Ok(nonce_len + seal_len)
            }
            Err(_) => {
                Err(())
            }
        }
    }

    pub fn open(&mut self, buf: &mut [u8]) -> Result<usize, String> {
        let nonce_len = ALGORITHM.nonce_len();

        if buf.len() < nonce_len {
            return Err("msg not long enough to contain nonce".into());
        } else if buf.len() > super::MAX_MESSAGE_SIZE {
            return Err("max message size exceeded".into());
        }

        let nonce = &mut self._working_nonce_buf[..nonce_len];
        nonce.copy_from_slice(&buf[..nonce_len]);

        aead::open_in_place(&self.key.opening, &nonce, &[], nonce_len, buf)
            .map(|buf| buf.len())
            .map_err(|_| String::from("decrypt failed"))
    }
}

// Tests for the crypto module
#[cfg(test)]
mod test {

    #[test]
    fn nonce_sanity() {
        let mut nonce = super::Nonce::new();
        let first = nonce.next().unwrap();
        let second = nonce.next().unwrap();
        assert!(first != second, "two nonces were the same! death! shame!");
    }

    #[test]
    fn nonce_overflow() {
        use num_bigint::BigUint;
        use num_traits::One;
        let mut nonce = super::Nonce::starting_from(&super::MAX_NONCE.clone() - &BigUint::one());
        if let Err(_) = nonce.next() {
            panic!("2^96 - 1 should be a valid nonce");
        }
        if let Ok(_) = nonce.next() {
            panic!("2^96 is not a valid nonce, it should overflow and fail.");
        }
    }

    #[test]
    fn raw_roundtrip() {
        use ring::aead;
        use ring::aead::{SealingKey, OpeningKey};
        use ring::rand::{SecureRandom, SystemRandom};

        let rng = SystemRandom::new();
        let mut key_bytes = vec![0u8; super::ALGORITHM.key_len()];
        let mut nonce_bytes = vec![0u8; super::ALGORITHM.nonce_len()];
        rng.fill(&mut key_bytes).unwrap();
        rng.fill(&mut nonce_bytes).unwrap();
        let key = SealingKey::new(super::ALGORITHM, &key_bytes).unwrap();

        let data = [1u8; 1350];
        let out_suffix_capacity = super::ALGORITHM.tag_len();
        let mut in_out = vec![1u8; data.len() + out_suffix_capacity];
        aead::seal_in_place(&key, &nonce_bytes, &[],
                            &mut in_out, out_suffix_capacity).unwrap();

        let opening_key = OpeningKey::new(super::ALGORITHM, &key_bytes).unwrap();
        let buf = aead::open_in_place(&opening_key, &nonce_bytes, &[],
                                      0, &mut in_out).unwrap();

        assert_eq!(buf.len(), 1350);
        assert_eq!(buf, &data[..]);
    }

    #[test]
    fn roundtrip() {
        use ::rand;
        use ::rand::distributions::{IndependentSample, Range};
        // generate some data, seal it, and then make sure it unseals to the same thing
        let mut rng = rand::thread_rng();
        let between = Range::new(10, 10000);

        let key = super::gen_key();
        let mut handler = super::Handler::new(&key);
        let data_size: usize = between.ind_sample(&mut rng);
        let mut data = vec![0u8; super::super::MAX_MESSAGE_SIZE];
        for i in 0..data_size {
            data[i] = rand::random();
        }

        let orig = data[..data_size].to_owned();

        let cipher_len = handler.seal(&mut data, data_size).unwrap();
        let decrypted_len = handler.open(&mut data[..cipher_len]).unwrap();
        assert_eq!(decrypted_len, data_size);
        assert_eq!(orig, &data[..decrypted_len], "original and decrypted don't match!");
    }

    #[test]
    fn key_sanity() {
        use std::collections::HashSet;

        let mut set: HashSet<Vec<u8>> = HashSet::with_capacity(10000);

        for _ in 0..10000 {
            let key = super::gen_key();
            assert!(set.insert(key));
        }
    }

    #[test]
    fn arc_encryption_uniqueness() {
        use core::ops::DerefMut;
        use std::sync::{Arc, Mutex};

        let key = super::gen_key();
        let handler = Arc::new(Mutex::new(super::Handler::new(&key)));
        let handler2 = handler.clone();

        let mut data = vec![0u8; super::super::MAX_MESSAGE_SIZE];

        let first = {
            let mutex = &handler;
            let mut crypto = mutex.lock().unwrap();
            let cipher_len = crypto.deref_mut().seal(&mut data, 4096).unwrap();
            data[..cipher_len].to_owned()
        };
        let second = {
            let mutex = &handler2;
            let mut crypto = mutex.lock().unwrap();
            let cipher_len = crypto.deref_mut().seal(&mut data, 4096).unwrap();
            data[..cipher_len].to_owned()
        };

        println!("{:?}", &first);
        println!("{:?}", &second);
        assert!(first != second);
    }
}

#[cfg(all(feature = "nightly", test))]
mod bench {
    extern crate test;
    const DATA_SIZE: usize = 16384;

    #[bench]
    fn bench_nonce_output(b: &mut test::Bencher) {
        let mut nonce = super::Nonce::new();
        b.bytes = 12; // kind of
        b.iter(|| {
            nonce.next()
        })
    }

    #[bench]
    fn bench_raw_seal(b: &mut test::Bencher) {
        use ring::aead;
        use ring::aead::SealingKey;
        use ring::rand::{SecureRandom, SystemRandom};

        let rng = SystemRandom::new();
        let mut key_bytes = vec![0u8; super::ALGORITHM.key_len()];
        let mut nonce_bytes = vec![0u8; super::ALGORITHM.nonce_len()];
        rng.fill(&mut key_bytes).unwrap();
        let key = SealingKey::new(super::ALGORITHM, &key_bytes).unwrap();

        let data = [1u8; DATA_SIZE];
        let out_suffix_capacity = super::ALGORITHM.tag_len();
        let mut in_out = vec![1u8; data.len() + out_suffix_capacity];

        b.bytes = DATA_SIZE as u64;
        b.iter(|| {
            rng.fill(&mut nonce_bytes).unwrap();
            aead::seal_in_place(&key, &nonce_bytes, &[], &mut in_out,
                                out_suffix_capacity).unwrap()
        })
    }

    #[bench]
    fn bench_raw_open(b: &mut test::Bencher) {
        use ring::aead;
        use ring::aead::{SealingKey, OpeningKey};
        use ring::rand::{SecureRandom, SystemRandom};

        let rng = SystemRandom::new();
        let mut key_bytes = vec![0u8; super::ALGORITHM.key_len()];
        let mut nonce_bytes = vec![0u8; super::ALGORITHM.nonce_len()];
        rng.fill(&mut key_bytes).unwrap();
        rng.fill(&mut nonce_bytes).unwrap();
        let key = SealingKey::new(super::ALGORITHM, &key_bytes).unwrap();
        let opening_key = OpeningKey::new(super::ALGORITHM, &key_bytes).unwrap();

        let data = [1u8; DATA_SIZE];
        let out_suffix_capacity = super::ALGORITHM.tag_len();
        let mut in_out = vec![1u8; data.len() + out_suffix_capacity];

        b.bytes = DATA_SIZE as u64;

        let sealed_len = aead::seal_in_place(&key, &nonce_bytes, &[], &mut in_out,
                                             out_suffix_capacity).unwrap();
        b.iter(|| { aead::open_in_place(&opening_key, &nonce_bytes, &[],
                                        0, &mut in_out[..sealed_len]).unwrap(); });
    }

    #[bench]
    fn bench_seal(b: &mut test::Bencher) {
        let key = super::gen_key();
        let mut handler = super::Handler::new(&key);
        let mut buf = vec![0u8; super::super::MAX_MESSAGE_SIZE];
        b.bytes = DATA_SIZE as u64;
        b.iter(|| handler.seal(&mut buf, DATA_SIZE))
    }

    #[bench]
    fn bench_open(b: &mut test::Bencher) {
        let key = super::gen_key();
        let mut handler = super::Handler::new(&key);
        let mut buf = vec![0u8; super::super::MAX_MESSAGE_SIZE];
        let sealed_len = handler.seal(&mut buf, DATA_SIZE).unwrap();
        b.bytes = DATA_SIZE as u64;
        b.iter(|| handler.open(&mut buf[..sealed_len]))
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
#[macro_use] extern crate pact_v1_matching;
extern crate pact_v1_mock_server;
#[macro_use] extern crate rustful;
#[macro_use] extern crate p_macro;
#[macro_use] extern crate log;
#[macro_use] extern crate maplit;
extern crate simplelog;
extern crate uuid;
extern crate rustc_serialize;
#[macro_use] extern crate hyper;

use clap::{Arg, App, SubCommand, AppSettings, ErrorKind, ArgMatches};
use std::env;
use std::str::FromStr;
use std::fs::{self, File};
use log::{LogLevelFilter};
use simplelog::{CombinedLogger, TermLogger, FileLogger};

fn display_error(error: String, matches: &ArgMatches) -> ! {
    println!("ERROR: {}", error);
    println!("");
    println!("{}", matches.usage());
    panic!("{}", error)
}

mod server;
mod create_mock;
mod list;

static SPEC_VERSION: &'static str = "1.0.0";

fn print_version() {
    println!("\npact mock server version  : v{}", crate_version!());
    println!("pact specification version: v{}", SPEC_VERSION);
}

fn setup_loggers(level: &str, command: &str, output: Option<&str>) {
    let log_level = match level {
        "none" => LogLevelFilter::Off,
        _ => LogLevelFilter::from_str(level).unwrap()
    };
    if command == "start" {
        let log_file = match output {
            Some(path) => {
                fs::create_dir_all(path).unwrap();
                format!("{}/pact_v1_mock_server.log", path)
            },
            None => s!("pact_v1_mock_server.log")
        };
        CombinedLogger::init(
            vec![
                TermLogger::new(log_level),
                FileLogger::new(log_level, File::create(log_file).unwrap())
            ]
        ).unwrap();
    } else {
        TermLogger::init(log_level).unwrap();
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let version = format!("v{}", crate_version!());
    let app = App::new(program)
        .version(version.as_str())
        .about("Standalone Pact mock server")
        .version_short("v")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::ColoredHelp)
        .arg(Arg::with_name("port")
            .short("p")
            .long("port")
            .takes_value(true)
            .use_delimiter(false)
            .help("port the master mock server runs on (defaults to 8080)"))
        .arg(Arg::with_name("host")
            .short("h")
            .long("host")
            .takes_value(true)
            .use_delimiter(false)
            .help("hostname the master mock server runs on (defaults to localhost)"))
        .arg(Arg::with_name("loglevel")
            .short("l")
            .long("loglevel")
            .takes_value(true)
            .use_delimiter(false)
            .possible_values(&["error", "warn", "info", "debug", "trace", "none"])
            .help("Log level for mock servers to write to the log file (defaults to info)"))
        .subcommand(SubCommand::with_name("start")
                .about("Starts the master mock server")
                .setting(AppSettings::ColoredHelp)
                .arg(Arg::with_name("output")
                      .short("o")
                      .long("output")
                      .takes_value(true)
                      .use_delimiter(false)
                      .help("the directory where to write files to (defaults to current directory)")))
        .subcommand(SubCommand::with_name("list")
                .about("Lists all the running mock servers")
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("create")
                .about("Creates a new mock server from a pact file")
                .arg(Arg::with_name("file")
                    .short("f")
                    .long("file")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required(true)
                    .help("the pact file to define the mock server"))
                .setting(AppSettings::ColoredHelp));

    let matches = app.get_matches_safe();
    match matches {
        Ok(ref matches) => {
            setup_loggers(matches.value_of("loglevel").unwrap_or("info"),
                matches.subcommand_name().unwrap(), matches.subcommand().1.unwrap().value_of("output"));
            let port = matches.value_of("port").unwrap_or("8080");
            let host = matches.value_of("host").unwrap_or("localhost");
            match port.parse::<u16>() {
                Ok(p) => {
                    match matches.subcommand() {
                        ("start", Some(_)) => server::start_server(p),
                        ("list", Some(sub_matches)) => list::list_mock_servers(host, p, sub_matches),
                        ("create", Some(sub_matches)) => create_mock::create_mock_server(host, p, sub_matches),
                        _ => ()
                    }
                },
                Err(_) => display_error(format!("{} is not a valid port number", port), matches)
            }
        },
        Err(ref err) => {
            match err.kind {
                ErrorKind::HelpDisplayed => (),
                ErrorKind::VersionDisplayed => print_version(),
                _ => err.exit()
            }
        }
    }
}
<commit_msg>use path struct so creating log file works on all OSs<commit_after>#[macro_use] extern crate clap;
#[macro_use] extern crate pact_v1_matching;
extern crate pact_v1_mock_server;
#[macro_use] extern crate rustful;
#[macro_use] extern crate p_macro;
#[macro_use] extern crate log;
#[macro_use] extern crate maplit;
extern crate simplelog;
extern crate uuid;
extern crate rustc_serialize;
#[macro_use] extern crate hyper;

use clap::{Arg, App, SubCommand, AppSettings, ErrorKind, ArgMatches};
use std::env;
use std::str::FromStr;
use std::fs::{self, File};
use std::io;
use log::{LogLevelFilter};
use simplelog::{CombinedLogger, TermLogger, FileLogger};
use std::path::PathBuf;
use std::fs::OpenOptions;

fn display_error(error: String, matches: &ArgMatches) -> ! {
    println!("ERROR: {}", error);
    println!("");
    println!("{}", matches.usage());
    panic!("{}", error)
}

mod server;
mod create_mock;
mod list;

static SPEC_VERSION: &'static str = "1.0.0";

fn print_version() {
    println!("\npact mock server version  : v{}", crate_version!());
    println!("pact specification version: v{}", SPEC_VERSION);
}

fn setup_loggers(level: &str, command: &str, output: Option<&str>) -> Result<(), io::Error> {
    let log_level = match level {
        "none" => LogLevelFilter::Off,
        _ => LogLevelFilter::from_str(level).unwrap()
    };
    if command == "start" {
        let log_file = match output {
            Some(p) => {
                try!(fs::create_dir_all(p));
                let mut path = PathBuf::from(p);
                path.push("pact_v1_mock_server.log");
                path
            },
            None => PathBuf::from("pact_v1_mock_server.log")
        };
        let file = try!(OpenOptions::new()
            .read(false)
            .write(true)
            .append(true)
            .create(true)
            .open(log_file));
        CombinedLogger::init(
            vec![
                TermLogger::new(log_level),
                FileLogger::new(log_level, file)
            ]
        ).unwrap();
    } else {
        TermLogger::init(log_level).unwrap();
    }
    Ok(())
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    let version = format!("v{}", crate_version!());
    let app = App::new(program)
        .version(version.as_str())
        .about("Standalone Pact mock server")
        .version_short("v")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::SubcommandRequired)
        .setting(AppSettings::GlobalVersion)
        .setting(AppSettings::VersionlessSubcommands)
        .setting(AppSettings::ColoredHelp)
        .arg(Arg::with_name("port")
            .short("p")
            .long("port")
            .takes_value(true)
            .use_delimiter(false)
            .help("port the master mock server runs on (defaults to 8080)"))
        .arg(Arg::with_name("host")
            .short("h")
            .long("host")
            .takes_value(true)
            .use_delimiter(false)
            .help("hostname the master mock server runs on (defaults to localhost)"))
        .arg(Arg::with_name("loglevel")
            .short("l")
            .long("loglevel")
            .takes_value(true)
            .use_delimiter(false)
            .possible_values(&["error", "warn", "info", "debug", "trace", "none"])
            .help("Log level for mock servers to write to the log file (defaults to info)"))
        .subcommand(SubCommand::with_name("start")
                .about("Starts the master mock server")
                .setting(AppSettings::ColoredHelp)
                .arg(Arg::with_name("output")
                      .short("o")
                      .long("output")
                      .takes_value(true)
                      .use_delimiter(false)
                      .help("the directory where to write files to (defaults to current directory)")))
        .subcommand(SubCommand::with_name("list")
                .about("Lists all the running mock servers")
                .setting(AppSettings::ColoredHelp))
        .subcommand(SubCommand::with_name("create")
                .about("Creates a new mock server from a pact file")
                .arg(Arg::with_name("file")
                    .short("f")
                    .long("file")
                    .takes_value(true)
                    .use_delimiter(false)
                    .required(true)
                    .help("the pact file to define the mock server"))
                .setting(AppSettings::ColoredHelp));

    let matches = app.get_matches_safe();
    match matches {
        Ok(ref matches) => {
            if let Err(err) = setup_loggers(matches.value_of("loglevel").unwrap_or("info"),
                matches.subcommand_name().unwrap(),
                matches.subcommand().1.unwrap().value_of("output")) {
                display_error(format!("Could not setup loggers: {}", err), matches);
            }
            let port = matches.value_of("port").unwrap_or("8080");
            let host = matches.value_of("host").unwrap_or("localhost");
            match port.parse::<u16>() {
                Ok(p) => {
                    match matches.subcommand() {
                        ("start", Some(_)) => server::start_server(p),
                        ("list", Some(sub_matches)) => list::list_mock_servers(host, p, sub_matches),
                        ("create", Some(sub_matches)) => create_mock::create_mock_server(host, p, sub_matches),
                        _ => ()
                    }
                },
                Err(_) => display_error(format!("{} is not a valid port number", port), matches)
            }
        },
        Err(ref err) => {
            match err.kind {
                ErrorKind::HelpDisplayed => (),
                ErrorKind::VersionDisplayed => print_version(),
                _ => err.exit()
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate polydraw;

use polydraw::{Application, Renderer, RenderFrame};
use polydraw::geom::line::{LineSegment, LineIntersection};
use polydraw::geom::point::Point;
use polydraw::draw::{RGB, bresenham, hline, vline};

struct IntersectionRenderer {
   intersection: Option<Point<f64>>,

   l1: LineSegment<f64>,
   l2: LineSegment<f64>,

   top_left: Point<f64>,
   top_right: Point<f64>,
   bottom_left: Point<f64>,
   bottom_right: Point<f64>,

   width: u32,
   height: u32,
}

impl IntersectionRenderer {
   fn new() -> Self {
      IntersectionRenderer {
         intersection: None,

         l1: LineSegment::default(),
         l2: LineSegment::default(),

         top_left: Point::default(),
         top_right: Point::default(),
         bottom_left: Point::default(),
         bottom_right: Point::default(),

         width: 0,
         height: 0,
      }
   }

   fn point_rect(&self, frame: &mut RenderFrame, x: i32, y: i32, color: &RGB) {
      let half = 12;
      let right_x = x + half;
      let left_x = x - half;
      let top_y = y + half;
      let bottom_y = y - half;

      hline(frame, left_x, right_x, top_y, color);
      hline(frame, left_x, right_x, bottom_y, color);

      vline(frame, left_x, bottom_y, top_y, color);
      vline(frame, right_x, bottom_y, top_y, color);
   }

   fn recalc(&mut self) {
      self.l1.update(
         self.bottom_left.x, self.bottom_left.y,
         self.width as f64 - self.top_right.x, self.height as f64 - self.top_right.y
      );

      self.l2.update(
         self.top_left.x, self.height as f64 - self.top_left.y,
         self.width as f64 - self.bottom_right.x, self.bottom_right.y
      );

      let intersection = self.l1.line().intersect(self.l2.line());
      match intersection {
         LineIntersection::Point(p) => {
            self.intersection = Some(p);
         },
         _ => {
            self.intersection = None;
         }
      }
   }
}

impl Renderer for IntersectionRenderer {
   fn init(&mut self, width: u32, height: u32) {
      self.bottom_left.update(100_f64, 120_f64);
      self.top_right.update(100_f64, 100_f64);

      self.top_left.update(140_f64, 90_f64);
      self.bottom_right.update(140_f64, 100_f64);

      self.width = width;
      self.height = height;

      self.recalc();
   }

   fn resized(&mut self, width: u32, height: u32) {
      self.width = width;
      self.height = height;

      self.recalc();
   }

   fn render(&mut self, frame: &mut RenderFrame) {
      frame.clear();

      let l1_color = RGB::new(127, 223, 255);
      let l2_color = RGB::new(127, 255, 223);
      let intersection_color = RGB::new(255, 223, 191);

      let l1_p1_x = self.l1.x1() as i32;
      let l1_p1_y = self.l1.y1() as i32;

      let l1_p2_x = self.l1.x2() as i32;
      let l1_p2_y = self.l1.y2() as i32;

      let l2_p1_x = self.l2.x1() as i32;
      let l2_p1_y = self.l2.y1() as i32;

      let l2_p2_x = self.l2.x2() as i32;
      let l2_p2_y = self.l2.y2() as i32;

      bresenham(frame, l1_p1_x, l1_p1_y, l1_p2_x, l1_p2_y, &l1_color);
      bresenham(frame, l2_p1_x, l2_p1_y, l2_p2_x, l2_p2_y, &l2_color);

      self.point_rect(frame, l1_p1_x, l1_p1_y, &l1_color);
      self.point_rect(frame, l1_p2_x, l1_p2_y, &l1_color);
      self.point_rect(frame, l2_p1_x, l2_p1_y, &l2_color);
      self.point_rect(frame, l2_p2_x, l2_p2_y, &l2_color);

      match self.intersection {
         Some(ref p) => {
            self.point_rect(frame, p.x as i32, p.y as i32, &intersection_color);
         },
         _ => {}
      }
   }
}

fn main() {
   let mut renderer = IntersectionRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Intersection")
      .run();
}
<commit_msg>Dragging the segment points in the intersection example<commit_after>extern crate polydraw;

use std::cmp::max;

use polydraw::{Application, Renderer, RenderFrame};
use polydraw::geom::line::{LineSegment, LineIntersection};
use polydraw::geom::point::Point;
use polydraw::draw::{RGB, bresenham, hline, vline};

const HALF_RECT: i32 = 12;

#[derive (Debug)]
enum ActivePoint {
   Line1Point1,
   Line1Point2,
   Line2Point1,
   Line2Point2,
}

struct IntersectionRenderer {
   intersection: Option<Point<f64>>,

   l1: LineSegment<f64>,
   l2: LineSegment<f64>,

   mouse_x: i32,
   mouse_y: i32,

   width: u32,
   height: u32,

   line_color: RGB,
   default_color: RGB,
   hover_color: RGB,
   intersection_color: RGB,

   dragged_point: Option<ActivePoint>,
}

impl IntersectionRenderer {
   fn new() -> Self {
      IntersectionRenderer {
         intersection: None,

         l1: LineSegment::default(),
         l2: LineSegment::default(),

         mouse_x: -10000,
         mouse_y: -10000,

         width: 0,
         height: 0,

         line_color: RGB::new(93, 181, 241),
         default_color: RGB::new(127, 191, 63),
         hover_color: RGB::new(255, 255, 255),
         intersection_color: RGB::new(127, 127, 255),

         dragged_point: None,
      }
   }

   fn line_point_rect(&self, frame: &mut RenderFrame, x: i32, y: i32) {
      self.point_rect(frame, x, y, self.hit_test_color(x, y));
   }

   fn point_rect(&self, frame: &mut RenderFrame, x: i32, y: i32, color: &RGB) {
      let right_x = x + HALF_RECT;
      let left_x = x - HALF_RECT;
      let top_y = y + HALF_RECT;
      let bottom_y = y - HALF_RECT;

      hline(frame, left_x, right_x, top_y, color);
      hline(frame, left_x, right_x, bottom_y, color);

      vline(frame, left_x, bottom_y, top_y, color);
      vline(frame, right_x, bottom_y, top_y, color);
   }

   fn hit_test_color(&self, x: i32, y: i32) -> &RGB {
      if self.hit_test(x, y) {
         &self.hover_color
      } else {
         &self.default_color
      }
   }

   fn hit_test(&self, x: i32, y: i32) -> bool {
      let distance = max((x - self.mouse_x).abs(), (y - self.mouse_y).abs());
      distance <= HALF_RECT
   }

   fn active_point(&self) -> Option<ActivePoint> {
      let l1_p1_x = self.l1.x1() as i32;
      let l1_p1_y = self.l1.y1() as i32;

      if self.hit_test(l1_p1_x, l1_p1_y) {
         return Some(ActivePoint::Line1Point1);
      }

      let l1_p2_x = self.l1.x2() as i32;
      let l1_p2_y = self.l1.y2() as i32;

      if self.hit_test(l1_p2_x, l1_p2_y) {
         return Some(ActivePoint::Line1Point2);
      }

      let l2_p1_x = self.l2.x1() as i32;
      let l2_p1_y = self.l2.y1() as i32;

      if self.hit_test(l2_p1_x, l2_p1_y) {
         return Some(ActivePoint::Line2Point1);
      }

      let l2_p2_x = self.l2.x2() as i32;
      let l2_p2_y = self.l2.y2() as i32;

      if self.hit_test(l2_p2_x, l2_p2_y) {
         return Some(ActivePoint::Line2Point2);
      }

      None
   }

   fn recalc_intersection(&mut self) {
      let intersection = self.l1.line().intersect(self.l2.line());
      match intersection {
         LineIntersection::Point(p) => {
            self.intersection = Some(p);
         },
         _ => {
            self.intersection = None;
         }
      }
   }
}

impl Renderer for IntersectionRenderer {
   fn init(&mut self, width: u32, height: u32) {
      self.l1.update(
         100_f64, 120_f64,
         width as f64 - 100_f64, height as f64 - 100_f64
      );

      self.l2.update(
         140_f64, height as f64 - 90_f64,
         width as f64 - 140_f64, 100_f64
      );

      self.width = width;
      self.height = height;

      self.recalc_intersection();
   }

   fn resized(&mut self, width: u32, height: u32) {
      let dx: f64 = width as f64 - self.width as f64;
      let dy: f64 = height as f64 - self.height as f64;

      let l1_p1_x = self.l1.x1();
      let l1_p1_y = self.l1.y1();

      let l1_p2_x = self.l1.x2();
      let l1_p2_y = self.l1.y2();

      let l2_p1_x = self.l2.x1();
      let l2_p1_y = self.l2.y1();

      let l2_p2_x = self.l2.x2();
      let l2_p2_y = self.l2.y2();

      self.l1.update(l1_p1_x, l1_p1_y, l1_p2_x + dx, l1_p2_y + dy);

      self.l2.update(l2_p1_x, l2_p1_y + dy, l2_p2_x + dx, l2_p2_y);

      self.width = width;
      self.height = height;

      self.recalc_intersection();
   }

   fn mouse_moved(&mut self, x: i32, y: i32) {
      self.mouse_x = x;
      self.mouse_y = y;

      let x_f64 = x as f64;
      let y_f64 = y as f64;

      match self.dragged_point {
         Some(ActivePoint::Line1Point1) => {
            let x2 = self.l1.x2();
            let y2 = self.l1.y2();
            self.l1.update(x_f64, y_f64, x2, y2);
         },

         Some(ActivePoint::Line1Point2) => {
            let x1 = self.l1.x1();
            let y1 = self.l1.y1();
            self.l1.update(x1, y1, x_f64, y_f64);
         },

         Some(ActivePoint::Line2Point1) => {
            let x2 = self.l2.x2();
            let y2 = self.l2.y2();
            self.l2.update(x_f64, y_f64, x2, y2);
         },

         Some(ActivePoint::Line2Point2) => {
            let x1 = self.l2.x1();
            let y1 = self.l2.y1();
            self.l2.update(x1, y1, x_f64, y_f64);
         },

         _ => {
            return;
         }
      }

      self.recalc_intersection();
   }

   fn mouse_left_button_pressed(&mut self) {
      self.dragged_point = self.active_point();
   }

   fn mouse_left_button_released(&mut self) {
      self.dragged_point = None;
   }

   fn render(&mut self, frame: &mut RenderFrame) {
      frame.clear();

      let l1_p1_x = self.l1.x1() as i32;
      let l1_p1_y = self.l1.y1() as i32;

      let l1_p2_x = self.l1.x2() as i32;
      let l1_p2_y = self.l1.y2() as i32;

      let l2_p1_x = self.l2.x1() as i32;
      let l2_p1_y = self.l2.y1() as i32;

      let l2_p2_x = self.l2.x2() as i32;
      let l2_p2_y = self.l2.y2() as i32;

      bresenham(frame, l1_p1_x, l1_p1_y, l1_p2_x, l1_p2_y, &self.line_color);
      bresenham(frame, l2_p1_x, l2_p1_y, l2_p2_x, l2_p2_y, &self.line_color);

      self.line_point_rect(frame, l1_p1_x, l1_p1_y);
      self.line_point_rect(frame, l1_p2_x, l1_p2_y);
      self.line_point_rect(frame, l2_p1_x, l2_p1_y);
      self.line_point_rect(frame, l2_p2_x, l2_p2_y);

      match self.intersection {
         Some(ref p) => {
            self.point_rect(frame, p.x as i32, p.y as i32, &self.intersection_color);
         },
         _ => {}
      }
   }
}

fn main() {
   let mut renderer = IntersectionRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Intersection")
      .run();
}
<|endoftext|>


<commit_before>use std::cmp;

use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::attr;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::Target;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by reference, where
    /// the argument type is `Copy` and small enough to be more efficient to always
    /// pass by value.
    ///
    /// **Why is this bad?** In many calling conventions instances of structs will
    /// be passed through registers if they fit into two or less general purpose
    /// registers.
    ///
    /// **Known problems:** This lint is target register size dependent, it is
    /// limited to 32-bit to try and reduce portability problems between 32 and
    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
    /// will be different.
    ///
    /// The configuration option `trivial_copy_size_limit` can be set to override
    /// this limit for a project.
    ///
    /// This lint attempts to allow passing arguments by reference if a reference
    /// to that argument is returned. This is implemented by comparing the lifetime
    /// of the argument and return value for equality. However, this can cause
    /// false positives in cases involving multiple lifetimes that are bounded by
    /// each other.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// fn foo(v: &u32) {}
    /// ```
    ///
    /// ```rust
    /// // Better
    /// fn foo(v: u32) {}
    /// ```
    pub TRIVIALLY_COPY_PASS_BY_REF,
    pedantic,
    "functions taking small copyable arguments by reference"
}

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by value, where
    /// the argument type is `Copy` and large enough to be worth considering
    /// passing by reference. Does not trigger if the function is being exported,
    /// because that might induce API breakage, if the parameter is declared as mutable,
    /// or if the argument is a `self`.
    ///
    /// **Why is this bad?** Arguments passed by value might result in an unnecessary
    /// shallow copy, taking up more space in the stack and requiring a call to
    /// `memcpy`, which which can be expensive.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Bad
    /// fn foo(v: TooLarge) {}
    /// ```
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Good
    /// fn foo(v: &TooLarge) {}
    /// ```
    pub LARGE_TYPES_PASSED_BY_VALUE,
    pedantic,
    "functions taking large arguments by value"
}

#[derive(Copy, Clone)]
pub struct PassByRefOrValue {
    ref_min_size: u64,
    value_max_size: u64,
}

impl<'tcx> PassByRefOrValue {
    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
        let ref_min_size = ref_min_size.unwrap_or_else(|| {
            let bit_width = u64::from(target.pointer_width);
            // Cap the calculated bit width at 32-bits to reduce
            // portability problems between 32 and 64-bit targets
            let bit_width = cmp::min(bit_width, 32);
            #[allow(clippy::integer_division)]
            let byte_width = bit_width / 8;
            // Use a limit of 2 times the register byte width
            byte_width * 2
        });

        Self {
            ref_min_size,
            value_max_size,
        }
    }

    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);

        let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));

        for (index, (input, &ty)) in decl.inputs.iter().zip(fn_sig.inputs()).enumerate() {
            // All spans generated from a proc-macro invocation are the same...
            match span {
                Some(s) if s == input.span => return,
                _ => (),
            }

            match ty.kind() {
                ty::Ref(input_lt, ty, Mutability::Not) => {
                    // Use lifetimes to determine if we're returning a reference to the
                    // argument. In that case we can't switch to pass-by-value as the
                    // argument will not live long enough.
                    let output_lts = match *fn_sig.output().kind() {
                        ty::Ref(output_lt, _, _) => vec![output_lt],
                        ty::Adt(_, substs) => substs.regions().collect(),
                        _ => vec![],
                    };

                    if_chain! {
                        if !output_lts.contains(&input_lt);
                        if is_copy(cx, ty);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size <= self.ref_min_size;
                        if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind;
                        then {
                            let value_type = if is_self_ty(decl_ty) {
                                "self".into()
                            } else {
                                snippet(cx, decl_ty.span, "_").into()
                            };
                            span_lint_and_sugg(
                                cx,
                                TRIVIALLY_COPY_PASS_BY_REF,
                                input.span,
                                &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size),
                                "consider passing by value instead",
                                value_type,
                                Applicability::Unspecified,
                            );
                        }
                    }
                },

                ty::Adt(_, _) | ty::Array(_, _) | ty::Tuple(_) => {
                    // if function has a body and parameter is annotated with mut, ignore
                    if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
                        match param.pat.kind {
                            PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
                            _ => continue,
                        }
                    }

                    if_chain! {
                        if !cx.access_levels.is_exported(hir_id);
                        if is_copy(cx, ty);
                        if !is_self_ty(input);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size > self.value_max_size;
                        then {
                            span_lint_and_sugg(
                                cx,
                                LARGE_TYPES_PASSED_BY_VALUE,
                                input.span,
                                &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size),
                                "consider passing by reference instead",
                                format!("&{}", snippet(cx, input.span, "_")),
                                Applicability::MaybeIncorrect,
                            );
                        }
                    }
                },

                _ => {},
            }
        }
    }
}

impl_lint_pass!(PassByRefOrValue => [TRIVIALLY_COPY_PASS_BY_REF, LARGE_TYPES_PASSED_BY_VALUE]);

impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
        if item.span.from_expansion() {
            return;
        }

        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
            self.check_poly_fn(cx, item.hir_id, &*method_sig.decl, None);
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        _body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _, attrs) => {
                if header.abi != Abi::Rust {
                    return;
                }
                for a in attrs {
                    if let Some(meta_items) = a.meta_item_list() {
                        if a.has_name(sym::proc_macro_derive)
                            || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))
                        {
                            return;
                        }
                    }
                }
            },
            FnKind::Method(..) => (),
            FnKind::Closure(..) => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(
                item.kind,
                ItemKind::Impl { of_trait: Some(_), .. } | ItemKind::Trait(..)
            ) {
                return;
            }
        }

        self.check_poly_fn(cx, hir_id, decl, Some(span));
    }
}
<commit_msg>Auto merge of #6554 - sozysozbot:master, r=flip1995<commit_after>use std::cmp;

use crate::utils::{is_copy, is_self_ty, snippet, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_ast::attr;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{BindingAnnotation, Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node, PatKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
use rustc_target::abi::LayoutOf;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::Target;

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by reference, where
    /// the argument type is `Copy` and small enough to be more efficient to always
    /// pass by value.
    ///
    /// **Why is this bad?** In many calling conventions instances of structs will
    /// be passed through registers if they fit into two or less general purpose
    /// registers.
    ///
    /// **Known problems:** This lint is target register size dependent, it is
    /// limited to 32-bit to try and reduce portability problems between 32 and
    /// 64-bit, but if you are compiling for 8 or 16-bit targets then the limit
    /// will be different.
    ///
    /// The configuration option `trivial_copy_size_limit` can be set to override
    /// this limit for a project.
    ///
    /// This lint attempts to allow passing arguments by reference if a reference
    /// to that argument is returned. This is implemented by comparing the lifetime
    /// of the argument and return value for equality. However, this can cause
    /// false positives in cases involving multiple lifetimes that are bounded by
    /// each other.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// // Bad
    /// fn foo(v: &u32) {}
    /// ```
    ///
    /// ```rust
    /// // Better
    /// fn foo(v: u32) {}
    /// ```
    pub TRIVIALLY_COPY_PASS_BY_REF,
    pedantic,
    "functions taking small copyable arguments by reference"
}

declare_clippy_lint! {
    /// **What it does:** Checks for functions taking arguments by value, where
    /// the argument type is `Copy` and large enough to be worth considering
    /// passing by reference. Does not trigger if the function is being exported,
    /// because that might induce API breakage, if the parameter is declared as mutable,
    /// or if the argument is a `self`.
    ///
    /// **Why is this bad?** Arguments passed by value might result in an unnecessary
    /// shallow copy, taking up more space in the stack and requiring a call to
    /// `memcpy`, which can be expensive.
    ///
    /// **Example:**
    ///
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Bad
    /// fn foo(v: TooLarge) {}
    /// ```
    /// ```rust
    /// #[derive(Clone, Copy)]
    /// struct TooLarge([u8; 2048]);
    ///
    /// // Good
    /// fn foo(v: &TooLarge) {}
    /// ```
    pub LARGE_TYPES_PASSED_BY_VALUE,
    pedantic,
    "functions taking large arguments by value"
}

#[derive(Copy, Clone)]
pub struct PassByRefOrValue {
    ref_min_size: u64,
    value_max_size: u64,
}

impl<'tcx> PassByRefOrValue {
    pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self {
        let ref_min_size = ref_min_size.unwrap_or_else(|| {
            let bit_width = u64::from(target.pointer_width);
            // Cap the calculated bit width at 32-bits to reduce
            // portability problems between 32 and 64-bit targets
            let bit_width = cmp::min(bit_width, 32);
            #[allow(clippy::integer_division)]
            let byte_width = bit_width / 8;
            // Use a limit of 2 times the register byte width
            byte_width * 2
        });

        Self {
            ref_min_size,
            value_max_size,
        }
    }

    fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) {
        let fn_def_id = cx.tcx.hir().local_def_id(hir_id);

        let fn_sig = cx.tcx.fn_sig(fn_def_id);
        let fn_sig = cx.tcx.erase_late_bound_regions(fn_sig);

        let fn_body = cx.enclosing_body.map(|id| cx.tcx.hir().body(id));

        for (index, (input, &ty)) in decl.inputs.iter().zip(fn_sig.inputs()).enumerate() {
            // All spans generated from a proc-macro invocation are the same...
            match span {
                Some(s) if s == input.span => return,
                _ => (),
            }

            match ty.kind() {
                ty::Ref(input_lt, ty, Mutability::Not) => {
                    // Use lifetimes to determine if we're returning a reference to the
                    // argument. In that case we can't switch to pass-by-value as the
                    // argument will not live long enough.
                    let output_lts = match *fn_sig.output().kind() {
                        ty::Ref(output_lt, _, _) => vec![output_lt],
                        ty::Adt(_, substs) => substs.regions().collect(),
                        _ => vec![],
                    };

                    if_chain! {
                        if !output_lts.contains(&input_lt);
                        if is_copy(cx, ty);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size <= self.ref_min_size;
                        if let hir::TyKind::Rptr(_, MutTy { ty: ref decl_ty, .. }) = input.kind;
                        then {
                            let value_type = if is_self_ty(decl_ty) {
                                "self".into()
                            } else {
                                snippet(cx, decl_ty.span, "_").into()
                            };
                            span_lint_and_sugg(
                                cx,
                                TRIVIALLY_COPY_PASS_BY_REF,
                                input.span,
                                &format!("this argument ({} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", size, self.ref_min_size),
                                "consider passing by value instead",
                                value_type,
                                Applicability::Unspecified,
                            );
                        }
                    }
                },

                ty::Adt(_, _) | ty::Array(_, _) | ty::Tuple(_) => {
                    // if function has a body and parameter is annotated with mut, ignore
                    if let Some(param) = fn_body.and_then(|body| body.params.get(index)) {
                        match param.pat.kind {
                            PatKind::Binding(BindingAnnotation::Unannotated, _, _, _) => {},
                            _ => continue,
                        }
                    }

                    if_chain! {
                        if !cx.access_levels.is_exported(hir_id);
                        if is_copy(cx, ty);
                        if !is_self_ty(input);
                        if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes());
                        if size > self.value_max_size;
                        then {
                            span_lint_and_sugg(
                                cx,
                                LARGE_TYPES_PASSED_BY_VALUE,
                                input.span,
                                &format!("this argument ({} byte) is passed by value, but might be more efficient if passed by reference (limit: {} byte)", size, self.value_max_size),
                                "consider passing by reference instead",
                                format!("&{}", snippet(cx, input.span, "_")),
                                Applicability::MaybeIncorrect,
                            );
                        }
                    }
                },

                _ => {},
            }
        }
    }
}

impl_lint_pass!(PassByRefOrValue => [TRIVIALLY_COPY_PASS_BY_REF, LARGE_TYPES_PASSED_BY_VALUE]);

impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
        if item.span.from_expansion() {
            return;
        }

        if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
            self.check_poly_fn(cx, item.hir_id, &*method_sig.decl, None);
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        kind: FnKind<'tcx>,
        decl: &'tcx FnDecl<'_>,
        _body: &'tcx Body<'_>,
        span: Span,
        hir_id: HirId,
    ) {
        if span.from_expansion() {
            return;
        }

        match kind {
            FnKind::ItemFn(.., header, _, attrs) => {
                if header.abi != Abi::Rust {
                    return;
                }
                for a in attrs {
                    if let Some(meta_items) = a.meta_item_list() {
                        if a.has_name(sym::proc_macro_derive)
                            || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))
                        {
                            return;
                        }
                    }
                }
            },
            FnKind::Method(..) => (),
            FnKind::Closure(..) => return,
        }

        // Exclude non-inherent impls
        if let Some(Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(hir_id)) {
            if matches!(
                item.kind,
                ItemKind::Impl { of_trait: Some(_), .. } | ItemKind::Trait(..)
            ) {
                return;
            }
        }

        self.check_poly_fn(cx, hir_id, decl, Some(span));
    }
}
<|endoftext|>