<commit_before>use std::sync::ONCE_INIT;
use conduit::{Handler, Method};

use cargo_registry::user::NewUser;
use cargo_registry::krate::EncodableCrate;
use record::GhUser;

// Users: `crates-tester-1` and `crates-tester-2`
// Passwords: ask acrichto or gankro
// Teams: `crates-test-org:core`, `crates-test-org:just-for-crates-2`
// tester-1 is on core only, tester-2 is on both

static GH_USER_1: GhUser = GhUser {
    login: "crates-tester-1",
    init: ONCE_INIT,
};
static GH_USER_2: GhUser = GhUser {
    login: "crates-tester-2",
    init: ONCE_INIT,
};

fn mock_user_on_only_x() -> NewUser<'static> {
    GH_USER_1.user()
}
fn mock_user_on_x_and_y() -> NewUser<'static> {
    GH_USER_2.user()
}

fn body_for_team_y() -> &'static str {
    r#"{"users":["github:crates-test-org:just-for-crates-2"]}"#
}

fn body_for_team_x() -> &'static str {
    r#"{"users":["github:crates-test-org:core"]}"#
}

// Test adding team without `github:`
#[test]
fn not_github() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_not_github");

    let body = r#"{"users":["dropbox:foo:foo"]}"#;
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_not_github/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0].detail.contains("unknown organization"),
        "{:?}",
        json.errors
    );
}

#[test]
fn weird_name() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_weird_name");

    let body = r#"{"users":["github:foo/../bar:wut"]}"#;
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_weird_name/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0]
            .detail
            .contains("organization cannot contain",),
        "{:?}",
        json.errors
    );
}

// Test adding team without second `:`
#[test]
fn one_colon() {
    let (_b, app, middle) = ::app();
    let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_one_colon");

    let body = r#"{"users":["github:foo"]}"#;
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_one_colon/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0].detail.contains("missing github team"),
        "{:?}",
        json.errors
    );
}

#[test]
fn nonexistent_team() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_nonexistent");

    let body = r#"{"users":["github:crates-test-org:this-does-not-exist"]}"#;
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_nonexistent/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0]
            .detail
            .contains("don't have permission to query a necessary property",),
        "{:?}",
        json.errors
    );
}

// Test adding team as owner when on it
#[test]
fn add_team_as_member() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_team_member");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_team_member/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
}

// Test adding team as owner when not on in
#[test]
fn add_team_as_non_member() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_only_x(), "foo_team_non_member");

    let body = body_for_team_y();
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_team_non_member/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0].detail.contains("don't have permission"),
        "{:?}",
        json.errors
    );
}

#[test]
fn remove_team_as_named_owner() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_remove_team");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_remove_team/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_remove_team/owners")
                .with_method(Method::Delete)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();
        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = ::new_req_body_version_2(::krate("foo_remove_team"));
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/new")
                .with_body(&body)
                .with_method(Method::Put),
        )
    );
    assert!(
        json.errors[0].detail.contains("another user"),
        "{:?}",
        json.errors
    );
}

#[test]
fn remove_team_as_team_owner() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_remove_team_owner");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_remove_team_owner/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();
        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = body_for_team_x();
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_remove_team_owner/owners")
                .with_method(Method::Delete)
                .with_body(body.as_bytes()),
        )
    );

    assert!(
        json.errors[0]
            .detail
            .contains("only owners have permission",),
        "{:?}",
        json.errors
    );

    let body = ::new_req_body_version_2(::krate("foo_remove_team_owner"));
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/new")
                .with_body(&body)
                .with_method(Method::Put),
        )
    );
}

// Test trying to publish a krate we don't own
#[test]
fn publish_not_owned() {
    let (_b, app, middle) = ::app();

    let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_not_owned");

    let body = body_for_team_y();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_not_owned/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();
        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = ::new_req_body_version_2(::krate("foo_not_owned"));
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/new")
                .with_body(&body)
                .with_method(Method::Put),
        )
    );
    assert!(
        json.errors[0].detail.contains("another user"),
        "{:?}",
        json.errors
    );
}

// Test trying to publish a krate we do own (but only because of teams)
#[test]
fn publish_owned() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_team_owned");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_team_owned/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();
        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = ::new_req_body_version_2(::krate("foo_team_owned"));
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/new")
                .with_body(&body)
                .with_method(Method::Put),
        )
    );
}

// Test trying to change owners (when only on an owning team)
#[test]
fn add_owners_as_team_owner() {
    let (_b, app, middle) = ::app();
    let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_add_owner");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_add_owner/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();
        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = r#"{"users":["FlashCat"]}"#; // User doesn't matter
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_add_owner/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0]
            .detail
            .contains("only owners have permission",),
        "{:?}",
        json.errors
    );
}

#[test]
fn crates_by_team_id() {
    let (_b, app, middle) = ::app();

    let team = {
        let conn = app.diesel_database.get().unwrap();
        let u = ::new_user("user_foo").create_or_update(&conn).unwrap();
        let t = ::new_team("team_foo").create_or_update(&conn).unwrap();
        let krate = ::CrateBuilder::new("foo", u.id).expect_build(&conn);
        ::add_team_to_crate(&t, &krate, &u, &conn).unwrap();
        t
    };

    let mut req = ::req(app, Method::Get, "/api/v1/crates");
    req.with_query(&format!("team_id={}", team.id));
    let mut response = ok_resp!(middle.call(&mut req));

    #[derive(Deserialize)]
    struct Response {
        crates: Vec<EncodableCrate>,
    }
    let response: Response = ::json(&mut response);
    assert_eq!(response.crates.len(), 1);
}

#[test]
fn crates_by_team_id_not_including_deleted_owners() {
    let (_b, app, middle) = ::app();

    let team = {
        let conn = app.diesel_database.get().unwrap();
        let u = ::new_user(GH_USER_2.login).create_or_update(&conn).unwrap();
        let t = ::new_team("github:crates-test-org:core")
            .create_or_update(&conn)
            .unwrap();
        let krate = ::CrateBuilder::new("foo", u.id).expect_build(&conn);
        ::add_team_to_crate(&t, &krate, &u, &conn).unwrap();
        krate.owner_remove(&app, &conn, &u, &t.login).unwrap();
        t
    };

    let mut req = ::req(app, Method::Get, "/api/v1/crates");
    req.with_query(&format!("team_id={}", team.id));
    let mut response = ok_resp!(middle.call(&mut req));

    #[derive(Deserialize)]
    struct Response {
        crates: Vec<EncodableCrate>,
    }
    let response: Response = ::json(&mut response);
    assert_eq!(response.crates.len(), 0);
}
<commit_msg>Make these tests fail if the github requests aren't actually succeeding<commit_after>use std::sync::ONCE_INIT;
use conduit::{Handler, Method};
use diesel::*;

use cargo_registry::user::NewUser;
use cargo_registry::krate::{Crate, EncodableCrate};
use record::GhUser;

// Users: `crates-tester-1` and `crates-tester-2`
// Passwords: ask acrichto or gankro
// Teams: `crates-test-org:core`, `crates-test-org:just-for-crates-2`
// tester-1 is on core only, tester-2 is on both

static GH_USER_1: GhUser = GhUser {
    login: "crates-tester-1",
    init: ONCE_INIT,
};
static GH_USER_2: GhUser = GhUser {
    login: "crates-tester-2",
    init: ONCE_INIT,
};

fn mock_user_on_only_x() -> NewUser<'static> {
    GH_USER_1.user()
}
fn mock_user_on_x_and_y() -> NewUser<'static> {
    GH_USER_2.user()
}

fn body_for_team_y() -> &'static str {
    r#"{"users":["github:crates-test-org:just-for-crates-2"]}"#
}

fn body_for_team_x() -> &'static str {
    r#"{"users":["github:crates-test-org:core"]}"#
}

// Test adding team without `github:`
#[test]
fn not_github() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_not_github");

    let body = r#"{"users":["dropbox:foo:foo"]}"#;
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_not_github/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0].detail.contains("unknown organization"),
        "{:?}",
        json.errors
    );
}

#[test]
fn weird_name() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_weird_name");

    let body = r#"{"users":["github:foo/../bar:wut"]}"#;
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_weird_name/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0]
            .detail
            .contains("organization cannot contain",),
        "{:?}",
        json.errors
    );
}

// Test adding team without second `:`
#[test]
fn one_colon() {
    let (_b, app, middle) = ::app();
    let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_one_colon");

    let body = r#"{"users":["github:foo"]}"#;
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_one_colon/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0].detail.contains("missing github team"),
        "{:?}",
        json.errors
    );
}

#[test]
fn nonexistent_team() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_nonexistent");

    let body = r#"{"users":["github:crates-test-org:this-does-not-exist"]}"#;
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_nonexistent/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0]
            .detail
            .contains("don't have permission to query a necessary property",),
        "{:?}",
        json.errors
    );
}

// Test adding team as owner when on it
#[test]
fn add_team_as_member() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_team_member");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_team_member/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();
        let krate = Crate::by_name("foo_team_member")
            .first::<Crate>(&*conn)
            .unwrap();
        assert_eq!(krate.owners(&*conn).unwrap().len(), 2);
    }
}

// Test adding team as owner when not on in
#[test]
fn add_team_as_non_member() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_only_x(), "foo_team_non_member");

    let body = body_for_team_y();
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_team_non_member/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0].detail.contains("don't have permission"),
        "{:?}",
        json.errors
    );
}

#[test]
fn remove_team_as_named_owner() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_remove_team");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_remove_team/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();
        let krate = Crate::by_name("foo_remove_team")
            .first::<Crate>(&*conn)
            .unwrap();
        assert_eq!(krate.owners(&*conn).unwrap().len(), 2);
    }

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_remove_team/owners")
                .with_method(Method::Delete)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();
        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = ::new_req_body_version_2(::krate("foo_remove_team"));
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/new")
                .with_body(&body)
                .with_method(Method::Put),
        )
    );
    assert!(
        json.errors[0].detail.contains("another user"),
        "{:?}",
        json.errors
    );
}

#[test]
fn remove_team_as_team_owner() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_remove_team_owner");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_remove_team_owner/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();

        let krate = Crate::by_name("foo_remove_team_owner")
            .first::<Crate>(&*conn)
            .unwrap();
        assert_eq!(krate.owners(&*conn).unwrap().len(), 2);

        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = body_for_team_x();
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_remove_team_owner/owners")
                .with_method(Method::Delete)
                .with_body(body.as_bytes()),
        )
    );

    assert!(
        json.errors[0]
            .detail
            .contains("only owners have permission",),
        "{:?}",
        json.errors
    );

    let body = ::new_req_body_version_2(::krate("foo_remove_team_owner"));
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/new")
                .with_body(&body)
                .with_method(Method::Put),
        )
    );
}

// Test trying to publish a krate we don't own
#[test]
fn publish_not_owned() {
    let (_b, app, middle) = ::app();

    let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_not_owned");

    let body = body_for_team_y();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_not_owned/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();

        let krate = Crate::by_name("foo_not_owned")
            .first::<Crate>(&*conn)
            .unwrap();
        assert_eq!(krate.owners(&*conn).unwrap().len(), 2);

        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = ::new_req_body_version_2(::krate("foo_not_owned"));
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/new")
                .with_body(&body)
                .with_method(Method::Put),
        )
    );
    assert!(
        json.errors[0].detail.contains("another user"),
        "{:?}",
        json.errors
    );
}

// Test trying to publish a krate we do own (but only because of teams)
#[test]
fn publish_owned() {
    let (_b, app, middle) = ::app();
    let mut req =
        ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_team_owned");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_team_owned/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();

        let krate = Crate::by_name("foo_team_owned")
            .first::<Crate>(&*conn)
            .unwrap();
        assert_eq!(krate.owners(&*conn).unwrap().len(), 2);

        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = ::new_req_body_version_2(::krate("foo_team_owned"));
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/new")
                .with_body(&body)
                .with_method(Method::Put),
        )
    );
}

// Test trying to change owners (when only on an owning team)
#[test]
fn add_owners_as_team_owner() {
    let (_b, app, middle) = ::app();
    let mut req = ::request_with_user_and_mock_crate(&app, mock_user_on_x_and_y(), "foo_add_owner");

    let body = body_for_team_x();
    ok_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_add_owner/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );

    {
        let conn = app.diesel_database.get().unwrap();

        let krate = Crate::by_name("foo_add_owner")
            .first::<Crate>(&*conn)
            .unwrap();
        assert_eq!(krate.owners(&*conn).unwrap().len(), 2);

        let user = mock_user_on_only_x().create_or_update(&conn).unwrap();
        ::sign_in_as(&mut req, &user);
    }
    let body = r#"{"users":["FlashCat"]}"#; // User doesn't matter
    let json = bad_resp!(
        middle.call(
            req.with_path("/api/v1/crates/foo_add_owner/owners")
                .with_method(Method::Put)
                .with_body(body.as_bytes()),
        )
    );
    assert!(
        json.errors[0]
            .detail
            .contains("only owners have permission",),
        "{:?}",
        json.errors
    );
}

#[test]
fn crates_by_team_id() {
    let (_b, app, middle) = ::app();

    let team = {
        let conn = app.diesel_database.get().unwrap();
        let u = ::new_user("user_foo").create_or_update(&conn).unwrap();
        let t = ::new_team("team_foo").create_or_update(&conn).unwrap();
        let krate = ::CrateBuilder::new("foo", u.id).expect_build(&conn);
        ::add_team_to_crate(&t, &krate, &u, &conn).unwrap();
        t
    };

    let mut req = ::req(app, Method::Get, "/api/v1/crates");
    req.with_query(&format!("team_id={}", team.id));
    let mut response = ok_resp!(middle.call(&mut req));

    #[derive(Deserialize)]
    struct Response {
        crates: Vec<EncodableCrate>,
    }
    let response: Response = ::json(&mut response);
    assert_eq!(response.crates.len(), 1);
}

#[test]
fn crates_by_team_id_not_including_deleted_owners() {
    let (_b, app, middle) = ::app();

    let team = {
        let conn = app.diesel_database.get().unwrap();
        let u = ::new_user(GH_USER_2.login).create_or_update(&conn).unwrap();
        let t = ::new_team("github:crates-test-org:core")
            .create_or_update(&conn)
            .unwrap();
        let krate = ::CrateBuilder::new("foo", u.id).expect_build(&conn);
        ::add_team_to_crate(&t, &krate, &u, &conn).unwrap();
        krate.owner_remove(&app, &conn, &u, &t.login).unwrap();
        t
    };

    let mut req = ::req(app, Method::Get, "/api/v1/crates");
    req.with_query(&format!("team_id={}", team.id));
    let mut response = ok_resp!(middle.call(&mut req));

    #[derive(Deserialize)]
    struct Response {
        crates: Vec<EncodableCrate>,
    }
    let response: Response = ::json(&mut response);
    assert_eq!(response.crates.len(), 0);
}
<|endoftext|>


<commit_before>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::atomic::{AtomicBool, Ordering::Relaxed},
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{
    debug_delay, warn, Acquire, AtomicUsize, Error, Lazy, OneShot, Result,
    SeqCst,
};

// This is lower for CI reasons.
#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const DESIRED_WAITING_THREADS: usize = 7;

static WAITING_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static SPAWNS: AtomicUsize = AtomicUsize::new(0);
static SPAWNING: AtomicBool = AtomicBool::new(false);

macro_rules! once {
    ($args:block) => {
        static E: AtomicBool = AtomicBool::new(false);
        if !E.compare_and_swap(false, true, Relaxed) {
            // only execute this once
            $args;
        }
    };
}

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            let res = self.cv.wait_until(&mut queue, cutoff);
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);
static BROKEN: AtomicBool = AtomicBool::new(false);

fn init_queue() -> Queue {
    debug_delay();
    for _ in 0..DESIRED_WAITING_THREADS {
        debug_delay();
        if let Err(e) = spawn_new_thread(true) {
            log::error!("failed to initialize threadpool: {:?}", e);
        }
    }
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work(is_immortal: bool) {
    let wait_limit = Duration::from_secs(1);

    let mut performed = 0;
    let mut contiguous_overshoots = 0;

    while is_immortal || performed < 5 || contiguous_overshoots < 3 {
        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        if let Some(task) = task_res {
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        while let Some(task) = QUEUE.try_recv() {
            debug_delay();
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        debug_delay();

        let waiting = WAITING_THREAD_COUNT.load(Acquire);

        if waiting > DESIRED_WAITING_THREADS {
            contiguous_overshoots += 1;
        } else {
            contiguous_overshoots = 0;
        }
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() -> Result<()> {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(Acquire);
    debug_delay();
    let waiting_threads = WAITING_THREAD_COUNT.load(Acquire);

    if waiting_threads >= DESIRED_WAITING_THREADS
        || total_workers >= MAX_THREADS
    {
        return Ok(());
    }

    if !SPAWNING.compare_and_swap(false, true, SeqCst) {
        spawn_new_thread(false)?;
    }

    Ok(())
}

fn spawn_new_thread(is_immortal: bool) -> Result<()> {
    if BROKEN.load(Relaxed) {
        return Err(Error::ReportableBug(
            "IO thread unexpectedly panicked. please report \
            this bug on the sled github repo."
                .to_string(),
        ));
    }

    let spawn_id = SPAWNS.fetch_add(1, SeqCst);

    TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
    let spawn_res = thread::Builder::new()
        .name(format!("sled-io-{}", spawn_id))
        .spawn(move || {
            SPAWNING.store(false, SeqCst);
            debug_delay();
            let res = std::panic::catch_unwind(|| perform_work(is_immortal));
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
            if is_immortal || res.is_err() {
                // IO thread panicked, shut down the system
                log::error!(
                    "IO thread unexpectedly terminated.
                    please report this error at the sled github repo. {:?}",
                    res
                );
                BROKEN.store(true, SeqCst);
            }
        });

    if let Err(e) = spawn_res {
        SPAWNING.store(false, SeqCst);
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}.",
                e,
            )
        });
    }

    Ok(())
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> Result<OneShot<R>>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static + Sized,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    let depth = QUEUE.send(Box::new(task));

    if depth > DESIRED_WAITING_THREADS {
        maybe_spawn_new_thread()?;
    }

    Ok(promise)
}
<commit_msg>use double-underscored variables in once! macro expansion<commit_after>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::atomic::{AtomicBool, Ordering::Relaxed},
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{
    debug_delay, warn, Acquire, AtomicUsize, Error, Lazy, OneShot, Result,
    SeqCst,
};

// This is lower for CI reasons.
#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const DESIRED_WAITING_THREADS: usize = 7;

static WAITING_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static SPAWNS: AtomicUsize = AtomicUsize::new(0);
static SPAWNING: AtomicBool = AtomicBool::new(false);

macro_rules! once {
    ($args:block) => {
        static __E: AtomicBool = AtomicBool::new(false);
        if !__E.compare_and_swap(false, true, Relaxed) {
            // only execute this once
            $args;
        }
    };
}

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            let res = self.cv.wait_until(&mut queue, cutoff);
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);
static BROKEN: AtomicBool = AtomicBool::new(false);

fn init_queue() -> Queue {
    debug_delay();
    for _ in 0..DESIRED_WAITING_THREADS {
        debug_delay();
        if let Err(e) = spawn_new_thread(true) {
            log::error!("failed to initialize threadpool: {:?}", e);
        }
    }
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work(is_immortal: bool) {
    let wait_limit = Duration::from_secs(1);

    let mut performed = 0;
    let mut contiguous_overshoots = 0;

    while is_immortal || performed < 5 || contiguous_overshoots < 3 {
        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        if let Some(task) = task_res {
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        while let Some(task) = QUEUE.try_recv() {
            debug_delay();
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        debug_delay();

        let waiting = WAITING_THREAD_COUNT.load(Acquire);

        if waiting > DESIRED_WAITING_THREADS {
            contiguous_overshoots += 1;
        } else {
            contiguous_overshoots = 0;
        }
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() -> Result<()> {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(Acquire);
    debug_delay();
    let waiting_threads = WAITING_THREAD_COUNT.load(Acquire);

    if waiting_threads >= DESIRED_WAITING_THREADS
        || total_workers >= MAX_THREADS
    {
        return Ok(());
    }

    if !SPAWNING.compare_and_swap(false, true, SeqCst) {
        spawn_new_thread(false)?;
    }

    Ok(())
}

fn spawn_new_thread(is_immortal: bool) -> Result<()> {
    if BROKEN.load(Relaxed) {
        return Err(Error::ReportableBug(
            "IO thread unexpectedly panicked. please report \
            this bug on the sled github repo."
                .to_string(),
        ));
    }

    let spawn_id = SPAWNS.fetch_add(1, SeqCst);

    TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
    let spawn_res = thread::Builder::new()
        .name(format!("sled-io-{}", spawn_id))
        .spawn(move || {
            SPAWNING.store(false, SeqCst);
            debug_delay();
            let res = std::panic::catch_unwind(|| perform_work(is_immortal));
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
            if is_immortal || res.is_err() {
                // IO thread panicked, shut down the system
                log::error!(
                    "IO thread unexpectedly terminated.
                    please report this error at the sled github repo. {:?}",
                    res
                );
                BROKEN.store(true, SeqCst);
            }
        });

    if let Err(e) = spawn_res {
        SPAWNING.store(false, SeqCst);
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}.",
                e,
            )
        });
    }

    Ok(())
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> Result<OneShot<R>>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static + Sized,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    let depth = QUEUE.send(Box::new(task));

    if depth > DESIRED_WAITING_THREADS {
        maybe_spawn_new_thread()?;
    }

    Ok(promise)
}
<|endoftext|>


<commit_before>use super::Value;
use mapping::Mapping;

// Implement a bunch of conversion to make it easier to create YAML values
// on the fly.

macro_rules! from_number {
    ($($ty:ident)*) => {
        $(
            impl From<$ty> for Value {
                fn from(n: $ty) -> Self {
                    Value::Number(n.into())
                }
            }
        )*
    };
}

from_number! {
    i8 i16 i32 i64 isize
    u8 u16 u32 u64 usize
    f32 f64
}

impl From<bool> for Value {
    /// Convert boolean to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let b = false;
    /// let x: Value = b.into();
    /// # }
    /// ```
    fn from(f: bool) -> Self {
        Value::Bool(f)
    }
}

impl From<String> for Value {
    /// Convert `String` to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let s: String = "lorem".to_string();
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: String) -> Self {
        Value::String(f)
    }
}

impl<'a> From<&'a str> for Value {
    /// Convert string slice to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let s: &str = "lorem";
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: &str) -> Self {
        Value::String(f.to_string())
    }
}

use std::borrow::Cow;

impl<'a> From<Cow<'a, str>> for Value {
    /// Convert copy-on-write string to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Borrowed("lorem");
    /// let x: Value = s.into();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Owned("lorem".to_string());
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: Cow<'a, str>) -> Self {
        Value::String(f.to_string())
    }
}

impl From<Mapping> for Value {
    /// Convert map (with string keys) to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::{Mapping, Value};
    ///
    /// let mut m = Mapping::new();
    /// m.insert("Lorem".into(), "ipsum".into());
    /// let x: Value = m.into();
    /// # }
    /// ```
    fn from(f: Mapping) -> Self {
        Value::Mapping(f)
    }
}

impl<T: Into<Value>> From<Vec<T>> for Value {
    /// Convert a `Vec` to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let v = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// # }
    /// ```
    fn from(f: Vec<T>) -> Self {
        Value::Sequence(f.into_iter().map(Into::into).collect())
    }
}

impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value {
    /// Convert a slice to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let v: &[&str] = &["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// # }
    /// ```
    fn from(f: &'a [T]) -> Self {
        Value::Sequence(f.iter().cloned().map(Into::into).collect())
    }
}

use std::iter::FromIterator;

impl<T: Into<Value>> FromIterator<T> for Value {
    /// Convert an iteratable type to a YAML sequence
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let v = std::iter::repeat(42).take(5);
    /// let x: Value = v.collect();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into_iter().collect();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use std::iter::FromIterator;
    /// use serde_yaml::Value;
    ///
    /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]);
    /// # }
    /// ```
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        let vec: Vec<Value> = iter.into_iter().map(|x| x.into()).collect();

        Value::Sequence(vec)
    }
}
<commit_msg>Resolve clippy redundant_closure lint<commit_after>use super::Value;
use mapping::Mapping;

// Implement a bunch of conversion to make it easier to create YAML values
// on the fly.

macro_rules! from_number {
    ($($ty:ident)*) => {
        $(
            impl From<$ty> for Value {
                fn from(n: $ty) -> Self {
                    Value::Number(n.into())
                }
            }
        )*
    };
}

from_number! {
    i8 i16 i32 i64 isize
    u8 u16 u32 u64 usize
    f32 f64
}

impl From<bool> for Value {
    /// Convert boolean to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let b = false;
    /// let x: Value = b.into();
    /// # }
    /// ```
    fn from(f: bool) -> Self {
        Value::Bool(f)
    }
}

impl From<String> for Value {
    /// Convert `String` to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let s: String = "lorem".to_string();
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: String) -> Self {
        Value::String(f)
    }
}

impl<'a> From<&'a str> for Value {
    /// Convert string slice to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let s: &str = "lorem";
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: &str) -> Self {
        Value::String(f.to_string())
    }
}

use std::borrow::Cow;

impl<'a> From<Cow<'a, str>> for Value {
    /// Convert copy-on-write string to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Borrowed("lorem");
    /// let x: Value = s.into();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    /// use std::borrow::Cow;
    ///
    /// let s: Cow<str> = Cow::Owned("lorem".to_string());
    /// let x: Value = s.into();
    /// # }
    /// ```
    fn from(f: Cow<'a, str>) -> Self {
        Value::String(f.to_string())
    }
}

impl From<Mapping> for Value {
    /// Convert map (with string keys) to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::{Mapping, Value};
    ///
    /// let mut m = Mapping::new();
    /// m.insert("Lorem".into(), "ipsum".into());
    /// let x: Value = m.into();
    /// # }
    /// ```
    fn from(f: Mapping) -> Self {
        Value::Mapping(f)
    }
}

impl<T: Into<Value>> From<Vec<T>> for Value {
    /// Convert a `Vec` to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let v = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// # }
    /// ```
    fn from(f: Vec<T>) -> Self {
        Value::Sequence(f.into_iter().map(Into::into).collect())
    }
}

impl<'a, T: Clone + Into<Value>> From<&'a [T]> for Value {
    /// Convert a slice to `Value`
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let v: &[&str] = &["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into();
    /// # }
    /// ```
    fn from(f: &'a [T]) -> Self {
        Value::Sequence(f.iter().cloned().map(Into::into).collect())
    }
}

use std::iter::FromIterator;

impl<T: Into<Value>> FromIterator<T> for Value {
    /// Convert an iteratable type to a YAML sequence
    ///
    /// # Examples
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let v = std::iter::repeat(42).take(5);
    /// let x: Value = v.collect();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use serde_yaml::Value;
    ///
    /// let v: Vec<_> = vec!["lorem", "ipsum", "dolor"];
    /// let x: Value = v.into_iter().collect();
    /// # }
    /// ```
    ///
    /// ```rust
    /// # extern crate serde_yaml;
    /// #
    /// # fn main() {
    /// use std::iter::FromIterator;
    /// use serde_yaml::Value;
    ///
    /// let x: Value = Value::from_iter(vec!["lorem", "ipsum", "dolor"]);
    /// # }
    /// ```
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        let vec = iter.into_iter().map(T::into).collect();

        Value::Sequence(vec)
    }
}
<|endoftext|>


<commit_before>use bullet::{BulletDrawable, bullets::Bullets};
use cgmath::{Angle, Deg, Point2};
use character::controls::CharacterInputState;
use critter::CritterData;
use data;
use game::constants::{ASPECT_RATIO, NORMAL_DEATH_SPRITE_OFFSET, SPRITE_OFFSET, VIEW_DISTANCE, ZOMBIE_SHEET_TOTAL_WIDTH, ZOMBIE_STILL_SPRITE_OFFSET};
use game::get_random_bool;
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{calc_hypotenuse, camera::CameraInputState, dimensions::{Dimensions, get_projection, get_view_matrix}, direction_movement, GameTime, get_orientation, orientation::{Orientation, Stance}, overlaps, texture::load_texture};
use shaders::{CharacterSheet, critter_pipeline, Position, Projection, VertexData};
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};
use terrain::path_finding::calc_next_movement;
use zombie::zombies::Zombies;

pub mod zombies;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Debug, Clone)]
pub struct ZombieDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  pub movement_direction: Point2<f32>,
  zombie_idx: usize,
  zombie_death_idx: usize,
  is_colliding: bool,
}

impl ZombieDrawable {
  pub fn new(position: Position) -> ZombieDrawable {
    let view = get_view_matrix(VIEW_DISTANCE);
    let projection = get_projection(view, ASPECT_RATIO);
    ZombieDrawable {
      projection,
      position,
      previous_position: Position::new([0.0, 0.0]),
      orientation: Orientation::Left,
      stance: Stance::Still,
      direction: Orientation::Left,
      movement_direction: Point2::new(0.0, 0.0),
      zombie_idx: 0,
      zombie_death_idx: 0,
      is_colliding: false,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, game_time: u64) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new([
        ci.x_movement - self.previous_position.position[0],
        ci.y_movement - self.previous_position.position[1]
      ]);

    self.previous_position = Position::new([ci.x_movement, ci.y_movement]);

    let x_y_distance_to_player = Point2::new(
      self.position.position[0] - offset_delta.position[0],
      self.position.position[1] - offset_delta.position[1]);

    let distance_to_player = calc_hypotenuse(x_y_distance_to_player.x.abs(), x_y_distance_to_player.y.abs());

    let mut movement_speed = 1.4;

    let is_alive = self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath;

    if is_alive {
      let zombie_pos = Position::new([ci.x_movement - self.position.position[0], ci.y_movement - self.position.position[1]]);

      let dir = calc_next_movement(zombie_pos, self.previous_position) as f32;
      self.direction = get_orientation(dir);

      if distance_to_player < 400.0 {
        self.movement_direction = direction_movement(dir);
        self.stance = Stance::Walking;
        movement_speed = 1.4;
      } else {
        self.movement_direction = self.idle_direction_movement(game_time);
        movement_speed = 1.0;
      }
    } else {
      self.movement_direction = Point2::new(0.0, 0.0);
    }

    self.position = Position::new([
      self.position.position[0] + offset_delta.position[0] + (self.movement_direction.x * movement_speed),
      self.position.position[1] + offset_delta.position[1] + (self.movement_direction.y * movement_speed)
    ]);
  }

  fn idle_direction_movement(&mut self, game_time: u64) -> Point2<f32> {
    if game_time % 5 == 0 {
      self.stance = Stance::Still;
      Point2::new(0.0, 0.0)
    } else if game_time % 2 == 0 {
      let angle = Deg(180.0);
      self.stance = Stance::Walking;
      self.direction = Orientation::Left;
      Point2::new(Angle::cos(angle), Angle::sin(angle))
    } else {
      let angle = Deg(0.0);
      self.stance = Stance::Walking;
      self.direction = Orientation::Right;
      Point2::new(Angle::cos(angle), Angle::sin(angle))
    }
  }

  fn check_bullet_hits(&mut self, bullets: &[BulletDrawable]) {
    bullets.iter().for_each(|bullet| {
      if overlaps(self.position, bullet.position, 15.0, 15.0) && self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
        self.stance =
          if get_random_bool() {
            Stance::NormalDeath
          } else {
            Stance::CriticalDeath
          };
      }
    });
  }

  pub fn update_alive_idx(&mut self, max_idx: usize) {
    if self.zombie_idx < max_idx {
      self.zombie_idx += 1;
    } else {
      self.zombie_idx = 0;
    }
  }

  pub fn update_death_idx(&mut self, max_idx: usize) {
    if self.zombie_death_idx < max_idx {
      self.zombie_death_idx += 1;
    }
  }
}

pub struct ZombieDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> ZombieDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> ZombieDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let zombie_bytes = include_bytes!("../../assets/zombie.png");

    let vertex_data: [VertexData; 4] = [
      VertexData::new([-25.0, -35.0], [0.0, 1.0]),
      VertexData::new([25.0, -35.0], [1.0, 1.0]),
      VertexData::new([25.0, 35.0], [1.0, 0.0]),
      VertexData::new([-25.0, 35.0], [0.0, 0.0]),
    ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data[..], &index_data[..]);

    let char_texture = load_texture(factory, zombie_bytes);
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              critter_pipeline::new())
      .unwrap();

    let pipeline_data = critter_pipeline::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_zombie();

    ZombieDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, drawable: &mut ZombieDrawable) -> CharacterSheet {
    let zombie_sprite = match drawable.stance {
      Stance::Still => {
        let sprite_idx = (drawable.direction as usize * 4 + drawable.zombie_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::Walking if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::NormalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 6 + drawable.zombie_death_idx + NORMAL_DEATH_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::CriticalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_death_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      _ => {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
    };

    let (y_div, row_idx) =
      if drawable.stance == Stance::NormalDeath || drawable.stance == Stance::CriticalDeath {
        (0.0, 2)
      } else {
        (1.0, 2)
      };

    let elements_x = ZOMBIE_SHEET_TOTAL_WIDTH / (zombie_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div,
      row_idx,
      index: zombie_sprite.1 as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut ZombieDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(&mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::prelude::System<'a> for PreDrawSystem {
  #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
  type SystemData = (WriteStorage<'a, Zombies>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, Bullets>,
                     Read<'a, Dimensions>,
                     Read<'a, GameTime>);

  fn run(&mut self, (mut zombies, camera_input, character_input, bullets, dim, gt): Self::SystemData) {
    use specs::join::Join;

    for (zs, camera, ci, bs) in (&mut zombies, &camera_input, &character_input, &bullets).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for z in &mut zs.zombies {
        z.update(&world_to_clip, ci, gt.0);
        z.check_bullet_hits(&bs.bullets);
      }
    }
  }
}
<commit_msg>Add random 8-direction movement for idle zombies<commit_after>use bullet::{BulletDrawable, bullets::Bullets};
use cgmath::{Angle, Deg, Point2};
use character::controls::CharacterInputState;
use critter::CritterData;
use data;
use game::{get_rand_from_range, get_random_bool};
use game::constants::{ASPECT_RATIO, NORMAL_DEATH_SPRITE_OFFSET, SPRITE_OFFSET, VIEW_DISTANCE, ZOMBIE_SHEET_TOTAL_WIDTH, ZOMBIE_STILL_SPRITE_OFFSET};
use gfx;
use gfx_app::{ColorFormat, DepthFormat};
use graphics::{calc_hypotenuse, camera::CameraInputState, dimensions::{Dimensions, get_projection, get_view_matrix}, direction_movement, GameTime, get_orientation, orientation::{Orientation, Stance}, overlaps, texture::load_texture};
use shaders::{CharacterSheet, critter_pipeline, Position, Projection, VertexData};
use specs;
use specs::prelude::{Read, ReadStorage, WriteStorage};
use terrain::path_finding::calc_next_movement;
use zombie::zombies::Zombies;

pub mod zombies;

const SHADER_VERT: &[u8] = include_bytes!("../shaders/character.v.glsl");
const SHADER_FRAG: &[u8] = include_bytes!("../shaders/character.f.glsl");

#[derive(Debug, Clone)]
pub struct ZombieDrawable {
  projection: Projection,
  pub position: Position,
  previous_position: Position,
  orientation: Orientation,
  pub stance: Stance,
  direction: Orientation,
  last_decision: u64,
  pub movement_direction: Point2<f32>,
  zombie_idx: usize,
  zombie_death_idx: usize,
  is_colliding: bool,
}

impl ZombieDrawable {
  pub fn new(position: Position) -> ZombieDrawable {
    let view = get_view_matrix(VIEW_DISTANCE);
    let projection = get_projection(view, ASPECT_RATIO);
    ZombieDrawable {
      projection,
      position,
      previous_position: Position::new([0.0, 0.0]),
      orientation: Orientation::Left,
      stance: Stance::Still,
      direction: Orientation::Left,
      last_decision: 0,
      movement_direction: Point2::new(0.0, 0.0),
      zombie_idx: 0,
      zombie_death_idx: 0,
      is_colliding: false,
    }
  }

  pub fn update(&mut self, world_to_clip: &Projection, ci: &CharacterInputState, game_time: u64) {
    self.projection = *world_to_clip;

    let offset_delta =
      Position::new([
        ci.x_movement - self.previous_position.position[0],
        ci.y_movement - self.previous_position.position[1]
      ]);

    self.previous_position = Position::new([ci.x_movement, ci.y_movement]);

    let x_y_distance_to_player = Point2::new(
      self.position.position[0] - offset_delta.position[0],
      self.position.position[1] - offset_delta.position[1]);

    let distance_to_player = calc_hypotenuse(x_y_distance_to_player.x.abs(), x_y_distance_to_player.y.abs());

    let mut movement_speed = 1.4;

    let is_alive = self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath;

    if is_alive {
      let zombie_pos = Position::new([ci.x_movement - self.position.position[0], ci.y_movement - self.position.position[1]]);

      if distance_to_player < 300.0 {
        let dir = calc_next_movement(zombie_pos, self.previous_position) as f32;
        self.direction = get_orientation(dir);
        self.movement_direction = direction_movement(dir);
        self.stance = Stance::Walking;
        movement_speed = 1.4;
      } else {
        self.movement_direction = self.idle_direction_movement(game_time);
        movement_speed = 1.0;
      }
    } else {
      self.movement_direction = Point2::new(0.0, 0.0);
    }

    self.position = Position::new([
      self.position.position[0] + offset_delta.position[0] + (self.movement_direction.x * movement_speed),
      self.position.position[1] + offset_delta.position[1] + (self.movement_direction.y * movement_speed)
    ]);
  }

  fn idle_direction_movement(&mut self, game_time: u64) -> Point2<f32> {
    if game_time % 5 == 0 {
      self.stance = Stance::Still;
      Point2::new(0.0, 0.0)
    } else if self.last_decision + 2 < game_time && game_time % 2 == 0 {
      self.stance = Stance::Walking;
      self.last_decision = game_time;
      let directions: [f32; 8] = [0.0, 45.0, 90.0, 135.0, 180.0, 225.0, 270.0, 315.0];
      let idx = get_rand_from_range(0, 7) as usize;
      let angle = directions[idx];
      self.direction = get_orientation(angle);
      Point2::new(Angle::cos(Deg(angle)), Angle::sin(Deg(angle)))
    } else {
      self.movement_direction
    }
  }

  fn check_bullet_hits(&mut self, bullets: &[BulletDrawable]) {
    bullets.iter().for_each(|bullet| {
      if overlaps(self.position, bullet.position, 15.0, 15.0) && self.stance != Stance::NormalDeath && self.stance != Stance::CriticalDeath {
        self.stance =
          if get_random_bool() {
            Stance::NormalDeath
          } else {
            Stance::CriticalDeath
          };
      }
    });
  }

  pub fn update_alive_idx(&mut self, max_idx: usize) {
    if self.zombie_idx < max_idx {
      self.zombie_idx += 1;
    } else {
      self.zombie_idx = 0;
    }
  }

  pub fn update_death_idx(&mut self, max_idx: usize) {
    if self.zombie_death_idx < max_idx {
      self.zombie_death_idx += 1;
    }
  }
}

pub struct ZombieDrawSystem<R: gfx::Resources> {
  bundle: gfx::pso::bundle::Bundle<R, critter_pipeline::Data<R>>,
  data: Vec<CritterData>,
}

impl<R: gfx::Resources> ZombieDrawSystem<R> {
  pub fn new<F>(factory: &mut F,
                rtv: gfx::handle::RenderTargetView<R, ColorFormat>,
                dsv: gfx::handle::DepthStencilView<R, DepthFormat>) -> ZombieDrawSystem<R>
                where F: gfx::Factory<R> {
    use gfx::traits::FactoryExt;

    let zombie_bytes = include_bytes!("../../assets/zombie.png");

    let vertex_data: [VertexData; 4] = [
      VertexData::new([-25.0, -35.0], [0.0, 1.0]),
      VertexData::new([25.0, -35.0], [1.0, 1.0]),
      VertexData::new([25.0, 35.0], [1.0, 0.0]),
      VertexData::new([-25.0, 35.0], [0.0, 0.0]),
    ];

    let index_data: [u16; 6] = [0, 1, 2, 2, 3, 0];

    let (vertex_buf, slice) = factory.create_vertex_buffer_with_slice(&vertex_data[..], &index_data[..]);

    let char_texture = load_texture(factory, zombie_bytes);
    let pso = factory
      .create_pipeline_simple(SHADER_VERT,
                              SHADER_FRAG,
                              critter_pipeline::new())
      .unwrap();

    let pipeline_data = critter_pipeline::Data {
      vbuf: vertex_buf,
      projection_cb: factory.create_constant_buffer(1),
      position_cb: factory.create_constant_buffer(1),
      character_sprite_cb: factory.create_constant_buffer(1),
      charactersheet: (char_texture, factory.create_sampler_linear()),
      out_color: rtv,
      out_depth: dsv,
    };

    let data = data::load_zombie();

    ZombieDrawSystem {
      bundle: gfx::Bundle::new(slice, pso, pipeline_data),
      data,
    }
  }

  fn get_next_sprite(&self, drawable: &mut ZombieDrawable) -> CharacterSheet {
    let zombie_sprite = match drawable.stance {
      Stance::Still => {
        let sprite_idx = (drawable.direction as usize * 4 + drawable.zombie_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::Walking if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::NormalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 6 + drawable.zombie_death_idx + NORMAL_DEATH_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      Stance::CriticalDeath if drawable.orientation != Orientation::Still => {
        let sprite_idx = (drawable.direction as usize * 8 + drawable.zombie_death_idx) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
      _ => {
        drawable.direction = drawable.orientation;
        let sprite_idx = (drawable.orientation as usize * 8 + drawable.zombie_idx + ZOMBIE_STILL_SPRITE_OFFSET) as usize;
        (&self.data[sprite_idx], sprite_idx)
      },
    };

    let (y_div, row_idx) =
      if drawable.stance == Stance::NormalDeath || drawable.stance == Stance::CriticalDeath {
        (0.0, 2)
      } else {
        (1.0, 2)
      };

    let elements_x = ZOMBIE_SHEET_TOTAL_WIDTH / (zombie_sprite.0.data[2] + SPRITE_OFFSET);
    CharacterSheet {
      x_div: elements_x,
      y_div,
      row_idx,
      index: zombie_sprite.1 as f32,
    }
  }

  pub fn draw<C>(&mut self,
                 mut drawable: &mut ZombieDrawable,
                 encoder: &mut gfx::Encoder<R, C>)
                 where C: gfx::CommandBuffer<R> {
    encoder.update_constant_buffer(&self.bundle.data.projection_cb, &drawable.projection);
    encoder.update_constant_buffer(&self.bundle.data.position_cb, &drawable.position);
    encoder.update_constant_buffer(&self.bundle.data.character_sprite_cb,
                                   &self.get_next_sprite(&mut drawable));
    self.bundle.encode(encoder);
  }
}

#[derive(Debug)]
pub struct PreDrawSystem;

impl PreDrawSystem {
  pub fn new() -> PreDrawSystem {
    PreDrawSystem {}
  }
}

impl<'a> specs::prelude::System<'a> for PreDrawSystem {
  #[cfg_attr(feature = "cargo-clippy", allow(type_complexity))]
  type SystemData = (WriteStorage<'a, Zombies>,
                     ReadStorage<'a, CameraInputState>,
                     ReadStorage<'a, CharacterInputState>,
                     ReadStorage<'a, Bullets>,
                     Read<'a, Dimensions>,
                     Read<'a, GameTime>);

  fn run(&mut self, (mut zombies, camera_input, character_input, bullets, dim, gt): Self::SystemData) {
    use specs::join::Join;

    for (zs, camera, ci, bs) in (&mut zombies, &camera_input, &character_input, &bullets).join() {
      let world_to_clip = dim.world_to_projection(camera);

      for z in &mut zs.zombies {
        z.update(&world_to_clip, ci, gt.0);
        z.check_bullet_hits(&bs.bullets);
      }
    }
  }
}
<|endoftext|>


<commit_before>extern crate combine;

use combine::parser::range::recognize;
use combine::parser::repeat::{skip_many, skip_many1};
use combine::parser::choice::optional;
use combine::parser::item::item;
use combine::parser::byte::digit;
use combine::Parser;

fn main() {
    let mut parser = recognize((
        skip_many1(digit()),
        optional((item(b'.'), skip_many(digit()))),
    )).and_then(|bs: &[u8]| {
        let s = unsafe { ::std::str::from_utf8_unchecked(bs) };
        s.parse::<f64>()
    });
    let result = parser.easy_parse(&b"123.45"[..]);
    assert_eq!(result, Ok((123.45, &b""[..])));
    println!("{:?}", result);
}
<commit_msg>Only use .parse in the number example so no_std works<commit_after>extern crate combine;

use combine::parser::range::recognize;
use combine::parser::repeat::{skip_many, skip_many1};
use combine::parser::choice::optional;
use combine::parser::item::item;
use combine::parser::byte::digit;
use combine::error::UnexpectedParse;
use combine::Parser;

fn main() {
    let mut parser = recognize((
        skip_many1(digit()),
        optional((item(b'.'), skip_many(digit()))),
    )).and_then(|bs: &[u8]| {
        let s = unsafe { ::std::str::from_utf8_unchecked(bs) };
        s.parse::<f64>().map_err(|_| UnexpectedParse::Unexpected)
    });
    let result = parser.parse(&b"123.45"[..]);
    assert_eq!(result, Ok((123.45, &b""[..])));
    println!("{:?}", result);
}
<|endoftext|>


<commit_before>use ipnetwork::IpNetwork;

use maxminddb::geoip2;

fn main() -> Result<(), String> {
    let mut args = std::env::args().skip(1);
    let reader = maxminddb::Reader::open_readfile(
        args.next()
            .ok_or("First argument must be the path to the IP database")?,
    )
    .unwrap();
    let cidr: String = args
        .next()
        .ok_or("Second argument must be the IP address and mask in CIDR notation")?
        .parse()
        .unwrap();
    let ip_net = if cidr.contains(":") {
        IpNetwork::V6(cidr.parse().unwrap())
    } else {
        IpNetwork::V4(cidr.parse().unwrap())
    };
    for r in reader.within(ip_net).map_err(|e| e.to_string())? {
        let i = r.map_err(|e| e.to_string())?;
        let (ip_net, info): (IpNetwork, geoip2::City) = (i.ip_net, i.info);
        println!("ip_net={}, info={:#?}", ip_net, info);
    }
    Ok(())
}
<commit_msg>within example<commit_after>use ipnetwork::IpNetwork;
use maxminddb::{Within, geoip2};

fn main() -> Result<(), String> {
    let mut args = std::env::args().skip(1);
    let reader = maxminddb::Reader::open_readfile(
        args.next()
            .ok_or("First argument must be the path to the IP database")?,
    )
    .unwrap();
    let cidr: String = args
        .next()
        .ok_or("Second argument must be the IP address and mask in CIDR notation, e.g. 0.0.0.0/0 or ::/0")?
        .parse()
        .unwrap();
    let ip_net = if cidr.contains(":") {
        IpNetwork::V6(cidr.parse().unwrap())
    } else {
        IpNetwork::V4(cidr.parse().unwrap())
    };

    let mut n = 0;
    let mut iter: Within<geoip2::City, _> = reader.within(ip_net).map_err(|e| e.to_string())?;
    while let Some(next) = iter.next() {
        let item = next.map_err(|e| e.to_string())?;
        let continent = item.info.continent.and_then(|c| c.code).unwrap_or("");
        let country = item.info.country.and_then(|c| c.iso_code).unwrap_or("");
        let city = match item.info.city.and_then(|c| c.names) {
            Some(names) => names.get("en").unwrap_or(&""),
            None => "",
        };
        if !city.is_empty() {
            println!("{} {}-{}-{}", item.ip_net, continent, country, city);
        } else if !country.is_empty() {
            println!("{} {}-{}", item.ip_net, continent, country);
        } else if !continent.is_empty() {
            println!("{} {}", item.ip_net, continent);
        }
        n += 1;
    }
    eprintln!("processed {} items", n);

    Ok(())
}
<|endoftext|>


<commit_before>use std::{self,
          env::VarError,
          ffi::{OsStr,
                OsString},
          str::FromStr};

/// Fetches the environment variable `key` from the current process, but only it is not empty.
///
/// This function augments the `std::env::var` function from the standard library, only by
/// returning a `VarError::NotPresent` if the environment variable is set, but the value is empty.
///
/// # Examples
///
/// ```
/// use habitat_core;
/// use std;
///
/// let key = "_I_AM_A_TEAPOT_COMMA_RIGHT_PEOPLE_QUESTION_MARK_";
/// std::env::set_var(key, "");
/// match habitat_core::env::var(key) {
///     Ok(val) => panic!("The environment variable {} is set but empty!", key),
///     Err(e) => {
///         println!("The environment variable {} is set, but empty. Not useful!",
///                  key)
///     }
/// }
/// ```
pub fn var<K: AsRef<OsStr>>(key: K) -> std::result::Result<String, VarError> {
    match std::env::var(key) {
        Ok(val) => {
            if val.is_empty() {
                Err(VarError::NotPresent)
            } else {
                Ok(val)
            }
        }
        Err(e) => Err(e),
    }
}

/// Fetches the environment variable `key` from the current process, but only it is not empty.
///
/// This function augments the `std::env::var_os` function from the standard library, only by
/// returning a `VarError::NotPresent` if the environment variable is set, but the value is empty.
///
/// # Examples
///
/// ```
/// use habitat_core;
/// use std;
///
/// let key = "_I_AM_A_TEAPOT_COMMA_RIGHT_PEOPLE_QUESTION_MARK_";
/// std::env::set_var(key, "");
/// match habitat_core::env::var_os(key) {
///     Some(val) => panic!("The environment variable {} is set but empty!", key),
///     None => {
///         println!("The environment variable {} is set, but empty. Not useful!",
///                  key)
///     }
/// }
/// ```
pub fn var_os<K: AsRef<OsStr>>(key: K) -> std::option::Option<OsString> {
    match std::env::var_os(key) {
        Some(val) => {
            if val.to_string_lossy().as_ref().is_empty() {
                None
            } else {
                Some(val)
            }
        }
        None => None,
    }
}

/// Declare a struct that implements the `Config` trait with a minimum of boilerplate.
/// This declares a simple newtype struct whose name comes from `$wrapping_type`,
/// which wraps the provided `$wrapped_type` and can be overridden by setting the
/// environment variable specified in `$env_var`.
///
/// Additionally, this macro provides a `From` (and implicitly `Into`) implementation
/// so the `$wrapping_type` can be ergonomically converted to `$wrapped_type`.
///
/// For example, if `$wrapping_type` were `Foo`, to access the overridden value and
/// pass it to a function `bar` which accepts `$wrapped_type`:
///
/// ```ignore
/// bar(Foo::configured_value().into());
/// ```
///
/// See `Config::configured_value`'s documentation for more.
///
/// In general this exists to make the work of other macros which implement wrappers for
/// specific wrapped types simpler since the remaining arguments which specify the
/// `FromStr` implementation will generally be the same for a given wrapped type.
#[macro_export]
macro_rules! env_config {
    (
        $wrapping_type:ident,
        $wrapped_type:ty,
        $env_var:ident,
        $default_value:expr,
        $from_str_err_type:ty,
        $from_str_input:ident,
        $from_str_return:expr
    ) => {
        use $crate::env::Config as _;

        struct $wrapping_type($wrapped_type);
        // A little trickery to avoid env var name collisions:
        // This enum can't ever be instantiated, but the compiler will give
        // an error if two invocations in a namespace give the same env_var.
        // It'd be nice to make this work globally, but I don't see a good way
        #[allow(non_camel_case_types, dead_code)]
        enum $env_var {}

        impl $crate::env::Config for $wrapping_type {
            const ENVVAR: &'static str = stringify!($env_var);
        }

        impl Default for $wrapping_type {
            fn default() -> Self { Self($default_value) }
        }

        impl std::str::FromStr for $wrapping_type {
            type Err = $from_str_err_type;

            fn from_str($from_str_input: &str) -> std::result::Result<Self, Self::Err> {
                $from_str_return
            }
        }

        impl std::convert::From<$wrapping_type> for $wrapped_type {
            fn from(x: $wrapping_type) -> $wrapped_type { x.0 }
        }
    };
}

/// Declare a struct `$wrapping_type` that stores a `std::time::Duration` and
/// implements the `Config` trait so that its value can be overridden by `$env_var_as_secs`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// habitat_core::env_config_duration!(PersistLoopPeriod,
///                                    HAB_PERSIST_LOOP_PERIOD_SECS,
///                                    Duration::from_secs(30));
/// ```
#[macro_export]
macro_rules! env_config_duration {
    ($wrapping_type:ident, $env_var_as_secs:ident, $default_value:expr) => {
        $crate::env_config!($wrapping_type,
                            std::time::Duration,
                            $env_var_as_secs,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self(std::time::Duration::from_secs(s.parse()?))));
    };
}

/// Declare a struct `$wrapping_type` that stores an integer of type `$type` and
/// implements the `Config` trait so that its value can be overridden by `$env_var`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// habitat_core::env_config_duration!(ThreadAliveThreshold,
///                                    HAB_THREAD_ALIVE_THRESHOLD_SECS,
///                                    Duration::from_secs(5 * 60));
/// ```
#[macro_export]
macro_rules! env_config_int {
    ($wrapping_type:ident, $type:ty, $env_var:ident, $default_value:expr) => {
        $crate::env_config!($wrapping_type,
                            $type,
                            $env_var,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self((s.parse()?))));
    };
}

/// Enable the creation of a value based on an environment variable
/// that can be supplied at runtime by the user.
pub trait Config: Default + FromStr {
    /// The environment variable that will be parsed to create an
    /// instance of `Self`.
    const ENVVAR: &'static str;

    /// Generate an instance of `Self` from the value of the
    /// environment variable `Self::ENVVAR`.
    ///
    /// If the environment variable is present and not empty, its
    /// value will be parsed as `Self`. If it cannot be parsed, or the
    /// environment variable is not present, the default value of the
    /// type will be given instead.
    fn configured_value() -> Self {
        match var(Self::ENVVAR) {
            Err(VarError::NotPresent) => Self::default(),
            Ok(val) => {
                match val.parse() {
                    Ok(parsed) => {
                        Self::log_parsable(&val);
                        parsed
                    }
                    Err(_) => {
                        Self::log_unparsable(&val);
                        Self::default()
                    }
                }
            }
            Err(VarError::NotUnicode(nu)) => {
                Self::log_unparsable(nu.to_string_lossy());
                Self::default()
            }
        }
    }

    /// Overridable function for logging when an environment variable
    /// value was found and was successfully parsed as a `Self`.
    ///
    /// By default, we log a message at the `warn` level.
    fn log_parsable(env_value: &str) {
        warn!("Found '{}' in environment; using value '{}'",
              Self::ENVVAR,
              env_value);
    }

    /// Overridable function for logging when an environment variable
    /// value was found and was _not_ successfully parsed as a `Self`.
    ///
    /// By default, we log a message at the `warn` level.
    fn log_unparsable<S>(env_value: S)
        where S: AsRef<str>
    {
        warn!("Found '{}' in environment, but value '{}' was unparsable; using default instead",
              Self::ENVVAR,
              env_value.as_ref());
    }
}
<commit_msg>Fix env_config_* macro doc tests<commit_after>use std::{self,
          env::VarError,
          ffi::{OsStr,
                OsString},
          str::FromStr};

/// Fetches the environment variable `key` from the current process, but only it is not empty.
///
/// This function augments the `std::env::var` function from the standard library, only by
/// returning a `VarError::NotPresent` if the environment variable is set, but the value is empty.
///
/// # Examples
///
/// ```
/// use habitat_core;
/// use std;
///
/// let key = "_I_AM_A_TEAPOT_COMMA_RIGHT_PEOPLE_QUESTION_MARK_";
/// std::env::set_var(key, "");
/// match habitat_core::env::var(key) {
///     Ok(val) => panic!("The environment variable {} is set but empty!", key),
///     Err(e) => {
///         println!("The environment variable {} is set, but empty. Not useful!",
///                  key)
///     }
/// }
/// ```
pub fn var<K: AsRef<OsStr>>(key: K) -> std::result::Result<String, VarError> {
    match std::env::var(key) {
        Ok(val) => {
            if val.is_empty() {
                Err(VarError::NotPresent)
            } else {
                Ok(val)
            }
        }
        Err(e) => Err(e),
    }
}

/// Fetches the environment variable `key` from the current process, but only it is not empty.
///
/// This function augments the `std::env::var_os` function from the standard library, only by
/// returning a `VarError::NotPresent` if the environment variable is set, but the value is empty.
///
/// # Examples
///
/// ```
/// use habitat_core;
/// use std;
///
/// let key = "_I_AM_A_TEAPOT_COMMA_RIGHT_PEOPLE_QUESTION_MARK_";
/// std::env::set_var(key, "");
/// match habitat_core::env::var_os(key) {
///     Some(val) => panic!("The environment variable {} is set but empty!", key),
///     None => {
///         println!("The environment variable {} is set, but empty. Not useful!",
///                  key)
///     }
/// }
/// ```
pub fn var_os<K: AsRef<OsStr>>(key: K) -> std::option::Option<OsString> {
    match std::env::var_os(key) {
        Some(val) => {
            if val.to_string_lossy().as_ref().is_empty() {
                None
            } else {
                Some(val)
            }
        }
        None => None,
    }
}

/// Declare a struct that implements the `Config` trait with a minimum of boilerplate.
/// This declares a simple newtype struct whose name comes from `$wrapping_type`,
/// which wraps the provided `$wrapped_type` and can be overridden by setting the
/// environment variable specified in `$env_var`.
///
/// Additionally, this macro provides a `From` (and implicitly `Into`) implementation
/// so the `$wrapping_type` can be ergonomically converted to `$wrapped_type`.
///
/// For example, if `$wrapping_type` were `Foo`, to access the overridden value and
/// pass it to a function `bar` which accepts `$wrapped_type`:
///
/// ```ignore
/// bar(Foo::configured_value().into());
/// ```
///
/// See `Config::configured_value`'s documentation for more.
///
/// In general this exists to make the work of other macros which implement wrappers for
/// specific wrapped types simpler since the remaining arguments which specify the
/// `FromStr` implementation will generally be the same for a given wrapped type.
#[macro_export]
macro_rules! env_config {
    (
        $wrapping_type:ident,
        $wrapped_type:ty,
        $env_var:ident,
        $default_value:expr,
        $from_str_err_type:ty,
        $from_str_input:ident,
        $from_str_return:expr
    ) => {
        use $crate::env::Config as _;

        struct $wrapping_type($wrapped_type);
        // A little trickery to avoid env var name collisions:
        // This enum can't ever be instantiated, but the compiler will give
        // an error if two invocations in a namespace give the same env_var.
        // It'd be nice to make this work globally, but I don't see a good way
        #[allow(non_camel_case_types, dead_code)]
        enum $env_var {}

        impl $crate::env::Config for $wrapping_type {
            const ENVVAR: &'static str = stringify!($env_var);
        }

        impl Default for $wrapping_type {
            fn default() -> Self { Self($default_value) }
        }

        impl std::str::FromStr for $wrapping_type {
            type Err = $from_str_err_type;

            fn from_str($from_str_input: &str) -> std::result::Result<Self, Self::Err> {
                $from_str_return
            }
        }

        impl std::convert::From<$wrapping_type> for $wrapped_type {
            fn from(x: $wrapping_type) -> $wrapped_type { x.0 }
        }
    };
}

/// Declare a struct `$wrapping_type` that stores a `std::time::Duration` and
/// implements the `Config` trait so that its value can be overridden by `$env_var_as_secs`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// use std::time::Duration;
/// habitat_core::env_config_duration!(PersistLoopPeriod,
///                                    HAB_PERSIST_LOOP_PERIOD_SECS,
///                                    Duration::from_secs(30));
/// ```
#[macro_export]
macro_rules! env_config_duration {
    ($wrapping_type:ident, $env_var_as_secs:ident, $default_value:expr) => {
        $crate::env_config!($wrapping_type,
                            std::time::Duration,
                            $env_var_as_secs,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self(std::time::Duration::from_secs(s.parse()?))));
    };
}

/// Declare a struct `$wrapping_type` that stores an integer of type `$type` and
/// implements the `Config` trait so that its value can be overridden by `$env_var`.
///
/// This is a thin wrapper around `env_config`. See its documentation for more details.
///
/// Example usage:
/// ```
/// use std::time::Duration;
/// habitat_core::env_config_duration!(ThreadAliveThreshold,
///                                    HAB_THREAD_ALIVE_THRESHOLD_SECS,
///                                    Duration::from_secs(5 * 60));
/// ```
#[macro_export]
macro_rules! env_config_int {
    ($wrapping_type:ident, $type:ty, $env_var:ident, $default_value:expr) => {
        $crate::env_config!($wrapping_type,
                            $type,
                            $env_var,
                            $default_value,
                            std::num::ParseIntError,
                            s,
                            Ok(Self((s.parse()?))));
    };
}

/// Enable the creation of a value based on an environment variable
/// that can be supplied at runtime by the user.
pub trait Config: Default + FromStr {
    /// The environment variable that will be parsed to create an
    /// instance of `Self`.
    const ENVVAR: &'static str;

    /// Generate an instance of `Self` from the value of the
    /// environment variable `Self::ENVVAR`.
    ///
    /// If the environment variable is present and not empty, its
    /// value will be parsed as `Self`. If it cannot be parsed, or the
    /// environment variable is not present, the default value of the
    /// type will be given instead.
    fn configured_value() -> Self {
        match var(Self::ENVVAR) {
            Err(VarError::NotPresent) => Self::default(),
            Ok(val) => {
                match val.parse() {
                    Ok(parsed) => {
                        Self::log_parsable(&val);
                        parsed
                    }
                    Err(_) => {
                        Self::log_unparsable(&val);
                        Self::default()
                    }
                }
            }
            Err(VarError::NotUnicode(nu)) => {
                Self::log_unparsable(nu.to_string_lossy());
                Self::default()
            }
        }
    }

    /// Overridable function for logging when an environment variable
    /// value was found and was successfully parsed as a `Self`.
    ///
    /// By default, we log a message at the `warn` level.
    fn log_parsable(env_value: &str) {
        warn!("Found '{}' in environment; using value '{}'",
              Self::ENVVAR,
              env_value);
    }

    /// Overridable function for logging when an environment variable
    /// value was found and was _not_ successfully parsed as a `Self`.
    ///
    /// By default, we log a message at the `warn` level.
    fn log_unparsable<S>(env_value: S)
        where S: AsRef<str>
    {
        warn!("Found '{}' in environment, but value '{}' was unparsable; using default instead",
              Self::ENVVAR,
              env_value.as_ref());
    }
}
<|endoftext|>


<commit_before>extern crate dbus;
use self::dbus::{Connection, Error, Message, MessageItem};

pub trait DBusInterface {
    fn call_method(&mut self, method: &str, conn: &Connection, m: &Message) -> Option<Message>;

    fn set_property(&mut self, prop: &str, value: MessageItem) -> Result<(), Error>;
    fn get_property(&self, prop: &str) -> Result<(), Error>;
}
<commit_msg>interface: add methods to support introspection<commit_after>extern crate dbus;
use self::dbus::{Connection, Error, Message, MessageItem};

pub enum DBusDirection {
    In,
    Out,
}

pub type DBusType = String;

pub struct DBusArgument {
    name: String,
    dbus_type: DBusType,

    direction: DBusDirection,
}

pub struct DBusMethod {
    name: String,
    args: Vec<DBusArgument>,
}

pub struct DBusSignal {
    name: String,
    args: Vec<DBusArgument>,
}

pub enum DBusAccess {
    Read,
    Write,
    ReadWrite,
}

pub struct DBusAnnotation {
    name: String,
    value: String,
}

pub struct DBusProperty {
    name: String,
    dbus_type: DBusType,
    access: DBusAccess,
    annotations: Vec<DBusAnnotation>,
}

pub trait DBusInterface {
    fn call_method(&mut self, method: &str, conn: &Connection, m: &Message) -> Option<Message>;

    fn set_property(&mut self, prop: &str, value: MessageItem) -> Result<(), Error>;
    fn get_property(&self, prop: &str) -> Result<(), Error>;

    fn methods(&self) -> &Vec<DBusMethod>;
    fn signals(&self) -> &Vec<DBusSignal>;
    fn properties(&self) -> &Vec<DBusProperty>;
}
<|endoftext|>


<commit_before>use std::ffi::{OsStr, OsString};
use std::io::prelude::*;
use std::{env, fs, path::Path, path::PathBuf, process};

/// Create temporary working directory with Cargo.toml manifest
pub fn clone_out_test(source: &str) -> (tempdir::TempDir, String) {
    let tmpdir =
        tempdir::TempDir::new("cargo-edit-test").expect("failed to construct temporary directory");
    fs::copy(source, tmpdir.path().join("Cargo.toml"))
        .unwrap_or_else(|err| panic!("could not copy test manifest: {}", err));
    let path = tmpdir
        .path()
        .join("Cargo.toml")
        .to_str()
        .unwrap()
        .to_string()
        .clone();

    (tmpdir, path)
}

/// Add directory
pub fn setup_alt_registry_config(path: &std::path::Path) {
    fs::create_dir(path.join(".cargo")).expect("failed to create .cargo directory");
    fs::copy(
        "tests/fixtures/alt-registry-cargo-config",
        path.join(".cargo").join("config"),
    )
    .unwrap_or_else(|err| panic!("could not copy test cargo config: {}", err));
}

/// Execute local cargo command, includes `--manifest-path`, expect command failed
pub fn execute_bad_command<S>(command: &[S], manifest: &str)
where
    S: AsRef<OsStr>,
{
    let subcommand_name = &command[0].as_ref();

    let call = process::Command::new(&get_command_path(subcommand_name))
        .args(command)
        .arg(format!("--manifest-path={}", manifest))
        .env("CARGO_IS_TEST", "1")
        .output()
        .unwrap();

    if call.status.success() {
        println!("Status code: {:?}", call.status);
        println!("STDOUT: {}", String::from_utf8_lossy(&call.stdout));
        println!("STDERR: {}", String::from_utf8_lossy(&call.stderr));
        panic!(
            "cargo-{} success to execute",
            subcommand_name.to_string_lossy()
        )
    }
}

/// Execute local cargo command, includes `--manifest-path`
pub fn execute_command<S>(command: &[S], manifest: &str)
where
    S: AsRef<OsStr>,
{
    let subcommand_name = &command[0].as_ref();

    let call = process::Command::new(&get_command_path(subcommand_name))
        .args(command)
        .arg(format!("--manifest-path={}", manifest))
        .env("CARGO_IS_TEST", "1")
        .output()
        .expect("call to test build failed");

    if !call.status.success() {
        println!("Status code: {:?}", call.status);
        println!("STDOUT: {}", String::from_utf8_lossy(&call.stdout));
        println!("STDERR: {}", String::from_utf8_lossy(&call.stderr));
        panic!(
            "cargo-{} failed to execute",
            subcommand_name.to_string_lossy()
        )
    }
}

/// Execute local cargo command in a given directory
pub fn execute_command_in_dir<S>(command: &[S], dir: &Path)
where
    S: AsRef<OsStr>,
{
    let subcommand_name = &command[0].as_ref();

    let call = process::Command::new(&get_command_path(subcommand_name))
        .args(command)
        .env("CARGO_IS_TEST", "1")
        .current_dir(dir)
        .output()
        .expect("call to test build failed");

    if !call.status.success() {
        println!("Status code: {:?}", call.status);
        println!("STDOUT: {}", String::from_utf8_lossy(&call.stdout));
        println!("STDERR: {}", String::from_utf8_lossy(&call.stderr));
        panic!(
            "cargo-{} failed to execute",
            subcommand_name.to_string_lossy()
        )
    }
}

/// Parse a manifest file as TOML
pub fn get_toml(manifest_path: &str) -> toml_edit::Document {
    let mut f = fs::File::open(manifest_path).unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    s.parse().expect("toml parse error")
}

pub fn get_command_path(s: impl AsRef<OsStr>) -> String {
    let target_dir: PathBuf = match env::var_os("CARGO_TARGET_DIR") {
        Some(dir) => dir.into(),
        None => env::current_dir()
            .expect("Failed to get current dir")
            .join("target"),
    };

    let mut binary_name = OsString::from("cargo-");
    binary_name.push(s.as_ref());

    target_dir
        .join("debug")
        .join(binary_name)
        .to_str()
        .unwrap()
        .to_string()
}
<commit_msg>Suppress warnings of unused fns in tests (#363)<commit_after>#![allow(unused)]
use std::ffi::{OsStr, OsString};
use std::io::prelude::*;
use std::{env, fs, path::Path, path::PathBuf, process};

/// Create temporary working directory with Cargo.toml manifest
pub fn clone_out_test(source: &str) -> (tempdir::TempDir, String) {
    let tmpdir =
        tempdir::TempDir::new("cargo-edit-test").expect("failed to construct temporary directory");
    fs::copy(source, tmpdir.path().join("Cargo.toml"))
        .unwrap_or_else(|err| panic!("could not copy test manifest: {}", err));
    let path = tmpdir
        .path()
        .join("Cargo.toml")
        .to_str()
        .unwrap()
        .to_string()
        .clone();

    (tmpdir, path)
}

/// Add directory
pub fn setup_alt_registry_config(path: &std::path::Path) {
    fs::create_dir(path.join(".cargo")).expect("failed to create .cargo directory");
    fs::copy(
        "tests/fixtures/alt-registry-cargo-config",
        path.join(".cargo").join("config"),
    )
    .unwrap_or_else(|err| panic!("could not copy test cargo config: {}", err));
}

/// Execute local cargo command, includes `--manifest-path`, expect command failed
pub fn execute_bad_command<S>(command: &[S], manifest: &str)
where
    S: AsRef<OsStr>,
{
    let subcommand_name = &command[0].as_ref();

    let call = process::Command::new(&get_command_path(subcommand_name))
        .args(command)
        .arg(format!("--manifest-path={}", manifest))
        .env("CARGO_IS_TEST", "1")
        .output()
        .unwrap();

    if call.status.success() {
        println!("Status code: {:?}", call.status);
        println!("STDOUT: {}", String::from_utf8_lossy(&call.stdout));
        println!("STDERR: {}", String::from_utf8_lossy(&call.stderr));
        panic!(
            "cargo-{} success to execute",
            subcommand_name.to_string_lossy()
        )
    }
}

/// Execute local cargo command, includes `--manifest-path`
pub fn execute_command<S>(command: &[S], manifest: &str)
where
    S: AsRef<OsStr>,
{
    let subcommand_name = &command[0].as_ref();

    let call = process::Command::new(&get_command_path(subcommand_name))
        .args(command)
        .arg(format!("--manifest-path={}", manifest))
        .env("CARGO_IS_TEST", "1")
        .output()
        .expect("call to test build failed");

    if !call.status.success() {
        println!("Status code: {:?}", call.status);
        println!("STDOUT: {}", String::from_utf8_lossy(&call.stdout));
        println!("STDERR: {}", String::from_utf8_lossy(&call.stderr));
        panic!(
            "cargo-{} failed to execute",
            subcommand_name.to_string_lossy()
        )
    }
}

/// Execute local cargo command in a given directory
pub fn execute_command_in_dir<S>(command: &[S], dir: &Path)
where
    S: AsRef<OsStr>,
{
    let subcommand_name = &command[0].as_ref();

    let call = process::Command::new(&get_command_path(subcommand_name))
        .args(command)
        .env("CARGO_IS_TEST", "1")
        .current_dir(dir)
        .output()
        .expect("call to test build failed");

    if !call.status.success() {
        println!("Status code: {:?}", call.status);
        println!("STDOUT: {}", String::from_utf8_lossy(&call.stdout));
        println!("STDERR: {}", String::from_utf8_lossy(&call.stderr));
        panic!(
            "cargo-{} failed to execute",
            subcommand_name.to_string_lossy()
        )
    }
}

/// Parse a manifest file as TOML
pub fn get_toml(manifest_path: &str) -> toml_edit::Document {
    let mut f = fs::File::open(manifest_path).unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s).unwrap();
    s.parse().expect("toml parse error")
}

pub fn get_command_path(s: impl AsRef<OsStr>) -> String {
    let target_dir: PathBuf = match env::var_os("CARGO_TARGET_DIR") {
        Some(dir) => dir.into(),
        None => env::current_dir()
            .expect("Failed to get current dir")
            .join("target"),
    };

    let mut binary_name = OsString::from("cargo-");
    binary_name.push(s.as_ref());

    target_dir
        .join("debug")
        .join(binary_name)
        .to_str()
        .unwrap()
        .to_string()
}
<|endoftext|>