<commit_before>extern crate futures;
extern crate tokio_core;
extern crate tokio_tls;
extern crate grpc;
#[macro_use]
extern crate log;

mod test_misc;

use std::sync::Arc;

use futures::future::*;
use futures::stream;
use futures::stream::Stream;

use grpc::*;
use grpc::server::*;
use grpc::client::*;
use grpc::method::*;
use grpc::marshall::*;
use grpc::error::*;
use grpc::futures_grpc::*;

use test_misc::*;

fn string_string_method(name: &str, streaming: GrpcStreaming)
    -> Arc<MethodDescriptor<String, String>>
{
    Arc::new(MethodDescriptor {
       name: name.to_owned(),
       streaming: streaming,
       req_marshaller: Box::new(MarshallerString),
       resp_marshaller: Box::new(MarshallerString),
   })
}

/// Single method server on random port
fn new_server<H>(name: &str, handler: H) -> GrpcServer
    where
        H : MethodHandler<String, String> + 'static + Sync + Send,
        H : GrpcStreamingFlavor,
{
    let mut methods = Vec::new();
    methods.push(ServerMethod::new(
        string_string_method(name, <H as GrpcStreamingFlavor>::streaming()),
        handler,
    ));
    GrpcServer::new_plain("[::1]:0", Default::default(), ServerServiceDefinition::new(methods))
}

/// Single unary method server
fn new_server_unary<H>(name: &str, handler: H) -> GrpcServer
    where H : Fn(GrpcRequestOptions, String) -> GrpcSingleResponse<String> + Sync + Send + 'static
{
    new_server(name, MethodHandlerUnary::new(handler))
}

/// Single server streaming method server
fn new_server_server_streaming<H>(name: &str, handler: H) -> GrpcServer
    where H : Fn(GrpcRequestOptions, String) -> GrpcStreamingResponse<String> + Sync + Send + 'static
{
    new_server(name, MethodHandlerServerStreaming::new(handler))
}

/// Single server streaming method server
fn new_server_client_streaming<H>(name: &str, handler: H) -> GrpcServer
    where H : Fn(GrpcRequestOptions, GrpcStreamSend<String>) -> GrpcSingleResponse<String> + Sync + Send + 'static
{
    new_server(name, MethodHandlerClientStreaming::new(handler))
}

/// Tester for unary methods
struct TesterUnary {
    name: String,
    client: GrpcClient,
    _server: GrpcServer,
}

impl TesterUnary {
    fn new<H>(handler: H) -> TesterUnary
        where H : Fn(GrpcRequestOptions, String) -> GrpcSingleResponse<String> + Sync + Send + 'static
    {
        let name = "/text/Unary";
        let server = new_server_unary(name, handler);
        let port = server.local_addr().port();
        TesterUnary {
            name: name.to_owned(),
            _server: server,
            client: GrpcClient::new("::1", port, false, Default::default()).unwrap()
        }
    }

    fn call(&self, param: &str) -> GrpcFutureSend<String> {
        self.client.call_unary(
            GrpcRequestOptions::new(),
            param.to_owned(),
            string_string_method(&self.name, GrpcStreaming::Unary))
                .drop_metadata()
    }

    fn call_expect_error<F : FnOnce(&GrpcError) -> bool>(&self, param: &str, expect: F) {
        match self.call(param).wait() {
            Ok(r) => panic!("expecting error, got: {:?}", r),
            Err(e) => assert!(expect(&e), "wrong error: {:?}", e),
        }
    }

    fn call_expect_grpc_error<F : FnOnce(&str) -> bool>(&self, param: &str, expect: F) {
        self.call_expect_error(param, |e| {
            match e {
                &GrpcError::GrpcMessage(GrpcMessageError { ref grpc_message, .. }) if expect(&grpc_message) => true,
                _ => false,
            }
        });
    }

    fn call_expect_grpc_error_contain(&self, param: &str, expect: &str) {
        self.call_expect_grpc_error(param, |m| m.find(expect).is_some());
    }
}

/// Tester for server streaming methods
struct TesterServerStreaming {
    name: String,
    client: GrpcClient,
    _server: GrpcServer,
}

impl TesterServerStreaming {
    fn new<H>(handler: H) -> Self
        where H : Fn(GrpcRequestOptions, String) -> GrpcStreamingResponse<String> + Sync + Send + 'static
    {
        let name = "/test/ServerStreaming";
        let server = new_server_server_streaming(name, handler);
        let port = server.local_addr().port();
        TesterServerStreaming {
            name: name.to_owned(),
            _server: server,
            client: GrpcClient::new("::1", port, false, Default::default()).unwrap()
        }
    }

    fn call(&self, param: &str) -> GrpcStream<String> {
        self.client.call_server_streaming(
            GrpcRequestOptions::new(),
            param.to_owned(),
            string_string_method(&self.name, GrpcStreaming::ServerStreaming)).drop_metadata()
    }
}

struct TesterClientStreaming {
    name: String,
    client: GrpcClient,
    _server: GrpcServer,
}

impl TesterClientStreaming {
    fn new<H>(handler: H) -> Self
        where H : Fn(GrpcRequestOptions, GrpcStreamSend<String>) -> GrpcSingleResponse<String> + Sync + Send + 'static
    {
        let name = "/test/ClientStreaming";
        let server = new_server_client_streaming(name, handler);
        let port = server.local_addr().port();
        TesterClientStreaming {
            name: name.to_owned(),
            _server: server,
            client: GrpcClient::new("::1", port, false, Default::default()).unwrap()
        }
    }

    fn call(&self) -> (stream::Sender<String, GrpcError>, GrpcFutureSend<String>) {
        let (tx, rx) = stream::channel();
        (
            tx,
            self.client.call_client_streaming(
                GrpcRequestOptions::new(),
                Box::new(rx),
                string_string_method(&self.name, GrpcStreaming::ClientStreaming)).drop_metadata(),
        )
    }
}

#[test]
fn unary() {
    let tester = TesterUnary::new(|_m, s| GrpcSingleResponse::completed(s));

    assert_eq!("aa", tester.call("aa").wait().unwrap());
}

#[test]
fn server_is_not_running() {
    let client = GrpcClient::new("::1", 2, false, Default::default()).unwrap();

    // TODO: https://github.com/tokio-rs/tokio-core/issues/12
    if false {
        let result = client.call_unary(
            GrpcRequestOptions::new(),
            "aa".to_owned(),
            string_string_method("/does/not/matter", GrpcStreaming::Unary)).wait();
        assert!(result.is_err(), result);
    }
}

#[test]
fn error_in_handler() {
    let tester = TesterUnary::new(|_m, _| GrpcSingleResponse::no_metadata(Err(GrpcError::Other("my error")).into_future()));

    tester.call_expect_grpc_error_contain("aa", "my error");
}

// TODO
//#[test]
fn panic_in_handler() {
    let tester = TesterUnary::new(|_m, _| panic!("icnap"));

    tester.call_expect_grpc_error("aa",
        |m| m.find("Panic").is_some() && m.find("icnap").is_some());
}

#[test]
fn server_streaming() {
    let test_sync = Arc::new(TestSync::new());
    let test_sync_server = test_sync.clone();

    let tester = TesterServerStreaming::new(move |_m, s| {
        let sync = test_sync_server.clone();
        GrpcStreamingResponse::no_metadata(test_misc::stream_thread_spawn_iter(move || {
            (0..3).map(move |i| {
                sync.take(i * 2 + 1);
                format!("{}{}", s, i)
            })
        }))
    });

    let mut rs = tester.call("x").wait();

    test_sync.take(0);
    assert_eq!("x0", rs.next().unwrap().unwrap());
    test_sync.take(2);
    assert_eq!("x1", rs.next().unwrap().unwrap());
    test_sync.take(4);
    assert_eq!("x2", rs.next().unwrap().unwrap());
    assert!(rs.next().is_none());
}

#[test]
fn client_streaming() {
    let tester = TesterClientStreaming::new(move |_m, s| {
        GrpcSingleResponse::no_metadata(s.fold(String::new(), |mut s, message| {
            s.push_str(&message);
            futures::finished::<_, GrpcError>(s)
        }))
    });

    let (tx, result) = tester.call();
    let tx = tx.send(Ok("aa".to_owned())).wait().ok().expect("aa");
    let tx = tx.send(Ok("bb".to_owned())).wait().ok().expect("bb");
    let tx = tx.send(Ok("cc".to_owned())).wait().ok().expect("cc");
    drop(tx);

    assert_eq!("aabbcc", result.wait().unwrap());
}
<commit_msg>Streaming call parameter type is now GrpcStreamingRequest<commit_after>extern crate futures;
extern crate tokio_core;
extern crate tokio_tls;
extern crate grpc;
#[macro_use]
extern crate log;

mod test_misc;

use std::sync::Arc;

use futures::future::*;
use futures::stream;
use futures::stream::Stream;

use grpc::*;
use grpc::server::*;
use grpc::client::*;
use grpc::method::*;
use grpc::marshall::*;
use grpc::error::*;
use grpc::futures_grpc::*;

use test_misc::*;

fn string_string_method(name: &str, streaming: GrpcStreaming)
    -> Arc<MethodDescriptor<String, String>>
{
    Arc::new(MethodDescriptor {
       name: name.to_owned(),
       streaming: streaming,
       req_marshaller: Box::new(MarshallerString),
       resp_marshaller: Box::new(MarshallerString),
   })
}

/// Single method server on random port
fn new_server<H>(name: &str, handler: H) -> GrpcServer
    where
        H : MethodHandler<String, String> + 'static + Sync + Send,
        H : GrpcStreamingFlavor,
{
    let mut methods = Vec::new();
    methods.push(ServerMethod::new(
        string_string_method(name, <H as GrpcStreamingFlavor>::streaming()),
        handler,
    ));
    GrpcServer::new_plain("[::1]:0", Default::default(), ServerServiceDefinition::new(methods))
}

/// Single unary method server
fn new_server_unary<H>(name: &str, handler: H) -> GrpcServer
    where H : Fn(GrpcRequestOptions, String) -> GrpcSingleResponse<String> + Sync + Send + 'static
{
    new_server(name, MethodHandlerUnary::new(handler))
}

/// Single server streaming method server
fn new_server_server_streaming<H>(name: &str, handler: H) -> GrpcServer
    where H : Fn(GrpcRequestOptions, String) -> GrpcStreamingResponse<String> + Sync + Send + 'static
{
    new_server(name, MethodHandlerServerStreaming::new(handler))
}

/// Single server streaming method server
fn new_server_client_streaming<H>(name: &str, handler: H) -> GrpcServer
    where H : Fn(GrpcRequestOptions, GrpcStreamingRequest<String>) -> GrpcSingleResponse<String> + Sync + Send + 'static
{
    new_server(name, MethodHandlerClientStreaming::new(handler))
}

/// Tester for unary methods
struct TesterUnary {
    name: String,
    client: GrpcClient,
    _server: GrpcServer,
}

impl TesterUnary {
    fn new<H>(handler: H) -> TesterUnary
        where H : Fn(GrpcRequestOptions, String) -> GrpcSingleResponse<String> + Sync + Send + 'static
    {
        let name = "/text/Unary";
        let server = new_server_unary(name, handler);
        let port = server.local_addr().port();
        TesterUnary {
            name: name.to_owned(),
            _server: server,
            client: GrpcClient::new("::1", port, false, Default::default()).unwrap()
        }
    }

    fn call(&self, param: &str) -> GrpcFutureSend<String> {
        self.client.call_unary(
            GrpcRequestOptions::new(),
            param.to_owned(),
            string_string_method(&self.name, GrpcStreaming::Unary))
                .drop_metadata()
    }

    fn call_expect_error<F : FnOnce(&GrpcError) -> bool>(&self, param: &str, expect: F) {
        match self.call(param).wait() {
            Ok(r) => panic!("expecting error, got: {:?}", r),
            Err(e) => assert!(expect(&e), "wrong error: {:?}", e),
        }
    }

    fn call_expect_grpc_error<F : FnOnce(&str) -> bool>(&self, param: &str, expect: F) {
        self.call_expect_error(param, |e| {
            match e {
                &GrpcError::GrpcMessage(GrpcMessageError { ref grpc_message, .. }) if expect(&grpc_message) => true,
                _ => false,
            }
        });
    }

    fn call_expect_grpc_error_contain(&self, param: &str, expect: &str) {
        self.call_expect_grpc_error(param, |m| m.find(expect).is_some());
    }
}

/// Tester for server streaming methods
struct TesterServerStreaming {
    name: String,
    client: GrpcClient,
    _server: GrpcServer,
}

impl TesterServerStreaming {
    fn new<H>(handler: H) -> Self
        where H : Fn(GrpcRequestOptions, String) -> GrpcStreamingResponse<String> + Sync + Send + 'static
    {
        let name = "/test/ServerStreaming";
        let server = new_server_server_streaming(name, handler);
        let port = server.local_addr().port();
        TesterServerStreaming {
            name: name.to_owned(),
            _server: server,
            client: GrpcClient::new("::1", port, false, Default::default()).unwrap()
        }
    }

    fn call(&self, param: &str) -> GrpcStream<String> {
        self.client.call_server_streaming(
            GrpcRequestOptions::new(),
            param.to_owned(),
            string_string_method(&self.name, GrpcStreaming::ServerStreaming)).drop_metadata()
    }
}

struct TesterClientStreaming {
    name: String,
    client: GrpcClient,
    _server: GrpcServer,
}

impl TesterClientStreaming {
    fn new<H>(handler: H) -> Self
        where H : Fn(GrpcRequestOptions, GrpcStreamingRequest<String>) -> GrpcSingleResponse<String> + Sync + Send + 'static
    {
        let name = "/test/ClientStreaming";
        let server = new_server_client_streaming(name, handler);
        let port = server.local_addr().port();
        TesterClientStreaming {
            name: name.to_owned(),
            _server: server,
            client: GrpcClient::new("::1", port, false, Default::default()).unwrap()
        }
    }

    fn call(&self) -> (stream::Sender<String, GrpcError>, GrpcFutureSend<String>) {
        let (tx, rx) = stream::channel();
        (
            tx,
            self.client.call_client_streaming(
                GrpcRequestOptions::new(),
                GrpcStreamingRequest::stream(rx),
                string_string_method(&self.name, GrpcStreaming::ClientStreaming)).drop_metadata(),
        )
    }
}

#[test]
fn unary() {
    let tester = TesterUnary::new(|_m, s| GrpcSingleResponse::completed(s));

    assert_eq!("aa", tester.call("aa").wait().unwrap());
}

#[test]
fn server_is_not_running() {
    let client = GrpcClient::new("::1", 2, false, Default::default()).unwrap();

    // TODO: https://github.com/tokio-rs/tokio-core/issues/12
    if false {
        let result = client.call_unary(
            GrpcRequestOptions::new(),
            "aa".to_owned(),
            string_string_method("/does/not/matter", GrpcStreaming::Unary)).wait();
        assert!(result.is_err(), result);
    }
}

#[test]
fn error_in_handler() {
    let tester = TesterUnary::new(|_m, _| GrpcSingleResponse::no_metadata(Err(GrpcError::Other("my error")).into_future()));

    tester.call_expect_grpc_error_contain("aa", "my error");
}

// TODO
//#[test]
fn panic_in_handler() {
    let tester = TesterUnary::new(|_m, _| panic!("icnap"));

    tester.call_expect_grpc_error("aa",
        |m| m.find("Panic").is_some() && m.find("icnap").is_some());
}

#[test]
fn server_streaming() {
    let test_sync = Arc::new(TestSync::new());
    let test_sync_server = test_sync.clone();

    let tester = TesterServerStreaming::new(move |_m, s| {
        let sync = test_sync_server.clone();
        GrpcStreamingResponse::no_metadata(test_misc::stream_thread_spawn_iter(move || {
            (0..3).map(move |i| {
                sync.take(i * 2 + 1);
                format!("{}{}", s, i)
            })
        }))
    });

    let mut rs = tester.call("x").wait();

    test_sync.take(0);
    assert_eq!("x0", rs.next().unwrap().unwrap());
    test_sync.take(2);
    assert_eq!("x1", rs.next().unwrap().unwrap());
    test_sync.take(4);
    assert_eq!("x2", rs.next().unwrap().unwrap());
    assert!(rs.next().is_none());
}

#[test]
fn client_streaming() {
    let tester = TesterClientStreaming::new(move |_m, s| {
        GrpcSingleResponse::no_metadata(s.drop_metadata().fold(String::new(), |mut s, message| {
            s.push_str(&message);
            futures::finished::<_, GrpcError>(s)
        }))
    });

    let (tx, result) = tester.call();
    let tx = tx.send(Ok("aa".to_owned())).wait().ok().expect("aa");
    let tx = tx.send(Ok("bb".to_owned())).wait().ok().expect("bb");
    let tx = tx.send(Ok("cc".to_owned())).wait().ok().expect("cc");
    drop(tx);

    assert_eq!("aabbcc", result.wait().unwrap());
}
<|endoftext|>


<commit_before>//! Tests for packages/target filter flags giving suggestions on which
//! packages/targets are available.

use cargo_test_support::project;

const EXAMPLE: u8 = 1 << 0;
const BIN: u8 = 1 << 1;
const TEST: u8 = 1 << 2;
const BENCH: u8 = 1 << 3;
const PACKAGE: u8 = 1 << 4;

fn list_availables_test(command: &str, targets: u8) {
    let full_project = project()
        .file("examples/a.rs", "fn main() { }")
        .file("examples/b.rs", "fn main() { }")
        .file("benches/bench1.rs", "")
        .file("benches/bench2.rs", "")
        .file("tests/test1.rs", "")
        .file("tests/test2.rs", "")
        .file("src/main.rs", "fn main() { }")
        .file("Cargo.lock", "") // for `cargo pkgid`
        .build();

    if targets & EXAMPLE != 0 {
        full_project
            .cargo(&format!("{} --example", command))
            .with_stderr(
                "\
error: \"--example\" takes one argument.
Available examples:
    a
    b

",
            )
            .with_status(101)
            .run();
    }

    if targets & BIN != 0 {
        full_project
            .cargo(&format!("{} --bin", command))
            .with_stderr(
                "\
error: \"--bin\" takes one argument.
Available binaries:
    foo

",
            )
            .with_status(101)
            .run();
    }

    if targets & BENCH != 0 {
        full_project
            .cargo(&format!("{} --bench", command))
            .with_stderr(
                "\
error: \"--bench\" takes one argument.
Available benches:
    bench1
    bench2

",
            )
            .with_status(101)
            .run();
    }

    if targets & TEST != 0 {
        full_project
            .cargo(&format!("{} --test", command))
            .with_stderr(
                "\
error: \"--test\" takes one argument.
Available tests:
    test1
    test2

",
            )
            .with_status(101)
            .run();
    }

    if targets & PACKAGE != 0 {
        full_project
            .cargo(&format!("{} -p", command))
            .with_stderr(
                "\
[ERROR] \"--package <SPEC>\" requires a SPEC format value, \
which can be any package ID specifier in the dependency graph.
Run `cargo help pkgid` for more information about SPEC format.

Possible packages/workspace members:
    foo

",
            )
            .with_status(101)
            .run();
    }

    let empty_project = project().file("src/lib.rs", "").build();

    if targets & EXAMPLE != 0 {
        empty_project
            .cargo(&format!("{} --example", command))
            .with_stderr(
                "\
error: \"--example\" takes one argument.
No examples available.

",
            )
            .with_status(101)
            .run();
    }

    if targets & BIN != 0 {
        empty_project
            .cargo(&format!("{} --bin", command))
            .with_stderr(
                "\
error: \"--bin\" takes one argument.
No binaries available.

",
            )
            .with_status(101)
            .run();
    }

    if targets & BENCH != 0 {
        empty_project
            .cargo(&format!("{} --bench", command))
            .with_stderr(
                "\
error: \"--bench\" takes one argument.
No benches available.

",
            )
            .with_status(101)
            .run();
    }

    if targets & TEST != 0 {
        empty_project
            .cargo(&format!("{} --test", command))
            .with_stderr(
                "\
error: \"--test\" takes one argument.
No tests available.

",
            )
            .with_status(101)
            .run();
    }
}

#[cargo_test]
fn build_list_availables() {
    list_availables_test("build", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn check_list_availables() {
    list_availables_test("check", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn doc_list_availables() {
    list_availables_test("doc", BIN | PACKAGE);
}

#[cargo_test]
fn fix_list_availables() {
    list_availables_test("fix", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn run_list_availables() {
    list_availables_test("run", EXAMPLE | BIN | PACKAGE);
}

#[cargo_test]
fn test_list_availables() {
    list_availables_test("test", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn bench_list_availables() {
    list_availables_test("bench", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn install_list_availables() {
    list_availables_test("install", EXAMPLE | BIN);
}

#[cargo_test]
fn rustdoc_list_availables() {
    list_availables_test("rustdoc", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn rustc_list_availables() {
    list_availables_test("rustc", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn pkgid_list_availables() {
    list_availables_test("pkgid", PACKAGE);
}
<commit_msg>test: list availables for clean,tree,update<commit_after>//! Tests for packages/target filter flags giving suggestions on which
//! packages/targets are available.

use cargo_test_support::project;

const EXAMPLE: u8 = 1 << 0;
const BIN: u8 = 1 << 1;
const TEST: u8 = 1 << 2;
const BENCH: u8 = 1 << 3;
const PACKAGE: u8 = 1 << 4;

fn list_availables_test(command: &str, targets: u8) {
    let full_project = project()
        .file("examples/a.rs", "fn main() { }")
        .file("examples/b.rs", "fn main() { }")
        .file("benches/bench1.rs", "")
        .file("benches/bench2.rs", "")
        .file("tests/test1.rs", "")
        .file("tests/test2.rs", "")
        .file("src/main.rs", "fn main() { }")
        .file("Cargo.lock", "") // for `cargo pkgid`
        .build();

    if targets & EXAMPLE != 0 {
        full_project
            .cargo(&format!("{} --example", command))
            .with_stderr(
                "\
error: \"--example\" takes one argument.
Available examples:
    a
    b

",
            )
            .with_status(101)
            .run();
    }

    if targets & BIN != 0 {
        full_project
            .cargo(&format!("{} --bin", command))
            .with_stderr(
                "\
error: \"--bin\" takes one argument.
Available binaries:
    foo

",
            )
            .with_status(101)
            .run();
    }

    if targets & BENCH != 0 {
        full_project
            .cargo(&format!("{} --bench", command))
            .with_stderr(
                "\
error: \"--bench\" takes one argument.
Available benches:
    bench1
    bench2

",
            )
            .with_status(101)
            .run();
    }

    if targets & TEST != 0 {
        full_project
            .cargo(&format!("{} --test", command))
            .with_stderr(
                "\
error: \"--test\" takes one argument.
Available tests:
    test1
    test2

",
            )
            .with_status(101)
            .run();
    }

    if targets & PACKAGE != 0 {
        full_project
            .cargo(&format!("{} -p", command))
            .with_stderr(
                "\
[ERROR] \"--package <SPEC>\" requires a SPEC format value, \
which can be any package ID specifier in the dependency graph.
Run `cargo help pkgid` for more information about SPEC format.

Possible packages/workspace members:
    foo

",
            )
            .with_status(101)
            .run();
    }

    let empty_project = project().file("src/lib.rs", "").build();

    if targets & EXAMPLE != 0 {
        empty_project
            .cargo(&format!("{} --example", command))
            .with_stderr(
                "\
error: \"--example\" takes one argument.
No examples available.

",
            )
            .with_status(101)
            .run();
    }

    if targets & BIN != 0 {
        empty_project
            .cargo(&format!("{} --bin", command))
            .with_stderr(
                "\
error: \"--bin\" takes one argument.
No binaries available.

",
            )
            .with_status(101)
            .run();
    }

    if targets & BENCH != 0 {
        empty_project
            .cargo(&format!("{} --bench", command))
            .with_stderr(
                "\
error: \"--bench\" takes one argument.
No benches available.

",
            )
            .with_status(101)
            .run();
    }

    if targets & TEST != 0 {
        empty_project
            .cargo(&format!("{} --test", command))
            .with_stderr(
                "\
error: \"--test\" takes one argument.
No tests available.

",
            )
            .with_status(101)
            .run();
    }
}

#[cargo_test]
fn build_list_availables() {
    list_availables_test("build", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn check_list_availables() {
    list_availables_test("check", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn doc_list_availables() {
    list_availables_test("doc", BIN | PACKAGE);
}

#[cargo_test]
fn fix_list_availables() {
    list_availables_test("fix", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn run_list_availables() {
    list_availables_test("run", EXAMPLE | BIN | PACKAGE);
}

#[cargo_test]
fn test_list_availables() {
    list_availables_test("test", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn bench_list_availables() {
    list_availables_test("bench", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn install_list_availables() {
    list_availables_test("install", EXAMPLE | BIN);
}

#[cargo_test]
fn rustdoc_list_availables() {
    list_availables_test("rustdoc", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn rustc_list_availables() {
    list_availables_test("rustc", EXAMPLE | BIN | TEST | BENCH | PACKAGE);
}

#[cargo_test]
fn pkgid_list_availables() {
    list_availables_test("pkgid", PACKAGE);
}

#[cargo_test]
fn tree_list_availables() {
    list_availables_test("tree", PACKAGE);
}

#[cargo_test]
fn clean_list_availables() {
    list_availables_test("clean", PACKAGE);
}

#[cargo_test]
fn update_list_availables() {
    list_availables_test("update", PACKAGE);
}
<|endoftext|>


<commit_before>use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::{env, str};

use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
use toml_edit;

use errors::*;
use dependency::Dependency;

const MANIFEST_FILENAME: &str = "Cargo.toml";

/// A Cargo Manifest
#[derive(Debug, Clone)]
pub struct Manifest {
    /// Manifest contents as TOML data
    pub data: toml_edit::Document,
}

/// If a manifest is specified, return that one, otherise perform a manifest search starting from
/// the current directory.
/// If a manifest is specified, return that one. If a path is specified, perform a manifest search
/// starting from there. If nothing is specified, start searching from the current directory
/// (`cwd`).
fn find(specified: &Option<PathBuf>) -> Result<PathBuf> {
    match *specified {
        Some(ref path)
            if fs::metadata(&path)
                .chain_err(|| "Failed to get cargo file metadata")?
                .is_file() =>
        {
            Ok(path.to_owned())
        }
        Some(ref path) => search(path),
        None => search(&env::current_dir().chain_err(|| "Failed to get current directory")?),
    }
}

/// Search for Cargo.toml in this directory and recursively up the tree until one is found.
fn search(dir: &Path) -> Result<PathBuf> {
    let manifest = dir.join(MANIFEST_FILENAME);

    if fs::metadata(&manifest).is_ok() {
        Ok(manifest)
    } else {
        dir.parent()
            .ok_or_else(|| ErrorKind::MissingManifest.into())
            .and_then(|dir| search(dir))
    }
}

fn merge_inline_table(old_dep: &mut toml_edit::Item, new: &toml_edit::Item) {
    for (k, v) in new.as_inline_table()
        .expect("expected an inline table")
        .iter()
    {
        old_dep[k] = toml_edit::value(v.clone());
    }
}

fn str_or_1_len_table(item: &toml_edit::Item) -> bool {
    item.is_str() || item.as_table_like().map(|t| t.len() == 1).unwrap_or(false)
}
/// Merge a new dependency into an old entry. See `Dependency::to_toml` for what the format of the
/// new dependency will be.
fn merge_dependencies(old_dep: &mut toml_edit::Item, new: &Dependency) {
    assert!(!old_dep.is_none());

    let new_toml = new.to_toml().1;

    if str_or_1_len_table(old_dep) {
        // The old dependency is just a version/git/path. We are safe to overwrite.
        *old_dep = new_toml;
    } else if old_dep.is_table_like() {
        for key in &["version", "path", "git"] {
            // remove this key/value pairs
            old_dep[key] = toml_edit::Item::None;
        }
        if let Some(name) = new_toml.as_str() {
            old_dep["version"] = toml_edit::value(name);
        } else {
            merge_inline_table(old_dep, &new_toml);
        }
    } else {
        unreachable!("Invalid old dependency type");
    }

    old_dep.as_inline_table_mut().map(|t| t.fmt());
}

/// Print a message if the new dependency version is different from the old one.
fn print_upgrade_if_necessary(
    crate_name: &str,
    old_dep: &toml_edit::Item,
    new_version: &toml_edit::Item,
) -> Result<()> {
    let old_version = if str_or_1_len_table(old_dep) {
        old_dep.clone()
    } else if old_dep.is_table_like() {
        let version = old_dep["version"].clone();
        if version.is_none() {
            return Err("Missing version field".into());
        }
        version
    } else {
        unreachable!("Invalid old dependency type")
    };

    if let (Some(old_version), Some(new_version)) = (old_version.as_str(), new_version.as_str()) {
        if old_version == new_version {
            return Ok(());
        }
        let bufwtr = BufferWriter::stdout(ColorChoice::Always);
        let mut buffer = bufwtr.buffer();
        buffer
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))
            .chain_err(|| "Failed to set output colour")?;
        write!(&mut buffer, "Upgrading ").chain_err(|| "Failed to write upgrade message")?;
        buffer
            .set_color(&ColorSpec::new())
            .chain_err(|| "Failed to clear output colour")?;
        write!(
            &mut buffer,
            "{} v{} -> v{}\n",
            crate_name,
            old_version,
            new_version,
        ).chain_err(|| "Failed to write upgrade versions")?;
        bufwtr
            .print(&buffer)
            .chain_err(|| "Failed to print upgrade message")?;
    }
    Ok(())
}

impl Manifest {
    /// Look for a `Cargo.toml` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process's working directory is used as a starting point.
    pub fn find_file(path: &Option<PathBuf>) -> Result<File> {
        find(path).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .chain_err(|| "Failed to find Cargo.toml")
        })
    }

    /// Open the `Cargo.toml` for a path (or the process' `cwd`)
    pub fn open(path: &Option<PathBuf>) -> Result<Manifest> {
        let mut file = Manifest::find_file(path)?;
        let mut data = String::new();
        file.read_to_string(&mut data)
            .chain_err(|| "Failed to read manifest contents")?;

        data.parse().chain_err(|| "Unable to parse Cargo.toml")
    }

    /// Get the specified table from the manifest.
    pub fn get_table<'a>(&'a mut self, table_path: &[String]) -> Result<&'a mut toml_edit::Item> {
        /// Descend into a manifest until the required table is found.
        fn descend<'a>(
            input: &'a mut toml_edit::Item,
            path: &[String],
        ) -> Result<&'a mut toml_edit::Item> {
            if let Some(segment) = path.get(0) {
                // surround it by quotes in order to parse it as a literal key
                let value = input[&segment].or_insert(toml_edit::table());

                if value.is_table_like() {
                    descend(value, &path[1..])
                } else {
                    Err(ErrorKind::NonExistentTable(segment.clone()).into())
                }
            } else {
                Ok(input)
            }
        }

        descend(&mut self.data.root, table_path)
    }

    /// Get all sections in the manifest that exist and might contain dependencies.
    /// The returned items are always `Table` or `InlineTable`.
    pub fn get_sections(&self) -> Vec<(Vec<String>, toml_edit::Item)> {
        let mut sections = Vec::new();

        for dependency_type in &["dev-dependencies", "build-dependencies", "dependencies"] {
            // Dependencies can be in the three standard sections...
            if self.data[dependency_type].is_table_like() {
                sections.push((
                    vec![dependency_type.to_string()],
                    self.data[dependency_type].clone(),
                ))
            }

            // ... and in `target.<target>.(build-/dev-)dependencies`.
            let target_sections = self.data
                .as_table()
                .get("target")
                .and_then(toml_edit::Item::as_table_like)
                .into_iter()
                .flat_map(|t| t.iter())
                .filter_map(|(target_name, target_table)| {
                    let dependency_table = &target_table[dependency_type];
                    dependency_table.as_table_like().map(|_| {
                        (
                            vec![
                                "target".to_string(),
                                target_name.to_string(),
                                dependency_type.to_string(),
                            ],
                            dependency_table.clone(),
                        )
                    })
                });

            sections.extend(target_sections);
        }

        sections
    }

    /// Overwrite a file with TOML data.
    pub fn write_to_file(&self, file: &mut File) -> Result<()> {
        if self.data["package"].is_none() && self.data["project"].is_none() {
            if !self.data["workspace"].is_none() {
                Err(ErrorKind::UnexpectedRootManifest)?;
            } else {
                Err(ErrorKind::InvalidManifest)?;
            }
        }

        let s = self.data.to_string();
        let new_contents_bytes = s.as_bytes();

        // We need to truncate the file, otherwise the new contents
        // will be mixed up with the old ones.
        file.set_len(new_contents_bytes.len() as u64)
            .chain_err(|| "Failed to truncate Cargo.toml")?;
        file.write_all(new_contents_bytes)
            .chain_err(|| "Failed to write updated Cargo.toml")
    }

    /// Add entry to a Cargo.toml.
    pub fn insert_into_table(&mut self, table_path: &[String], dep: &Dependency) -> Result<()> {
        let table = self.get_table(table_path)?;

        if table[&dep.name].is_none() {
            // insert a new entry
            let (ref name, ref mut new_dependency) = dep.to_toml();
            table[name] = new_dependency.clone();
        } else {
            // update an existing entry
            merge_dependencies(&mut table[&dep.name], dep);
            table.as_inline_table_mut().map(|t| t.fmt());
        }
        Ok(())
    }

    /// Update an entry in Cargo.toml.
    pub fn update_table_entry(&mut self, table_path: &[String], dep: &Dependency) -> Result<()> {
        let table = self.get_table(table_path)?;
        let new_dep = dep.to_toml().1;

        // If (and only if) there is an old entry, merge the new one in.
        if !table[&dep.name].is_none() {
            if let Err(e) = print_upgrade_if_necessary(&dep.name, &table[&dep.name], &new_dep) {
                eprintln!("Error while displaying upgrade message, {}", e);
            }
            merge_dependencies(&mut table[&dep.name], dep);
            table.as_inline_table_mut().map(|t| t.fmt());
        }

        Ok(())
    }

    /// Remove entry from a Cargo.toml.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate cargo_edit;
    /// # extern crate toml_edit;
    /// # fn main() {
    ///     use cargo_edit::{Dependency, Manifest};
    ///     use toml_edit;
    ///
    ///     let mut manifest = Manifest { data: toml_edit::Document::new() };
    ///     let dep = Dependency::new("cargo-edit").set_version("0.1.0");
    ///     let _ = manifest.insert_into_table(&vec!["dependencies".to_owned()], &dep);
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    ///     assert!(manifest.data["dependencies"].is_none());
    /// # }
    /// ```
    pub fn remove_from_table(&mut self, table: &str, name: &str) -> Result<()> {
        if !self.data[table].is_table_like() {
            Err(ErrorKind::NonExistentTable(table.into()))?;
        } else {
            {
                let dep = &mut self.data[table][name];
                if dep.is_none() {
                    Err(ErrorKind::NonExistentDependency(name.into(), table.into()))?;
                }
                // remove the dependency
                *dep = toml_edit::Item::None;
            }

            // remove table if empty
            if self.data[table].as_table_like().unwrap().is_empty() {
                self.data[table] = toml_edit::Item::None;
            }
        }
        Ok(())
    }

    /// Add multiple dependencies to manifest
    pub fn add_deps(&mut self, table: &[String], deps: &[Dependency]) -> Result<()> {
        deps.iter()
            .map(|dep| self.insert_into_table(table, dep))
            .collect::<Result<Vec<_>>>()?;

        Ok(())
    }
}

impl str::FromStr for Manifest {
    type Err = Error;

    /// Read manifest data from string
    fn from_str(input: &str) -> ::std::result::Result<Self, Self::Err> {
        let d: toml_edit::Document = input.parse().chain_err(|| "Manifest not valid TOML")?;

        Ok(Manifest { data: d })
    }
}

#[cfg(test)]
mod tests {
    use dependency::Dependency;
    use super::*;
    use toml_edit;

    #[test]
    fn add_remove_dependency() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let clone = manifest.clone();
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let _ = manifest.insert_into_table(&["dependencies".to_owned()], &dep);
        assert!(
            manifest
                .remove_from_table("dependencies", &dep.name)
                .is_ok()
        );
        assert_eq!(manifest.data.to_string(), clone.data.to_string());
    }

    #[test]
    fn update_dependency() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        manifest
            .insert_into_table(&["dependencies".to_owned()], &dep)
            .unwrap();

        let new_dep = Dependency::new("cargo-edit").set_version("0.2.0");
        manifest
            .update_table_entry(&["dependencies".to_owned()], &new_dep)
            .unwrap();
    }

    #[test]
    fn update_wrong_dependency() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        manifest
            .insert_into_table(&["dependencies".to_owned()], &dep)
            .unwrap();
        let original = manifest.clone();

        let new_dep = Dependency::new("wrong-dep").set_version("0.2.0");
        manifest
            .update_table_entry(&["dependencies".to_owned()], &new_dep)
            .unwrap();

        assert_eq!(manifest.data.to_string(), original.data.to_string());
    }

    #[test]
    fn remove_dependency_no_section() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        assert!(
            manifest
                .remove_from_table("dependencies", &dep.name)
                .is_err()
        );
    }

    #[test]
    fn remove_dependency_non_existent() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let other_dep = Dependency::new("other-dep").set_version("0.1.0");
        let _ = manifest.insert_into_table(&["dependencies".to_owned()], &other_dep);
        assert!(
            manifest
                .remove_from_table("dependencies", &dep.name)
                .is_err()
        );
    }
}
<commit_msg>remove outdated comment<commit_after>use std::fs::{self, File, OpenOptions};
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::{env, str};

use termcolor::{BufferWriter, Color, ColorChoice, ColorSpec, WriteColor};
use toml_edit;

use errors::*;
use dependency::Dependency;

const MANIFEST_FILENAME: &str = "Cargo.toml";

/// A Cargo Manifest
#[derive(Debug, Clone)]
pub struct Manifest {
    /// Manifest contents as TOML data
    pub data: toml_edit::Document,
}

/// If a manifest is specified, return that one, otherise perform a manifest search starting from
/// the current directory.
/// If a manifest is specified, return that one. If a path is specified, perform a manifest search
/// starting from there. If nothing is specified, start searching from the current directory
/// (`cwd`).
fn find(specified: &Option<PathBuf>) -> Result<PathBuf> {
    match *specified {
        Some(ref path)
            if fs::metadata(&path)
                .chain_err(|| "Failed to get cargo file metadata")?
                .is_file() =>
        {
            Ok(path.to_owned())
        }
        Some(ref path) => search(path),
        None => search(&env::current_dir().chain_err(|| "Failed to get current directory")?),
    }
}

/// Search for Cargo.toml in this directory and recursively up the tree until one is found.
fn search(dir: &Path) -> Result<PathBuf> {
    let manifest = dir.join(MANIFEST_FILENAME);

    if fs::metadata(&manifest).is_ok() {
        Ok(manifest)
    } else {
        dir.parent()
            .ok_or_else(|| ErrorKind::MissingManifest.into())
            .and_then(|dir| search(dir))
    }
}

fn merge_inline_table(old_dep: &mut toml_edit::Item, new: &toml_edit::Item) {
    for (k, v) in new.as_inline_table()
        .expect("expected an inline table")
        .iter()
    {
        old_dep[k] = toml_edit::value(v.clone());
    }
}

fn str_or_1_len_table(item: &toml_edit::Item) -> bool {
    item.is_str() || item.as_table_like().map(|t| t.len() == 1).unwrap_or(false)
}
/// Merge a new dependency into an old entry. See `Dependency::to_toml` for what the format of the
/// new dependency will be.
fn merge_dependencies(old_dep: &mut toml_edit::Item, new: &Dependency) {
    assert!(!old_dep.is_none());

    let new_toml = new.to_toml().1;

    if str_or_1_len_table(old_dep) {
        // The old dependency is just a version/git/path. We are safe to overwrite.
        *old_dep = new_toml;
    } else if old_dep.is_table_like() {
        for key in &["version", "path", "git"] {
            // remove this key/value pairs
            old_dep[key] = toml_edit::Item::None;
        }
        if let Some(name) = new_toml.as_str() {
            old_dep["version"] = toml_edit::value(name);
        } else {
            merge_inline_table(old_dep, &new_toml);
        }
    } else {
        unreachable!("Invalid old dependency type");
    }

    old_dep.as_inline_table_mut().map(|t| t.fmt());
}

/// Print a message if the new dependency version is different from the old one.
fn print_upgrade_if_necessary(
    crate_name: &str,
    old_dep: &toml_edit::Item,
    new_version: &toml_edit::Item,
) -> Result<()> {
    let old_version = if str_or_1_len_table(old_dep) {
        old_dep.clone()
    } else if old_dep.is_table_like() {
        let version = old_dep["version"].clone();
        if version.is_none() {
            return Err("Missing version field".into());
        }
        version
    } else {
        unreachable!("Invalid old dependency type")
    };

    if let (Some(old_version), Some(new_version)) = (old_version.as_str(), new_version.as_str()) {
        if old_version == new_version {
            return Ok(());
        }
        let bufwtr = BufferWriter::stdout(ColorChoice::Always);
        let mut buffer = bufwtr.buffer();
        buffer
            .set_color(ColorSpec::new().set_fg(Some(Color::Green)).set_bold(true))
            .chain_err(|| "Failed to set output colour")?;
        write!(&mut buffer, "Upgrading ").chain_err(|| "Failed to write upgrade message")?;
        buffer
            .set_color(&ColorSpec::new())
            .chain_err(|| "Failed to clear output colour")?;
        write!(
            &mut buffer,
            "{} v{} -> v{}\n",
            crate_name,
            old_version,
            new_version,
        ).chain_err(|| "Failed to write upgrade versions")?;
        bufwtr
            .print(&buffer)
            .chain_err(|| "Failed to print upgrade message")?;
    }
    Ok(())
}

impl Manifest {
    /// Look for a `Cargo.toml` file
    ///
    /// Starts at the given path an goes into its parent directories until the manifest file is
    /// found. If no path is given, the process's working directory is used as a starting point.
    pub fn find_file(path: &Option<PathBuf>) -> Result<File> {
        find(path).and_then(|path| {
            OpenOptions::new()
                .read(true)
                .write(true)
                .open(path)
                .chain_err(|| "Failed to find Cargo.toml")
        })
    }

    /// Open the `Cargo.toml` for a path (or the process' `cwd`)
    pub fn open(path: &Option<PathBuf>) -> Result<Manifest> {
        let mut file = Manifest::find_file(path)?;
        let mut data = String::new();
        file.read_to_string(&mut data)
            .chain_err(|| "Failed to read manifest contents")?;

        data.parse().chain_err(|| "Unable to parse Cargo.toml")
    }

    /// Get the specified table from the manifest.
    pub fn get_table<'a>(&'a mut self, table_path: &[String]) -> Result<&'a mut toml_edit::Item> {
        /// Descend into a manifest until the required table is found.
        fn descend<'a>(
            input: &'a mut toml_edit::Item,
            path: &[String],
        ) -> Result<&'a mut toml_edit::Item> {
            if let Some(segment) = path.get(0) {
                let value = input[&segment].or_insert(toml_edit::table());

                if value.is_table_like() {
                    descend(value, &path[1..])
                } else {
                    Err(ErrorKind::NonExistentTable(segment.clone()).into())
                }
            } else {
                Ok(input)
            }
        }

        descend(&mut self.data.root, table_path)
    }

    /// Get all sections in the manifest that exist and might contain dependencies.
    /// The returned items are always `Table` or `InlineTable`.
    pub fn get_sections(&self) -> Vec<(Vec<String>, toml_edit::Item)> {
        let mut sections = Vec::new();

        for dependency_type in &["dev-dependencies", "build-dependencies", "dependencies"] {
            // Dependencies can be in the three standard sections...
            if self.data[dependency_type].is_table_like() {
                sections.push((
                    vec![dependency_type.to_string()],
                    self.data[dependency_type].clone(),
                ))
            }

            // ... and in `target.<target>.(build-/dev-)dependencies`.
            let target_sections = self.data
                .as_table()
                .get("target")
                .and_then(toml_edit::Item::as_table_like)
                .into_iter()
                .flat_map(|t| t.iter())
                .filter_map(|(target_name, target_table)| {
                    let dependency_table = &target_table[dependency_type];
                    dependency_table.as_table_like().map(|_| {
                        (
                            vec![
                                "target".to_string(),
                                target_name.to_string(),
                                dependency_type.to_string(),
                            ],
                            dependency_table.clone(),
                        )
                    })
                });

            sections.extend(target_sections);
        }

        sections
    }

    /// Overwrite a file with TOML data.
    pub fn write_to_file(&self, file: &mut File) -> Result<()> {
        if self.data["package"].is_none() && self.data["project"].is_none() {
            if !self.data["workspace"].is_none() {
                Err(ErrorKind::UnexpectedRootManifest)?;
            } else {
                Err(ErrorKind::InvalidManifest)?;
            }
        }

        let s = self.data.to_string();
        let new_contents_bytes = s.as_bytes();

        // We need to truncate the file, otherwise the new contents
        // will be mixed up with the old ones.
        file.set_len(new_contents_bytes.len() as u64)
            .chain_err(|| "Failed to truncate Cargo.toml")?;
        file.write_all(new_contents_bytes)
            .chain_err(|| "Failed to write updated Cargo.toml")
    }

    /// Add entry to a Cargo.toml.
    pub fn insert_into_table(&mut self, table_path: &[String], dep: &Dependency) -> Result<()> {
        let table = self.get_table(table_path)?;

        if table[&dep.name].is_none() {
            // insert a new entry
            let (ref name, ref mut new_dependency) = dep.to_toml();
            table[name] = new_dependency.clone();
        } else {
            // update an existing entry
            merge_dependencies(&mut table[&dep.name], dep);
            table.as_inline_table_mut().map(|t| t.fmt());
        }
        Ok(())
    }

    /// Update an entry in Cargo.toml.
    pub fn update_table_entry(&mut self, table_path: &[String], dep: &Dependency) -> Result<()> {
        let table = self.get_table(table_path)?;
        let new_dep = dep.to_toml().1;

        // If (and only if) there is an old entry, merge the new one in.
        if !table[&dep.name].is_none() {
            if let Err(e) = print_upgrade_if_necessary(&dep.name, &table[&dep.name], &new_dep) {
                eprintln!("Error while displaying upgrade message, {}", e);
            }
            merge_dependencies(&mut table[&dep.name], dep);
            table.as_inline_table_mut().map(|t| t.fmt());
        }

        Ok(())
    }

    /// Remove entry from a Cargo.toml.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate cargo_edit;
    /// # extern crate toml_edit;
    /// # fn main() {
    ///     use cargo_edit::{Dependency, Manifest};
    ///     use toml_edit;
    ///
    ///     let mut manifest = Manifest { data: toml_edit::Document::new() };
    ///     let dep = Dependency::new("cargo-edit").set_version("0.1.0");
    ///     let _ = manifest.insert_into_table(&vec!["dependencies".to_owned()], &dep);
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_ok());
    ///     assert!(manifest.remove_from_table("dependencies", &dep.name).is_err());
    ///     assert!(manifest.data["dependencies"].is_none());
    /// # }
    /// ```
    pub fn remove_from_table(&mut self, table: &str, name: &str) -> Result<()> {
        if !self.data[table].is_table_like() {
            Err(ErrorKind::NonExistentTable(table.into()))?;
        } else {
            {
                let dep = &mut self.data[table][name];
                if dep.is_none() {
                    Err(ErrorKind::NonExistentDependency(name.into(), table.into()))?;
                }
                // remove the dependency
                *dep = toml_edit::Item::None;
            }

            // remove table if empty
            if self.data[table].as_table_like().unwrap().is_empty() {
                self.data[table] = toml_edit::Item::None;
            }
        }
        Ok(())
    }

    /// Add multiple dependencies to manifest
    pub fn add_deps(&mut self, table: &[String], deps: &[Dependency]) -> Result<()> {
        deps.iter()
            .map(|dep| self.insert_into_table(table, dep))
            .collect::<Result<Vec<_>>>()?;

        Ok(())
    }
}

impl str::FromStr for Manifest {
    type Err = Error;

    /// Read manifest data from string
    fn from_str(input: &str) -> ::std::result::Result<Self, Self::Err> {
        let d: toml_edit::Document = input.parse().chain_err(|| "Manifest not valid TOML")?;

        Ok(Manifest { data: d })
    }
}

#[cfg(test)]
mod tests {
    use dependency::Dependency;
    use super::*;
    use toml_edit;

    #[test]
    fn add_remove_dependency() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let clone = manifest.clone();
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let _ = manifest.insert_into_table(&["dependencies".to_owned()], &dep);
        assert!(
            manifest
                .remove_from_table("dependencies", &dep.name)
                .is_ok()
        );
        assert_eq!(manifest.data.to_string(), clone.data.to_string());
    }

    #[test]
    fn update_dependency() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        manifest
            .insert_into_table(&["dependencies".to_owned()], &dep)
            .unwrap();

        let new_dep = Dependency::new("cargo-edit").set_version("0.2.0");
        manifest
            .update_table_entry(&["dependencies".to_owned()], &new_dep)
            .unwrap();
    }

    #[test]
    fn update_wrong_dependency() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        manifest
            .insert_into_table(&["dependencies".to_owned()], &dep)
            .unwrap();
        let original = manifest.clone();

        let new_dep = Dependency::new("wrong-dep").set_version("0.2.0");
        manifest
            .update_table_entry(&["dependencies".to_owned()], &new_dep)
            .unwrap();

        assert_eq!(manifest.data.to_string(), original.data.to_string());
    }

    #[test]
    fn remove_dependency_no_section() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        assert!(
            manifest
                .remove_from_table("dependencies", &dep.name)
                .is_err()
        );
    }

    #[test]
    fn remove_dependency_non_existent() {
        let mut manifest = Manifest {
            data: toml_edit::Document::new(),
        };
        let dep = Dependency::new("cargo-edit").set_version("0.1.0");
        let other_dep = Dependency::new("other-dep").set_version("0.1.0");
        let _ = manifest.insert_into_table(&["dependencies".to_owned()], &other_dep);
        assert!(
            manifest
                .remove_from_table("dependencies", &dep.name)
                .is_err()
        );
    }
}
<|endoftext|>


<commit_before>//! Protocol messages
//!
//! All protocol messages are serialized by serde according to the bincode data format. For
//! transmission on the wire, `tokio_io::codec::length_delimited` is used to prepend protocol
//! messages by an additional length header, thereby creating frames. It is crucial to
//!
//! The main type `Message` and the types in its fields are dump containers, which are not
//! responsible for any protocol logic (except for syntactic validation including validation of
//! `PublicKey` and `SecretKey` fields). Consequently, all fields of `Message` and all fields of
//! its contained types such as `Header` and `Payload` are public.

use secp256k1::key::{PublicKey, SecretKey};
use secp256k1::Signature;
use ::{SessionId, PeerIndex, SymmetricKey, SequenceNum};
use field::Fp;

/// A protocol message
///
/// Protocol messages consist of a header and a payload.
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct Message {
    pub header: Header,
    pub payload: Payload,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct Header {
    pub session_id: SessionId,
    pub peer_index: PeerIndex,
    pub sequence_num: SequenceNum,
    pub signature: Signature,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) enum Payload {
    KeyExchange(KeyExchange),
    DcExponential(DcExponential),
    DcMain(DcMain),
    Blame(Blame),
    Confirm(Confirm),
    Reveal(Reveal),
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct KeyExchange {
    pub ke_pk: PublicKey,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct DcExponential {
    pub commitment: [u8; 32],
    pub dc_exp: Vec<Fp>,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct DcMain {
    pub ok: bool,
    pub dc_xor: Vec<Vec<u8>>,
    pub ke_pk: PublicKey,
    pub extension: Extension,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) enum Extension {
    None,
    DcAddSecp256k1Scalar(/* TODO */),
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct Blame {
    pub ke_sk: SecretKey,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct Confirm {
    pub data: Vec<u8>,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct Reveal {
    pub keys: Vec<(PeerIndex, SymmetricKey)>,
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use tokio_io::codec::length_delimited;
    use tokio_serde_bincode::{ReadBincode, WriteBincode};
    use futures::sink::Sink;
    use futures::{Future, Stream};

    use super::*;
    use secp256k1::key::SecretKey;

    #[cfg(test)]
    fn roundtrip_serde_bincode(payload: Payload) {
        let msg1 = Message {
            header: dummy_header(),
            payload: payload,
        };

        // Write message
        let pipe = Cursor::new(Vec::new());
        let write = WriteBincode::new(length_delimited::FramedWrite::new(pipe));
        let write = write.send(msg1.clone()).wait().unwrap();

        // Read message again
        let pipe = Cursor::new(write.into_inner().into_inner().into_inner());
        let read = ReadBincode::<_ ,Message>::new(length_delimited::FramedRead::new(pipe));
        let msg2 = read.wait().next().unwrap().unwrap();

        assert_eq!(msg1, msg2);
    }

    #[cfg(test)]
    fn dummy_header() -> Header {
        // Create secret key, public key, message digest and signature
        let slice: [u8; 32] = [0xab; 32];
        let sk = SecretKey::from_slice(&::SECP256K1, &slice).unwrap();
        let slice: [u8; 32] = [0x01; 32];
        let sign_msg = ::secp256k1::Message::from_slice(&slice).unwrap();
        let sig = ::SECP256K1.sign(&sign_msg, &sk).unwrap();

        Header {
            peer_index: 2,
            session_id: SessionId([56; 32]),
            sequence_num: 14,
            signature: sig,
        }
    }

    #[test]
    fn roundtrip_keyexchange() {
        let slice: [u8; 32] = [0x4f; 32];
        let sk = SecretKey::from_slice(&::SECP256K1, &slice).unwrap();
        let ke_pk = PublicKey::from_secret_key(&::SECP256K1, &sk).unwrap();
        assert!(ke_pk.is_valid());

        let payload = Payload::KeyExchange(KeyExchange {
            ke_pk: ke_pk,
        });

        roundtrip_serde_bincode(payload);
    }

    #[test]
    fn roundtrip_dcexponential() {
        let payload = Payload::DcExponential(DcExponential {
            commitment: [9; 32],
            dc_exp: vec![Fp::from_u127(Fp::prime()), Fp::from_u127(0), Fp::from_u127(656)],
        });

        roundtrip_serde_bincode(payload);
    }
}
<commit_msg>Move signature out of header<commit_after>//! Protocol messages
//!
//! All protocol messages are serialized by serde according to the bincode data format. For
//! transmission on the wire, `tokio_io::codec::length_delimited` is used to prepend protocol
//! messages by an additional length header, thereby creating frames. It is crucial to
//!
//! The main type `Message` and the types in its fields are dump containers, which are not
//! responsible for any protocol logic (except for syntactic validation including validation of
//! `PublicKey` and `SecretKey` fields). Consequently, all fields of `Message` and all fields of
//! its contained types such as `Header` and `Payload` are public.

use secp256k1::key::{PublicKey, SecretKey};
use secp256k1::Signature;
use ::{SessionId, PeerIndex, SymmetricKey, SequenceNum};
use field::Fp;

/// A protocol message
///
/// Protocol messages consist of a header and a payload.
#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct Message {
    pub header: Header,
    pub payload: Payload,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct Header {
    pub session_id: SessionId,
    pub peer_index: PeerIndex,
    pub sequence_num: SequenceNum,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct SignedMessage {
    pub message: Message,
    pub signature: Signature,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) enum Payload {
    KeyExchange(KeyExchange),
    DcExponential(DcExponential),
    DcMain(DcMain),
    Blame(Blame),
    Confirm(Confirm),
    Reveal(Reveal),
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct KeyExchange {
    pub ke_pk: PublicKey,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct DcExponential {
    pub commitment: [u8; 32],
    pub dc_exp: Vec<Fp>,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct DcMain {
    pub ok: bool,
    pub dc_xor: Vec<Vec<u8>>,
    pub ke_pk: PublicKey,
    pub extension: Extension,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) enum Extension {
    None,
    DcAddSecp256k1Scalar(/* TODO */),
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct Blame {
    pub ke_sk: SecretKey,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub struct Confirm {
    pub data: Vec<u8>,
}

#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)]
pub(crate) struct Reveal {
    pub keys: Vec<(PeerIndex, SymmetricKey)>,
}

#[cfg(test)]
mod tests {
    use std::io::Cursor;
    use tokio_io::codec::length_delimited;
    use tokio_serde_bincode::{ReadBincode, WriteBincode};
    use futures::sink::Sink;
    use futures::{Future, Stream};

    use super::*;
    use secp256k1::key::SecretKey;

    #[cfg(test)]
    fn roundtrip_serde_bincode(payload: Payload) {
        let msg1 = Message {
            header: dummy_header(),
            payload: payload,
        }.add_signature();

        // Write message
        let pipe = Cursor::new(Vec::new());
        let write = WriteBincode::new(length_delimited::FramedWrite::new(pipe));
        let write = write.send(msg1.clone()).wait().unwrap();

        // Read message again
        let pipe = Cursor::new(write.into_inner().into_inner().into_inner());
        let read = ReadBincode::<_ ,Message>::new(length_delimited::FramedRead::new(pipe));
        let msg2 = read.wait().next().unwrap().unwrap();

        assert_eq!(msg1, msg2);
    }

    #[test]
    fn roundtrip_keyexchange() {
        let slice: [u8; 32] = [0x4f; 32];
        let sk = SecretKey::from_slice(&::SECP256K1, &slice).unwrap();
        let ke_pk = PublicKey::from_secret_key(&::SECP256K1, &sk).unwrap();
        assert!(ke_pk.is_valid());

        let payload = Payload::KeyExchange(KeyExchange {
            ke_pk: ke_pk,
        });

        roundtrip_serde_bincode(payload);
    }

    #[test]
    fn roundtrip_dcexponential() {
        let payload = Payload::DcExponential(DcExponential {
            commitment: [9; 32],
            dc_exp: vec![Fp::from_u127(Fp::prime()), Fp::from_u127(0), Fp::from_u127(656)],
        });

        roundtrip_serde_bincode(payload);
    }

    #[cfg(test)]
    fn dummy_header() -> Header {
        Header {
            peer_index: 2,
            session_id: SessionId([56; 32]),
            sequence_num: 14,
        }
    }

    #[cfg(test)]
    fn sign(msg: Message) -> SignedMessage {
        // Create secret key, public key, message digest and signature
        let slice: [u8; 32] = [0xab; 32];
        let sk = SecretKey::from_slice(&::SECP256K1, &slice).unwrap();
        let slice: [u8; 32] = [0x01; 32];
        let digest = ::secp256k1::Message::from_slice(&slice).unwrap();
        let sig = ::SECP256K1.sign(&digest, &sk).unwrap();
        SignedMessage {
            message: msg,
            signature: sig,
        }
    }
}
<|endoftext|>


<commit_before>extern crate concurrent;

#[cfg(test)]
mod semaphore_prim {

    use super::concurrent::primitives::Semaphore;

    use std::thread;

    #[test]
    fn it_should_not_acquired_more_than_semaphore_contains_with_try_acquire() {
        let mut s = Semaphore::new(3);

        let res1 = s.try_acquire();
        let res2 = s.try_acquire();
        let res3 = s.try_acquire();
        let res4 = s.try_acquire();

        assert_eq!(res1, Some(3));
        assert_eq!(res2, Some(2));
        assert_eq!(res3, Some(1));
        assert_eq!(res4, None);
    }

    #[test]
    fn thread_should_try_to_acquire_resource() {
        let mut s = Semaphore::new(1);

        let res = s.acquire();
        thread::spawn(
            move || {
                let try_res = s.try_acquire();
                assert_eq!(try_res, None);
            }
        );
        assert_eq!(res, Some(1));
    }

    #[test]
    fn it_should_acquire_each_time_new_resource() {
        let mut s = Semaphore::new(3);

        let res3 = s.acquire();
        let res2 = s.acquire();

        assert_eq!(res3, Some(3));
        assert_eq!(res2, Some(2));
    }

    #[test]
    fn acquire_released_resource() {
        let mut s = Semaphore::new(3);

        let res = s.acquire();
        assert_eq!(res, Some(3));
        s.release();

        let reacquired_res = s.acquire();
        assert_eq!(reacquired_res, Some(3));
    }

    #[test]
    fn acquire_update_release_acquire_resource_with_new_value() {
        let mut s = Semaphore::new(1);
        let res_index = s.acquire();
        let res_val = s.get(res_index.unwrap());

        assert_eq!(res_val, Some(0));

        s.update(res_index.unwrap(), 10);
        s.release();

        let res_index = s.acquire();
        let res_val = s.get(res_index.unwrap());

        assert_eq!(res_val, Some(10));
    }

    #[test]
    fn acquire_update_released_multiple_resources() {
        let mut s = Semaphore::new(3);
        let res_index3 = s.acquire();
        let res_index2 = s.acquire();
        let res_index1 = s.acquire();

        s.update(res_index3.unwrap(), 10);
        s.update(res_index2.unwrap(), 20);
        s.update(res_index1.unwrap(), 30);

        s.release();
        s.release();
        s.release();

        let res_index3 = s.acquire();
        let res_index2 = s.acquire();
        let res_index1 = s.acquire();

        assert_eq!(s.get(res_index3.unwrap()), Some(10));
        assert_eq!(s.get(res_index2.unwrap()), Some(20));
        assert_eq!(s.get(res_index1.unwrap()), Some(30));
    }

    //find a way how to prevent use resource when thread release it
    //test for locking thread on acquire method if there is no free resources semaphore has
}<commit_msg>add test on local modification<commit_after>extern crate concurrent;

#[cfg(test)]
mod semaphore_prim {

    use super::concurrent::primitives::Semaphore;

    use std::thread;

    #[test]
    fn it_should_not_acquired_more_than_semaphore_contains_with_try_acquire() {
        let mut s = Semaphore::new(3);

        let res1 = s.try_acquire();
        let res2 = s.try_acquire();
        let res3 = s.try_acquire();
        let res4 = s.try_acquire();

        assert_eq!(res1, Some(3));
        assert_eq!(res2, Some(2));
        assert_eq!(res3, Some(1));
        assert_eq!(res4, None);
    }

    #[test]
    fn thread_should_try_to_acquire_resource() {
        let mut s = Semaphore::new(1);

        let res = s.acquire();
        thread::spawn(
            move || {
                let try_res = s.try_acquire();
                assert_eq!(try_res, None);
            }
        );
        assert_eq!(res, Some(1));
    }

    #[test]
    fn it_should_acquire_each_time_new_resource() {
        let mut s = Semaphore::new(3);

        let res3 = s.acquire();
        let res2 = s.acquire();

        assert_eq!(res3, Some(3));
        assert_eq!(res2, Some(2));
    }

    #[test]
    fn acquire_released_resource() {
        let mut s = Semaphore::new(3);

        let res = s.acquire();
        assert_eq!(res, Some(3));
        s.release();

        let reacquired_res = s.acquire();
        assert_eq!(reacquired_res, Some(3));
    }

    #[test]
    fn acquire_update_release_acquire_resource_with_new_value() {
        let mut s = Semaphore::new(1);
        let res_index = s.acquire();
        let res_val = s.get(res_index.unwrap());

        assert_eq!(res_val, Some(0));

        s.update(res_index.unwrap(), 10);
        s.release();

        let res_index = s.acquire();
        let res_val = s.get(res_index.unwrap());

        assert_eq!(res_val, Some(10));
    }

    #[test]
    fn acquire_update_released_multiple_resources() {
        let mut s = Semaphore::new(3);
        let res_index3 = s.acquire();
        let res_index2 = s.acquire();
        let res_index1 = s.acquire();

        s.update(res_index3.unwrap(), 10);
        s.update(res_index2.unwrap(), 20);
        s.update(res_index1.unwrap(), 30);

        s.release();
        s.release();
        s.release();

        let res_index3 = s.acquire();
        let res_index2 = s.acquire();
        let res_index1 = s.acquire();

        assert_eq!(s.get(res_index3.unwrap()), Some(10));
        assert_eq!(s.get(res_index2.unwrap()), Some(20));
        assert_eq!(s.get(res_index1.unwrap()), Some(30));
    }

    #[test]
    fn it_should_not_modify_semaphore_resource_when_modify_local_value_only() {
        let mut s = Semaphore::new(1);
        let index = s.acquire();

        let res = s.get(index.unwrap());
        let res = res.map(|v| v + 10);

        assert_eq!(res, Some(10));
        assert_eq!(s.get(index.unwrap()), Some(0));
    }

    //find a way how to prevent use resource when thread release it
    //test for locking thread on acquire method if there is no free resources semaphore has
}<|endoftext|>


<commit_before>extern crate gcc;
#[cfg(feature = "bindgen")]
extern crate bindgen;

#[cfg(not(feature = "bindgen"))]
use std::fs;
use std::env;
use std::path::Path;

#[cfg(feature = "bindgen")]
fn generate_binding(out_file: &Path) {
    let _ = bindgen::builder()
        .clang_arg("--std=c++11")
        .clang_arg(if cfg!(feature = "sse42") {
                       "-msse4.2"
                   } else {
                       "-march=native"
                   })
        .header("src/fasthash.hpp")
        .no_unstable_rust()
        .generate_inline_functions(true)
        .disable_name_namespacing()
        .hide_type(".*PCCP.*")
        .whitelisted_function("^CityHash.*")
        .whitelisted_function("^farmhash.*")
        .whitelisted_function("^lookup3.*")
        .whitelisted_function("^metrohash.*")
        .whitelisted_function("^mum_hash.*")
        .whitelisted_function("^MurmurHash.*")
        .whitelisted_function("^SpookyHasher.*")
        .whitelisted_function("^t1ha.*")
        .whitelisted_function("^XXH.*")
        .link_static("fasthash")
        .generate()
        .unwrap()
        .write_to_file(out_file)
        .expect("fail to write bindings");
}

#[cfg(not(feature = "bindgen"))]
fn generate_binding(out_file: &Path) {
    let suffix = if cfg!(target_os = "macos") {
        "macos"
    } else {
        "linux"
    };

    fs::copy(format!("src/fasthash_{}.rs", suffix), out_file).expect("fail to copy bindings");
}

fn main() {
    let mut gcc_config = gcc::Build::new();

    gcc_config
        .file("src/fasthash.cpp")
        .file("src/smhasher/City.cpp")
        .file("src/smhasher/farmhash-c.c")
        .file("src/smhasher/lookup3.cpp")
        .file("src/smhasher/mum.cc")
        .file("src/smhasher/metrohash64.cpp")
        .file("src/smhasher/metrohash128.cpp")
        .file("src/smhasher/MurmurHash1.cpp")
        .file("src/smhasher/MurmurHash2.cpp")
        .file("src/smhasher/MurmurHash3.cpp")
        .file("src/smhasher/Spooky.cpp")
        .file("src/smhasher/t1ha.cc")
        .file("src/smhasher/xxhash.c");

    if cfg!(feature = "sse42") {
        gcc_config
            .flag("-msse4.2")
            .file("src/smhasher/metrohash64crc.cpp")
            .file("src/smhasher/metrohash128crc.cpp");
    }

    gcc_config.compile("libfasthash.a");

    let out_dir = env::var("OUT_DIR").unwrap();
    let out_file = Path::new(&out_dir).join("src/fasthash.rs");

    generate_binding(&out_file);

    if cfg!(target_os = "macos") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        println!("cargo:rustc-link-lib=dylib=stdc++");
        println!("cargo:rustc-link-lib=dylib=gcc");
    }
}
<commit_msg>smhasher makes regular use of switch fallthrough, so disable warning<commit_after>extern crate gcc;
#[cfg(feature = "bindgen")]
extern crate bindgen;

#[cfg(not(feature = "bindgen"))]
use std::fs;
use std::env;
use std::path::Path;

#[cfg(feature = "bindgen")]
fn generate_binding(out_file: &Path) {
    let _ = bindgen::builder()
        .clang_arg("--std=c++11")
        .clang_arg(if cfg!(feature = "sse42") {
                       "-msse4.2"
                   } else {
                       "-march=native"
                   })
        .header("src/fasthash.hpp")
        .no_unstable_rust()
        .generate_inline_functions(true)
        .disable_name_namespacing()
        .hide_type(".*PCCP.*")
        .whitelisted_function("^CityHash.*")
        .whitelisted_function("^farmhash.*")
        .whitelisted_function("^lookup3.*")
        .whitelisted_function("^metrohash.*")
        .whitelisted_function("^mum_hash.*")
        .whitelisted_function("^MurmurHash.*")
        .whitelisted_function("^SpookyHasher.*")
        .whitelisted_function("^t1ha.*")
        .whitelisted_function("^XXH.*")
        .link_static("fasthash")
        .generate()
        .unwrap()
        .write_to_file(out_file)
        .expect("fail to write bindings");
}

#[cfg(not(feature = "bindgen"))]
fn generate_binding(out_file: &Path) {
    let suffix = if cfg!(target_os = "macos") {
        "macos"
    } else {
        "linux"
    };

    fs::copy(format!("src/fasthash_{}.rs", suffix), out_file).expect("fail to copy bindings");
}

fn main() {
    let mut gcc_config = gcc::Build::new();

    gcc_config
        .flag("-Wno-implicit-fallthrough")
        .file("src/fasthash.cpp")
        .file("src/smhasher/City.cpp")
        .file("src/smhasher/farmhash-c.c")
        .file("src/smhasher/lookup3.cpp")
        .file("src/smhasher/mum.cc")
        .file("src/smhasher/metrohash64.cpp")
        .file("src/smhasher/metrohash128.cpp")
        .file("src/smhasher/MurmurHash1.cpp")
        .file("src/smhasher/MurmurHash2.cpp")
        .file("src/smhasher/MurmurHash3.cpp")
        .file("src/smhasher/Spooky.cpp")
        .file("src/smhasher/t1ha.cc")
        .file("src/smhasher/xxhash.c");

    if cfg!(feature = "sse42") {
        gcc_config
            .flag("-msse4.2")
            .file("src/smhasher/metrohash64crc.cpp")
            .file("src/smhasher/metrohash128crc.cpp");
    }

    gcc_config.compile("libfasthash.a");

    let out_dir = env::var("OUT_DIR").unwrap();
    let out_file = Path::new(&out_dir).join("src/fasthash.rs");

    generate_binding(&out_file);

    if cfg!(target_os = "macos") {
        println!("cargo:rustc-link-lib=dylib=c++");
    } else {
        println!("cargo:rustc-link-lib=dylib=stdc++");
        println!("cargo:rustc-link-lib=dylib=gcc");
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Syn Developers
//
// 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.

#![cfg(feature = "extra-traits")]

extern crate proc_macro2;
extern crate syn;

use proc_macro2::{Ident, Literal, Span, TokenStream};
use syn::buffer::TokenBuffer;
use syn::*;

#[macro_use]
mod macros;

fn lit<T: Into<Literal>>(t: T) -> Lit {
    Lit::new(t.into())
}

fn ident(s: &str) -> Ident {
    Ident::new(s, Span::call_site())
}

#[test]
fn test_meta_item_word() {
    run_test("#[foo]", Meta::Word(ident("foo")))
}

#[test]
fn test_meta_item_name_value() {
    run_test(
        "#[foo = 5]",
        MetaNameValue {
            ident: ident("foo").into(),
            eq_token: Default::default(),
            lit: lit(Literal::i32_unsuffixed(5)),
        },
    )
}

#[test]
fn test_meta_item_bool_value() {
    run_test(
        "#[foo = true]",
        MetaNameValue {
            ident: ident("foo").into(),
            eq_token: Default::default(),
            lit: Lit::Bool(LitBool {
                value: true,
                span: Span::call_site(),
            }),
        },
    );
    run_test(
        "#[foo = false]",
        MetaNameValue {
            ident: ident("foo").into(),
            eq_token: Default::default(),
            lit: Lit::Bool(LitBool {
                value: false,
                span: Span::call_site(),
            }),
        },
    )
}

#[test]
fn test_meta_item_list_lit() {
    run_test(
        "#[foo(5)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![NestedMeta::Literal(lit(Literal::i32_unsuffixed(5)))],
        },
    )
}

#[test]
fn test_meta_item_list_word() {
    run_test(
        "#[foo(bar)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![NestedMeta::Meta(Meta::Word(ident("bar").into()))],
        },
    )
}

#[test]
fn test_meta_item_list_name_value() {
    run_test(
        "#[foo(bar = 5)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![NestedMeta::Meta(
                MetaNameValue {
                    ident: ident("bar").into(),
                    eq_token: Default::default(),
                    lit: lit(Literal::i32_unsuffixed(5)),
                }.into(),
            ),],
        },
    )
}

#[test]
fn test_meta_item_list_bool_value() {
    run_test(
        "#[foo(bar = true)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![NestedMeta::Meta(
                MetaNameValue {
                    ident: ident("bar").into(),
                    eq_token: Default::default(),
                    lit: Lit::Bool(LitBool {
                        value: true,
                        span: Span::call_site()
                    }),
                }.into(),
            ),],
        },
    )
}

#[test]
fn test_meta_item_multiple() {
    run_test(
        "#[foo(word, name = 5, list(name2 = 6), word2)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![
                NestedMeta::Meta(Meta::Word(ident("word").into())),
                NestedMeta::Meta(
                    MetaNameValue {
                        ident: ident("name").into(),
                        eq_token: Default::default(),
                        lit: lit(Literal::i32_unsuffixed(5)),
                    }.into(),
                ),
                NestedMeta::Meta(
                    MetaList {
                        ident: ident("list").into(),
                        paren_token: Default::default(),
                        nested: punctuated![NestedMeta::Meta(
                            MetaNameValue {
                                ident: ident("name2").into(),
                                eq_token: Default::default(),
                                lit: lit(Literal::i32_unsuffixed(6)),
                            }.into(),
                        ),],
                    }.into(),
                ),
                NestedMeta::Meta(Meta::Word(ident("word2").into())),
            ],
        },
    )
}

fn run_test<T: Into<Meta>>(input: &str, expected: T) {
    let tokens = input.parse::<TokenStream>().unwrap();
    let buf = TokenBuffer::new2(tokens);
    let attr = match Attribute::old_parse_outer(buf.begin()) {
        Ok((e, rest)) => {
            assert!(rest.eof());
            e
        }
        Err(err) => panic!(err.to_string()),
    };
    assert_eq!(expected.into(), attr.interpret_meta().unwrap());
}
<commit_msg>Simplify attribute parsing in test<commit_after>// Copyright 2018 Syn Developers
//
// 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.

#![cfg(feature = "extra-traits")]

extern crate proc_macro2;
extern crate syn;

use proc_macro2::{Ident, Literal, Span};
use syn::synom::Parser;
use syn::*;

#[macro_use]
mod macros;

fn lit<T: Into<Literal>>(t: T) -> Lit {
    Lit::new(t.into())
}

fn ident(s: &str) -> Ident {
    Ident::new(s, Span::call_site())
}

#[test]
fn test_meta_item_word() {
    run_test("#[foo]", Meta::Word(ident("foo")))
}

#[test]
fn test_meta_item_name_value() {
    run_test(
        "#[foo = 5]",
        MetaNameValue {
            ident: ident("foo").into(),
            eq_token: Default::default(),
            lit: lit(Literal::i32_unsuffixed(5)),
        },
    )
}

#[test]
fn test_meta_item_bool_value() {
    run_test(
        "#[foo = true]",
        MetaNameValue {
            ident: ident("foo").into(),
            eq_token: Default::default(),
            lit: Lit::Bool(LitBool {
                value: true,
                span: Span::call_site(),
            }),
        },
    );
    run_test(
        "#[foo = false]",
        MetaNameValue {
            ident: ident("foo").into(),
            eq_token: Default::default(),
            lit: Lit::Bool(LitBool {
                value: false,
                span: Span::call_site(),
            }),
        },
    )
}

#[test]
fn test_meta_item_list_lit() {
    run_test(
        "#[foo(5)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![NestedMeta::Literal(lit(Literal::i32_unsuffixed(5)))],
        },
    )
}

#[test]
fn test_meta_item_list_word() {
    run_test(
        "#[foo(bar)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![NestedMeta::Meta(Meta::Word(ident("bar").into()))],
        },
    )
}

#[test]
fn test_meta_item_list_name_value() {
    run_test(
        "#[foo(bar = 5)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![NestedMeta::Meta(
                MetaNameValue {
                    ident: ident("bar").into(),
                    eq_token: Default::default(),
                    lit: lit(Literal::i32_unsuffixed(5)),
                }.into(),
            ),],
        },
    )
}

#[test]
fn test_meta_item_list_bool_value() {
    run_test(
        "#[foo(bar = true)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![NestedMeta::Meta(
                MetaNameValue {
                    ident: ident("bar").into(),
                    eq_token: Default::default(),
                    lit: Lit::Bool(LitBool {
                        value: true,
                        span: Span::call_site()
                    }),
                }.into(),
            ),],
        },
    )
}

#[test]
fn test_meta_item_multiple() {
    run_test(
        "#[foo(word, name = 5, list(name2 = 6), word2)]",
        MetaList {
            ident: ident("foo").into(),
            paren_token: Default::default(),
            nested: punctuated![
                NestedMeta::Meta(Meta::Word(ident("word").into())),
                NestedMeta::Meta(
                    MetaNameValue {
                        ident: ident("name").into(),
                        eq_token: Default::default(),
                        lit: lit(Literal::i32_unsuffixed(5)),
                    }.into(),
                ),
                NestedMeta::Meta(
                    MetaList {
                        ident: ident("list").into(),
                        paren_token: Default::default(),
                        nested: punctuated![NestedMeta::Meta(
                            MetaNameValue {
                                ident: ident("name2").into(),
                                eq_token: Default::default(),
                                lit: lit(Literal::i32_unsuffixed(6)),
                            }.into(),
                        ),],
                    }.into(),
                ),
                NestedMeta::Meta(Meta::Word(ident("word2").into())),
            ],
        },
    )
}

fn run_test<T: Into<Meta>>(input: &str, expected: T) {
    let attrs = Attribute::parse_outer.parse_str(input).unwrap();
    assert_eq!(attrs.len(), 1);
    let attr = attrs.into_iter().next().unwrap();
    assert_eq!(expected.into(), attr.interpret_meta().unwrap());
}
<|endoftext|>


<commit_before>extern crate procrs;
extern crate argparse;
#[macro_use]
extern crate prettytable;
use prettytable::Table;
use prettytable::format::FormatBuilder;
use std::collections::HashMap;
use std::iter::repeat;
use procrs::pid::*;
use procrs::TaskId;
use argparse::{ArgumentParser, StoreTrue, Store};

fn main() {
    let opts = parse_args();
    let (query, long, perf, verbose, tree) =
        (opts.query, opts.long, opts.perf, opts.verbose, opts.tree);

    let mut pids = PidIter::new_query(query).unwrap()
        .collect::<Result<Vec<_>, _>>().unwrap();

    let mut name_indent = HashMap::new();

    if verbose {
        for pid in pids {
            println!("{:?}", pid);
        }
        return
    }

    if opts.tree {
        pids = treeify_names(pids, &mut name_indent);
    } else {
        pids.sort_by(|p1, p2| p1.stat.pid.cmp(&p2.stat.pid));
    };
    // Assume hertz is 100.
    // TODO: Look this up via syscall (no /proc value for it)
    let hertz = 100;
    let minute_hertz = hertz * 60;
    let hour_hertz = minute_hertz * 60;

    let mut table = Table::init(
        pids.iter().map(|p| {
            // When we have a tree, the name is prepended with an indent.
            let mut name = match tree {
                false => String::new(),
                true => name_indent.remove(&p.stat.pid).unwrap()
            };

            // For long output, try using the cmdline first.
            // FIXME: Sometimes prog_name != cmdline[0].
            if !long {
                name.push_str(&p.stat.comm);
            } else {
                let cmdline = p.cmdline.join(" ");
                name.push_str(
                    match cmdline {
                         ref s if s.len() > 0 => s,
                        _ => &p.stat.comm
                    }
                );
            }

            match (long, perf) {
                (_, false) => {
                    row![p.stat.pid, p.stat.ppid, name]
                },
                (_, true) => {
                    let rss = p.status.vmrss.map(|m| (m / 1024).to_string()).unwrap_or("".to_owned());
                    let raw_time = p.stat.utime + p.stat.stime;
                    let second_utime = raw_time / hertz % 60;
                    let minute_utime = raw_time / minute_hertz % 60;
                    let hour_utime = raw_time / hour_hertz % 60;
                    let cputime = format!(
                        "{:02}:{:02}:{:02}",
                        hour_utime,
                        minute_utime,
                        second_utime
                    );
                    row![p.stat.pid, p.stat.ppid, rss, cputime, name]
                }
            }
        }).collect::<Vec<_>>()
    );

    table.set_titles(
        match (long, perf) {
            (false, false) =>
                row!["Pid", "Ppid", "Cmd"],
            (true, false) =>
                row!["Pid", "Ppid", "Cmd"],
            (false, true) =>
                row!["Pid", "Ppid", "RSS", "Time", "Cmd"],
            (true, true) =>
                row!["Pid", "Ppid", "RSS", "Time", "Cmd"]
        }
    );
    table.set_format(
        FormatBuilder::new()
            .column_separator(' ')
            .build()
    );
    table.printstd();
}

// Given a vector of Pid structs, treeify their names, and return them in the right order.
// This is similar to ps -AH.
fn treeify_names(pids: Vec<Pid>, name_indents: &mut HashMap<TaskId, String>) -> Vec<Pid> {
    let mut child_pids = HashMap::new();
    for pid in pids {
        let ppid = pid.stat.ppid;
        child_pids.entry(ppid)
            .or_insert(Vec::new())
            .push(pid);
    }
    enumerate_children(0, &mut child_pids, name_indents, -1)
}

// Enumerate children pids, and return them.
fn enumerate_children(pid: TaskId, child_pids: &mut HashMap<TaskId, Vec<Pid>>,
    name_indents: &mut HashMap<TaskId, String>, indent: i32) -> Vec<Pid> {
    name_indents.insert(pid,
        match indent {
            i if i >= 0 =>
                repeat("  ").take(i as usize).collect::<String>(),
            _ => "".to_owned()
        }
    );
    let mut pids = Vec::new();
    let ppids = match child_pids.remove(&pid) {
        Some(v) => v,
        None => { return pids; }
    };
    for pid in ppids {
        let pid_num = pid.stat.pid;
        pids.push(pid);
        pids.append(
            &mut enumerate_children(pid_num, child_pids, name_indents, indent + 1)
        );
    }
    pids
}

struct ProgOpts {
    query: PidQuery,
    tree: bool,
    perf: bool,
    long: bool,
    verbose: bool
}

fn parse_args() -> ProgOpts {
    let mut opts = ProgOpts {
        query: PidQuery::NoneQuery,
        tree: false,
        perf: false,
        long: false,
        verbose: false
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Query linux processes");
        ap.refer(&mut opts.tree)
            .add_option(&["-t", "--tree"], StoreTrue, "Display process tree");
        ap.refer(&mut opts.perf)
            .add_option(&["-p", "--perf"], StoreTrue, "Display performance information");
        ap.refer(&mut opts.long)
            .add_option(&["-l", "--long"], StoreTrue, "Display more information");
        ap.refer(&mut opts.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue, "Verbose output");
        ap.refer(&mut opts.query)
            .add_argument("query", Store, "Optional query to search by, pid or string");
        ap.parse_args_or_exit();
    }

    opts
}
<commit_msg>Implement threads for psq (but not for procps yet)<commit_after>extern crate procrs;
extern crate argparse;
#[macro_use]
extern crate prettytable;
use prettytable::Table;
use prettytable::row::Row;
use prettytable::format::FormatBuilder;
use std::collections::HashMap;
use std::iter::repeat;
use procrs::pid::*;
use procrs::TaskId;
use argparse::{ArgumentParser, StoreTrue, Store};

fn main() {
    let opts = parse_args();
    let (query, long, perf, verbose, tree, threads) =
        (opts.query, opts.long, opts.perf, opts.verbose, opts.tree, opts.threads);

    let pid_iter = PidIter::new_query(query);
    let mut pids = pid_iter.unwrap()
        .collect::<Result<Vec<_>, _>>().unwrap();

    let mut name_indent = HashMap::new();

    if verbose {
        for pid in pids {
            println!("{:?}", pid);
        }
        return
    }

    if opts.tree {
        pids = treeify_names(pids, &mut name_indent);
    } else {
        pids.sort_by(|p1, p2| p1.stat.pid.cmp(&p2.stat.pid));
    };
    // Assume hertz is 100.
    // TODO: Look this up via syscall (no /proc value for it)
    let hertz = 100;
    let minute_hertz = hertz * 60;
    let hour_hertz = minute_hertz * 60;

    let mut table = Table::init(
        pids.iter().map(|p| {
            // When we have a tree, the name is prepended with an indent.
            let mut name = match tree {
                false => String::new(),
                true => name_indent.remove(&p.stat.pid).unwrap()
            };

            // For long output, try using the cmdline first.
            // FIXME: Sometimes prog_name != cmdline[0].
            if !long {
                name.push_str(&p.stat.comm);
            } else {
                let cmdline = p.cmdline.join(" ");
                name.push_str(
                    match cmdline {
                         ref s if s.len() > 0 => s,
                        _ => &p.stat.comm
                    }
                );
            }

            let mut row = Vec::new();
            match threads {
                false => row.push(cell!(p.stat.pid)),
                true => {
                    row.push(cell!(p.status.tgid));
                    row.push(cell!(p.status.pid));
                }
            };
            row.push(cell!(p.stat.ppid));
            match (long, perf) {
                (_, false) => {
                    row.push(cell!(name));
                },
                (_, true) => {
                    let rss = p.status.vmrss.map(|m| (m / 1024).to_string()).unwrap_or("".to_owned());
                    let raw_time = p.stat.utime + p.stat.stime;
                    let second_utime = raw_time / hertz % 60;
                    let minute_utime = raw_time / minute_hertz % 60;
                    let hour_utime = raw_time / hour_hertz % 60;
                    let cputime = format!(
                        "{:02}:{:02}:{:02}",
                        hour_utime,
                        minute_utime,
                        second_utime
                    );
                    row.push(cell!(rss));
                    row.push(cell!(cputime));
                }
            }
            row.push(cell!(name));
            Row::new(row)
        }).collect::<Vec<_>>()
    );

    let mut titles = Vec::new();
    titles.push(cell!("Pid"));
    if threads {
        titles.push(cell!("Tid"));
    }
    // TODO: Possible remove Ppid from when long is false,
    // and have Cmd/Args as separate columns for long.
    match (long, perf) {
        (_, false) =>
            titles.extend_from_slice(&[cell!("Ppid"), cell!("Cmd")]),
        (_, true) =>
            titles.extend_from_slice(&[cell!("RSS"), cell!("Time"), cell!("Cmd")])
    };
    table.set_titles(Row::new(titles));
    table.set_format(
        FormatBuilder::new()
            .column_separator(' ')
            .build()
    );
    table.printstd();
}

// Given a vector of Pid structs, treeify their names, and return them in the right order.
// This is similar to ps -AH.
fn treeify_names(pids: Vec<Pid>, name_indents: &mut HashMap<TaskId, String>) -> Vec<Pid> {
    let mut child_pids = HashMap::new();
    for pid in pids {
        let ppid = pid.stat.ppid;
        child_pids.entry(ppid)
            .or_insert(Vec::new())
            .push(pid);
    }
    enumerate_children(0, &mut child_pids, name_indents, -1)
}

// Enumerate children pids, and return them.
fn enumerate_children(pid: TaskId, child_pids: &mut HashMap<TaskId, Vec<Pid>>,
    name_indents: &mut HashMap<TaskId, String>, indent: i32) -> Vec<Pid> {
    name_indents.insert(pid,
        match indent {
            i if i >= 0 =>
                repeat("  ").take(i as usize).collect::<String>(),
            _ => "".to_owned()
        }
    );
    let mut pids = Vec::new();
    let ppids = match child_pids.remove(&pid) {
        Some(v) => v,
        None => { return pids; }
    };
    for pid in ppids {
        let pid_num = pid.stat.pid;
        pids.push(pid);
        pids.append(
            &mut enumerate_children(pid_num, child_pids, name_indents, indent + 1)
        );
    }
    pids
}

struct ProgOpts {
    query: PidQuery,
    tree: bool,
    threads: bool,
    perf: bool,
    long: bool,
    verbose: bool
}

fn parse_args() -> ProgOpts {
    let mut opts = ProgOpts {
        query: PidQuery::NoneQuery,
        tree: false,
        threads: false,
        perf: false,
        long: false,
        verbose: false
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Query linux processes");
        ap.refer(&mut opts.threads)
            .add_option(&["-t", "--threads"], StoreTrue, "Display individual threads");
        ap.refer(&mut opts.tree)
            .add_option(&["-T", "--tree"], StoreTrue, "Display commands in tree hierarchy");
        ap.refer(&mut opts.perf)
            .add_option(&["-p", "--perf"], StoreTrue, "Display columns about performance");
        ap.refer(&mut opts.long)
            .add_option(&["-l", "--long"], StoreTrue, "Display columns with more information");
        ap.refer(&mut opts.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue, "Verbose output");
        ap.refer(&mut opts.query)
            .add_argument("query", Store, "Optional query to search by, pid or string");
        ap.parse_args_or_exit();
    }

    opts
}
<|endoftext|>