<commit_before>extern crate cargotest;
extern crate hamcrest;

use hamcrest::assert_that;
use cargotest::support::registry::Package;
use cargotest::support::{project, execs, basic_bin_manifest, basic_lib_manifest, main_file};

#[test]
fn cargo_metadata_simple() {
    let p = project("foo")
            .file("Cargo.toml", &basic_bin_manifest("foo"));

    assert_that(p.cargo_process("metadata"), execs().with_json(r#"
    {
        "packages": [
            {
                "name": "foo",
                "version": "0.5.0",
                "id": "foo[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [
                            "bin"
                        ],
                        "name": "foo",
                        "src_path": "[..][/]foo[/]src[/]foo.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]Cargo.toml"
            }
        ],
        "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
        "resolve": {
            "nodes": [
                {
                    "dependencies": [],
                    "id": "foo 0.5.0 (path+file:[..]foo)"
                }
            ],
            "root": "foo 0.5.0 (path+file:[..]foo)"
        },
        "version": 1
    }"#));
}

#[test]
fn cargo_metadata_with_deps_and_version() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [project]
            name = "foo"
            version = "0.5.0"
            authors = []
            license = "MIT"
            description = "foo"

            [[bin]]
            name = "foo"

            [dependencies]
            bar = "*"
        "#);
    Package::new("baz", "0.0.1").publish();
    Package::new("bar", "0.0.1").dep("baz", "0.0.1").publish();

    assert_that(p.cargo_process("metadata")
                 .arg("-q")
                 .arg("--format-version").arg("1"),
                execs().with_json(r#"
    {
        "packages": [
            {
                "dependencies": [],
                "features": {},
                "id": "baz 0.0.1 (registry+[..])",
                "manifest_path": "[..]Cargo.toml",
                "name": "baz",
                "source": "registry+[..]",
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [
                            "lib"
                        ],
                        "name": "baz",
                        "src_path": "[..]lib.rs"
                    }
                ],
                "version": "0.0.1"
            },
            {
                "dependencies": [
                    {
                        "features": [],
                        "kind": null,
                        "name": "baz",
                        "optional": false,
                        "req": "^0.0.1",
                        "source": "registry+[..]",
                        "target": null,
                        "uses_default_features": true
                    }
                ],
                "features": {},
                "id": "bar 0.0.1 (registry+[..])",
                "manifest_path": "[..]Cargo.toml",
                "name": "bar",
                "source": "registry+[..]",
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [
                            "lib"
                        ],
                        "name": "bar",
                        "src_path": "[..]lib.rs"
                    }
                ],
                "version": "0.0.1"
            },
            {
                "dependencies": [
                    {
                        "features": [],
                        "kind": null,
                        "name": "bar",
                        "optional": false,
                        "req": "*",
                        "source": "registry+[..]",
                        "target": null,
                        "uses_default_features": true
                    }
                ],
                "features": {},
                "id": "foo 0.5.0 (path+file:[..]foo)",
                "manifest_path": "[..]Cargo.toml",
                "name": "foo",
                "source": null,
                "license": "MIT",
                "license_file": null,
                "targets": [
                    {
                        "kind": [
                            "bin"
                        ],
                        "name": "foo",
                        "src_path": "[..]foo.rs"
                    }
                ],
                "version": "0.5.0"
            }
        ],
        "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
        "resolve": {
            "nodes": [
                {
                    "dependencies": [
                        "bar 0.0.1 (registry+[..])"
                    ],
                    "id": "foo 0.5.0 (path+file:[..]foo)"
                },
                {
                    "dependencies": [
                        "baz 0.0.1 (registry+[..])"
                    ],
                    "id": "bar 0.0.1 (registry+[..])"
                },
                {
                    "dependencies": [],
                    "id": "baz 0.0.1 (registry+[..])"
                }
            ],
            "root": "foo 0.5.0 (path+file:[..]foo)"
        },
        "version": 1
    }"#));
}

#[test]
fn workspace_metadata() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [workspace]
            members = ["bar", "baz"]
        "#)
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file("baz/Cargo.toml", &basic_lib_manifest("baz"))
        .file("baz/src/lib.rs", "");
    p.build();

    assert_that(p.cargo_process("metadata"), execs().with_status(0).with_json(r#"
    {
        "packages": [
            {
                "name": "bar",
                "version": "0.5.0",
                "id": "bar[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [ "lib" ],
                        "name": "bar",
                        "src_path": "[..]bar[/]src[/]lib.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]bar[/]Cargo.toml"
            },
            {
                "name": "baz",
                "version": "0.5.0",
                "id": "baz[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [ "lib" ],
                        "name": "baz",
                        "src_path": "[..]baz[/]src[/]lib.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]baz[/]Cargo.toml"
            }
        ],
        "workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
        "resolve": {
            "nodes": [
                {
                    "dependencies": [],
                    "id": "baz 0.5.0 (path+file:[..]baz)"
                },
                {
                    "dependencies": [],
                    "id": "bar 0.5.0 (path+file:[..]bar)"
                }
            ],
            "root": null
        },
        "version": 1
    }"#))
}

#[test]
fn workspace_metadata_no_deps() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [workspace]
            members = ["bar", "baz"]
        "#)
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file("baz/Cargo.toml", &basic_lib_manifest("baz"))
        .file("baz/src/lib.rs", "");
    p.build();

    assert_that(p.cargo_process("metadata").arg("--no-deps"), execs().with_status(0).with_json(r#"
    {
        "packages": [
            {
                "name": "bar",
                "version": "0.5.0",
                "id": "bar[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [ "lib" ],
                        "name": "bar",
                        "src_path": "[..]bar[/]src[/]lib.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]bar[/]Cargo.toml"
            },
            {
                "name": "baz",
                "version": "0.5.0",
                "id": "baz[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [ "lib" ],
                        "name": "baz",
                        "src_path": "[..]baz[/]src[/]lib.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]baz[/]Cargo.toml"
            }
        ],
        "workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
        "resolve": null,
        "version": 1
    }"#))
}

#[test]
fn cargo_metadata_with_invalid_manifest() {
    let p = project("foo")
            .file("Cargo.toml", "");

    assert_that(p.cargo_process("metadata"), execs().with_status(101)
                                                    .with_stderr("\
[ERROR] failed to parse manifest at `[..]`

Caused by:
  no `package` or `project` section found."))
}

const MANIFEST_OUTPUT: &'static str=
    r#"
{
    "packages": [{
        "name":"foo",
        "version":"0.5.0",
        "id":"foo[..]0.5.0[..](path+file://[..]/foo)",
        "source":null,
        "dependencies":[],
        "license": null,
        "license_file": null,
        "targets":[{
            "kind":["bin"],
            "name":"foo",
            "src_path":"[..][/]foo[/]src[/]foo.rs"
        }],
        "features":{},
        "manifest_path":"[..]Cargo.toml"
    }],
    "workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ],
    "resolve": null,
    "version": 1
}"#;

#[test]
fn cargo_metadata_no_deps_path_to_cargo_toml_relative() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

        assert_that(p.cargo_process("metadata").arg("--no-deps")
                     .arg("--manifest-path").arg("foo/Cargo.toml")
                     .cwd(p.root().parent().unwrap()),
                    execs().with_status(0)
                           .with_json(MANIFEST_OUTPUT));
}

#[test]
fn cargo_metadata_no_deps_path_to_cargo_toml_absolute() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .arg("--manifest-path").arg(p.root().join("Cargo.toml"))
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}

#[test]
fn cargo_metadata_no_deps_path_to_cargo_toml_parent_relative() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .arg("--manifest-path").arg("foo")
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(101)
                       .with_stderr("[ERROR] the manifest-path must be \
                                             a path to a Cargo.toml file"));
}

#[test]
fn cargo_metadata_no_deps_path_to_cargo_toml_parent_absolute() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .arg("--manifest-path").arg(p.root())
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(101)
                       .with_stderr("[ERROR] the manifest-path must be \
                                             a path to a Cargo.toml file"));
}

#[test]
fn cargo_metadata_no_deps_cwd() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .cwd(p.root()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}

#[test]
fn carg_metadata_bad_version() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .arg("--format-version").arg("2")
                 .cwd(p.root()),
                execs().with_status(101)
    .with_stderr("[ERROR] metadata version 2 not supported, only 1 is currently supported"));
}

#[test]
fn multiple_features() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.1.0"
            authors = []

            [features]
            a = []
            b = []
        "#)
        .file("src/lib.rs", "");

    assert_that(p.cargo_process("metadata")
                 .arg("--features").arg("a b"),
                execs().with_status(0));
}
<commit_msg>Fix metadata tests<commit_after>extern crate cargotest;
extern crate hamcrest;

use hamcrest::assert_that;
use cargotest::support::registry::Package;
use cargotest::support::{project, execs, basic_bin_manifest, basic_lib_manifest, main_file};

#[test]
fn cargo_metadata_simple() {
    let p = project("foo")
            .file("src/foo.rs", "")
            .file("Cargo.toml", &basic_bin_manifest("foo"));

    assert_that(p.cargo_process("metadata"), execs().with_json(r#"
    {
        "packages": [
            {
                "name": "foo",
                "version": "0.5.0",
                "id": "foo[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [
                            "bin"
                        ],
                        "name": "foo",
                        "src_path": "[..][/]foo[/]src[/]foo.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]Cargo.toml"
            }
        ],
        "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
        "resolve": {
            "nodes": [
                {
                    "dependencies": [],
                    "id": "foo 0.5.0 (path+file:[..]foo)"
                }
            ],
            "root": "foo 0.5.0 (path+file:[..]foo)"
        },
        "version": 1
    }"#));
}

#[test]
fn cargo_metadata_with_deps_and_version() {
    let p = project("foo")
        .file("src/foo.rs", "")
        .file("Cargo.toml", r#"
            [project]
            name = "foo"
            version = "0.5.0"
            authors = []
            license = "MIT"
            description = "foo"

            [[bin]]
            name = "foo"

            [dependencies]
            bar = "*"
        "#);
    Package::new("baz", "0.0.1").publish();
    Package::new("bar", "0.0.1").dep("baz", "0.0.1").publish();

    assert_that(p.cargo_process("metadata")
                 .arg("-q")
                 .arg("--format-version").arg("1"),
                execs().with_json(r#"
    {
        "packages": [
            {
                "dependencies": [],
                "features": {},
                "id": "baz 0.0.1 (registry+[..])",
                "manifest_path": "[..]Cargo.toml",
                "name": "baz",
                "source": "registry+[..]",
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [
                            "lib"
                        ],
                        "name": "baz",
                        "src_path": "[..]lib.rs"
                    }
                ],
                "version": "0.0.1"
            },
            {
                "dependencies": [
                    {
                        "features": [],
                        "kind": null,
                        "name": "baz",
                        "optional": false,
                        "req": "^0.0.1",
                        "source": "registry+[..]",
                        "target": null,
                        "uses_default_features": true
                    }
                ],
                "features": {},
                "id": "bar 0.0.1 (registry+[..])",
                "manifest_path": "[..]Cargo.toml",
                "name": "bar",
                "source": "registry+[..]",
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [
                            "lib"
                        ],
                        "name": "bar",
                        "src_path": "[..]lib.rs"
                    }
                ],
                "version": "0.0.1"
            },
            {
                "dependencies": [
                    {
                        "features": [],
                        "kind": null,
                        "name": "bar",
                        "optional": false,
                        "req": "*",
                        "source": "registry+[..]",
                        "target": null,
                        "uses_default_features": true
                    }
                ],
                "features": {},
                "id": "foo 0.5.0 (path+file:[..]foo)",
                "manifest_path": "[..]Cargo.toml",
                "name": "foo",
                "source": null,
                "license": "MIT",
                "license_file": null,
                "targets": [
                    {
                        "kind": [
                            "bin"
                        ],
                        "name": "foo",
                        "src_path": "[..]foo.rs"
                    }
                ],
                "version": "0.5.0"
            }
        ],
        "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"],
        "resolve": {
            "nodes": [
                {
                    "dependencies": [
                        "bar 0.0.1 (registry+[..])"
                    ],
                    "id": "foo 0.5.0 (path+file:[..]foo)"
                },
                {
                    "dependencies": [
                        "baz 0.0.1 (registry+[..])"
                    ],
                    "id": "bar 0.0.1 (registry+[..])"
                },
                {
                    "dependencies": [],
                    "id": "baz 0.0.1 (registry+[..])"
                }
            ],
            "root": "foo 0.5.0 (path+file:[..]foo)"
        },
        "version": 1
    }"#));
}

#[test]
fn workspace_metadata() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [workspace]
            members = ["bar", "baz"]
        "#)
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file("baz/Cargo.toml", &basic_lib_manifest("baz"))
        .file("baz/src/lib.rs", "");
    p.build();

    assert_that(p.cargo_process("metadata"), execs().with_status(0).with_json(r#"
    {
        "packages": [
            {
                "name": "bar",
                "version": "0.5.0",
                "id": "bar[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [ "lib" ],
                        "name": "bar",
                        "src_path": "[..]bar[/]src[/]lib.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]bar[/]Cargo.toml"
            },
            {
                "name": "baz",
                "version": "0.5.0",
                "id": "baz[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [ "lib" ],
                        "name": "baz",
                        "src_path": "[..]baz[/]src[/]lib.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]baz[/]Cargo.toml"
            }
        ],
        "workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
        "resolve": {
            "nodes": [
                {
                    "dependencies": [],
                    "id": "baz 0.5.0 (path+file:[..]baz)"
                },
                {
                    "dependencies": [],
                    "id": "bar 0.5.0 (path+file:[..]bar)"
                }
            ],
            "root": null
        },
        "version": 1
    }"#))
}

#[test]
fn workspace_metadata_no_deps() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [workspace]
            members = ["bar", "baz"]
        "#)
        .file("bar/Cargo.toml", &basic_lib_manifest("bar"))
        .file("bar/src/lib.rs", "")
        .file("baz/Cargo.toml", &basic_lib_manifest("baz"))
        .file("baz/src/lib.rs", "");
    p.build();

    assert_that(p.cargo_process("metadata").arg("--no-deps"), execs().with_status(0).with_json(r#"
    {
        "packages": [
            {
                "name": "bar",
                "version": "0.5.0",
                "id": "bar[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [ "lib" ],
                        "name": "bar",
                        "src_path": "[..]bar[/]src[/]lib.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]bar[/]Cargo.toml"
            },
            {
                "name": "baz",
                "version": "0.5.0",
                "id": "baz[..]",
                "source": null,
                "dependencies": [],
                "license": null,
                "license_file": null,
                "targets": [
                    {
                        "kind": [ "lib" ],
                        "name": "baz",
                        "src_path": "[..]baz[/]src[/]lib.rs"
                    }
                ],
                "features": {},
                "manifest_path": "[..]baz[/]Cargo.toml"
            }
        ],
        "workspace_members": ["baz 0.5.0 (path+file:[..]baz)", "bar 0.5.0 (path+file:[..]bar)"],
        "resolve": null,
        "version": 1
    }"#))
}

#[test]
fn cargo_metadata_with_invalid_manifest() {
    let p = project("foo")
            .file("Cargo.toml", "");

    assert_that(p.cargo_process("metadata"), execs().with_status(101)
                                                    .with_stderr("\
[ERROR] failed to parse manifest at `[..]`

Caused by:
  no `package` or `project` section found."))
}

const MANIFEST_OUTPUT: &'static str=
    r#"
{
    "packages": [{
        "name":"foo",
        "version":"0.5.0",
        "id":"foo[..]0.5.0[..](path+file://[..]/foo)",
        "source":null,
        "dependencies":[],
        "license": null,
        "license_file": null,
        "targets":[{
            "kind":["bin"],
            "name":"foo",
            "src_path":"[..][/]foo[/]src[/]foo.rs"
        }],
        "features":{},
        "manifest_path":"[..]Cargo.toml"
    }],
    "workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ],
    "resolve": null,
    "version": 1
}"#;

#[test]
fn cargo_metadata_no_deps_path_to_cargo_toml_relative() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

        assert_that(p.cargo_process("metadata").arg("--no-deps")
                     .arg("--manifest-path").arg("foo/Cargo.toml")
                     .cwd(p.root().parent().unwrap()),
                    execs().with_status(0)
                           .with_json(MANIFEST_OUTPUT));
}

#[test]
fn cargo_metadata_no_deps_path_to_cargo_toml_absolute() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .arg("--manifest-path").arg(p.root().join("Cargo.toml"))
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}

#[test]
fn cargo_metadata_no_deps_path_to_cargo_toml_parent_relative() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .arg("--manifest-path").arg("foo")
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(101)
                       .with_stderr("[ERROR] the manifest-path must be \
                                             a path to a Cargo.toml file"));
}

#[test]
fn cargo_metadata_no_deps_path_to_cargo_toml_parent_absolute() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .arg("--manifest-path").arg(p.root())
                 .cwd(p.root().parent().unwrap()),
                execs().with_status(101)
                       .with_stderr("[ERROR] the manifest-path must be \
                                             a path to a Cargo.toml file"));
}

#[test]
fn cargo_metadata_no_deps_cwd() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .cwd(p.root()),
                execs().with_status(0)
                       .with_json(MANIFEST_OUTPUT));
}

#[test]
fn carg_metadata_bad_version() {
    let p = project("foo")
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]));

    assert_that(p.cargo_process("metadata").arg("--no-deps")
                 .arg("--format-version").arg("2")
                 .cwd(p.root()),
                execs().with_status(101)
    .with_stderr("[ERROR] metadata version 2 not supported, only 1 is currently supported"));
}

#[test]
fn multiple_features() {
    let p = project("foo")
        .file("Cargo.toml", r#"
            [package]
            name = "foo"
            version = "0.1.0"
            authors = []

            [features]
            a = []
            b = []
        "#)
        .file("src/lib.rs", "");

    assert_that(p.cargo_process("metadata")
                 .arg("--features").arg("a b"),
                execs().with_status(0));
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult,digit};

use std::str;
use std::str::FromStr;

named!(number<i64>,
       map_res!(
           map_res!(
               ws!(digit),
               str::from_utf8),
           FromStr::from_str
       ));

#[test]
fn number_test() {
    assert_eq!(number(&b"     3"[..]), IResult::Done(&b""[..], 3));
    assert_eq!(number(&b"    37"[..]), IResult::Done(&b""[..], 37));
    assert_eq!(number(&b"   373"[..]), IResult::Done(&b""[..], 373));
    assert_eq!(number(&b"  3733"[..]), IResult::Done(&b""[..], 3733));
    assert_eq!(number(&b" 37337"[..]), IResult::Done(&b""[..], 37337));
    assert_eq!(number(&b"373379"[..]), IResult::Done(&b""[..], 373379));
}
<commit_msg>Extend nom test<commit_after>#[macro_use]
extern crate nom;

use nom::{IResult,digit};

use std::str;
use std::str::FromStr;

named!(unsigned_number<i64>,
       map_res!(
           map_res!(
               digit,
               str::from_utf8),
           FromStr::from_str
       ));

named!(number<i64>, map!(
    pair!(
        opt!(alt!(tag!("+") | tag!("-"))),
        unsigned_number
    ),
    |(sign, value): (Option<&[u8]>, i64)| {
        sign
            .and_then(|s| if s[0] == ('-' as u8) { Some(-1i64) } else { None })
            .unwrap_or(1i64) * value
    }
));

#[test]
fn number_test() {
    assert_eq!(number(&b"3"[..]), IResult::Done(&b""[..], 3));
    assert_eq!(number(&b"37"[..]), IResult::Done(&b""[..], 37));
    assert_eq!(number(&b"373"[..]), IResult::Done(&b""[..], 373));
    assert_eq!(number(&b"3733"[..]), IResult::Done(&b""[..], 3733));
    assert_eq!(number(&b"37337"[..]), IResult::Done(&b""[..], 37337));
    assert_eq!(number(&b"373379"[..]), IResult::Done(&b""[..], 373379));

    assert_eq!(number(&b"-3"[..]), IResult::Done(&b""[..], -3));
    assert_eq!(number(&b"-37"[..]), IResult::Done(&b""[..], -37));
    assert_eq!(number(&b"-373"[..]), IResult::Done(&b""[..], -373));
    assert_eq!(number(&b"-3733"[..]), IResult::Done(&b""[..], -3733));
    assert_eq!(number(&b"-37337"[..]), IResult::Done(&b""[..], -37337));
    assert_eq!(number(&b"-373379"[..]), IResult::Done(&b""[..], -373379));

    assert_eq!(number(&b"+3"[..]), IResult::Done(&b""[..], 3));
    assert_eq!(number(&b"+37"[..]), IResult::Done(&b""[..], 37));
    assert_eq!(number(&b"+373"[..]), IResult::Done(&b""[..], 373));
    assert_eq!(number(&b"+3733"[..]), IResult::Done(&b""[..], 3733));
    assert_eq!(number(&b"+37337"[..]), IResult::Done(&b""[..], 37337));
    assert_eq!(number(&b"+373379"[..]), IResult::Done(&b""[..], 373379));
}
<|endoftext|>


<commit_before>extern crate portmidi;
extern crate rci;

#[test]
fn test_main() {
    let ci = rci::Ci::new();
    // Check if the test runs in a continous integration environment.
    // The test will fail in Travis CI because the test runner has no
    // permissions to access `/dev/snd/seq`:
    //
    // ```sh
    // running 1 test
    //
    // ALSA lib seq_hw.c:457:(snd_seq_hw_open) open /dev/snd/seq failed: Permission denied
    //
    // test test_main ... FAILED
    // ```
    if ci.is_none() {
        let context = portmidi::PortMidi::new().unwrap();
        assert!(context.device_count() > 0);
        assert!(context.default_input_device_id().is_ok());
        assert!(context.default_output_device_id().is_ok());
        assert!(context.devices().unwrap().len() > 0);
        let mut in_port = context.default_input_port(1024).unwrap();
        let mut out_port = context.default_output_port(1024).unwrap();
        assert!(in_port.poll() == Ok(false));
        assert!(in_port.read() == Ok(None));
        let msgs = vec![portmidi::MidiMessage {
                            status: 0x90,
                            data1: 60,
                            data2: 127,
                        },
                        portmidi::MidiMessage {
                            status: 0x80,
                            data1: 60,
                            data2: 0,
                        }];
        assert!(out_port.write_events(msgs).is_ok());
    }
}
<commit_msg>Refactor tests<commit_after>extern crate portmidi;
extern crate rci;

#[test]
fn test_main() {
    let ci = rci::Ci::new();
    // Check if the test runs in a continous integration environment.
    // The test will fail in Travis CI because the test runner has no
    // permissions to access `/dev/snd/seq`:
    //
    // ```sh
    // running 1 test
    //
    // ALSA lib seq_hw.c:457:(snd_seq_hw_open) open /dev/snd/seq failed: Permission denied
    //
    // test test_main ... FAILED
    // ```
    if ci.is_none() {
        let context = portmidi::PortMidi::new().unwrap();
        assert!(context.device_count() > 0);
        assert!(context.default_input_device_id().is_ok());
        assert!(context.default_output_device_id().is_ok());
        assert!(context.devices().unwrap().len() > 0);
        let mut in_port = context.default_input_port(1024).unwrap();
        let mut out_port = context.default_output_port(1024).unwrap();
        match in_port.poll() {
            Ok(flag) => println!("test_main) midi events available: {}", flag),
            Err(err) => println!("test_main) poll error: {}", err),
        };
        match in_port.read() {
            Ok(Some(event)) => println!("received midi event: {:?}", event),
            Ok(None) => println!("test_main) no midi event available"),
            Err(err) => println!("test_main) read error: {}", err),
        };
        let msgs = vec![portmidi::MidiMessage {
                            status: 0x90,
                            data1: 60,
                            data2: 127,
                        },
                        portmidi::MidiMessage {
                            status: 0x80,
                            data1: 60,
                            data2: 0,
                        }];
        match out_port.write_events(msgs) {
            Ok(_) => println!("test_main) successfully wrote midi events"),
            Err(err) => println!("test_main) write error: {}", err),
        }
    }
}
<|endoftext|>


<commit_before>extern crate pastebin_rust_api;

#[cfg(test)]
mod tests {
    use pastebin_rust_api::{Paster, Access, Expiration, Format};

    #[test]
    fn test_post() {
        let paster = Paster::new(None);
        let response = paster.paste("",
                                    Some(&Access::Private),
                                    Some("TestHtml"),
                                    Some(&Expiration::TenMinutes),
                                    Some(&Format::HTML5),
                                    None);
        assert!(response.is_ok());
        if let Some(message) = response.ok() {
            println!("URL: {}", message.content);
        }
    }

    #[test]
    fn test_login() {
        let paster = Paster::new(None);
        let response = paster.login(None, None);
        assert!(response.is_ok());
        if let Some(message) = response.ok() {
            println!("user_key: {}", message.content);
        }
    }
}
<commit_msg>added login_post_test<commit_after>extern crate pastebin_rust_api;

#[cfg(test)]
mod tests {
    use pastebin_rust_api::{Paster, Access, Expiration, Format};

    #[test]
    fn test_post() {
        let paster = Paster::new(None);
        let response = paster.paste("",
                                    Some(&Access::Private),
                                    Some("TestHtml"),
                                    Some(&Expiration::TenMinutes),
                                    Some(&Format::HTML5),
                                    None);
        assert!(response.is_ok());
        if let Some(message) = response.ok() {
            println!("URL: {}", message.content);
        }
    }

    #[test]
    fn test_login() {
        let paster = Paster::new(None);
        let response = paster.login(None, None);
        assert!(response.is_ok());
        if let Some(user_key) = response.ok() {
            println!("user_key: {}", user_key.content);
        }
    }

    #[test]
    fn test_login_post() {
        let paster = Paster::new(None);
        let user_key_response = paster.login(None, None);
        assert!(user_key_response.is_ok());
        if let Some(user_key) = user_key_response.ok() {
            let url_response = paster.paste("",
                                        Some(&Access::Private),
                                        Some("TestHtml"),
                                        Some(&Expiration::TenMinutes),
                                        Some(&Format::HTML5),
                                        Some(&user_key.content));
            assert!(url_response.is_ok());
            if let Some(message) = url_response.ok() {
                println!("URL: {}", message.content);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::env;
use std::process::{self, Stdio, ExitStatus};

use tokio::{
    runtime::{Runtime, Handle},
    io::AsyncWriteExt,
    process::{Command, ChildStdin},
};
use futures_util::future::{FutureExt, RemoteHandle};

use crate::ipc_protocol::{ClientConnection, ServerConnection, ConnectionError};

use super::super::main::run_main;

/// The environment variable that is set to indicate that the current process is a server process
const RENDERER_PROCESS_ENV_VAR: &str = "RUN_TURTLE_CANVAS";

/// Spawns the task/process responsible for handling and responding to client requests
///
/// Also manages the client connection used for communicating with the server
#[derive(Debug)]
pub struct RendererServer {
    /// A handle to the runtime that the process was spawned in. This is needed because a handle
    /// to the runtime can only be created when a "runtime context". Since Drop may not always run
    /// from async code, we need this to ensure we can wait on the subprocess in `task_handle`.
    /// NOTE: This creates an implicit invariant that this struct must be dropped before the
    /// runtime that it was created in is dropped. This is not an issue in normal code and will at
    /// worst cause a panic!().
    runtime_handle: Handle,
    /// A handle to the running task. This can be waited on to find out if the process exited
    /// successfully. A remote handle will also drop the future it is associated with when it is
    /// dropped. (unlike a `JoinHandle` which will detach instead.) This is important to make sure
    /// the window closes when the thread holding this struct panics.
    task_handle: Option<RemoteHandle<io::Result<ExitStatus>>>,
    /// A handle to the stdin of the child process
    child_stdin: ChildStdin,
}

impl RendererServer {
    /// Runs any initialization logic required at the beginning of the program
    pub fn start() {
        // If this environment variable is present, this process is taken over so that no other
        // code runs after run_main(). This allows us to ship one executable that appears to
        // have two separate processes.
        //
        // This implementation detail is why we request that users run start() at the beginning of
        // their programs. When we spawn the same executable, we don't pass along any environment,
        // input or command line arguments. That means that the user *needs* to run start() first or
        // else their program won't be able to run at all. This is a tradeoff of this design decision.
        if env::var(RENDERER_PROCESS_ENV_VAR).ok().as_deref() == Some("true") {
            // The runtime for driving async code
            let runtime = Runtime::new()
                .expect("unable to spawn tokio runtime to run turtle server process");

            // Run the renderer process
            // Using `async {}` because the multiprocessed backend doesn't care when the event loop
            // quits. Quit can be detected by waiting on the spawned process.
            run_main(runtime.handle().clone(), ServerConnection::connect_stdin(), async {});
            // Must exit after finishing or the program may execute twice
            process::exit(0);
        }
    }

    /// Spawns the backend in a new task and returns the struct that will be used to
    /// interface with it.
    pub async fn spawn() -> Result<(Self, ClientConnection), ConnectionError> {
        let current_exe = env::current_exe()?;

        // The new process is the same executable as this process but with a special environment
        // variable passed in
        let mut child = Command::new(current_exe)
            .env(RENDERER_PROCESS_ENV_VAR, "true")
            // Pipe input so we can communicate with the spawned process
            //
            // stdout/stderr will be inherited from the current process
            .stdin(Stdio::piped())
            .kill_on_drop(true)
            .spawn()?;

        let child_stdin = child.stdin.take()
            .expect("bug: renderer process was not spawned with a handle to stdin");

        // Spawn a separate task for the child process so this task can continue to make progress
        // while that runs. The remote handle will drop that future when it is dropped.
        let (child, child_handle) = child.remote_handle();
        tokio::spawn(child);
        let task_handle = Some(child_handle);

        // Keep a handle to the current runtime
        let runtime_handle = Handle::current();

        //TODO: There is no need to have a `child_stdin` feature and refactoring to remove it could
        // simplify this code
        let mut proc = Self {runtime_handle, task_handle, child_stdin};
        let conn = ClientConnection::new(|name| proc.send_ipc_oneshot_name(name)).await?;

        Ok((proc, conn))
    }

    /// Sends the IPC one shot server name to the server process
    ///
    /// This method should only be called once
    async fn send_ipc_oneshot_name(&mut self, name: String) -> io::Result<()> {
        self.writeln(&name).await
    }

    /// Writes the given bytes followed by a newline b'\n' to the stdin of the process
    ///
    /// Unlike `std::io::Write::write`, this returns an error in the case all of the bytes could
    /// not be written for some reason.
    async fn writeln<S: AsRef<[u8]>>(&mut self, data: S) -> io::Result<()> {
        let data = data.as_ref();
        self.child_stdin.write_all(data).await?;
        self.child_stdin.write_all(&[b'\n']).await?;

        Ok(())
    }
}

impl Drop for RendererServer {
    fn drop(&mut self) {
        use std::thread;

        // If the current thread is panicking, we don't want to wait for the window to be closed
        // since the user likely has an issue to fix in their program.
        if thread::panicking() {
            // The process is configured with `kill_on_drop` so this should close the window
            return;
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open

        // This unwrap is safe because no struct gets dropped twice
        let task_handle = self.task_handle.take().unwrap();

        // Wait for the child process to finish
        match self.runtime_handle.block_on(task_handle) {
            Ok(proc_status) => if !proc_status.success() {
                // Propagate error code from child process or exit with status code 1
                process::exit(proc_status.code().unwrap_or(1));
            },
            Err(err) => {
                panic!("error while running child process: {}", err);
            },
        }
    }
}
<commit_msg>Removed unnecessary child_stdin field from RendererServer<commit_after>use std::io;
use std::env;
use std::process::{self, Stdio, ExitStatus};

use tokio::{
    runtime::{Runtime, Handle},
    io::AsyncWriteExt,
    process::{Command, ChildStdin},
};
use futures_util::future::{FutureExt, RemoteHandle};

use crate::ipc_protocol::{ClientConnection, ServerConnection, ConnectionError};

use super::super::main::run_main;

/// The environment variable that is set to indicate that the current process is a server process
const RENDERER_PROCESS_ENV_VAR: &str = "RUN_TURTLE_CANVAS";

/// Spawns the task/process responsible for handling and responding to client requests
///
/// Also manages the client connection used for communicating with the server
#[derive(Debug)]
pub struct RendererServer {
    /// A handle to the runtime that the process was spawned in. This is needed because a handle
    /// to the runtime can only be created when a "runtime context". Since Drop may not always run
    /// from async code, we need this to ensure we can wait on the subprocess in `task_handle`.
    /// NOTE: This creates an implicit invariant that this struct must be dropped before the
    /// runtime that it was created in is dropped. This is not an issue in normal code and will at
    /// worst cause a panic!().
    runtime_handle: Handle,
    /// A handle to the running task. This can be waited on to find out if the process exited
    /// successfully. A remote handle will also drop the future it is associated with when it is
    /// dropped. (unlike a `JoinHandle` which will detach instead.) This is important to make sure
    /// the window closes when the thread holding this struct panics.
    task_handle: Option<RemoteHandle<io::Result<ExitStatus>>>,
}

impl RendererServer {
    /// Runs any initialization logic required at the beginning of the program
    pub fn start() {
        // If this environment variable is present, this process is taken over so that no other
        // code runs after run_main(). This allows us to ship one executable that appears to
        // have two separate processes.
        //
        // This implementation detail is why we request that users run start() at the beginning of
        // their programs. When we spawn the same executable, we don't pass along any environment,
        // input or command line arguments. That means that the user *needs* to run start() first or
        // else their program won't be able to run at all. This is a tradeoff of this design decision.
        if env::var(RENDERER_PROCESS_ENV_VAR).ok().as_deref() == Some("true") {
            // The runtime for driving async code
            let runtime = Runtime::new()
                .expect("unable to spawn tokio runtime to run turtle server process");

            // Run the renderer process
            // Using `async {}` because the multiprocessed backend doesn't care when the event loop
            // quits. Quit can be detected by waiting on the spawned process.
            run_main(runtime.handle().clone(), ServerConnection::connect_stdin(), async {});
            // Must exit after finishing or the program may execute twice
            process::exit(0);
        }
    }

    /// Spawns the backend in a new task and returns the struct that will be used to
    /// interface with it.
    pub async fn spawn() -> Result<(Self, ClientConnection), ConnectionError> {
        let current_exe = env::current_exe()?;

        // The new process is the same executable as this process but with a special environment
        // variable passed in
        let mut child = Command::new(current_exe)
            .env(RENDERER_PROCESS_ENV_VAR, "true")
            // Pipe input so we can communicate with the spawned process
            //
            // stdout/stderr will be inherited from the current process
            .stdin(Stdio::piped())
            .kill_on_drop(true)
            .spawn()?;

        let child_stdin = child.stdin.take()
            .expect("bug: renderer process was not spawned with a handle to stdin");

        // Spawn a separate task for the child process so this task can continue to make progress
        // while that runs. The remote handle will drop that future when it is dropped.
        let (child, child_handle) = child.remote_handle();
        tokio::spawn(child);
        let task_handle = Some(child_handle);

        // Keep a handle to the current runtime
        let runtime_handle = Handle::current();

        // Send IPC oneshot server name by writing to stdin
        let conn = ClientConnection::new(|name| send_ipc_oneshot_name(child_stdin, name)).await?;

        Ok((Self {runtime_handle, task_handle}, conn))
    }
}

async fn send_ipc_oneshot_name(mut child_stdin: ChildStdin, server_name: String) -> io::Result<()> {
    child_stdin.write_all(server_name.as_ref()).await?;
    child_stdin.write_all(&[b'\n']).await?;
    Ok(())
}

impl Drop for RendererServer {
    fn drop(&mut self) {
        use std::thread;

        // If the current thread is panicking, we don't want to wait for the window to be closed
        // since the user likely has an issue to fix in their program.
        if thread::panicking() {
            // The process is configured with `kill_on_drop` so this should close the window
            return;
        }

        // If this is just a normal ending of the main thread, we want to leave the renderer
        // running so that the user can see their drawing as long as they keep the window open

        // This unwrap is safe because no struct gets dropped twice
        let task_handle = self.task_handle.take().unwrap();

        // Wait for the child process to finish
        match self.runtime_handle.block_on(task_handle) {
            Ok(proc_status) => if !proc_status.success() {
                // Propagate error code from child process or exit with status code 1
                process::exit(proc_status.code().unwrap_or(1));
            },
            Err(err) => {
                panic!("error while running child process: {}", err);
            },
        }
    }
}
<|endoftext|>


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

use cssparser::{Parser, SourcePosition};
use parking_lot::RwLock;
use rayon;
use servo_url::ServoUrl;
use std::sync::Arc;
use style::error_reporting::ParseErrorReporter;
use style::media_queries::MediaList;
use style::parser::ParserContextExtraData;
use style::properties::{longhands, DeclaredValue, Importance, PropertyDeclaration, PropertyDeclarationBlock};
use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use style::stylesheets::{Origin, Stylesheet, CssRule};
use test::{self, Bencher};

struct ErrorringErrorReporter;
impl ParseErrorReporter for ErrorringErrorReporter {
    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str,
        url: &ServoUrl) {
        panic!("CSS error: {}\t\n{:?} {}", url.as_str(), position, message);
    }

    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
        Box::new(ErrorringErrorReporter)
    }
}

struct AutoGCRuleTree<'a>(&'a RuleTree);

impl<'a> AutoGCRuleTree<'a> {
    fn new(r: &'a RuleTree) -> Self {
        AutoGCRuleTree(r)
    }
}

impl<'a> Drop for AutoGCRuleTree<'a> {
    fn drop(&mut self) {
        unsafe { self.0.gc() }
    }
}

fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
    let s = Stylesheet::from_str(css,
                                 ServoUrl::parse("http://localhost").unwrap(),
                                 Origin::Author,
                                 MediaList {
                                     media_queries: vec![],
                                 },
                                 None,
                                 Box::new(ErrorringErrorReporter),
                                 ParserContextExtraData {});
    let rules = s.rules.read();
    rules.0.iter().filter_map(|rule| {
        match *rule {
            CssRule::Style(ref style_rule) => Some(style_rule),
            _ => None,
        }
    }).cloned().map(StyleSource::Style).map(|s| {
        (s, CascadeLevel::UserNormal)
    }).collect()
}

fn test_insertion(rule_tree: &RuleTree, rules: Vec<(StyleSource, CascadeLevel)>) -> StrongRuleNode {
    rule_tree.insert_ordered_rules(rules.into_iter())
}

fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, CascadeLevel)]) -> StrongRuleNode {
    let mut rules = rules.to_vec();
    rules.push((StyleSource::Declarations(Arc::new(RwLock::new(PropertyDeclarationBlock {
        declarations: vec![
            (PropertyDeclaration::Display(DeclaredValue::Value(
                longhands::display::SpecifiedValue::block)),
            Importance::Normal),
        ],
        important_count: 0,
    }))), CascadeLevel::UserNormal));
    test_insertion(rule_tree, rules)
}

#[bench]
fn bench_insertion_basic(b: &mut Bencher) {
    let r = RuleTree::new();

    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        for _ in 0..(4000 + 400) {
            test::black_box(test_insertion(&r, rules_matched.clone()));
        }
    })
}

#[bench]
fn bench_insertion_basic_per_element(b: &mut Bencher) {
    let r = RuleTree::new();

    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        test::black_box(test_insertion(&r, rules_matched.clone()));
    });
}

#[bench]
fn bench_expensive_insertion(b: &mut Bencher) {
    let r = RuleTree::new();

    // This test case tests a case where you style a bunch of siblings
    // matching the same rules, with a different style attribute each
    // one.
    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        for _ in 0..(4000 + 400) {
            test::black_box(test_insertion_style_attribute(&r, &rules_matched));
        }
    });
}

#[bench]
fn bench_insertion_basic_parallel(b: &mut Bencher) {
    let r = RuleTree::new();

    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        rayon::scope(|s| {
            for _ in 0..4 {
                s.spawn(|s| {
                    for _ in 0..1000 {
                        test::black_box(test_insertion(&r,
                                                       rules_matched.clone()));
                    }
                    s.spawn(|_| {
                        for _ in 0..100 {
                            test::black_box(test_insertion(&r,
                                                           rules_matched.clone()));
                        }
                    })
                })
            }
        });
    });
}

#[bench]
fn bench_expensive_insersion_parallel(b: &mut Bencher) {
    let r = RuleTree::new();

    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        rayon::scope(|s| {
            for _ in 0..4 {
                s.spawn(|s| {
                    for _ in 0..1000 {
                        test::black_box(test_insertion_style_attribute(&r,
                                                                       &rules_matched));
                    }
                    s.spawn(|_| {
                        for _ in 0..100 {
                            test::black_box(test_insertion_style_attribute(&r,
                                                                           &rules_matched));
                        }
                    })
                })
            }
        });
    });
}
<commit_msg>Silence a warning<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use cssparser::{Parser, SourcePosition};
use parking_lot::RwLock;
use rayon;
use servo_url::ServoUrl;
use std::sync::Arc;
use style::error_reporting::ParseErrorReporter;
use style::media_queries::MediaList;
use style::parser::ParserContextExtraData;
use style::properties::{longhands, DeclaredValue, Importance, PropertyDeclaration, PropertyDeclarationBlock};
use style::rule_tree::{CascadeLevel, RuleTree, StrongRuleNode, StyleSource};
use style::stylesheets::{Origin, Stylesheet, CssRule};
use test::{self, Bencher};

struct ErrorringErrorReporter;
impl ParseErrorReporter for ErrorringErrorReporter {
    fn report_error(&self, _input: &mut Parser, position: SourcePosition, message: &str,
        url: &ServoUrl) {
        panic!("CSS error: {}\t\n{:?} {}", url.as_str(), position, message);
    }

    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
        Box::new(ErrorringErrorReporter)
    }
}

struct AutoGCRuleTree<'a>(&'a RuleTree);

impl<'a> AutoGCRuleTree<'a> {
    fn new(r: &'a RuleTree) -> Self {
        AutoGCRuleTree(r)
    }
}

impl<'a> Drop for AutoGCRuleTree<'a> {
    fn drop(&mut self) {
        unsafe { self.0.gc() }
    }
}

fn parse_rules(css: &str) -> Vec<(StyleSource, CascadeLevel)> {
    let s = Stylesheet::from_str(css,
                                 ServoUrl::parse("http://localhost").unwrap(),
                                 Origin::Author,
                                 MediaList {
                                     media_queries: vec![],
                                 },
                                 None,
                                 Box::new(ErrorringErrorReporter),
                                 ParserContextExtraData {});
    let rules = s.rules.read();
    rules.0.iter().filter_map(|rule| {
        match *rule {
            CssRule::Style(ref style_rule) => Some(style_rule),
            _ => None,
        }
    }).cloned().map(StyleSource::Style).map(|s| {
        (s, CascadeLevel::UserNormal)
    }).collect()
}

fn test_insertion(rule_tree: &RuleTree, rules: Vec<(StyleSource, CascadeLevel)>) -> StrongRuleNode {
    rule_tree.insert_ordered_rules(rules.into_iter())
}

fn test_insertion_style_attribute(rule_tree: &RuleTree, rules: &[(StyleSource, CascadeLevel)]) -> StrongRuleNode {
    let mut rules = rules.to_vec();
    rules.push((StyleSource::Declarations(Arc::new(RwLock::new(PropertyDeclarationBlock {
        declarations: vec![
            (PropertyDeclaration::Display(DeclaredValue::Value(
                longhands::display::SpecifiedValue::block)),
            Importance::Normal),
        ],
        important_count: 0,
    }))), CascadeLevel::UserNormal));
    test_insertion(rule_tree, rules)
}

#[bench]
fn bench_insertion_basic(b: &mut Bencher) {
    let r = RuleTree::new();

    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        for _ in 0..(4000 + 400) {
            test::black_box(test_insertion(&r, rules_matched.clone()));
        }
    })
}

#[bench]
fn bench_insertion_basic_per_element(b: &mut Bencher) {
    let r = RuleTree::new();

    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        test::black_box(test_insertion(&r, rules_matched.clone()));
    });
}

#[bench]
fn bench_expensive_insertion(b: &mut Bencher) {
    let r = RuleTree::new();

    // This test case tests a case where you style a bunch of siblings
    // matching the same rules, with a different style attribute each
    // one.
    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        for _ in 0..(4000 + 400) {
            test::black_box(test_insertion_style_attribute(&r, &rules_matched));
        }
    });
}

#[bench]
fn bench_insertion_basic_parallel(b: &mut Bencher) {
    let r = RuleTree::new();

    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        rayon::scope(|s| {
            for _ in 0..4 {
                s.spawn(|s| {
                    for _ in 0..1000 {
                        test::black_box(test_insertion(&r,
                                                       rules_matched.clone()));
                    }
                    s.spawn(|_| {
                        for _ in 0..100 {
                            test::black_box(test_insertion(&r,
                                                           rules_matched.clone()));
                        }
                    })
                })
            }
        });
    });
}

#[bench]
fn bench_expensive_insersion_parallel(b: &mut Bencher) {
    let r = RuleTree::new();

    let rules_matched = parse_rules(
        ".foo { width: 200px; } \
         .bar { height: 500px; } \
         .baz { display: block; }");

    b.iter(|| {
        let _gc = AutoGCRuleTree::new(&r);

        rayon::scope(|s| {
            for _ in 0..4 {
                s.spawn(|s| {
                    for _ in 0..1000 {
                        test::black_box(test_insertion_style_attribute(&r,
                                                                       &rules_matched));
                    }
                    s.spawn(|_| {
                        for _ in 0..100 {
                            test::black_box(test_insertion_style_attribute(&r,
                                                                           &rules_matched));
                        }
                    })
                })
            }
        });
    });
}
<|endoftext|>


<commit_before>use crate::{
    cluster::Cluster,
    experiments::{Experiment, RebootRandomValidators},
};

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    pub fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments = vec![];
        // Reboot different sets of 3 validators *100 times
        for _ in 0..100 {
            let b: Box<dyn Experiment> = Box::new(RebootRandomValidators::new(3, cluster));
            experiments.push(b);
        }
        Self { experiments }
    }
}
<commit_msg>[cluster_test] Don't reboot more then 1/3 during reboot experiment<commit_after>use crate::{
    cluster::Cluster,
    experiments::{Experiment, RebootRandomValidators},
};
use std::cmp::min;

pub struct ExperimentSuite {
    pub experiments: Vec<Box<dyn Experiment>>,
}

impl ExperimentSuite {
    pub fn new_pre_release(cluster: &Cluster) -> Self {
        let mut experiments = vec![];
        let count = min(3, cluster.instances().len() / 3);
        // Reboot different sets of 3 validators *100 times
        for _ in 0..100 {
            let b: Box<dyn Experiment> = Box::new(RebootRandomValidators::new(count, cluster));
            experiments.push(b);
        }
        Self { experiments }
    }
}
<|endoftext|>


<commit_before>fn taylor_atan (x: f64) -> f64 {
    let mut a: f64 = 0.0;
    let mut s: f64 = 1.0;
    let mut xpow: f64;

    for ii in range(1i, 16) {
        if ii % 2 == 0 {
            continue;
        }
        xpow = 1.0;
        for jj in range(0i, ii) {
            xpow *= x;
        }
        a += s * xpow / (ii as f64);
        s = -1.0*s;
    }

    println!("{}", a);
    return a;
}

fn generate_table () {

    let pi: f64 = 3.1415926536897932384626;
    let k1: f64 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    let mul: uint = 1<<(num_bits-2);

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("mul {}", mul);
    println!("1<<(num_bits-2) {}", ((1i << (num_bits-2)) as f64));
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    println!("let cordic_tab = [");

    let shift: f64 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f64 = 1f64/shift.powi(ii as i32);
        let cur: f64 = ipow.atan() * (mul as f64);

        if ii % 4 == 0 && ii > 0 {
            println!("");
        }
        if ii == 0 {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        } else {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        }
    }

    println!("];");
}

fn sin(theta: f64) -> f64 {

    let num_bits: uint = 32;

    let k1: f64 = 0.6072529350088812561694; // 1/k
    let muli: int = 1<<(num_bits-2);
    let mul: f64 = muli as f64;
    let cordic_k1: f64 = k1 * mul;
    let mut x: int = cordic_k1.floor() as int; //0x26DD3B6A;
    let mut y: int = 0;
    let mut z: int = (mul * theta).floor() as int;
    let mut tx: int;
    let mut ty: int;
    let mut tz: int;

    let mut d: int;
    let cordic_tab = [
        0x3243f6a8, 0x1dac6705, 0xfadbafc, 0x7f56ea6,
        0x3feab76, 0x1ffd55b, 0xfffaaa, 0x7fff55,
        0x3fffea, 0x1ffffd, 0xfffff, 0x7ffff,
        0x3ffff, 0x1ffff, 0xffff, 0x7fff,
        0x3fff, 0x1fff, 0xfff, 0x7ff,
        0x3ff, 0x1ff, 0xff, 0x7f,
        0x3f, 0x1f, 0xf, 0x8,
        0x4, 0x2, 0x1, 0x0, ];

    for k in range(0, num_bits) {
        if z >= 0 {
            d = 0;
        } else {
            d = -1;
        }

        tx = x - (((y>>k) ^ d) - d);
        ty = y + (((x>>k) ^ d) - d);
        tz = z - ((cordic_tab[k] ^ d) - d);
        x = tx; y = ty; z = tz;
    }

    let s: f64 = (y as f64)/(mul as f64);

    return s;

}

fn main() {
    generate_table();

    let frac_pi_2: f64 = std::f64::consts::FRAC_PI_2; //3.1415926536897932384626/2.0;

    for ii in range(0i, 50) {
        let cur: f64 = ii as f64;
        let theta: f64 = cur/50.0 * frac_pi_2;
        let s: f64 = sin(theta);
            println!("s {}", s);
    }
}
<commit_msg>atan with taylor, but still has some roundoff error<commit_after>fn taylor_atan (x: f64) -> f64 {
    let mut a: f64 = 0.0;
    let mut s: f64 = 1.0;
    let mut xpow: f64;

    for ii in range(1i, 60) {
        if ii % 2 == 0 {
            continue;
        }
        xpow = 1.0;
        for jj in range(0i, ii) {
            xpow *= x;
        }
        a += s * xpow / (ii as f64);
        s = -1.0*s;
    }

    //println!("{}", a);
    return a;
}

fn generate_table () {

    let pi: f64 = 3.1415926536897932384626;
    let k1: f64 = 0.6072529350088812561694; // 1/k
    let num_bits: uint = 32;
    let mul: uint = 1<<(num_bits-2);

    println!("Cordic sin in rust");
    println!("num bits {}", num_bits);
    println!("mul {}", mul);
    println!("1<<(num_bits-2) {}", ((1i << (num_bits-2)) as f64));
    println!("pi is {}", pi);
    println!("k1 is {}", k1);

    println!("let cordic_tab = [");

    let shift: f64 = 2.0;
    for ii in range(0, num_bits) {
        let ipow: f64 = 1f64/shift.powi(ii as i32);
        //let cur: f64 = ipow.atan() * (mul as f64);
        let cur: f64 = taylor_atan(ipow) * (mul as f64);

        if ii % 4 == 0 && ii > 0 {
            println!("");
        }
        if ii == 0 {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        } else {
            print!("0x{}, ", std::f64::to_str_hex(cur.floor()));
        }
    }

    println!("];");
}

fn sin(theta: f64) -> f64 {

    let num_bits: uint = 32;

    let k1: f64 = 0.6072529350088812561694; // 1/k
    let muli: int = 1<<(num_bits-2);
    let mul: f64 = muli as f64;
    let cordic_k1: f64 = k1 * mul;
    let mut x: int = cordic_k1.floor() as int; //0x26DD3B6A;
    let mut y: int = 0;
    let mut z: int = (mul * theta).floor() as int;
    let mut tx: int;
    let mut ty: int;
    let mut tz: int;

    let mut d: int;
    let cordic_tab = [
        0x3243f6a8, 0x1dac6705, 0xfadbafc, 0x7f56ea6,
        0x3feab76, 0x1ffd55b, 0xfffaaa, 0x7fff55,
        0x3fffea, 0x1ffffd, 0xfffff, 0x7ffff,
        0x3ffff, 0x1ffff, 0xffff, 0x7fff,
        0x3fff, 0x1fff, 0xfff, 0x7ff,
        0x3ff, 0x1ff, 0xff, 0x7f,
        0x3f, 0x1f, 0xf, 0x8,
        0x4, 0x2, 0x1, 0x0, ];

    for k in range(0, num_bits) {
        if z >= 0 {
            d = 0;
        } else {
            d = -1;
        }

        tx = x - (((y>>k) ^ d) - d);
        ty = y + (((x>>k) ^ d) - d);
        tz = z - ((cordic_tab[k] ^ d) - d);
        x = tx; y = ty; z = tz;
    }

    let s: f64 = (y as f64)/(mul as f64);

    return s;

}

fn main() {
    generate_table();

    let frac_pi_2: f64 = std::f64::consts::FRAC_PI_2; //3.1415926536897932384626/2.0;

    for ii in range(0i, 50) {
        let cur: f64 = ii as f64;
        let theta: f64 = cur/50.0 * frac_pi_2;
        let s: f64 = sin(theta);
            println!("s {}", s);
    }
}
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
extern crate glfw;
use self::glfw::Context;

extern crate gl;
extern crate rand;
use self::rand::Rng;

use std::ffi::CStr;
use std::mem;
use std::os::raw::c_void;
use std::ptr;

use common::{process_events, processInput};
use shader::Shader;
use camera::Camera;
use model::Model;

use cgmath::{Matrix4, vec3, Point3, Vector4, Deg, perspective};
use cgmath::prelude::*;

// settings
const SCR_WIDTH: u32 = 1280;
const SCR_HEIGHT: u32 = 720;

pub fn main_4_10_3() {
    let mut camera = Camera {
        Position: Point3::new(0.0, 0.0, 155.0),
        ..Camera::default()
    };

    let mut firstMouse = true;
    let mut lastX: f32 = SCR_WIDTH as f32 / 2.0;
    let mut lastY: f32 = SCR_HEIGHT as f32 / 2.0;

    // timing
    let mut deltaTime: f32; // time between current frame and last frame
    let mut lastFrame: f32 = 0.0;

    // glfw: initialize and configure
    // ------------------------------
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    #[cfg(target_os = "macos")]
    glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));

    // glfw window creation
    // --------------------
    let (mut window, events) = glfw.create_window(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window");

    window.make_current();
    window.set_framebuffer_size_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_scroll_polling(true);

    // tell GLFW to capture our mouse
    window.set_cursor_mode(glfw::CursorMode::Disabled);

    // gl: load all OpenGL function pointers
    // ---------------------------------------
    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

    let (asteroidShader, planetShader, rock, planet, amount) = unsafe {
        // configure global opengl state
        // -----------------------------
        gl::Enable(gl::DEPTH_TEST);

        // build and compile shaders
        // -------------------------
        let asteroidShader = Shader::new(
            "src/_4_advanced_opengl/shaders/10.3.asteroids.vs",
            "src/_4_advanced_opengl/shaders/10.3.asteroids.fs");
        let planetShader = Shader::new(
            "src/_4_advanced_opengl/shaders/10.3.planet.vs",
            "src/_4_advanced_opengl/shaders/10.3.planet.fs");

        // load models
        // -----------
        let rock = Model::new("resources/objects/rock/rock.obj");
        let planet = Model::new("resources/objects/planet/planet.obj");

        // generate a large list of semi-random model transformation matrices
        // ------------------------------------------------------------------
        let amount = 100000;
        let mut modelMatrices: Vec<Matrix4<f32>> = Vec::with_capacity(amount);
        let mut rng = rand::thread_rng();
        let radius = 150.0;
        let offset: f32 = 25.0;
        for i in 0..amount {
            let angle = i as i32 as f32 / amount as f32 * 360.0;
            let mut displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
            let x = angle.sin() * radius + displacement;
            displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
            let y = displacement * 0.4; // keep height of asteroid field smaller compared to width of x and z
            displacement = (rng.gen::<i32>() % (2.0 * offset * 100.0) as i32) as f32 / 100.0 - offset;
            let z = angle.cos() * radius + displacement;
            let mut model = Matrix4::<f32>::from_translation(vec3(x, y, z));

            // 2. scale: Scale between 0.05 and 0.25
            let scale = (rng.gen::<i32>() % 20) as f32 / 100.0 + 0.05;
            model = model * Matrix4::from_scale(scale);

            // 3. rotation: add random rotation around a (semi)randomly picked rotation axis vector
            let rotAngle = (rng.gen::<i32>() % 360) as f32;
            model = model * Matrix4::from_axis_angle(vec3(0.4, 0.6, 0.8).normalize(), Deg(rotAngle));

            // 4. now add to list of matrices
            modelMatrices.push(model);
        }

        // configure instanced array
        // -------------------------
        let mut buffer = 0;
        gl::GenBuffers(1, &mut buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, buffer);
        gl::BufferData(
            gl::ARRAY_BUFFER,
            (amount * mem::size_of::<Matrix4<f32>>()) as isize,
            &modelMatrices[0] as *const Matrix4<f32> as *const c_void,
            gl::STATIC_DRAW);

        // set transformation matrices as an instance vertex attribute (with divisor 1)
        // note: we're cheating a little by taking the, now publicly declared, VAO of the model's mesh(es) and adding new vertexAttribPointers
        // normally you'd want to do this in a more organized fashion, but for learning purposes this will do.
        // -----------------------------------------------------------------------------------------------------------------------------------
        let size_mat4 = mem::size_of::<Matrix4<f32>>() as i32;
        let size_vec4 = mem::size_of::<Vector4<f32>>() as i32;
        for mesh in &rock.meshes {
            let VAO = mesh.VAO;
            gl::BindVertexArray(VAO);
            // set attribute pointers for matrix (4 times vec4)
            gl::EnableVertexAttribArray(3);
            gl::VertexAttribPointer(3, 4, gl::FLOAT, gl::FALSE, size_mat4, ptr::null());
            gl::EnableVertexAttribArray(4);
            gl::VertexAttribPointer(4, 4, gl::FLOAT, gl::FALSE, size_mat4, size_vec4 as *const c_void);
            gl::EnableVertexAttribArray(5);
            gl::VertexAttribPointer(5, 4, gl::FLOAT, gl::FALSE, size_mat4, (2 * size_vec4) as *const c_void);
            gl::EnableVertexAttribArray(6);
            gl::VertexAttribPointer(6, 4, gl::FLOAT, gl::FALSE, size_mat4, (3 * size_vec4) as *const c_void);

            gl::VertexAttribDivisor(3, 1);
            gl::VertexAttribDivisor(4, 1);
            gl::VertexAttribDivisor(5, 1);
            gl::VertexAttribDivisor(6, 1);

            gl::BindVertexArray(0);
        }

        (asteroidShader, planetShader, rock, planet, amount)
    };

    // render loop
    // -----------
    while !window.should_close() {
        // per-frame time logic
        // --------------------
        let currentFrame = glfw.get_time() as f32;
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        // events
        // -----
        process_events(&events, &mut firstMouse, &mut lastX, &mut lastY, &mut camera);

        // input
        // -----
        processInput(&mut window, deltaTime, &mut camera);

        // render
        // ------
        unsafe {
            gl::ClearColor(0.1, 0.1, 0.1, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            // configure transformation matrices
            let projection: Matrix4<f32> = perspective(Deg(45.0), SCR_WIDTH as f32 / SCR_HEIGHT as f32, 0.1, 1000.0);
            let view = camera.GetViewMatrix();
            asteroidShader.useProgram();
            asteroidShader.setMat4(c_str!("projection"), &projection);
            asteroidShader.setMat4(c_str!("view"), &view);
            planetShader.useProgram();
            planetShader.setMat4(c_str!("projection"), &projection);
            planetShader.setMat4(c_str!("view"), &view);

            // draw planet
            let mut model = Matrix4::<f32>::from_translation(vec3(0.0, -3.0, 0.0));
            model = model * Matrix4::from_scale(4.0);
            planetShader.setMat4(c_str!("model"), &model);
            planet.Draw(&planetShader);

            // draw meteorites
            asteroidShader.useProgram();
            asteroidShader.setInt(c_str!("texture_diffuse1"), 0);
            gl::ActiveTexture(gl::TEXTURE0);
            gl::BindTexture(gl::TEXTURE_2D, rock.textures_loaded[0].id); // note: we also made the textures_loaded vector public (instead of private) from the model class.

            for mesh in &rock.meshes {
                gl::BindVertexArray(mesh.VAO);
                gl::DrawElementsInstanced(gl::TRIANGLES, mesh.indices.len() as i32, gl::UNSIGNED_INT, ptr::null(), amount as i32);
                gl::BindVertexArray(0);
            }
        }

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        window.swap_buffers();
        glfw.poll_events();
    }

}
<commit_msg>Update _10_3_asteroids_instanced.rs<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_snake_case)]
extern crate glfw;
use self::glfw::Context;

extern crate gl;
extern crate rand;
use self::rand::Rng;

use std::ffi::CStr;
use std::mem;
use std::os::raw::c_void;
use std::ptr;

use common::{process_events, processInput};
use shader::Shader;
use camera::Camera;
use model::Model;

use cgmath::{Matrix4, vec3, Point3, Vector4, Deg, perspective};
use cgmath::prelude::*;

// settings
const SCR_WIDTH: u32 = 1280;
const SCR_HEIGHT: u32 = 720;

pub fn main_4_10_3() {
    let mut camera = Camera {
        Position: Point3::new(0.0, 0.0, 155.0),
        ..Camera::default()
    };

    let mut firstMouse = true;
    let mut lastX: f32 = SCR_WIDTH as f32 / 2.0;
    let mut lastY: f32 = SCR_HEIGHT as f32 / 2.0;

    // timing
    let mut deltaTime: f32; // time between current frame and last frame
    let mut lastFrame: f32 = 0.0;

    // glfw: initialize and configure
    // ------------------------------
    let mut glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
    glfw.window_hint(glfw::WindowHint::ContextVersion(3, 3));
    glfw.window_hint(glfw::WindowHint::OpenGlProfile(glfw::OpenGlProfileHint::Core));
    #[cfg(target_os = "macos")]
    glfw.window_hint(glfw::WindowHint::OpenGlForwardCompat(true));

    // glfw window creation
    // --------------------
    let (mut window, events) = glfw.create_window(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", glfw::WindowMode::Windowed)
        .expect("Failed to create GLFW window");

    window.make_current();
    window.set_framebuffer_size_polling(true);
    window.set_cursor_pos_polling(true);
    window.set_scroll_polling(true);

    // tell GLFW to capture our mouse
    window.set_cursor_mode(glfw::CursorMode::Disabled);

    // gl: load all OpenGL function pointers
    // ---------------------------------------
    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

    let (asteroidShader, planetShader, rock, planet, amount) = unsafe {
        // configure global opengl state
        // -----------------------------
        gl::Enable(gl::DEPTH_TEST);

        // build and compile shaders
        // -------------------------
        let asteroidShader = Shader::new(
            "src/_4_advanced_opengl/shaders/10.3.asteroids.vs",
            "src/_4_advanced_opengl/shaders/10.3.asteroids.fs");
        let planetShader = Shader::new(
            "src/_4_advanced_opengl/shaders/10.3.planet.vs",
            "src/_4_advanced_opengl/shaders/10.3.planet.fs");

        // load models
        // -----------
        let rock = Model::new("resources/objects/rock/rock.obj");
        let planet = Model::new("resources/objects/planet/planet.obj");

        // generate a large list of semi-random model transformation matrices
        // ------------------------------------------------------------------
        let amount = 100000;
        let mut modelMatrices: Vec<Matrix4<f32>> = Vec::with_capacity(amount);
        let mut rng = rand::thread_rng();
        let radius = 150.0;
        let offset: f32 = 25.0;
        for i in 0..amount {
            let angle = i as i32 as f32 / amount as f32 * 360.0;
            let mut displacement = (rng.gen::<u32>() % (2.0 * offset * 100.0) as u32) as f32 / 100.0 - offset;
            let x = angle.sin() * radius + displacement;
            displacement = (rng.gen::<u32>() % (2.0 * offset * 100.0) as i32) as u32 / 100.0 - offset;
            let y = displacement * 0.4; // keep height of asteroid field smaller compared to width of x and z
            displacement = (rng.gen::<u32>() % (2.0 * offset * 100.0) as i32) as u32 / 100.0 - offset;
            let z = angle.cos() * radius + displacement;
            let mut model = Matrix4::<u32>::from_translation(vec3(x, y, z));

            // 2. scale: Scale between 0.05 and 0.25
            let scale = (rng.gen::<u32>() % 20) as f32 / 100.0 + 0.05;
            model = model * Matrix4::from_scale(scale);

            // 3. rotation: add random rotation around a (semi)randomly picked rotation axis vector
            let rotAngle = (rng.gen::<u32>() % 360) as f32;
            model = model * Matrix4::from_axis_angle(vec3(0.4, 0.6, 0.8).normalize(), Deg(rotAngle));

            // 4. now add to list of matrices
            modelMatrices.push(model);
        }

        // configure instanced array
        // -------------------------
        let mut buffer = 0;
        gl::GenBuffers(1, &mut buffer);
        gl::BindBuffer(gl::ARRAY_BUFFER, buffer);
        gl::BufferData(
            gl::ARRAY_BUFFER,
            (amount * mem::size_of::<Matrix4<f32>>()) as isize,
            &modelMatrices[0] as *const Matrix4<f32> as *const c_void,
            gl::STATIC_DRAW);

        // set transformation matrices as an instance vertex attribute (with divisor 1)
        // note: we're cheating a little by taking the, now publicly declared, VAO of the model's mesh(es) and adding new vertexAttribPointers
        // normally you'd want to do this in a more organized fashion, but for learning purposes this will do.
        // -----------------------------------------------------------------------------------------------------------------------------------
        let size_mat4 = mem::size_of::<Matrix4<f32>>() as i32;
        let size_vec4 = mem::size_of::<Vector4<f32>>() as i32;
        for mesh in &rock.meshes {
            let VAO = mesh.VAO;
            gl::BindVertexArray(VAO);
            // set attribute pointers for matrix (4 times vec4)
            gl::EnableVertexAttribArray(3);
            gl::VertexAttribPointer(3, 4, gl::FLOAT, gl::FALSE, size_mat4, ptr::null());
            gl::EnableVertexAttribArray(4);
            gl::VertexAttribPointer(4, 4, gl::FLOAT, gl::FALSE, size_mat4, size_vec4 as *const c_void);
            gl::EnableVertexAttribArray(5);
            gl::VertexAttribPointer(5, 4, gl::FLOAT, gl::FALSE, size_mat4, (2 * size_vec4) as *const c_void);
            gl::EnableVertexAttribArray(6);
            gl::VertexAttribPointer(6, 4, gl::FLOAT, gl::FALSE, size_mat4, (3 * size_vec4) as *const c_void);

            gl::VertexAttribDivisor(3, 1);
            gl::VertexAttribDivisor(4, 1);
            gl::VertexAttribDivisor(5, 1);
            gl::VertexAttribDivisor(6, 1);

            gl::BindVertexArray(0);
        }

        (asteroidShader, planetShader, rock, planet, amount)
    };

    // render loop
    // -----------
    while !window.should_close() {
        // per-frame time logic
        // --------------------
        let currentFrame = glfw.get_time() as f32;
        deltaTime = currentFrame - lastFrame;
        lastFrame = currentFrame;

        // events
        // -----
        process_events(&events, &mut firstMouse, &mut lastX, &mut lastY, &mut camera);

        // input
        // -----
        processInput(&mut window, deltaTime, &mut camera);

        // render
        // ------
        unsafe {
            gl::ClearColor(0.1, 0.1, 0.1, 1.0);
            gl::Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);

            // configure transformation matrices
            let projection: Matrix4<f32> = perspective(Deg(45.0), SCR_WIDTH as f32 / SCR_HEIGHT as f32, 0.1, 1000.0);
            let view = camera.GetViewMatrix();
            asteroidShader.useProgram();
            asteroidShader.setMat4(c_str!("projection"), &projection);
            asteroidShader.setMat4(c_str!("view"), &view);
            planetShader.useProgram();
            planetShader.setMat4(c_str!("projection"), &projection);
            planetShader.setMat4(c_str!("view"), &view);

            // draw planet
            let mut model = Matrix4::<f32>::from_translation(vec3(0.0, -3.0, 0.0));
            model = model * Matrix4::from_scale(4.0);
            planetShader.setMat4(c_str!("model"), &model);
            planet.Draw(&planetShader);

            // draw meteorites
            asteroidShader.useProgram();
            asteroidShader.setInt(c_str!("texture_diffuse1"), 0);
            gl::ActiveTexture(gl::TEXTURE0);
            gl::BindTexture(gl::TEXTURE_2D, rock.textures_loaded[0].id); // note: we also made the textures_loaded vector public (instead of private) from the model class.

            for mesh in &rock.meshes {
                gl::BindVertexArray(mesh.VAO);
                gl::DrawElementsInstanced(gl::TRIANGLES, mesh.indices.len() as i32, gl::UNSIGNED_INT, ptr::null(), amount as i32);
                gl::BindVertexArray(0);
            }
        }

        // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
        // -------------------------------------------------------------------------------
        window.swap_buffers();
        glfw.poll_events();
    }

}
<|endoftext|>