<commit_before>use delivery::git::git_command;
use delivery::utils::copy_recursive;
use delivery::utils::say;
use std::io::prelude::*;
use tempdir::TempDir;
use std::fs::File;
use std::path::Path;
use support::paths::fixture_file;
use std::process::{Command, Output};
use std::env;
use rustc_serialize::json::Json;
use delivery::utils::path_join_many::PathJoinMany;

// ** Functions used in tests **

fn setup() {
    say::turn_off_spinner();
}

/// Sets up a mock delivery git project from the test_repo fixture.
/// Includes copying in the `.delivery/config.json` that you plan
/// on using.
fn setup_mock_delivery_project_git(dot_config: &str) -> TempDir {
    let tmpdir = TempDir::new("mock-delivery-remote").unwrap();
    let test_repo_path = fixture_file("test_repo");
    panic_on_error!(copy_recursive(&test_repo_path.join(".delivery"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&test_repo_path.join("README.md"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&test_repo_path.join("cookbooks"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&fixture_file(dot_config), &tmpdir.path().join_many(&[".delivery", "config.json"])));
    panic_on_error!(git_command(&["init", tmpdir.path().to_str().unwrap()], tmpdir.path()));
    panic_on_error!(git_command(&["add", "."], tmpdir.path()));
    panic_on_error!(git_command(&["commit", "-a", "-m", "Initial Commit"], tmpdir.path()));
    tmpdir
}

/// Given a path, it copies the build cookbook into it, and turns it
/// into a git repository
fn setup_build_cookbook_project(tmpdir: &Path) {
    let build_cookbook_path = fixture_file("delivery_test");
    panic_on_error!(copy_recursive(&build_cookbook_path, &tmpdir.to_path_buf()));
    panic_on_error!(git_command(&["init", tmpdir.join("delivery_test").to_str().unwrap()], &tmpdir.join("delivery_test")));
    panic_on_error!(git_command(&["add", "."], &tmpdir.join("delivery_test")));
    panic_on_error!(git_command(&["commit", "-a", "-m", "Initial Commit"], &tmpdir.join("delivery_test")));
}

/// Clones a mock delivery git project to a local copy, as if it was
/// on a workstation. Also creates a mock delivery remote pointing at
/// the on-disk mocked delivery project.
fn setup_local_project_clone(delivery_project_git: &Path) -> TempDir {
    let tmpdir = TempDir::new("local-project").unwrap();
    panic_on_error!(git_command(&["clone",
                                  delivery_project_git.to_str().unwrap(),
                                  tmpdir.path().to_str().unwrap()
                                 ], tmpdir.path()));
    panic_on_error!(git_command(&["remote", "add", "delivery", delivery_project_git.to_str().unwrap()], tmpdir.path()));
    let mut command = delivery_cmd();
    command.arg("setup")
           .arg("--user").arg("cavalera")
           .arg("--server").arg("localhost")
           .arg("--ent").arg("family")
           .arg("--org").arg("sepultura")
           .arg("--for").arg("master")
           .arg("--config-path").arg(tmpdir.path().to_str().unwrap());
    assert_command_successful(&mut command, &tmpdir);
    tmpdir
}

/// Makes a change to a project on the named branch. Creates a
/// file named `filename` and writes some stuff to it.
///
/// When it returns, the project you pass in will be left on your
/// new branch.
fn setup_change(tmpdir: &TempDir, branch: &str, filename: &str) {
    panic_on_error!(git_command(&["checkout", "master"], tmpdir.path()));
    panic_on_error!(git_command(&["branch", branch], tmpdir.path()));
    {
        let mut f = panic_on_error!(File::create(&tmpdir.path().join(filename)));
        panic_on_error!(f.write_all(b"I like cookies"));
    }
    panic_on_error!(git_command(&["add", filename], tmpdir.path()));
    panic_on_error!(git_command(&["commit", "-a", "-m", filename], tmpdir.path()));
}

/// Checks out the named branch
fn setup_checkout_branch(tmpdir: &TempDir, branch: &str) {
    panic_on_error!(git_command(&["checkout", branch], tmpdir.path()));
}

/// Runs the `Command` in `Dir`, and makes sure it exists with 0
/// Returns the result
fn assert_command_successful(command: &mut Command, dir: &TempDir) -> Output {
    let result = panic_on_error!(command.current_dir(&dir.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed command {:?}\nOUT: {}\nERR: {}\nPath: {}", command, &output, &error, dir.path().to_str().unwrap());
    };
    result
}

/// Same as `assert_command_successful` above, excepts it asserts the command
/// exits with a non-0 status code
fn assert_command_failed(command: &mut Command, dir: &TempDir) -> Output {
    let result = panic_on_error!(command.current_dir(&dir.path()).output());
    if result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Command {:?} should have failed!\nOUT: {}\nERR: {}\nPath: {}", command, &output, &error, dir.path().to_str().unwrap());
    };
    result
}

/// Builds the command to run delivery review
fn delivery_review_command(pipeline: &str) -> Command {
    let mut command = delivery_cmd();
    command.arg("review").arg("--no-open").arg("--for").arg(pipeline);
    command
}

/// Builds the command to run a sample job
fn delivery_verify_command(job_root: &TempDir) -> Command {
    let mut command = delivery_cmd();
    command.arg("job")
           .arg("verify")
           .arg("unit")
           .arg("--no-spinner")
           .arg("--job-root").arg(job_root.path().to_str().unwrap());
    command
}

/// Calls delivery review, and creates the two stub branches that the
/// api would create (`_reviews/PIPELINE/BRANCH/1` and `_reviews/PIPELINE/BRANCH/latest`)
fn delivery_review(local: &TempDir, remote: &TempDir, branch: &str, pipeline: &str) {
    panic_on_error!(git_command(&["checkout", branch], local.path()));
    let mut command = delivery_review_command(pipeline);
    assert_command_successful(&mut command, local);

    // Stub out the behavior of the delivery-api
    panic_on_error!(git_command(&["branch", &format!("_reviews/{}/{}/1", pipeline, branch)], remote.path()));
    panic_on_error!(git_command(&["branch", &format!("_reviews/{}/{}/latest", pipeline, branch)], remote.path()));
}

/// Returns a Command set to the delivery binary created when you
/// ran `cargo test`.
fn delivery_cmd() -> Command {
    let mut delivery_path = env::current_exe().unwrap();
    delivery_path.pop();
    Command::new(delivery_path.join("delivery").to_str().unwrap())
}

/// A handy debugging function. Insert it when you want to sleep,
/// pass it a tmpdir, and you can inspect it.
///
/// Make sure you run `cargo test -- --nocapture` to see the output.
#[allow(dead_code)]
fn debug_sleep(tmpdir: &TempDir) {
    println!("Sleeping for 1000 seconds for {:?}", tmpdir.path());
    panic_on_error!(Command::new("sleep").arg("1000").output());
}

// ** Actual tests **

// Tests `delivery review`. Fails if the command fails, or if we fail to create
// the remote branch _for/master/rust/test, which is what we need to push to
// the API server.
test!(review {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    setup_change(&local_project, "rust/test", "freaky");
    delivery_review(&local_project, &delivery_project_git, "rust/test", "master");
    setup_checkout_branch(&delivery_project_git, "_for/master/rust/test");
});

test!(review_with_a_v1_config {
    let delivery_project_git = setup_mock_delivery_project_git("v1_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    setup_change(&local_project, "rust/test", "freaky");
    delivery_review(&local_project, &delivery_project_git, "rust/test", "master");
    setup_checkout_branch(&delivery_project_git, "_for/master/rust/test");
});

test!(review_without_dependencies {
    let delivery_project_git = setup_mock_delivery_project_git("no_deps_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    setup_change(&local_project, "rust/test", "freaky");
    delivery_review(&local_project, &delivery_project_git, "rust/test", "master");
    setup_checkout_branch(&delivery_project_git, "_for/master/rust/test");
});

test!(review_with_an_invalid_config {
    let delivery_project_git = setup_mock_delivery_project_git("invalid_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    setup_change(&local_project, "rust/test", "freaky");
    let mut command = delivery_review_command("rust/test");
    assert_command_failed(&mut command, &local_project);
});

test!(job_verify_unit_with_path_config {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let mut command = delivery_verify_command(&job_root);
    assert_command_successful(&mut command, &local_project);
});

test!(job_verify_unit_with_git_config {
    let delivery_project_git = setup_mock_delivery_project_git("git_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    let job_root = TempDir::new("job-root").unwrap();
    setup_build_cookbook_project(&job_root.path());
    setup_change(&local_project, "rust/test", "freaky");
    let mut command = delivery_verify_command(&job_root);
    assert_command_successful(&mut command, &local_project);
});

// TODO: This test requires internet access... we should move it out
// into an Acceptance-stage test instead of here in unit tests. It's
// impossible to run on a plane, for instance :(
test!(job_verify_unit_with_supermarket_config {
    let delivery_project_git = setup_mock_delivery_project_git("supermarket_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let mut command = delivery_verify_command(&job_root);
    assert_command_failed(&mut command, &local_project);
    assert!(job_root.path().join_many(&["chef", "cookbooks", "httpd"]).is_dir());
    assert!(job_root.path().join_many(&["chef", "cookbooks", "httpd", "templates", "default", "magic.erb"]).is_file());
});

test!(job_verify_dna_json {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project, "rust/test", "freaky");
    let mut command = delivery_verify_command(&job_root);
    assert_command_successful(&mut command, &local_project);
    let mut dna_file = panic_on_error!(File::open(&job_root.path().join_many(&["chef", "dna.json"])));
    let mut dna_json = String::new();
    panic_on_error!(dna_file.read_to_string(&mut dna_json));
    let dna_data = panic_on_error!(Json::from_str(&dna_json));
    match dna_data.find_path(&["delivery", "workspace", "repo"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("repo").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/repo, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "chef"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("chef").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/chef, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "cache"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("cache").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/cache, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "root"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().to_str().unwrap());
        },
        None => panic!("No delivery/workspace/root, {}", dna_data)
    };
    match dna_data.find_path(&["delivery_builder", "build_user"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), "dbuild");
        },
        None => panic!("No delivery_builderl/build_user, {}", dna_data)
    };
});
<commit_msg>Take Path not TempDir in setup_change<commit_after>use delivery::git::git_command;
use delivery::utils::copy_recursive;
use delivery::utils::say;
use std::io::prelude::*;
use tempdir::TempDir;
use std::fs::File;
use std::path::Path;
use support::paths::fixture_file;
use std::process::{Command, Output};
use std::env;
use rustc_serialize::json::Json;
use delivery::utils::path_join_many::PathJoinMany;

// ** Functions used in tests **

fn setup() {
    say::turn_off_spinner();
}

/// Sets up a mock delivery git project from the test_repo fixture.
/// Includes copying in the `.delivery/config.json` that you plan
/// on using.
fn setup_mock_delivery_project_git(dot_config: &str) -> TempDir {
    let tmpdir = TempDir::new("mock-delivery-remote").unwrap();
    let test_repo_path = fixture_file("test_repo");
    panic_on_error!(copy_recursive(&test_repo_path.join(".delivery"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&test_repo_path.join("README.md"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&test_repo_path.join("cookbooks"), &tmpdir.path().to_path_buf()));
    panic_on_error!(copy_recursive(&fixture_file(dot_config), &tmpdir.path().join_many(&[".delivery", "config.json"])));
    panic_on_error!(git_command(&["init", tmpdir.path().to_str().unwrap()], tmpdir.path()));
    panic_on_error!(git_command(&["add", "."], tmpdir.path()));
    panic_on_error!(git_command(&["commit", "-a", "-m", "Initial Commit"], tmpdir.path()));
    tmpdir
}

/// Given a path, it copies the build cookbook into it, and turns it
/// into a git repository
fn setup_build_cookbook_project(tmpdir: &Path) {
    let build_cookbook_path = fixture_file("delivery_test");
    panic_on_error!(copy_recursive(&build_cookbook_path, &tmpdir.to_path_buf()));
    panic_on_error!(git_command(&["init", tmpdir.join("delivery_test").to_str().unwrap()], &tmpdir.join("delivery_test")));
    panic_on_error!(git_command(&["add", "."], &tmpdir.join("delivery_test")));
    panic_on_error!(git_command(&["commit", "-a", "-m", "Initial Commit"], &tmpdir.join("delivery_test")));
}

/// Clones a mock delivery git project to a local copy, as if it was
/// on a workstation. Also creates a mock delivery remote pointing at
/// the on-disk mocked delivery project.
fn setup_local_project_clone(delivery_project_git: &Path) -> TempDir {
    let tmpdir = TempDir::new("local-project").unwrap();
    panic_on_error!(git_command(&["clone",
                                  delivery_project_git.to_str().unwrap(),
                                  tmpdir.path().to_str().unwrap()
                                 ], tmpdir.path()));
    panic_on_error!(git_command(&["remote", "add", "delivery", delivery_project_git.to_str().unwrap()], tmpdir.path()));
    let mut command = delivery_cmd();
    command.arg("setup")
           .arg("--user").arg("cavalera")
           .arg("--server").arg("localhost")
           .arg("--ent").arg("family")
           .arg("--org").arg("sepultura")
           .arg("--for").arg("master")
           .arg("--config-path").arg(tmpdir.path().to_str().unwrap());
    assert_command_successful(&mut command, &tmpdir);
    tmpdir
}

/// Makes a change to a project on the named branch. Creates a
/// file named `filename` and writes some stuff to it.
///
/// When it returns, the project you pass in will be left on your
/// new branch.
fn setup_change(tmpdir: &Path, branch: &str, filename: &str) {
    panic_on_error!(git_command(&["checkout", "master"], tmpdir));
    panic_on_error!(git_command(&["branch", branch], tmpdir));
    {
        let mut f = panic_on_error!(File::create(&tmpdir.join(filename)));
        panic_on_error!(f.write_all(b"I like cookies"));
    }
    panic_on_error!(git_command(&["add", filename], tmpdir));
    panic_on_error!(git_command(&["commit", "-a", "-m", filename], tmpdir));
}

/// Checks out the named branch
fn setup_checkout_branch(tmpdir: &TempDir, branch: &str) {
    panic_on_error!(git_command(&["checkout", branch], tmpdir.path()));
}

/// Runs the `Command` in `Dir`, and makes sure it exists with 0
/// Returns the result
fn assert_command_successful(command: &mut Command, dir: &TempDir) -> Output {
    let result = panic_on_error!(command.current_dir(&dir.path()).output());
    if ! result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Failed command {:?}\nOUT: {}\nERR: {}\nPath: {}", command, &output, &error, dir.path().to_str().unwrap());
    };
    result
}

/// Same as `assert_command_successful` above, excepts it asserts the command
/// exits with a non-0 status code
fn assert_command_failed(command: &mut Command, dir: &TempDir) -> Output {
    let result = panic_on_error!(command.current_dir(&dir.path()).output());
    if result.status.success() {
        let output = String::from_utf8_lossy(&result.stdout);
        let error = String::from_utf8_lossy(&result.stderr);
        panic!("Command {:?} should have failed!\nOUT: {}\nERR: {}\nPath: {}", command, &output, &error, dir.path().to_str().unwrap());
    };
    result
}

/// Builds the command to run delivery review
fn delivery_review_command(pipeline: &str) -> Command {
    let mut command = delivery_cmd();
    command.arg("review").arg("--no-open").arg("--for").arg(pipeline);
    command
}

/// Builds the command to run a sample job
fn delivery_verify_command(job_root: &TempDir) -> Command {
    let mut command = delivery_cmd();
    command.arg("job")
           .arg("verify")
           .arg("unit")
           .arg("--no-spinner")
           .arg("--job-root").arg(job_root.path().to_str().unwrap());
    command
}

/// Calls delivery review, and creates the two stub branches that the
/// api would create (`_reviews/PIPELINE/BRANCH/1` and `_reviews/PIPELINE/BRANCH/latest`)
fn delivery_review(local: &TempDir, remote: &TempDir, branch: &str, pipeline: &str) {
    panic_on_error!(git_command(&["checkout", branch], local.path()));
    let mut command = delivery_review_command(pipeline);
    assert_command_successful(&mut command, local);

    // Stub out the behavior of the delivery-api
    panic_on_error!(git_command(&["branch", &format!("_reviews/{}/{}/1", pipeline, branch)], remote.path()));
    panic_on_error!(git_command(&["branch", &format!("_reviews/{}/{}/latest", pipeline, branch)], remote.path()));
}

/// Returns a Command set to the delivery binary created when you
/// ran `cargo test`.
fn delivery_cmd() -> Command {
    let mut delivery_path = env::current_exe().unwrap();
    delivery_path.pop();
    Command::new(delivery_path.join("delivery").to_str().unwrap())
}

/// A handy debugging function. Insert it when you want to sleep,
/// pass it a tmpdir, and you can inspect it.
///
/// Make sure you run `cargo test -- --nocapture` to see the output.
#[allow(dead_code)]
fn debug_sleep(tmpdir: &TempDir) {
    println!("Sleeping for 1000 seconds for {:?}", tmpdir.path());
    panic_on_error!(Command::new("sleep").arg("1000").output());
}

// ** Actual tests **

// Tests `delivery review`. Fails if the command fails, or if we fail to create
// the remote branch _for/master/rust/test, which is what we need to push to
// the API server.
test!(review {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    setup_change(&local_project.path(), "rust/test", "freaky");
    delivery_review(&local_project, &delivery_project_git, "rust/test", "master");
    setup_checkout_branch(&delivery_project_git, "_for/master/rust/test");
});

test!(review_with_a_v1_config {
    let delivery_project_git = setup_mock_delivery_project_git("v1_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    setup_change(&local_project.path(), "rust/test", "freaky");
    delivery_review(&local_project, &delivery_project_git, "rust/test", "master");
    setup_checkout_branch(&delivery_project_git, "_for/master/rust/test");
});

test!(review_without_dependencies {
    let delivery_project_git = setup_mock_delivery_project_git("no_deps_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    setup_change(&local_project.path(), "rust/test", "freaky");
    delivery_review(&local_project, &delivery_project_git, "rust/test", "master");
    setup_checkout_branch(&delivery_project_git, "_for/master/rust/test");
});

test!(review_with_an_invalid_config {
    let delivery_project_git = setup_mock_delivery_project_git("invalid_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    setup_change(&local_project.path(), "rust/test", "freaky");
    let mut command = delivery_review_command("rust/test");
    assert_command_failed(&mut command, &local_project);
});

test!(job_verify_unit_with_path_config {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project.path(), "rust/test", "freaky");
    let mut command = delivery_verify_command(&job_root);
    assert_command_successful(&mut command, &local_project);
});

test!(job_verify_unit_with_git_config {
    let delivery_project_git = setup_mock_delivery_project_git("git_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    let job_root = TempDir::new("job-root").unwrap();
    setup_build_cookbook_project(&job_root.path());
    setup_change(&local_project.path(), "rust/test", "freaky");
    let mut command = delivery_verify_command(&job_root);
    assert_command_successful(&mut command, &local_project);
});

// TODO: This test requires internet access... we should move it out
// into an Acceptance-stage test instead of here in unit tests. It's
// impossible to run on a plane, for instance :(
test!(job_verify_unit_with_supermarket_config {
    let delivery_project_git = setup_mock_delivery_project_git("supermarket_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project.path(), "rust/test", "freaky");
    let mut command = delivery_verify_command(&job_root);
    assert_command_failed(&mut command, &local_project);
    assert!(job_root.path().join_many(&["chef", "cookbooks", "httpd"]).is_dir());
    assert!(job_root.path().join_many(&["chef", "cookbooks", "httpd", "templates", "default", "magic.erb"]).is_file());
});

test!(job_verify_dna_json {
    let delivery_project_git = setup_mock_delivery_project_git("path_config.json");
    let local_project = setup_local_project_clone(&delivery_project_git.path());
    let job_root = TempDir::new("job-root").unwrap();
    setup_change(&local_project.path(), "rust/test", "freaky");
    let mut command = delivery_verify_command(&job_root);
    assert_command_successful(&mut command, &local_project);
    let mut dna_file = panic_on_error!(File::open(&job_root.path().join_many(&["chef", "dna.json"])));
    let mut dna_json = String::new();
    panic_on_error!(dna_file.read_to_string(&mut dna_json));
    let dna_data = panic_on_error!(Json::from_str(&dna_json));
    match dna_data.find_path(&["delivery", "workspace", "repo"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("repo").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/repo, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "chef"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("chef").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/chef, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "cache"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().join("cache").to_str().unwrap());
        },
        None => panic!("No delivery/workspace/cache, {}", dna_data)
    };
    match dna_data.find_path(&["delivery", "workspace", "root"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), job_root.path().to_str().unwrap());
        },
        None => panic!("No delivery/workspace/root, {}", dna_data)
    };
    match dna_data.find_path(&["delivery_builder", "build_user"]) {
        Some(data) => {
            assert!(data.is_string());
            assert_eq!(data.as_string().unwrap(), "dbuild");
        },
        None => panic!("No delivery_builderl/build_user, {}", dna_data)
    };
});
<|endoftext|>


<commit_before>//! Contains test for all types supporting `bind_parameter`
//!
//! These tests assume there is a Stage table with a Varchar in 'A', an Integer in 'B' and a Real
//! in 'C'
extern crate odbc;
use odbc::*;

#[test]
#[ignore]
/// tested in windows中文版 codepage 936
fn _exec_direct() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    // select '你好' as hello
    if let Ok(Data(mut stmt)) = stmt.exec_direct_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32].as_slice()) {
        while let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),  // when  你好 is encoded by gbk, it is [196, 227, 186, 195]
                None => panic!(" NULL"),
            }
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
#[ignore]
/// tested in windows中文版 codepage 936
fn _prepare_1() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select '你好' as hello where 1 = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 32, 49, 32, 61, 32, 63, 32].as_slice()).unwrap();
    let stmt = stmt.bind_parameter(1, &1).unwrap();

    match stmt.execute().unwrap() {
        Data(mut stmt) => {
            while let Some(mut cursor) = stmt.fetch().unwrap() {
                match cursor.get_data::<Vec<u8>>(1).unwrap() {
                    Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),
                    None => panic!(" NULL"),
                }
            }
        }
        NoData(_) => {
            panic!("SELECT did not return result set");
        }
    }

}

#[test]
#[ignore]
/// tested in windows中文版 codepage 936
fn _prepare_2() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "sa", "123456").unwrap();
    // select '你好' as hello where '你好' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 32, 39, 196, 227, 186, 195, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    // bind  gbk encoded byte
    let param = vec![196u8, 227u8, 186u8, 195u8];
    let stmt = stmt.bind_parameter(1, &param).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        while let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),
                None => panic!(" NULL"),
            }
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
fn exec_direct() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    // select 'hello'
    if let Ok(Data(mut stmt)) = stmt.exec_direct_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32].as_slice()) {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),  // when  hello is encoded by utf8, it is [104, 101, 108, 108, 111]
                None => panic!(" NULL"),
            }
        } else {
            panic!("No Data");
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
fn prepare_1() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select 'hello' where 'hello' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32, 119, 104, 101, 114, 101, 32, 39, 104, 101, 108, 108, 111, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    let stmt = stmt.bind_parameter(1, &"hello").unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data");
        }
    } else {
        panic!("SELECT did not return result set");
    }

}

#[test]
fn prepare_2() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select 'hello' where 'hello' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32, 119, 104, 101, 114, 101, 32, 39, 104, 101, 108, 108, 111, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    // bind  utf encoded byte
    let param: Vec<u8> = vec![104, 101, 108, 108, 111];
    let stmt = stmt.bind_parameter(1, &param).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data");
        }
    } else {
        panic!("SELECT did not return result set");
    }
}
<commit_msg>add customOdbcType for bindParameter with none utf8 bytes<commit_after>//! Contains test for all types supporting `bind_parameter`
//!
//! These tests assume there is a Stage table with a Varchar in 'A', an Integer in 'B' and a Real
//! in 'C'
extern crate odbc;
use odbc::*;

#[test]
#[ignore]
/// tested in windows中文版 codepage 936
fn _exec_direct() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    // select '你好' as hello
    if let Ok(Data(mut stmt)) = stmt.exec_direct_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32].as_slice()) {
        while let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),  // when  你好 is encoded by gbk, it is [196, 227, 186, 195]
                None => panic!(" NULL"),
            }
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
#[ignore]
/// tested in windows中文版 codepage 936
fn _prepare_1() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select '你好' as hello where 1 = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 196, 227, 186, 195, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 32, 49, 32, 61, 32, 63, 32].as_slice()).unwrap();
    let stmt = stmt.bind_parameter(1, &1).unwrap();

    match stmt.execute().unwrap() {
        Data(mut stmt) => {
            while let Some(mut cursor) = stmt.fetch().unwrap() {
                match cursor.get_data::<Vec<u8>>(1).unwrap() {
                    Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),
                    None => panic!(" NULL"),
                }
            }
        }
        NoData(_) => {
            panic!("SELECT did not return result set");
        }
    }

}

#[test]
//#[ignore]
/// tested in windows中文版 codepage 936
fn _prepare_2() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "sa", "123456").unwrap();
    // select '你好' as hello where '你好' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 228, 189, 160, 229, 165, 189, 39, 32, 97, 115, 32, 104, 101, 108, 108, 111, 32, 119, 104, 101, 114, 101, 32, 39, 228, 189, 160, 229, 165, 189, 39, 32, 61, 32, 63].as_slice()).unwrap();
    // bind  gbk encoded byte
    let param = CustomOdbcType {
        data: &[228, 189, 160, 229, 165, 189]
    };
    let stmt = stmt.bind_parameter(1, &param).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![196, 227, 186, 195]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data")
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
fn exec_direct() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    let stmt = Statement::with_parent(&conn).unwrap();

    // select 'hello'
    if let Ok(Data(mut stmt)) = stmt.exec_direct_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32].as_slice()) {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),  // when  hello is encoded by utf8, it is [104, 101, 108, 108, 111]
                None => panic!(" NULL"),
            }
        } else {
            panic!("No Data");
        }
    } else {
        panic!("SELECT did not return result set");
    }
}

#[test]
fn prepare_1() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select 'hello' where 'hello' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32, 119, 104, 101, 114, 101, 32, 39, 104, 101, 108, 108, 111, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    let stmt = stmt.bind_parameter(1, &"hello").unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data");
        }
    } else {
        panic!("SELECT did not return result set");
    }

}

/// CustomOdbcType  for bindParameter
struct CustomOdbcType<'a> {
    data: &'a [u8],
}

unsafe impl<'a> OdbcType<'a> for CustomOdbcType<'a> {
    fn sql_data_type() -> ffi::SqlDataType {
        ffi::SQL_VARCHAR
    }
    fn c_data_type() -> ffi::SqlCDataType {
        ffi::SQL_C_CHAR
    }

    fn convert(buffer: &'a [u8]) -> Self {
        CustomOdbcType {
            data: buffer
        }
    }

    fn column_size(&self) -> ffi::SQLULEN {
        self.data.len() as ffi::SQLULEN
    }

    fn value_ptr(&self) -> ffi::SQLPOINTER {
        self.data.as_ptr() as *const Self as ffi::SQLPOINTER
    }
}

#[test]
fn prepare_2() {
    let env = create_environment_v3().unwrap();
    let conn = env.connect("TestDataSource", "", "").unwrap();
    // select 'hello' where 'hello' = ?
    let stmt = Statement::with_parent(&conn).unwrap().prepare_bytes(vec![115, 101, 108, 101, 99, 116, 32, 39, 104, 101, 108, 108, 111, 39, 32, 119, 104, 101, 114, 101, 32, 39, 104, 101, 108, 108, 111, 39, 32, 61, 32, 63, 32].as_slice()).unwrap();
    // bind  utf encoded byte
//    let param: Vec<u8> = vec![104, 101, 108, 108, 111];
    let param = CustomOdbcType {
        data: &[104, 101, 108, 108, 111]
    };
    let stmt = stmt.bind_parameter(1, &param).unwrap();

    if let Ok(Data(mut stmt)) = stmt.execute() {
        if let Some(mut cursor) = stmt.fetch().unwrap() {
            match cursor.get_data::<Vec<u8>>(1).unwrap() {
                Some(val) => assert_eq!(val, vec![104, 101, 108, 108, 111]),
                None => panic!(" NULL"),
            }
        } else {
            panic!("No data");
        }
    } else {
        panic!("SELECT did not return result set");
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate arrayfire as af;

use std::error::Error;
use std::thread;
use std::time::Duration;
use af::*;

macro_rules! implement_handler {
    ($fn_name:ident, $msg: expr) => (

        pub fn $fn_name(error_code: AfError) {
            println!("{:?}", $msg);
            match error_code {
                AfError::SUCCESS => {}, /* No-op */
                _ => panic!("Error message: {}", error_code.description()),
            }
        }

    )
}

implement_handler!(handler_sample1, "Error Handler Sample1");
implement_handler!(handler_sample2, "Error Handler Sample2");
implement_handler!(handler_sample3, "Error Handler Sample3");
implement_handler!(handler_sample4, "Error Handler Sample4");

pub const HANDLE1: Callback<'static> = Callback{ cb: &handler_sample1};
pub const HANDLE2: Callback<'static> = Callback{ cb: &handler_sample2};
pub const HANDLE3: Callback<'static> = Callback{ cb: &handler_sample3};
pub const HANDLE4: Callback<'static> = Callback{ cb: &handler_sample4};

#[allow(unused_must_use)]
#[test]
fn check_error_handler_mutation() {

    for i in 0..4 {
        thread::Builder::new().name(format!("child {}",i+1).to_string()).spawn(move || {
            println!("{:?}", thread::current());
            match i {
                0 => register_error_handler(HANDLE1),
                1 => register_error_handler(HANDLE2),
                2 => register_error_handler(HANDLE3),
                3 => register_error_handler(HANDLE4),
                _ => panic!("Impossible scenario"),
            }
        });
    }

    af::info();
    thread::sleep(Duration::from_millis(50));

}
<commit_msg>Remove unused declaration from tests<commit_after>extern crate arrayfire as af;

use std::error::Error;
use std::thread;
use std::time::Duration;
use af::*;

macro_rules! implement_handler {
    ($fn_name:ident, $msg: expr) => (

        pub fn $fn_name(error_code: AfError) {
            println!("{:?}", $msg);
            match error_code {
                AfError::SUCCESS => {}, /* No-op */
                _ => panic!("Error message: {}", error_code.description()),
            }
        }

    )
}

implement_handler!(handler_sample1, "Error Handler Sample1");
implement_handler!(handler_sample2, "Error Handler Sample2");
implement_handler!(handler_sample3, "Error Handler Sample3");
implement_handler!(handler_sample4, "Error Handler Sample4");

pub const HANDLE1: Callback<'static> = Callback{ cb: &handler_sample1};
pub const HANDLE2: Callback<'static> = Callback{ cb: &handler_sample2};
pub const HANDLE3: Callback<'static> = Callback{ cb: &handler_sample3};
pub const HANDLE4: Callback<'static> = Callback{ cb: &handler_sample4};

#[allow(unused_must_use)]
#[test]
fn check_error_handler_mutation() {

    for i in 0..4 {
        thread::Builder::new().name(format!("child {}",i+1).to_string()).spawn(move || {
            println!("{:?}", thread::current());
            match i {
                0 => register_error_handler(HANDLE1),
                1 => register_error_handler(HANDLE2),
                2 => register_error_handler(HANDLE3),
                3 => register_error_handler(HANDLE4),
                _ => panic!("Impossible scenario"),
            }
        });
    }

    af::info();
    thread::sleep(Duration::from_millis(50));

}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{HexDisplay,IResult,FlatMapper,Mapper,Mapper2,Producer,ProducerState,FileProducer};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;

fn mp4_box(input:&[u8]) -> IResult<&[u8], &[u8]> {

  take!(offset_parser 4);
  match offset_parser(input) {
    Done(i, offset_bytes) => {
      let offset:u32 = (offset_bytes[3] as u32) + (offset_bytes[2] as u32) * 0x100 + (offset_bytes[1] as u32) * 0x10000 + (offset_bytes[0] as u32) * 0x1000000;
      let sz: usize = offset as usize;
      //println!("box size: {} -> {} (input: {})", offset_bytes.to_hex(8), sz, i.len());
      if i.len() >= sz - 4 {
        return Done(&i[(sz-4)..], &i[0..(sz-4)])
      } else {
        return Incomplete(1234)
      }
    },
    e => e
  }
}

#[derive(PartialEq,Eq,Debug)]
struct FileType<'a> {
  major_brand:         &'a str,
  major_brand_version: &'a [u8],
  compatible_brands:   Vec<&'a str>
}

#[derive(PartialEq,Eq,Debug)]
pub struct Mvhd1 {
  version:       u8,
  flags:         u32,
  created_date:  u32,
  modified_date: u32
}

#[derive(PartialEq,Eq,Debug)]
pub struct Mvhd2 {
  created_date:  u64,
  modified_date: u64,
  scale:         u32,
  duration:      u32
}

/*
#[derive(PartialEq,Eq,Debug)]
struct Mvhd3 {
  duration:      u64,
  speed:         f32,
  volume:        f32, // 2 bytes
*/
  /* 10 bytes reserved */
/*  scaleA:        f32,
  rotateB:       f32,
  angleU:        f32,
  rotateC:       f32,
  scaleD:        f32,
  angleV:        f32,
  positionX:     f32,
  positionY:     f32,
  scaleW:        f32,
  preview:       u64,
  poster:        u32,
  selection:     u64,
  current_time:  u32,
  track_id:      u32
}*/

#[derive(PartialEq,Eq,Debug)]
pub enum MvhdBox {
  M1(Mvhd1),
  M2(Mvhd2),
  M3
  /*M3(Mvhd3)*/
}

#[derive(PartialEq,Eq,Debug)]
pub enum MoovBox {
  Mdra,
  Dref,
  Cmov,
  Rmra,
  Iods,
  Mvhd,
  Clip,
  Trak,
  Udta
}

#[derive(PartialEq,Eq,Debug)]
enum MP4Box<'a> {
  Ftyp(FileType<'a>),
  Moov(Vec<MoovBox>),
  Mdat,
  Free,
  Skip,
  Wide,
  Unknown
}

take!(offset 4);
tag!(ftyp    "ftyp".as_bytes());

fn brand_name(input:&[u8]) -> IResult<&[u8],&str> {
  take!(major_brand_bytes 4);
  major_brand_bytes(input).map_res(str::from_utf8)
}
take!(major_brand_version 4);
many0!(compatible_brands<&[u8], &str> brand_name);

fn filetype_parser<'a>(input: &'a[u8]) -> IResult<&'a [u8], FileType<'a> > {
  chaining_parser!(input, ||{FileType{major_brand: m, major_brand_version:v, compatible_brands: c}},
    m: brand_name,
    v: major_brand_version,
    c: compatible_brands,)
}

o!(filetype <&[u8], FileType>  ftyp ~ [ filetype_parser ]);

fn filetype_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match filetype(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)    => {
      Done(i, MP4Box::Ftyp(o))
    }
  }
}

tag!(moov_tag "moov".as_bytes());

tag!(mdra    "mdra".as_bytes());
fn moov_mdra(input:&[u8]) -> IResult<&[u8], MoovBox> {
  mdra(input).map(|o| MoovBox::Mdra)
}

tag!(dref    "dref".as_bytes());
fn moov_dref(input:&[u8]) -> IResult<&[u8], MoovBox> {
  dref(input).map(|o| MoovBox::Dref)
}

tag!(cmov    "cmov".as_bytes());
fn moov_cmov(input:&[u8]) -> IResult<&[u8], MoovBox> {
  cmov(input).map(|o| MoovBox::Cmov)
}

tag!(rmra    "rmra".as_bytes());
fn moov_rmra(input:&[u8]) -> IResult<&[u8], MoovBox> {
  rmra(input).map(|o| MoovBox::Rmra)
}

tag!(iods    "iods".as_bytes());
fn moov_iods(input:&[u8]) -> IResult<&[u8], MoovBox> {
  iods(input).map(|o| MoovBox::Iods)
}

tag!(mvhd    "mvhd".as_bytes());
fn moov_mvhd(input:&[u8]) -> IResult<&[u8], MoovBox> {
  mvhd(input).map(|o| MoovBox::Mvhd)
  /*let res = mvhd(input).map(|o| MoovBox::Mvhd);
  match res {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)    => {
      println!("MVHD box content:\n{}", i.to_hex(8));
      Done(i,o)
    }
  }*/
}

tag!(clip    "clip".as_bytes());
fn moov_clip(input:&[u8]) -> IResult<&[u8], MoovBox> {
  clip(input).map(|o| MoovBox::Clip)
}

tag!(trak    "trak".as_bytes());
fn moov_trak(input:&[u8]) -> IResult<&[u8], MoovBox> {
  trak(input).map(|o| MoovBox::Trak)
}

tag!(udta   "udta".as_bytes());
fn moov_udta(input:&[u8]) -> IResult<&[u8], MoovBox> {
  udta(input).map(|o| MoovBox::Udta)
}

alt!(moov_internal<&[u8], MoovBox>, moov_mdra | moov_dref | moov_cmov |
     moov_rmra | moov_iods | moov_mvhd | moov_clip | moov_trak | moov_udta);

fn moov(input:&[u8]) -> IResult<&[u8], MoovBox> {
  match mp4_box(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)    => {
      match moov_internal(o) {
        Error(a)      => Error(a),
        Incomplete(a) => Incomplete(a),
        Done(i2, o2)  => {
          Done(i, o2)
        }

      }
    }
  }
}

many0!(moov_many<&[u8],MoovBox> moov);

o!(moov_box_internal <&[u8], Vec<MoovBox> >  moov_tag ~ [ moov_many ]);
fn moov_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match moov_box_internal(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)  => {
      Done(i, MP4Box::Moov(o))
    }
  }
}

tag!(mdat    "mdat".as_bytes());
fn mdat_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match mdat(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, _)    => {
      Done(i, MP4Box::Mdat)
    }
  }
}
tag!(free    "free".as_bytes());
fn free_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match free(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, _)    => {
      Done(i, MP4Box::Free)
    }
  }
}

tag!(skip    "skip".as_bytes());
fn skip_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match free(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, _)    => {
      Done(i, MP4Box::Skip)
    }
  }
}

tag!(wide    "wide".as_bytes());
fn wide_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match free(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, _)    => {
      Done(i, MP4Box::Wide)
    }
  }
}

fn unknown_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  println!("calling UNKNOWN");
  Done(input, MP4Box::Unknown)
}

alt!(box_parser_internal<&[u8], MP4Box>, filetype_box | moov_box | mdat_box | free_box | skip_box | wide_box | unknown_box);
fn box_parser(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match mp4_box(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)    => {
      match box_parser_internal(o) {
        Error(a)      => Error(a),
        Incomplete(a) => Incomplete(a),
        Done(i2, o2)  => {
          Done(i, o2)
        }
      }
    }
  }
}

fn data_interpreter(bytes:&[u8]) -> IResult<&[u8], ()> {
  //println!("bytes:\n{}", bytes.to_hex(8));
  match box_parser(bytes) {
    Done(i, o) => {
      match o {
        MP4Box::Ftyp(f) => println!("-> FTYP: {:?}", f),
        MP4Box::Moov(m) => {println!("-> MOOV: {:?}", m); println!("remaining:\n{}", i.to_hex(8))},
        MP4Box::Mdat    => println!("-> MDAT"),
        MP4Box::Free    => println!("-> FREE"),
        MP4Box::Skip    => println!("-> SKIP"),
        MP4Box::Wide    => println!("-> WIDE"),
        MP4Box::Unknown => println!("-> UNKNOWN")
      }
      //println!("remaining:\n{}", i.to_hex(8));
      Done(i,())
    },
    Error(a) => {
      println!("mp4 parsing error: {:?}", a);
      Error(a)
    },
    Incomplete(a) => {
      println!("incomplete: {:?}", a);
      Incomplete(a)
    }
  }
}

fn multiple_data_interpreter(bytes:&[u8]) -> IResult<&[u8], ()> {
  match data_interpreter(bytes) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, ())   => {
      println!("NEXT BOX");
      match data_interpreter(i) {
        Error(a)      => Error(a),
        Incomplete(a) => Incomplete(a),
        Done(i2,())   => {
          println!("NEXT BOX 2");
          match data_interpreter(i2) {
            Error(a)      => Error(a),
            Incomplete(a) => Incomplete(a),
            Done(i3,())   => {
              println!("NEXT BOX 3");
              match data_interpreter(i3) {
                Error(a)      => Error(a),
                Incomplete(a) => Incomplete(a),
                Done(i4,())   => {
                  println!("NEXT BOX 4");
                  let res = data_interpreter(i4);
                  println!("res4: {:?}", res);
                  res
                }
              }
            }
          }
        }
      }
    },
  }
}

many0!(full_data_interpreter<&[u8],()> data_interpreter);

fn parse_mp4_file(filename: &str) {
  FileProducer::new(filename, 40000).map(|producer: FileProducer| {
    let mut p = producer;
    match p.produce() {
      ProducerState::Data(bytes) => {
        multiple_data_interpreter(bytes);
      },
      _ => println!("got error")
    }
    /*
    pusher!(ps, full_data_interpreter);
    ps(&mut p);
    */
    //assert!(false);
  });

}
#[test]
fn file_test() {
  parse_mp4_file("small.mp4");
}
#[test]
fn bunny_test() {
  parse_mp4_file("bigbuckbunny.mp4");
}
<commit_msg>simplify code by using map and flat_map<commit_after>#[macro_use]
extern crate nom;

use nom::{HexDisplay,IResult,FlatMapper,Mapper,Mapper2,Producer,ProducerState,FileProducer};
use nom::IResult::*;

use std::str;
use std::collections::HashMap;

fn mp4_box(input:&[u8]) -> IResult<&[u8], &[u8]> {

  take!(offset_parser 4);
  match offset_parser(input) {
    Done(i, offset_bytes) => {
      let offset:u32 = (offset_bytes[3] as u32) + (offset_bytes[2] as u32) * 0x100 + (offset_bytes[1] as u32) * 0x10000 + (offset_bytes[0] as u32) * 0x1000000;
      let sz: usize = offset as usize;
      //println!("box size: {} -> {} (input: {})", offset_bytes.to_hex(8), sz, i.len());
      if i.len() >= sz - 4 {
        return Done(&i[(sz-4)..], &i[0..(sz-4)])
      } else {
        return Incomplete(1234)
      }
    },
    e => e
  }
}

#[derive(PartialEq,Eq,Debug)]
struct FileType<'a> {
  major_brand:         &'a str,
  major_brand_version: &'a [u8],
  compatible_brands:   Vec<&'a str>
}

#[derive(PartialEq,Eq,Debug)]
pub struct Mvhd1 {
  version:       u8,
  flags:         u32,
  created_date:  u32,
  modified_date: u32
}

#[derive(PartialEq,Eq,Debug)]
pub struct Mvhd2 {
  created_date:  u64,
  modified_date: u64,
  scale:         u32,
  duration:      u32
}

/*
#[derive(PartialEq,Eq,Debug)]
struct Mvhd3 {
  duration:      u64,
  speed:         f32,
  volume:        f32, // 2 bytes
*/
  /* 10 bytes reserved */
/*  scaleA:        f32,
  rotateB:       f32,
  angleU:        f32,
  rotateC:       f32,
  scaleD:        f32,
  angleV:        f32,
  positionX:     f32,
  positionY:     f32,
  scaleW:        f32,
  preview:       u64,
  poster:        u32,
  selection:     u64,
  current_time:  u32,
  track_id:      u32
}*/

#[derive(PartialEq,Eq,Debug)]
pub enum MvhdBox {
  M1(Mvhd1),
  M2(Mvhd2),
  M3
  /*M3(Mvhd3)*/
}

#[derive(PartialEq,Eq,Debug)]
pub enum MoovBox {
  Mdra,
  Dref,
  Cmov,
  Rmra,
  Iods,
  Mvhd,
  Clip,
  Trak,
  Udta
}

#[derive(PartialEq,Eq,Debug)]
enum MP4Box<'a> {
  Ftyp(FileType<'a>),
  Moov(Vec<MoovBox>),
  Mdat,
  Free,
  Skip,
  Wide,
  Unknown
}

take!(offset 4);
tag!(ftyp    "ftyp".as_bytes());

fn brand_name(input:&[u8]) -> IResult<&[u8],&str> {
  take!(major_brand_bytes 4);
  major_brand_bytes(input).map_res(str::from_utf8)
}
take!(major_brand_version 4);
many0!(compatible_brands<&[u8], &str> brand_name);

fn filetype_parser<'a>(input: &'a[u8]) -> IResult<&'a [u8], FileType<'a> > {
  chaining_parser!(input, ||{FileType{major_brand: m, major_brand_version:v, compatible_brands: c}},
    m: brand_name,
    v: major_brand_version,
    c: compatible_brands,)
}

o!(filetype <&[u8], FileType>  ftyp ~ [ filetype_parser ]);

fn filetype_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match filetype(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)    => {
      Done(i, MP4Box::Ftyp(o))
    }
  }
}

tag!(moov_tag "moov".as_bytes());

tag!(mdra    "mdra".as_bytes());
fn moov_mdra(input:&[u8]) -> IResult<&[u8], MoovBox> {
  mdra(input).map(|o| MoovBox::Mdra)
}

tag!(dref    "dref".as_bytes());
fn moov_dref(input:&[u8]) -> IResult<&[u8], MoovBox> {
  dref(input).map(|o| MoovBox::Dref)
}

tag!(cmov    "cmov".as_bytes());
fn moov_cmov(input:&[u8]) -> IResult<&[u8], MoovBox> {
  cmov(input).map(|o| MoovBox::Cmov)
}

tag!(rmra    "rmra".as_bytes());
fn moov_rmra(input:&[u8]) -> IResult<&[u8], MoovBox> {
  rmra(input).map(|o| MoovBox::Rmra)
}

tag!(iods    "iods".as_bytes());
fn moov_iods(input:&[u8]) -> IResult<&[u8], MoovBox> {
  iods(input).map(|o| MoovBox::Iods)
}

tag!(mvhd    "mvhd".as_bytes());
fn moov_mvhd(input:&[u8]) -> IResult<&[u8], MoovBox> {
  mvhd(input).map(|o| MoovBox::Mvhd)
  /*let res = mvhd(input).map(|o| MoovBox::Mvhd);
  match res {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)    => {
      println!("MVHD box content:\n{}", i.to_hex(8));
      Done(i,o)
    }
  }*/
}

tag!(clip    "clip".as_bytes());
fn moov_clip(input:&[u8]) -> IResult<&[u8], MoovBox> {
  clip(input).map(|o| MoovBox::Clip)
}

tag!(trak    "trak".as_bytes());
fn moov_trak(input:&[u8]) -> IResult<&[u8], MoovBox> {
  trak(input).map(|o| MoovBox::Trak)
}

tag!(udta   "udta".as_bytes());
fn moov_udta(input:&[u8]) -> IResult<&[u8], MoovBox> {
  udta(input).map(|o| MoovBox::Udta)
}

alt!(moov_internal<&[u8], MoovBox>, moov_mdra | moov_dref | moov_cmov |
     moov_rmra | moov_iods | moov_mvhd | moov_clip | moov_trak | moov_udta);

fn moov(input:&[u8]) -> IResult<&[u8], MoovBox> {
  match mp4_box(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)    => {
      match moov_internal(o) {
        Error(a)      => Error(a),
        Incomplete(a) => Incomplete(a),
        Done(i2, o2)  => {
          Done(i, o2)
        }

      }
    }
  }
}

many0!(moov_many<&[u8],MoovBox> moov);

o!(moov_box_internal <&[u8], Vec<MoovBox> >  moov_tag ~ [ moov_many ]);

fn moov_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  match moov_box_internal(input) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, o)  => {
      Done(i, MP4Box::Moov(o))
    }
  }
}

tag!(mdat    "mdat".as_bytes());
fn mdat_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  mdat(input).map(|_| MP4Box::Mdat)
}
tag!(free    "free".as_bytes());
fn free_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  free(input).map(|_| MP4Box::Free)
}

tag!(skip    "skip".as_bytes());
fn skip_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  skip(input).map(|_| MP4Box::Skip)
}

tag!(wide    "wide".as_bytes());
fn wide_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  wide(input).map(|_| MP4Box::Wide)
}

fn unknown_box(input:&[u8]) -> IResult<&[u8], MP4Box> {
  println!("calling UNKNOWN");
  Done(input, MP4Box::Unknown)
}

alt!(box_parser_internal<&[u8], MP4Box>, filetype_box | moov_box | mdat_box | free_box | skip_box | wide_box | unknown_box);
fn box_parser(input:&[u8]) -> IResult<&[u8], MP4Box> {
  mp4_box(input).flat_map(box_parser_internal)
}

fn data_interpreter(bytes:&[u8]) -> IResult<&[u8], ()> {
  //println!("bytes:\n{}", bytes.to_hex(8));
  match box_parser(bytes) {
    Done(i, o) => {
      match o {
        MP4Box::Ftyp(f) => println!("-> FTYP: {:?}", f),
        MP4Box::Moov(m) => {println!("-> MOOV: {:?}", m); println!("remaining:\n{}", i.to_hex(8))},
        MP4Box::Mdat    => println!("-> MDAT"),
        MP4Box::Free    => println!("-> FREE"),
        MP4Box::Skip    => println!("-> SKIP"),
        MP4Box::Wide    => println!("-> WIDE"),
        MP4Box::Unknown => println!("-> UNKNOWN")
      }
      //println!("remaining:\n{}", i.to_hex(8));
      Done(i,())
    },
    Error(a) => {
      println!("mp4 parsing error: {:?}", a);
      Error(a)
    },
    Incomplete(a) => {
      println!("incomplete: {:?}", a);
      Incomplete(a)
    }
  }
}

fn multiple_data_interpreter(bytes:&[u8]) -> IResult<&[u8], ()> {
  match data_interpreter(bytes) {
    Error(a)      => Error(a),
    Incomplete(a) => Incomplete(a),
    Done(i, ())   => {
      println!("NEXT BOX");
      match data_interpreter(i) {
        Error(a)      => Error(a),
        Incomplete(a) => Incomplete(a),
        Done(i2,())   => {
          println!("NEXT BOX 2");
          match data_interpreter(i2) {
            Error(a)      => Error(a),
            Incomplete(a) => Incomplete(a),
            Done(i3,())   => {
              println!("NEXT BOX 3");
              match data_interpreter(i3) {
                Error(a)      => Error(a),
                Incomplete(a) => Incomplete(a),
                Done(i4,())   => {
                  println!("NEXT BOX 4");
                  let res = data_interpreter(i4);
                  println!("res4: {:?}", res);
                  res
                }
              }
            }
          }
        }
      }
    },
  }
}

many0!(full_data_interpreter<&[u8],()> data_interpreter);

fn parse_mp4_file(filename: &str) {
  FileProducer::new(filename, 40000).map(|producer: FileProducer| {
    let mut p = producer;
    match p.produce() {
      ProducerState::Data(bytes) => {
        multiple_data_interpreter(bytes);
      },
      _ => println!("got error")
    }
    /*
    pusher!(ps, full_data_interpreter);
    ps(&mut p);
    */
    //assert!(false);
  });

}
#[test]
fn file_test() {
  parse_mp4_file("small.mp4");
}
#[test]
fn bunny_test() {
  parse_mp4_file("bigbuckbunny.mp4");
}
<|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 https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
use crate::dom::bindings::codegen::Bindings::XRBinding;
use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionCreationOptions;
use crate::dom::bindings::codegen::Bindings::XRBinding::{XRMethods, XRSessionMode};
use crate::dom::bindings::error::Error;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::gamepad::Gamepad;
use crate::dom::gamepadevent::GamepadEventType;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::vrdisplay::VRDisplay;
use crate::dom::vrdisplayevent::VRDisplayEvent;
use crate::dom::xrsession::XRSession;
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender;
use profile_traits::ipc;
use std::rc::Rc;
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg};
use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState};

#[dom_struct]
pub struct XR {
    eventtarget: EventTarget,
    displays: DomRefCell<Vec<Dom<VRDisplay>>>,
    gamepads: DomRefCell<Vec<Dom<Gamepad>>>,
}

impl XR {
    fn new_inherited() -> XR {
        XR {
            eventtarget: EventTarget::new_inherited(),
            displays: DomRefCell::new(Vec::new()),
            gamepads: DomRefCell::new(Vec::new()),
        }
    }

    pub fn new(global: &GlobalScope) -> DomRoot<XR> {
        let root = reflect_dom_object(Box::new(XR::new_inherited()), global, XRBinding::Wrap);
        root.register();
        root
    }
}

impl Drop for XR {
    fn drop(&mut self) {
        self.unregister();
    }
}

impl XRMethods for XR {
    #[allow(unrooted_must_root)]
    /// https://immersive-web.github.io/webxr/#dom-xr-supportssessionmode
    fn SupportsSessionMode(&self, mode: XRSessionMode) -> Rc<Promise> {
        // XXXManishearth this should select an XR device first
        let promise = Promise::new(&self.global());
        if mode == XRSessionMode::Immersive_vr {
            promise.resolve_native(&());
        } else {
            // XXXManishearth support other modes
            promise.reject_error(Error::NotSupported);
        }

        promise
    }

    #[allow(unrooted_must_root)]
    /// https://immersive-web.github.io/webxr/#dom-xr-requestsession
    fn RequestSession(&self, options: &XRSessionCreationOptions) -> Rc<Promise> {
        let promise = Promise::new(&self.global());
        if options.mode != XRSessionMode::Immersive_vr {
            promise.reject_error(Error::NotSupported);
            return promise;
        }

        let displays = self.get_displays();

        let displays = match displays {
            Ok(d) => d,
            Err(_) => {
                promise.reject_native(&());
                return promise;
            },
        };

        // XXXManishearth filter for displays which can_present
        if displays.is_empty() {
            promise.reject_error(Error::Security);
        }

        let session = XRSession::new(&self.global(), &displays[0]);
        promise.resolve_native(&session);
        // whether or not we should initiate presentation is unclear
        // https://github.com/immersive-web/webxr/issues/453

        promise
    }
}

impl XR {
    #[allow(unrooted_must_root)]
    pub fn get_displays(&self) -> Result<Vec<DomRoot<VRDisplay>>, ()> {
        if let Some(webvr_thread) = self.webvr_thread() {
            let (sender, receiver) =
                ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
            webvr_thread.send(WebVRMsg::GetDisplays(sender)).unwrap();

            // FIXME(#22505) we should not block here and instead produce a promise
            match receiver.recv().unwrap() {
                Ok(displays) => {
                    // Sync displays
                    for display in displays {
                        self.sync_display(&display);
                    }
                },
                Err(_) => return Err(()),
            }
        } else {
            // WebVR spec: The Promise MUST be rejected if WebVR is not enabled/supported.
            return Err(());
        }

        // convert from Dom to DomRoot
        Ok(self
            .displays
            .borrow()
            .iter()
            .map(|d| DomRoot::from_ref(&**d))
            .collect())
    }

    fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
        self.global().as_window().webvr_thread()
    }

    fn find_display(&self, display_id: u32) -> Option<DomRoot<VRDisplay>> {
        self.displays
            .borrow()
            .iter()
            .find(|d| d.DisplayId() == display_id)
            .map(|d| DomRoot::from_ref(&**d))
    }

    fn register(&self) {
        if let Some(webvr_thread) = self.webvr_thread() {
            let msg = WebVRMsg::RegisterContext(self.global().pipeline_id());
            webvr_thread.send(msg).unwrap();
        }
    }

    fn unregister(&self) {
        if let Some(webvr_thread) = self.webvr_thread() {
            let msg = WebVRMsg::UnregisterContext(self.global().pipeline_id());
            webvr_thread.send(msg).unwrap();
        }
    }

    fn sync_display(&self, display: &WebVRDisplayData) -> DomRoot<VRDisplay> {
        if let Some(existing) = self.find_display(display.display_id) {
            existing.update_display(&display);
            existing
        } else {
            let root = VRDisplay::new(&self.global(), display.clone());
            self.displays.borrow_mut().push(Dom::from_ref(&*root));
            root
        }
    }

    fn handle_display_event(&self, event: WebVRDisplayEvent) {
        match event {
            WebVRDisplayEvent::Connect(ref display) => {
                let display = self.sync_display(&display);
                display.handle_webvr_event(&event);
                self.notify_display_event(&display, &event);
            },
            WebVRDisplayEvent::Disconnect(id) => {
                if let Some(display) = self.find_display(id) {
                    display.handle_webvr_event(&event);
                    self.notify_display_event(&display, &event);
                }
            },
            WebVRDisplayEvent::Activate(ref display, _) |
            WebVRDisplayEvent::Deactivate(ref display, _) |
            WebVRDisplayEvent::Blur(ref display) |
            WebVRDisplayEvent::Focus(ref display) |
            WebVRDisplayEvent::PresentChange(ref display, _) |
            WebVRDisplayEvent::Change(ref display) => {
                let display = self.sync_display(&display);
                display.handle_webvr_event(&event);
            },
            WebVRDisplayEvent::Pause(id) |
            WebVRDisplayEvent::Resume(id) |
            WebVRDisplayEvent::Exit(id) => {
                if let Some(display) = self.find_display(id) {
                    display.handle_webvr_event(&event);
                }
            },
        };
    }

    fn handle_gamepad_event(&self, event: WebVRGamepadEvent) {
        match event {
            WebVRGamepadEvent::Connect(data, state) => {
                if let Some(gamepad) = self.find_gamepad(state.gamepad_id) {
                    gamepad.update_from_vr(&state);
                } else {
                    // new gamepad
                    self.sync_gamepad(Some(data), &state);
                }
            },
            WebVRGamepadEvent::Disconnect(id) => {
                if let Some(gamepad) = self.find_gamepad(id) {
                    gamepad.update_connected(false);
                }
            },
        };
    }

    pub fn handle_webvr_event(&self, event: WebVREvent) {
        match event {
            WebVREvent::Display(event) => {
                self.handle_display_event(event);
            },
            WebVREvent::Gamepad(event) => {
                self.handle_gamepad_event(event);
            },
        };
    }

    pub fn handle_webvr_events(&self, events: Vec<WebVREvent>) {
        for event in events {
            self.handle_webvr_event(event);
        }
    }

    fn notify_display_event(&self, display: &VRDisplay, event: &WebVRDisplayEvent) {
        let event = VRDisplayEvent::new_from_webvr(&self.global(), &display, &event);
        event
            .upcast::<Event>()
            .fire(self.global().upcast::<EventTarget>());
    }
}

// Gamepad
impl XR {
    fn find_gamepad(&self, gamepad_id: u32) -> Option<DomRoot<Gamepad>> {
        self.gamepads
            .borrow()
            .iter()
            .find(|g| g.gamepad_id() == gamepad_id)
            .map(|g| DomRoot::from_ref(&**g))
    }

    fn sync_gamepad(&self, data: Option<WebVRGamepadData>, state: &WebVRGamepadState) {
        if let Some(existing) = self.find_gamepad(state.gamepad_id) {
            existing.update_from_vr(&state);
        } else {
            let index = self.gamepads.borrow().len();
            let data = data.unwrap_or_default();
            let root = Gamepad::new_from_vr(&self.global(), index as i32, &data, &state);
            self.gamepads.borrow_mut().push(Dom::from_ref(&*root));
            if state.connected {
                root.notify_event(GamepadEventType::Connected);
            }
        }
    }

    // Gamepads are synced immediately in response to the API call.
    // The current approach allows the to sample gamepad state multiple times per frame. This
    // guarantees that the gamepads always have a valid state and can be very useful for
    // motion capture or drawing applications.
    pub fn get_gamepads(&self) -> Vec<DomRoot<Gamepad>> {
        if let Some(wevbr_sender) = self.webvr_thread() {
            let (sender, receiver) =
                ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
            let synced_ids = self
                .gamepads
                .borrow()
                .iter()
                .map(|g| g.gamepad_id())
                .collect();
            wevbr_sender
                .send(WebVRMsg::GetGamepads(synced_ids, sender))
                .unwrap();
            match receiver.recv().unwrap() {
                Ok(gamepads) => {
                    // Sync displays
                    for gamepad in gamepads {
                        self.sync_gamepad(gamepad.0, &gamepad.1);
                    }
                },
                Err(_) => {},
            }
        }

        // We can add other not VR related gamepad providers here
        self.gamepads
            .borrow()
            .iter()
            .map(|g| DomRoot::from_ref(&**g))
            .collect()
    }
}
<commit_msg>Remove unrooted_must_root<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 https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::VRDisplayBinding::VRDisplayMethods;
use crate::dom::bindings::codegen::Bindings::XRBinding;
use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionCreationOptions;
use crate::dom::bindings::codegen::Bindings::XRBinding::{XRMethods, XRSessionMode};
use crate::dom::bindings::error::Error;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::event::Event;
use crate::dom::eventtarget::EventTarget;
use crate::dom::gamepad::Gamepad;
use crate::dom::gamepadevent::GamepadEventType;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::vrdisplay::VRDisplay;
use crate::dom::vrdisplayevent::VRDisplayEvent;
use crate::dom::xrsession::XRSession;
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSender;
use profile_traits::ipc;
use std::rc::Rc;
use webvr_traits::{WebVRDisplayData, WebVRDisplayEvent, WebVREvent, WebVRMsg};
use webvr_traits::{WebVRGamepadData, WebVRGamepadEvent, WebVRGamepadState};

#[dom_struct]
pub struct XR {
    eventtarget: EventTarget,
    displays: DomRefCell<Vec<Dom<VRDisplay>>>,
    gamepads: DomRefCell<Vec<Dom<Gamepad>>>,
}

impl XR {
    fn new_inherited() -> XR {
        XR {
            eventtarget: EventTarget::new_inherited(),
            displays: DomRefCell::new(Vec::new()),
            gamepads: DomRefCell::new(Vec::new()),
        }
    }

    pub fn new(global: &GlobalScope) -> DomRoot<XR> {
        let root = reflect_dom_object(Box::new(XR::new_inherited()), global, XRBinding::Wrap);
        root.register();
        root
    }
}

impl Drop for XR {
    fn drop(&mut self) {
        self.unregister();
    }
}

impl XRMethods for XR {
    #[allow(unrooted_must_root)]
    /// https://immersive-web.github.io/webxr/#dom-xr-supportssessionmode
    fn SupportsSessionMode(&self, mode: XRSessionMode) -> Rc<Promise> {
        // XXXManishearth this should select an XR device first
        let promise = Promise::new(&self.global());
        if mode == XRSessionMode::Immersive_vr {
            promise.resolve_native(&());
        } else {
            // XXXManishearth support other modes
            promise.reject_error(Error::NotSupported);
        }

        promise
    }

    #[allow(unrooted_must_root)]
    /// https://immersive-web.github.io/webxr/#dom-xr-requestsession
    fn RequestSession(&self, options: &XRSessionCreationOptions) -> Rc<Promise> {
        let promise = Promise::new(&self.global());
        if options.mode != XRSessionMode::Immersive_vr {
            promise.reject_error(Error::NotSupported);
            return promise;
        }

        let displays = self.get_displays();

        let displays = match displays {
            Ok(d) => d,
            Err(_) => {
                promise.reject_native(&());
                return promise;
            },
        };

        // XXXManishearth filter for displays which can_present
        if displays.is_empty() {
            promise.reject_error(Error::Security);
        }

        let session = XRSession::new(&self.global(), &displays[0]);
        promise.resolve_native(&session);
        // whether or not we should initiate presentation is unclear
        // https://github.com/immersive-web/webxr/issues/453

        promise
    }
}

impl XR {
    pub fn get_displays(&self) -> Result<Vec<DomRoot<VRDisplay>>, ()> {
        if let Some(webvr_thread) = self.webvr_thread() {
            let (sender, receiver) =
                ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
            webvr_thread.send(WebVRMsg::GetDisplays(sender)).unwrap();

            // FIXME(#22505) we should not block here and instead produce a promise
            match receiver.recv().unwrap() {
                Ok(displays) => {
                    // Sync displays
                    for display in displays {
                        self.sync_display(&display);
                    }
                },
                Err(_) => return Err(()),
            }
        } else {
            // WebVR spec: The Promise MUST be rejected if WebVR is not enabled/supported.
            return Err(());
        }

        // convert from Dom to DomRoot
        Ok(self
            .displays
            .borrow()
            .iter()
            .map(|d| DomRoot::from_ref(&**d))
            .collect())
    }

    fn webvr_thread(&self) -> Option<IpcSender<WebVRMsg>> {
        self.global().as_window().webvr_thread()
    }

    fn find_display(&self, display_id: u32) -> Option<DomRoot<VRDisplay>> {
        self.displays
            .borrow()
            .iter()
            .find(|d| d.DisplayId() == display_id)
            .map(|d| DomRoot::from_ref(&**d))
    }

    fn register(&self) {
        if let Some(webvr_thread) = self.webvr_thread() {
            let msg = WebVRMsg::RegisterContext(self.global().pipeline_id());
            webvr_thread.send(msg).unwrap();
        }
    }

    fn unregister(&self) {
        if let Some(webvr_thread) = self.webvr_thread() {
            let msg = WebVRMsg::UnregisterContext(self.global().pipeline_id());
            webvr_thread.send(msg).unwrap();
        }
    }

    fn sync_display(&self, display: &WebVRDisplayData) -> DomRoot<VRDisplay> {
        if let Some(existing) = self.find_display(display.display_id) {
            existing.update_display(&display);
            existing
        } else {
            let root = VRDisplay::new(&self.global(), display.clone());
            self.displays.borrow_mut().push(Dom::from_ref(&*root));
            root
        }
    }

    fn handle_display_event(&self, event: WebVRDisplayEvent) {
        match event {
            WebVRDisplayEvent::Connect(ref display) => {
                let display = self.sync_display(&display);
                display.handle_webvr_event(&event);
                self.notify_display_event(&display, &event);
            },
            WebVRDisplayEvent::Disconnect(id) => {
                if let Some(display) = self.find_display(id) {
                    display.handle_webvr_event(&event);
                    self.notify_display_event(&display, &event);
                }
            },
            WebVRDisplayEvent::Activate(ref display, _) |
            WebVRDisplayEvent::Deactivate(ref display, _) |
            WebVRDisplayEvent::Blur(ref display) |
            WebVRDisplayEvent::Focus(ref display) |
            WebVRDisplayEvent::PresentChange(ref display, _) |
            WebVRDisplayEvent::Change(ref display) => {
                let display = self.sync_display(&display);
                display.handle_webvr_event(&event);
            },
            WebVRDisplayEvent::Pause(id) |
            WebVRDisplayEvent::Resume(id) |
            WebVRDisplayEvent::Exit(id) => {
                if let Some(display) = self.find_display(id) {
                    display.handle_webvr_event(&event);
                }
            },
        };
    }

    fn handle_gamepad_event(&self, event: WebVRGamepadEvent) {
        match event {
            WebVRGamepadEvent::Connect(data, state) => {
                if let Some(gamepad) = self.find_gamepad(state.gamepad_id) {
                    gamepad.update_from_vr(&state);
                } else {
                    // new gamepad
                    self.sync_gamepad(Some(data), &state);
                }
            },
            WebVRGamepadEvent::Disconnect(id) => {
                if let Some(gamepad) = self.find_gamepad(id) {
                    gamepad.update_connected(false);
                }
            },
        };
    }

    pub fn handle_webvr_event(&self, event: WebVREvent) {
        match event {
            WebVREvent::Display(event) => {
                self.handle_display_event(event);
            },
            WebVREvent::Gamepad(event) => {
                self.handle_gamepad_event(event);
            },
        };
    }

    pub fn handle_webvr_events(&self, events: Vec<WebVREvent>) {
        for event in events {
            self.handle_webvr_event(event);
        }
    }

    fn notify_display_event(&self, display: &VRDisplay, event: &WebVRDisplayEvent) {
        let event = VRDisplayEvent::new_from_webvr(&self.global(), &display, &event);
        event
            .upcast::<Event>()
            .fire(self.global().upcast::<EventTarget>());
    }
}

// Gamepad
impl XR {
    fn find_gamepad(&self, gamepad_id: u32) -> Option<DomRoot<Gamepad>> {
        self.gamepads
            .borrow()
            .iter()
            .find(|g| g.gamepad_id() == gamepad_id)
            .map(|g| DomRoot::from_ref(&**g))
    }

    fn sync_gamepad(&self, data: Option<WebVRGamepadData>, state: &WebVRGamepadState) {
        if let Some(existing) = self.find_gamepad(state.gamepad_id) {
            existing.update_from_vr(&state);
        } else {
            let index = self.gamepads.borrow().len();
            let data = data.unwrap_or_default();
            let root = Gamepad::new_from_vr(&self.global(), index as i32, &data, &state);
            self.gamepads.borrow_mut().push(Dom::from_ref(&*root));
            if state.connected {
                root.notify_event(GamepadEventType::Connected);
            }
        }
    }

    // Gamepads are synced immediately in response to the API call.
    // The current approach allows the to sample gamepad state multiple times per frame. This
    // guarantees that the gamepads always have a valid state and can be very useful for
    // motion capture or drawing applications.
    pub fn get_gamepads(&self) -> Vec<DomRoot<Gamepad>> {
        if let Some(wevbr_sender) = self.webvr_thread() {
            let (sender, receiver) =
                ipc::channel(self.global().time_profiler_chan().clone()).unwrap();
            let synced_ids = self
                .gamepads
                .borrow()
                .iter()
                .map(|g| g.gamepad_id())
                .collect();
            wevbr_sender
                .send(WebVRMsg::GetGamepads(synced_ids, sender))
                .unwrap();
            match receiver.recv().unwrap() {
                Ok(gamepads) => {
                    // Sync displays
                    for gamepad in gamepads {
                        self.sync_gamepad(gamepad.0, &gamepad.1);
                    }
                },
                Err(_) => {},
            }
        }

        // We can add other not VR related gamepad providers here
        self.gamepads
            .borrow()
            .iter()
            .map(|g| DomRoot::from_ref(&**g))
            .collect()
    }
}
<|endoftext|>


<commit_before>//! "Weighted" graph types

use std;
use std::ops::{Deref,DerefMut};

use smallvec::SmallVec;

use super::interface::{self, Id};

/// Trait bounds for types used as edge and node data payloads.
pub trait Data: Clone {}
impl<T> Data for T where T: Clone {}

// ----------------------------------------------------------------
// Edge

/// Weighted edge type.
#[derive(Clone,Debug)]
pub struct Edge<T: Data, I: Id> {
    source: I,
    target: I,
    data: T
}

impl<T, I> interface::Edge for Edge<T, I>
    where I: Id,
          T: Data {
    type NodeId = I;
    #[inline]
    fn endpoints(&self) -> (Self::NodeId, Self::NodeId) {
        (self.source, self.target)
    }
}

impl<T, I> interface::DirectedEdge for Edge<T, I>
    where I: Id,
          T: Data {
    #[inline]
    fn source(&self) -> I { self.source }

    #[inline]
    fn target(&self) -> I { self.target }
}

impl<T, I> interface::DirectedEdgeMut for Edge<T, I>
    where I: Id,
          T: Data {
    fn rev(&mut self) {
        ::std::mem::swap(&mut self.source, &mut self.target);
    }
}

impl<T: Data, I: Id> Edge<T, I> {
    /// Create an edge with the given source & target node indices and
    /// weight data.
    pub fn new(source: I, target: I, data: T) -> Self {
        Edge{source: source, target: target, data: data}
    }

    /// Retrieve a reference to the edge's data (weight)
    pub fn data(&self) -> &T {
        &self.data
    }
}

impl<T: Data, I: Id> Deref for Edge<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T: Data, I: Id> DerefMut for Edge<T, I> {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.data
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}

impl<T: Data, I: Id, I2: Copy> From<(I2, I2, T)> for Edge<T, I>
    where I: From<I2> {
    fn from(u: (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2)
    }
}

impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: &'a (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}
impl<'a, T: Data, I: Id, I2: Copy> From<&'a (I2, I2, T)> for Edge<T, I>
    where T: Clone, I: From<I2> {
    fn from(u: &'a (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2.clone())
    }
}

// ----------------------------------------------------------------
// Node

///  Weighted node implementation.
///
/// A reference to the node's weight data can be obtained using the type's
/// `Deref` implementation.
///
/// ```rust
/// use cripes::util::graph::{EdgeIndex,WeightedNode};
///
/// # fn main() {
/// let n = WeightedNode::<_, EdgeIndex<u8>>::new(32);
/// assert_eq!(32, *n);
/// # }
/// ```

#[derive(Clone,Debug)]
pub struct Node<T: Data, I: Id> {
    incoming_edges: SmallVec<[I; 8]>,
    outgoing_edges: SmallVec<[I; 8]>,
    data: T
}

impl<T: Data, I: Id> Node<T, I> {
    /// Instantiate a node with the given data.
    pub fn new(data: T) -> Self {
        Node{incoming_edges: SmallVec::new(), outgoing_edges: SmallVec::new(), data: data}
    }

    /// Retrieve a reference to the nodes's data (weight)
    pub fn data(&self) -> &T {
        &self.data
    }
}

impl<T: Data, I: Id> Deref for Node<T, I> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T: Data, I: Id> DerefMut for Node<T, I> {
    #[inline]
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.data
    }
}

impl<T: Data, I: Id> From<T> for Node<T, I> {
    #[inline]
    fn from(data: T) -> Self {
        Self::new(data)
    }
}

impl<T, I> interface::Node for Node<T, I>
    where T: Data, I: Id {
    type EdgeId = I;
    fn edges(&self) -> std::iter::Chain<std::slice::Iter<Self::EdgeId>,std::slice::Iter<Self::EdgeId>> {
        self.incoming_edges.iter().chain(self.outgoing_edges.iter())
    }
}

impl<T, I> interface::DirectedNode for Node<T, I>
    where T: Data, I: Id {
    impl_basic_node!(I);
}

impl<T, I> interface::DirectedNodeMut for Node<T, I>
    where T: Data, I: Id {
    impl_basic_node_mut!(I);
}
<commit_msg>util/graph/weighted: remove `Clone` bound for edge and node weights<commit_after>//! "Weighted" graph types

use std;
use std::ops::{Deref,DerefMut};

use smallvec::SmallVec;

use super::interface::{self, Id};

// ----------------------------------------------------------------
// Edge

/// Weighted edge type.
#[derive(Debug)]
pub struct Edge<T, I: Id> {
    source: I,
    target: I,
    data: T
}

impl<T, I: Id> Clone for Edge<T, I>
    where T: Clone
{
    fn clone(&self) -> Self {
        Edge{source: self.source, target: self.target, data: self.data.clone()}
    }
}

impl<T, I: Id> interface::Edge for Edge<T, I> {
    type NodeId = I;
    #[inline]
    fn endpoints(&self) -> (Self::NodeId, Self::NodeId) {
        (self.source, self.target)
    }
}

impl<T, I: Id> interface::DirectedEdge for Edge<T, I> {
    #[inline]
    fn source(&self) -> I { self.source }

    #[inline]
    fn target(&self) -> I { self.target }
}

impl<T, I: Id> interface::DirectedEdgeMut for Edge<T, I> {
    fn rev(&mut self) {
        ::std::mem::swap(&mut self.source, &mut self.target);
    }
}

impl<T, I: Id> Edge<T, I> {
    /// Create an edge with the given source & target node indices and
    /// weight data.
    pub fn new(source: I, target: I, data: T) -> Self {
        Edge{source: source, target: target, data: data}
    }

    /// Retrieve a reference to the edge's data (weight)
    pub fn data(&self) -> &T {
        &self.data
    }
}

impl<T, I: Id> Deref for Edge<T, I> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T, I: Id> DerefMut for Edge<T, I> {
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.data
    }
}

impl<T, I: Id, I2: Copy> From<(I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}

impl<T, I: Id, I2: Copy> From<(I2, I2, T)> for Edge<T, I>
    where I: From<I2> {
    fn from(u: (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2)
    }
}

impl<'a, T, I: Id, I2: Copy> From<&'a (I2, I2)> for Edge<T, I>
    where T: Default, I: From<I2> {
    fn from(u: &'a (I2, I2)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), Default::default())
    }
}
impl<'a, T, I: Id, I2: Copy> From<&'a (I2, I2, T)> for Edge<T, I>
    where T: Clone, I: From<I2> {
    fn from(u: &'a (I2, I2, T)) -> Self {
        Self::new(I::from(u.0), I::from(u.1), u.2.clone())
    }
}

// ----------------------------------------------------------------
// Node

///  Weighted node implementation.
///
/// A reference to the node's weight data can be obtained using the type's
/// `Deref` implementation.
///
/// ```rust
/// use cripes::util::graph::{EdgeIndex,WeightedNode};
///
/// # fn main() {
/// let n = WeightedNode::<_, EdgeIndex<u8>>::new(32);
/// assert_eq!(32, *n);
/// # }
/// ```

#[derive(Debug)]
pub struct Node<T, I: Id> {
    incoming_edges: SmallVec<[I; 8]>,
    outgoing_edges: SmallVec<[I; 8]>,
    data: T
}

impl<T, I: Id> Node<T, I> {
    /// Instantiate a node with the given data.
    pub fn new(data: T) -> Self {
        Node{incoming_edges: SmallVec::new(), outgoing_edges: SmallVec::new(), data: data}
    }

    /// Retrieve a reference to the nodes's data (weight)
    pub fn data(&self) -> &T {
        &self.data
    }
}
impl<T, I: Id> Clone for Node<T, I>
    where T: Clone
{
    fn clone(&self) -> Self {
        Node{incoming_edges: self.incoming_edges.clone(),
             outgoing_edges: self.outgoing_edges.clone(),
             data: self.data.clone()}
    }
}

impl<T, I: Id> Deref for Node<T, I> {
    type Target = T;
    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<T, I: Id> DerefMut for Node<T, I> {
    #[inline]
    fn deref_mut(&mut self) -> &mut <Self as Deref>::Target {
        &mut self.data
    }
}

impl<T, I: Id> From<T> for Node<T, I> {
    #[inline]
    fn from(data: T) -> Self {
        Self::new(data)
    }
}

impl<T, I: Id> interface::Node for Node<T, I> {
    type EdgeId = I;
    fn edges(&self) -> std::iter::Chain<std::slice::Iter<Self::EdgeId>,std::slice::Iter<Self::EdgeId>> {
        self.incoming_edges.iter().chain(self.outgoing_edges.iter())
    }
}

impl<T, I: Id> interface::DirectedNode for Node<T, I> {
    impl_basic_node!(I);
}

impl<T, I: Id> interface::DirectedNodeMut for Node<T, I> {
    impl_basic_node_mut!(I);
}
<|endoftext|>


<commit_before>extern crate robots;

use robots::actors::{Actor,ActorCell};
use std::sync::Mutex;
use std::any::Any;
use std::thread;
use std::time;
use super::super::gpioaccess::{DirectionProxied,PinProxyContract,PwmProxyContract};
use super::super::gpioaccess::proxyimpl::{PinProxy,PwmProxy};

#[derive(Copy, Clone, PartialEq,Debug)]
pub enum PinCommands {
	Blink(u64),
	Switch,
}

pub struct PinActor {
	pinproxy :  Mutex<PinProxy>,
}

impl Actor for PinActor {
	fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<PinCommands>(_message){
			match *_message {
				PinCommands::Blink(times) => {
					let pin = self.pinproxy.lock().unwrap();
					match pin.export() {
						Ok(()) => {
							println!("Pin exported");
							for _ in 1..times {
								pin.set_direction(DirectionProxied::Out);
								pin.set_direction(DirectionProxied::High);
								thread::sleep(time::Duration::from_millis(400));
								pin.set_direction(DirectionProxied::Low);
								thread::sleep(time::Duration::from_millis(400));
								println!("Blink");
							}
							match pin.unexport() {
								Ok(()) => {
									println!("Pin unexported");
								}
								_ => {}
							}
						}
						_ => {}
					}
				},
				PinCommands::Switch => { }
			}
		}
	}
}

impl PinActor{
	pub fn new(pin_number: u64) -> PinActor {
		PinActor{ pinproxy : Mutex::new(PinProxy::new(pin_number)) }
	}
}

#[derive(Copy, Clone, PartialEq,Debug)]
pub enum PwmCommands {
	MoveToDegree(u16)
}

pub struct PwmActor {
	pwmproxy :  Result<Mutex<PwmProxy>,()>,
}

impl Actor for PwmActor {
	fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		println!("pwm received message");
		if let Ok(_message) = Box::<Any>::downcast::<PwmCommands>(_message){
			println!("pwm recognized command");
			match *_message {
				PwmCommands::MoveToDegree(degree) => {
					println!("pwm movetodegree");
					match self.pwmproxy {
						Ok(ref pwmproxyresult) =>
						{
							let pwm = pwmproxyresult.lock().unwrap();
							match pwm.export() {
								Ok(()) => {
									println!("Pwm exported");
									match pwm.set_period_ns(50_000_000)
									{
										Ok(()) => {
											println!("Pwm setting period");
											match pwm.enable(true)
											{
												Ok(()) => {
													println!("Pwm enable");
													for x in 1..10 {
														println!("Pwm {}",x);
														pwm.increase_to_max(0.05);
														pwm.decrease_to_minimum(0.05);
													}
													match pwm.enable(false)
													{
														Ok(()) => {
															println!("Pwm disable");
														}
														_ => println!("Pwm disabled failed")
													}
												}
												_ => println!("Pwm enabled failed")
											}
										}
										_ => println!("Pwm set period failed")
									}
									match pwm.unexport() {
										Ok(()) => {
											println!("Pwm unexported");
										}
										_ => println!("Pwm unexport failed")
									}
								}
								_ => println!("Pwm export failed")
							}
						}
						_ => println!("No Pwm")
					}

					println!("pwm done");
				}
			}
		}
	}
}

impl PwmActor{
	pub fn new(number: u32) -> PwmActor {
		match PwmProxy::new(0,number)
		{
			Ok(pwmproxy) =>  PwmActor{ pwmproxy : Ok(Mutex::new(pwmproxy)) },
			_ => PwmActor{ pwmproxy : Err(()) },
		}
	}
}<commit_msg>period ...<commit_after>extern crate robots;

use robots::actors::{Actor,ActorCell};
use std::sync::Mutex;
use std::any::Any;
use std::thread;
use std::time;
use super::super::gpioaccess::{DirectionProxied,PinProxyContract,PwmProxyContract};
use super::super::gpioaccess::proxyimpl::{PinProxy,PwmProxy};

#[derive(Copy, Clone, PartialEq,Debug)]
pub enum PinCommands {
	Blink(u64),
	Switch,
}

pub struct PinActor {
	pinproxy :  Mutex<PinProxy>,
}

impl Actor for PinActor {
	fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<PinCommands>(_message){
			match *_message {
				PinCommands::Blink(times) => {
					let pin = self.pinproxy.lock().unwrap();
					match pin.export() {
						Ok(()) => {
							println!("Pin exported");
							for _ in 1..times {
								pin.set_direction(DirectionProxied::Out);
								pin.set_direction(DirectionProxied::High);
								thread::sleep(time::Duration::from_millis(400));
								pin.set_direction(DirectionProxied::Low);
								thread::sleep(time::Duration::from_millis(400));
								println!("Blink");
							}
							match pin.unexport() {
								Ok(()) => {
									println!("Pin unexported");
								}
								_ => {}
							}
						}
						_ => {}
					}
				},
				PinCommands::Switch => { }
			}
		}
	}
}

impl PinActor{
	pub fn new(pin_number: u64) -> PinActor {
		PinActor{ pinproxy : Mutex::new(PinProxy::new(pin_number)) }
	}
}

#[derive(Copy, Clone, PartialEq,Debug)]
pub enum PwmCommands {
	MoveToDegree(u16)
}

pub struct PwmActor {
	pwmproxy :  Result<Mutex<PwmProxy>,()>,
}

impl Actor for PwmActor {
	fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		println!("pwm received message");
		if let Ok(_message) = Box::<Any>::downcast::<PwmCommands>(_message){
			println!("pwm recognized command");
			match *_message {
				PwmCommands::MoveToDegree(degree) => {
					println!("pwm movetodegree");
					match self.pwmproxy {
						Ok(ref pwmproxyresult) =>
						{
							let pwm = pwmproxyresult.lock().unwrap();
							match pwm.export() {
								Ok(()) => {
									println!("Pwm exported");
									match pwm.set_period_ns(10_000_000)
									{
										Ok(()) => {
											println!("Pwm setting period");
											match pwm.enable(true)
											{
												Ok(()) => {
													println!("Pwm enable");
													for x in 1..10 {
														println!("Pwm {}",x);
														pwm.increase_to_max(0.05);
														pwm.decrease_to_minimum(0.05);
													}
													match pwm.enable(false)
													{
														Ok(()) => {
															println!("Pwm disable");
														}
														_ => println!("Pwm disabled failed")
													}
												}
												_ => println!("Pwm enabled failed")
											}
										}
										_ => println!("Pwm set period failed")
									}
									match pwm.unexport() {
										Ok(()) => {
											println!("Pwm unexported");
										}
										_ => println!("Pwm unexport failed")
									}
								}
								_ => println!("Pwm export failed")
							}
						}
						_ => println!("No Pwm")
					}

					println!("pwm done");
				}
			}
		}
	}
}

impl PwmActor{
	pub fn new(number: u32) -> PwmActor {
		match PwmProxy::new(0,number)
		{
			Ok(pwmproxy) =>  PwmActor{ pwmproxy : Ok(Mutex::new(pwmproxy)) },
			_ => PwmActor{ pwmproxy : Err(()) },
		}
	}
}<|endoftext|>