<commit_before>//! This crate makes it easier to write integration tests for CLI
//! applications.  It's based on the "workdir" pattern used by BurntSushi's
//! [xsv][] and [ripgrep][] crates, but packaged in an easy-to-reuse form.
//!
//! To use this crate, add the following lines to your `Cargo.toml` file:
//!
//! ```toml
//! [dev-dependencies]
//! # You can replace "*" with the current version of this crate.
//! cli_test_dir = "*"
//! ```
//!
//! Then add the following to the top of `tests/tests.rs`:
//!
//! ```rust,no_run
//! extern crate cli_test_dir;
//! ```
//!
//! You should now be able to write tests as follows:
//!
//! ```
//! use cli_test_dir::*;
//!
//! #[test]
//! fn write_output_file() {
//!     let testdir = TestDir::new("myapp", "write_output_file");
//!     testdir.cmd()
//!         .arg("out.txt")
//!         .expect_success();
//!     testdir.expect_path("out.txt");
//! }
//! ```
//!
//! You can use any options from [`std::process::Command`][Command] to invoke
//! your program.
//!
//! [Command]: https://doc.rust-lang.org/std/process/struct.Command.html
//!
//! ## Testing that the program ran successfully
//!
//! To check that a command succeeds, we can write:
//!
//! ```
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("true", "true_succeeds");
//! testdir.cmd().expect_success();
//! ```
//!
//! But this test would fail:
//!
//! ```rust,should_panic
//! # use cli_test_dir::*;
//! // Fails.
//! let testdir = TestDir::new("false", "false_succeeds");
//! testdir.cmd().expect_success();
//! ```
//!
//! ## Testing that the program exited with an error.
//!
//! Sometimes you want to test that a program fails to run successfully.
//!
//! ```
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("false", "false_fails");
//! testdir.cmd().expect_failure();
//! ```
//!
//! And as you would expect, this test would fail:
//!
//! ```rust,should_panic
//! # use cli_test_dir::*;
//! // Fails.
//! let testdir = TestDir::new("true", "true_fails");
//! testdir.cmd().expect_failure();
//! ```
//!
//! ## File input and output
//!
//! The `src_path` function can be used to build paths relative to the
//! top-level of our crate, and `expect_path` can be used to make sure an
//! output file exists:
//!
//! ```rust,no_run
//! # // Don't run because `cp` will have path problems on Windows.
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("cp", "cp_copies_files");
//! testdir.cmd()
//!   .arg(testdir.src_path("fixtures/input.txt"))
//!   .arg("output.txt")
//!   .expect_success();
//! testdir.expect_path("output.txt");
//! ```
//!
//! We can also create the input file manually or look for specific
//! contents in the output file if we wish:
//!
//! ```
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("cp", "cp_copies_files_2");
//! testdir.create_file("input.txt", "Hello, world!\n");
//! testdir.cmd()
//!   .arg("input.txt")
//!   .arg("output.txt")
//!   .expect_success();
//! testdir.expect_contains("output.txt", "Hello");
//! testdir.expect_file_contents("output.txt", "Hello, world!\n");
//! ```
//!
//! ## Standard input and output
//!
//! We can also test standard input and output:
//!
//! ```
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("cat", "cat_passes_data_through");
//! let output = testdir.cmd()
//!   .output_with_stdin("Hello\n")
//!   .expect_success();
//! assert_eq!(output.stdout_str(), "Hello\n");
//! ```
//!
//! ## Contributing
//!
//! Your feedback and contributions are welcome!  Please see
//! [GitHub](https://github.com/emk/subtitles-rs) for details.
//!
//! [ripgrep]: https://github.com/BurntSushi/ripgrep
//! [xsv]: https://github.com/BurntSushi/xsv

use std::env;
use std::fmt;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process;
use std::str;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread;
use std::time;

static TEST_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// This code is inspired by the `WorkDir` pattern that BurntSushi uses to
/// test CLI tools like `ripgrep` and `xsv`.
pub struct TestDir {
    bin: PathBuf,
    dir: PathBuf,
}

impl TestDir {
    /// Create a new `TestDir` for the current test.  You must specify
    /// `bin_name` (the name of a binary built by the current crate) and
    /// `test_name` (a unique name for the current test).
    ///
    /// If our output directory exists from a previous test run, it will be
    /// deleted.
    pub fn new(bin_name: &str, test_name: &str) -> TestDir {
        let mut bin_dir = env::current_exe()
            .expect("Could not find executable")
            .parent()
            .expect("Could not find parent directory for executable")
            .to_path_buf();
        if bin_dir.ends_with("deps") {
            bin_dir.pop();
        }
        let id = TEST_ID.fetch_add(1, Ordering::SeqCst);
        let dir = bin_dir.join("integration-tests")
            .join(test_name)
            .join(format!("{}", id));
        if dir.exists() {
            fs::remove_dir_all(&dir)
                .expect("Could not remove test output directory");
        }

        // Work around https://github.com/rust-lang/rust/issues/33707.
        let mut err = None;
        for _ in 0..10 {
            match fs::create_dir_all(&dir) {
                Ok(_) => {
                    err = None;
                    break;
                }
                Err(e) => {
                    err = Some(e);
                }
            }
            thread::sleep(time::Duration::from_millis(500));
        }
        if let Some(e) = err {
            panic!("Could not create test output directory: {}", e);
        }

        let mut bin = bin_dir.join(&bin_name);
        if !bin.exists() {
            writeln!(io::stderr(),
                     "WARNING: could not find {}, will search PATH",
                     bin.display())
                .expect("could not write to stderr");
            bin = Path::new(&bin_name).to_owned();
        }

        TestDir {
            bin: bin,
            dir: dir,
        }
    }

    /// Return a `std::process::Command` object that can be used to execute
    /// the binary.
    pub fn cmd(&self) -> process::Command {
        let mut cmd = process::Command::new(&self.bin);
        cmd.current_dir(&self.dir);
        cmd
    }

    /// Return a path relative to the source directory of the current
    /// crate.  Useful for finding fixtures.
    pub fn src_path<P: AsRef<Path>>(&self, path: P) -> PathBuf {
        let cwd = env::current_dir().expect("Could not get current dir");
        fs::canonicalize(cwd.join(path))
            .expect("Could not canonicalize path")
    }

    /// Create a file in our test directory with the specified contents.
    pub fn create_file<P, S>(&self, path: P, contents: S)
        where P: AsRef<Path>, S: AsRef<[u8]>
    {
        let path = self.dir.join(path);
        fs::create_dir_all(path.parent().expect("expected parent"))
            .expect("could not create directory");
        let mut f = fs::File::create(&path).expect("can't create file");
        f.write_all(contents.as_ref()).expect("can't write to file");
    }

    /// If `path` does not point to valid path, fail the current test.
    pub fn expect_path<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        assert!(path.exists(), format!("{} exists", path.display()));
    }

    /// Verify that the file contains the specified data.
    pub fn expect_file_contents<P, S>(&self, path: P, expected: S)
        where P: AsRef<Path>, S: AsRef<[u8]>
    {
        let path = self.dir.join(path);
        let expected = expected.as_ref();
        self.expect_path(&path);
        let mut f = fs::File::open(&path).expect("could not open file");
        let mut found = vec![];
        f.read_to_end(&mut found).expect("could not read file");
        expect_data_eq(path.display(), &found, expected);
    }

    /// Verify that the contents of the file match the specified pattern.
    /// Someday this should support `std::str::pattern::Pattern` so that we
    /// can support both strings and regular expressions, but that hasn't
    /// been stabilized yet.
    pub fn expect_contains<P>(&self, path: P, pattern: &str)
        where P: AsRef<Path>
    {
        let path = self.dir.join(path);
        self.expect_path(&path);
        let mut f = fs::File::open(&path).expect("could not open file");
        let mut found = vec![];
        f.read_to_end(&mut found).expect("could not read file");
        let found = str::from_utf8(&found).expect("expected UTF-8 file");
        assert!(found.contains(pattern),
                format!("expected {} to match {:?}, but it contained {:?}",
                        path.display(), pattern, found));
    }
}

/// Internal helper function which compares to blobs of potentially binary data.
fn expect_data_eq<D>(source: D, found: &[u8], expected: &[u8])
    where D: fmt::Display
{
    if found != expected {
        // TODO: If the data appears to be actual binary, do a better job
        // of printing it.
        panic!("expected {} to equal {:?}, found {:?}",
               source,
               String::from_utf8_lossy(expected).as_ref(),
               String::from_utf8_lossy(found).as_ref());
    }
}

/// Extension methods for `std::process::Command`.
pub trait CommandExt {
    /// Spawn this command, passing it the specified data on standard
    /// input.
    fn output_with_stdin<S: AsRef<[u8]>>(&mut self, input: S)
                                         -> io::Result<process::Output>;
}

impl CommandExt for process::Command {
    fn output_with_stdin<S>(&mut self, input: S)
                            -> io::Result<process::Output>
        where S: AsRef<[u8]>
    {
        let input = input.as_ref().to_owned();
        let mut child: process::Child = self.stdin(process::Stdio::piped())
            .stdout(process::Stdio::piped())
            .stderr(process::Stdio::piped())
            .spawn()
            .expect("error running command");
        let mut stdin = child.stdin.take()
            .expect("std in is unexpectedly missing");
        let worker = thread::spawn(move || {
            stdin.write_all(&input)
                .expect("could not write to stdin");
            stdin.flush()
                .expect("could not flush data to child's stdin");
        });
        let result = child.wait_with_output();
        worker.join().expect("stdin writer failed");
        result
    }
}

/// Extension methods for `std::process::Output`.
pub trait OutputExt {
    /// Get standard output as a `str`.
    fn stdout_str(&self) -> &str;

    /// Get standard error as a `str`.
    fn stderr_str(&self) -> &str;
}

impl OutputExt for process::Output {
    fn stdout_str(&self) -> &str {
        str::from_utf8(&self.stdout)
            .expect("stdout was not UTF-8 text")
    }

    fn stderr_str(&self) -> &str {
        str::from_utf8(&self.stderr)
            .expect("stderr was not UTF-8 text")
    }
}

/// We define `expect_status` on quite a few related types to support
/// different calling patterns.
pub trait ExpectStatus {
    /// Expect the child process to succeed, and return a
    /// `std::process::Output` object with its output.
    fn expect_success(self) -> process::Output;

    /// Expect the child process to fail, and return `std::process::Output`
    /// object with its output.
    fn expect_failure(self) -> process::Output;
}

impl ExpectStatus for process::Output {
    fn expect_success(self) -> process::Output {
        if !self.status.success() {
            io::stdout().write_all(&self.stdout)
                .expect("could not write to stdout");
            io::stderr().write_all(&self.stderr)
                .expect("could not write to stderr");
            panic!("expected command to succeed, got {:?}", self.status)
        }
        self
    }

    fn expect_failure(self) -> process::Output {
        if self.status.success() {
            io::stdout().write_all(&self.stdout)
                .expect("could not write to stdout");
            io::stderr().write_all(&self.stderr)
                .expect("could not write to stderr");
            panic!("expected command to fail, got {:?}", self.status)
        }
        self
    }

}

impl<ES: ExpectStatus, E: fmt::Debug> ExpectStatus for Result<ES, E> {
    fn expect_success(self) -> process::Output {
        // Unwrap the result, fail on error, and pass `expect_success` to
        // our wrapped type.
        match self {
            Ok(es) => es.expect_success(),
            Err(err) => panic!("error running command: {:?}", err),
        }
    }

    fn expect_failure(self) -> process::Output {
        // Unwrap the result, fail on error, and pass `expect_failure` to
        // our wrapped type.
        match self {
            Ok(es) => es.expect_failure(),
            // Note that this means we couldn't _run_ the command (perhaps
            // because it doesn't exist or wasn't in our path), not that it
            // ran but failed.
            Err(err) => panic!("error running command: {:?}", err),
        }
    }
}

impl<'a> ExpectStatus for &'a mut process::Command {
    fn expect_success(self) -> process::Output {
        self.output().expect_success()
    }

    fn expect_failure(self) -> process::Output {
        self.output().expect_failure()
    }
}

impl ExpectStatus for process::Child {
    fn expect_success(self) -> process::Output {
        self.wait_with_output().expect_success()
    }

    fn expect_failure(self) -> process::Output {
        self.wait_with_output().expect_failure()
    }
}
<commit_msg>Tweak expect_path error message to be clearer<commit_after>//! This crate makes it easier to write integration tests for CLI
//! applications.  It's based on the "workdir" pattern used by BurntSushi's
//! [xsv][] and [ripgrep][] crates, but packaged in an easy-to-reuse form.
//!
//! To use this crate, add the following lines to your `Cargo.toml` file:
//!
//! ```toml
//! [dev-dependencies]
//! # You can replace "*" with the current version of this crate.
//! cli_test_dir = "*"
//! ```
//!
//! Then add the following to the top of `tests/tests.rs`:
//!
//! ```rust,no_run
//! extern crate cli_test_dir;
//! ```
//!
//! You should now be able to write tests as follows:
//!
//! ```
//! use cli_test_dir::*;
//!
//! #[test]
//! fn write_output_file() {
//!     let testdir = TestDir::new("myapp", "write_output_file");
//!     testdir.cmd()
//!         .arg("out.txt")
//!         .expect_success();
//!     testdir.expect_path("out.txt");
//! }
//! ```
//!
//! You can use any options from [`std::process::Command`][Command] to invoke
//! your program.
//!
//! [Command]: https://doc.rust-lang.org/std/process/struct.Command.html
//!
//! ## Testing that the program ran successfully
//!
//! To check that a command succeeds, we can write:
//!
//! ```
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("true", "true_succeeds");
//! testdir.cmd().expect_success();
//! ```
//!
//! But this test would fail:
//!
//! ```rust,should_panic
//! # use cli_test_dir::*;
//! // Fails.
//! let testdir = TestDir::new("false", "false_succeeds");
//! testdir.cmd().expect_success();
//! ```
//!
//! ## Testing that the program exited with an error.
//!
//! Sometimes you want to test that a program fails to run successfully.
//!
//! ```
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("false", "false_fails");
//! testdir.cmd().expect_failure();
//! ```
//!
//! And as you would expect, this test would fail:
//!
//! ```rust,should_panic
//! # use cli_test_dir::*;
//! // Fails.
//! let testdir = TestDir::new("true", "true_fails");
//! testdir.cmd().expect_failure();
//! ```
//!
//! ## File input and output
//!
//! The `src_path` function can be used to build paths relative to the
//! top-level of our crate, and `expect_path` can be used to make sure an
//! output file exists:
//!
//! ```rust,no_run
//! # // Don't run because `cp` will have path problems on Windows.
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("cp", "cp_copies_files");
//! testdir.cmd()
//!   .arg(testdir.src_path("fixtures/input.txt"))
//!   .arg("output.txt")
//!   .expect_success();
//! testdir.expect_path("output.txt");
//! ```
//!
//! We can also create the input file manually or look for specific
//! contents in the output file if we wish:
//!
//! ```
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("cp", "cp_copies_files_2");
//! testdir.create_file("input.txt", "Hello, world!\n");
//! testdir.cmd()
//!   .arg("input.txt")
//!   .arg("output.txt")
//!   .expect_success();
//! testdir.expect_contains("output.txt", "Hello");
//! testdir.expect_file_contents("output.txt", "Hello, world!\n");
//! ```
//!
//! ## Standard input and output
//!
//! We can also test standard input and output:
//!
//! ```
//! # use cli_test_dir::*;
//! let testdir = TestDir::new("cat", "cat_passes_data_through");
//! let output = testdir.cmd()
//!   .output_with_stdin("Hello\n")
//!   .expect_success();
//! assert_eq!(output.stdout_str(), "Hello\n");
//! ```
//!
//! ## Contributing
//!
//! Your feedback and contributions are welcome!  Please see
//! [GitHub](https://github.com/emk/subtitles-rs) for details.
//!
//! [ripgrep]: https://github.com/BurntSushi/ripgrep
//! [xsv]: https://github.com/BurntSushi/xsv

use std::env;
use std::fmt;
use std::fs;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process;
use std::str;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread;
use std::time;

static TEST_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// This code is inspired by the `WorkDir` pattern that BurntSushi uses to
/// test CLI tools like `ripgrep` and `xsv`.
pub struct TestDir {
    bin: PathBuf,
    dir: PathBuf,
}

impl TestDir {
    /// Create a new `TestDir` for the current test.  You must specify
    /// `bin_name` (the name of a binary built by the current crate) and
    /// `test_name` (a unique name for the current test).
    ///
    /// If our output directory exists from a previous test run, it will be
    /// deleted.
    pub fn new(bin_name: &str, test_name: &str) -> TestDir {
        let mut bin_dir = env::current_exe()
            .expect("Could not find executable")
            .parent()
            .expect("Could not find parent directory for executable")
            .to_path_buf();
        if bin_dir.ends_with("deps") {
            bin_dir.pop();
        }
        let id = TEST_ID.fetch_add(1, Ordering::SeqCst);
        let dir = bin_dir.join("integration-tests")
            .join(test_name)
            .join(format!("{}", id));
        if dir.exists() {
            fs::remove_dir_all(&dir)
                .expect("Could not remove test output directory");
        }

        // Work around https://github.com/rust-lang/rust/issues/33707.
        let mut err = None;
        for _ in 0..10 {
            match fs::create_dir_all(&dir) {
                Ok(_) => {
                    err = None;
                    break;
                }
                Err(e) => {
                    err = Some(e);
                }
            }
            thread::sleep(time::Duration::from_millis(500));
        }
        if let Some(e) = err {
            panic!("Could not create test output directory: {}", e);
        }

        let mut bin = bin_dir.join(&bin_name);
        if !bin.exists() {
            writeln!(io::stderr(),
                     "WARNING: could not find {}, will search PATH",
                     bin.display())
                .expect("could not write to stderr");
            bin = Path::new(&bin_name).to_owned();
        }

        TestDir {
            bin: bin,
            dir: dir,
        }
    }

    /// Return a `std::process::Command` object that can be used to execute
    /// the binary.
    pub fn cmd(&self) -> process::Command {
        let mut cmd = process::Command::new(&self.bin);
        cmd.current_dir(&self.dir);
        cmd
    }

    /// Return a path relative to the source directory of the current
    /// crate.  Useful for finding fixtures.
    pub fn src_path<P: AsRef<Path>>(&self, path: P) -> PathBuf {
        let cwd = env::current_dir().expect("Could not get current dir");
        fs::canonicalize(cwd.join(path))
            .expect("Could not canonicalize path")
    }

    /// Create a file in our test directory with the specified contents.
    pub fn create_file<P, S>(&self, path: P, contents: S)
        where P: AsRef<Path>, S: AsRef<[u8]>
    {
        let path = self.dir.join(path);
        fs::create_dir_all(path.parent().expect("expected parent"))
            .expect("could not create directory");
        let mut f = fs::File::create(&path).expect("can't create file");
        f.write_all(contents.as_ref()).expect("can't write to file");
    }

    /// If `path` does not point to valid path, fail the current test.
    pub fn expect_path<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        assert!(path.exists(), format!("{} should exist", path.display()));
    }

    /// Verify that the file contains the specified data.
    pub fn expect_file_contents<P, S>(&self, path: P, expected: S)
        where P: AsRef<Path>, S: AsRef<[u8]>
    {
        let path = self.dir.join(path);
        let expected = expected.as_ref();
        self.expect_path(&path);
        let mut f = fs::File::open(&path).expect("could not open file");
        let mut found = vec![];
        f.read_to_end(&mut found).expect("could not read file");
        expect_data_eq(path.display(), &found, expected);
    }

    /// Verify that the contents of the file match the specified pattern.
    /// Someday this should support `std::str::pattern::Pattern` so that we
    /// can support both strings and regular expressions, but that hasn't
    /// been stabilized yet.
    pub fn expect_contains<P>(&self, path: P, pattern: &str)
        where P: AsRef<Path>
    {
        let path = self.dir.join(path);
        self.expect_path(&path);
        let mut f = fs::File::open(&path).expect("could not open file");
        let mut found = vec![];
        f.read_to_end(&mut found).expect("could not read file");
        let found = str::from_utf8(&found).expect("expected UTF-8 file");
        assert!(found.contains(pattern),
                format!("expected {} to match {:?}, but it contained {:?}",
                        path.display(), pattern, found));
    }
}

/// Internal helper function which compares to blobs of potentially binary data.
fn expect_data_eq<D>(source: D, found: &[u8], expected: &[u8])
    where D: fmt::Display
{
    if found != expected {
        // TODO: If the data appears to be actual binary, do a better job
        // of printing it.
        panic!("expected {} to equal {:?}, found {:?}",
               source,
               String::from_utf8_lossy(expected).as_ref(),
               String::from_utf8_lossy(found).as_ref());
    }
}

/// Extension methods for `std::process::Command`.
pub trait CommandExt {
    /// Spawn this command, passing it the specified data on standard
    /// input.
    fn output_with_stdin<S: AsRef<[u8]>>(&mut self, input: S)
                                         -> io::Result<process::Output>;
}

impl CommandExt for process::Command {
    fn output_with_stdin<S>(&mut self, input: S)
                            -> io::Result<process::Output>
        where S: AsRef<[u8]>
    {
        let input = input.as_ref().to_owned();
        let mut child: process::Child = self.stdin(process::Stdio::piped())
            .stdout(process::Stdio::piped())
            .stderr(process::Stdio::piped())
            .spawn()
            .expect("error running command");
        let mut stdin = child.stdin.take()
            .expect("std in is unexpectedly missing");
        let worker = thread::spawn(move || {
            stdin.write_all(&input)
                .expect("could not write to stdin");
            stdin.flush()
                .expect("could not flush data to child's stdin");
        });
        let result = child.wait_with_output();
        worker.join().expect("stdin writer failed");
        result
    }
}

/// Extension methods for `std::process::Output`.
pub trait OutputExt {
    /// Get standard output as a `str`.
    fn stdout_str(&self) -> &str;

    /// Get standard error as a `str`.
    fn stderr_str(&self) -> &str;
}

impl OutputExt for process::Output {
    fn stdout_str(&self) -> &str {
        str::from_utf8(&self.stdout)
            .expect("stdout was not UTF-8 text")
    }

    fn stderr_str(&self) -> &str {
        str::from_utf8(&self.stderr)
            .expect("stderr was not UTF-8 text")
    }
}

/// We define `expect_status` on quite a few related types to support
/// different calling patterns.
pub trait ExpectStatus {
    /// Expect the child process to succeed, and return a
    /// `std::process::Output` object with its output.
    fn expect_success(self) -> process::Output;

    /// Expect the child process to fail, and return `std::process::Output`
    /// object with its output.
    fn expect_failure(self) -> process::Output;
}

impl ExpectStatus for process::Output {
    fn expect_success(self) -> process::Output {
        if !self.status.success() {
            io::stdout().write_all(&self.stdout)
                .expect("could not write to stdout");
            io::stderr().write_all(&self.stderr)
                .expect("could not write to stderr");
            panic!("expected command to succeed, got {:?}", self.status)
        }
        self
    }

    fn expect_failure(self) -> process::Output {
        if self.status.success() {
            io::stdout().write_all(&self.stdout)
                .expect("could not write to stdout");
            io::stderr().write_all(&self.stderr)
                .expect("could not write to stderr");
            panic!("expected command to fail, got {:?}", self.status)
        }
        self
    }

}

impl<ES: ExpectStatus, E: fmt::Debug> ExpectStatus for Result<ES, E> {
    fn expect_success(self) -> process::Output {
        // Unwrap the result, fail on error, and pass `expect_success` to
        // our wrapped type.
        match self {
            Ok(es) => es.expect_success(),
            Err(err) => panic!("error running command: {:?}", err),
        }
    }

    fn expect_failure(self) -> process::Output {
        // Unwrap the result, fail on error, and pass `expect_failure` to
        // our wrapped type.
        match self {
            Ok(es) => es.expect_failure(),
            // Note that this means we couldn't _run_ the command (perhaps
            // because it doesn't exist or wasn't in our path), not that it
            // ran but failed.
            Err(err) => panic!("error running command: {:?}", err),
        }
    }
}

impl<'a> ExpectStatus for &'a mut process::Command {
    fn expect_success(self) -> process::Output {
        self.output().expect_success()
    }

    fn expect_failure(self) -> process::Output {
        self.output().expect_failure()
    }
}

impl ExpectStatus for process::Child {
    fn expect_success(self) -> process::Output {
        self.wait_with_output().expect_success()
    }

    fn expect_failure(self) -> process::Output {
        self.wait_with_output().expect_failure()
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 The http-serve developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE.txt or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT.txt or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Test program which serves the current directory on `http://127.0.0.1:1337/`.
//! Note this requires `--features dir`.

use http::header::{self, HeaderMap, HeaderValue};
use http_serve::dir;
use hyper::service::{make_service_fn, service_fn};
use hyper::Body;
use std::fmt::Write;
use std::io::Write as RawWrite;
use std::sync::Arc;

fn is_dir(dir: &nix::dir::Dir, ent: &nix::dir::Entry) -> Result<bool, nix::Error> {
    if let Some(t) = ent.file_type() {
        return Ok(t == nix::dir::Type::Directory);
    }
    use nix::sys::stat::{fstatat, SFlag};
    use std::os::unix::io::AsRawFd;
    let stat = fstatat(
        dir.as_raw_fd(),
        ent.file_name(),
        nix::fcntl::AtFlags::empty(),
    )?;
    let mode = SFlag::from_bits(stat.st_mode).unwrap();
    Ok(mode.contains(SFlag::S_IFDIR))
}

fn reply(
    req: http::Request,
    node: dir::Node,
) -> Result<http::Response, ::std::io::Error> {
    if node.metadata().is_dir() {
        if !req.uri().path().ends_with("/") {
            let mut loc = ::bytes::BytesMut::with_capacity(req.uri().path().len() + 1);
            write!(loc, "{}/", req.uri().path()).unwrap();
            let loc = HeaderValue::from_maybe_shared(loc.freeze()).unwrap();
            return Ok(http::Response::builder()
                .status(http::StatusCode::MOVED_PERMANENTLY)
                .header(http::header::LOCATION, loc)
                .body(Body::empty())
                .unwrap());
        }
        let (mut resp, stream) = http_serve::streaming_body(&req).build();
        if let Some(mut w) = stream {
            let mut dir = nix::dir::Dir::from(node.into_file()).unwrap(); // TODO: don't unwrap.
            write!(
                &mut w,
                "<!DOCTYPE html>\n<title>directory listing</title>\n
\n"
            )?;
            let mut ents: Vec<_> = dir.iter().map(|e| e.unwrap()).collect();
            ents.sort_unstable_by(|a, b| a.file_name().cmp(b.file_name()));
            for ent in ents {
                let p = match ent.file_name().to_str() {
                    Err(_) => continue, // skip non-UTF-8
                    Ok(".") => continue,
                    Ok(p) => p,
                };
                if p == ".." && req.uri().path() == "/" {
                    continue;
                };
                write!(&mut w, "
")?;
                htmlescape::encode_minimal_w(p, &mut w)?;
                if is_dir {
                    write!(&mut w, "/")?;
                }
                write!(&mut w, "\n")?;
            }
            write!(&mut w, "
\n")?;
        }
        resp.headers_mut()
            .insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html"));
        return Ok(resp);
    }
    let mut h = HeaderMap::new();
    node.add_encoding_headers(&mut h);
    if let Some(dot) = req.uri().path().rfind('.') {
        let ext = &req.uri().path()[dot + 1..];
        if let Some(mime_type) = mime_guess::get_mime_type_str(ext) {
            h.insert(header::CONTENT_TYPE, HeaderValue::from_static(mime_type));
        }
    }
    let f = node.into_file_entity(h)?;
    Ok(http_serve::serve(f, &req))
}

async fn serve(
    fs_dir: &Arc<dir::FsDir>,
    req: http::Request,
) -> Result<http::Response, ::std::io::Error> {
    let p = if req.uri().path() == "/" {
        "."
    } else {
        &req.uri().path()[1..]
    };
    // TODO: this should go through the same unwrapping.
    let node = Arc::clone(&fs_dir).get(p, req.headers()).await?;
    let e = match reply(req, node) {
        Ok(res) => return Ok(res),
        Err(e) => e,
    };
    let status = match e.kind() {
        ::std::io::ErrorKind::NotFound => http::StatusCode::NOT_FOUND,
        _ => http::StatusCode::INTERNAL_SERVER_ERROR,
    };
    Ok(http::Response::builder()
        .status(status)
        .body(format!("I/O error: {}", e).into())
        .unwrap())
}

#[tokio::main]
async fn main() {
    let dir: &'static Arc<dir::FsDir> =
        Box::leak(Box::new(dir::FsDir::builder().for_path(".").unwrap()));
    env_logger::init();
    let addr = ([127, 0, 0, 1], 1337).into();
    let make_svc = make_service_fn(move |_conn| {
        futures::future::ok::<_, std::convert::Infallible>(service_fn(move |req| serve(dir, req)))
    });
    let server = hyper::Server::bind(&addr).serve(make_svc);
    println!("Serving . on http://{} with 1 thread.", server.local_addr());
    server.await.unwrap();
}
<commit_msg>cleanup serve_dir example<commit_after>// Copyright (c) 2020 The http-serve developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE.txt or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT.txt or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Test program which serves the current directory on `http://127.0.0.1:1337/`.
//! Note this requires `--features dir`.

use futures_util::future;
use http::header::{self, HeaderMap, HeaderValue};
use http_serve::dir;
use hyper::service::{make_service_fn, service_fn};
use hyper::Body;
use std::fmt::Write;
use std::io::Write as RawWrite;
use std::sync::Arc;

fn is_dir(dir: &nix::dir::Dir, ent: &nix::dir::Entry) -> Result<bool, nix::Error> {
    if let Some(t) = ent.file_type() {
        return Ok(t == nix::dir::Type::Directory);
    }
    use nix::sys::stat::{fstatat, SFlag};
    use std::os::unix::io::AsRawFd;
    let stat = fstatat(
        dir.as_raw_fd(),
        ent.file_name(),
        nix::fcntl::AtFlags::empty(),
    )?;
    let mode = SFlag::from_bits(stat.st_mode).unwrap();
    Ok(mode.contains(SFlag::S_IFDIR))
}

fn reply(
    req: http::Request,
    node: dir::Node,
) -> Result<http::Response, ::std::io::Error> {
    if node.metadata().is_dir() {
        if !req.uri().path().ends_with("/") {
            let mut loc = ::bytes::BytesMut::with_capacity(req.uri().path().len() + 1);
            write!(loc, "{}/", req.uri().path()).unwrap();
            let loc = HeaderValue::from_maybe_shared(loc.freeze()).unwrap();
            return Ok(http::Response::builder()
                .status(http::StatusCode::MOVED_PERMANENTLY)
                .header(http::header::LOCATION, loc)
                .body(Body::empty())
                .unwrap());
        }
        let (mut resp, stream) = http_serve::streaming_body(&req).build();
        if let Some(mut w) = stream {
            let mut dir = nix::dir::Dir::from(node.into_file()).unwrap(); // TODO: don't unwrap.
            write!(
                &mut w,
                "<!DOCTYPE html>\n<title>directory listing</title>\n
\n"
            )?;
            let mut ents: Vec<_> = dir.iter().map(|e| e.unwrap()).collect();
            ents.sort_unstable_by(|a, b| a.file_name().cmp(b.file_name()));
            for ent in ents {
                let p = match ent.file_name().to_str() {
                    Err(_) => continue, // skip non-UTF-8
                    Ok(".") => continue,
                    Ok(p) => p,
                };
                if p == ".." && req.uri().path() == "/" {
                    continue;
                };
                write!(&mut w, "
")?;
                htmlescape::encode_minimal_w(p, &mut w)?;
                if is_dir {
                    write!(&mut w, "/")?;
                }
                write!(&mut w, "\n")?;
            }
            write!(&mut w, "
\n")?;
        }
        resp.headers_mut()
            .insert(header::CONTENT_TYPE, HeaderValue::from_static("text/html"));
        return Ok(resp);
    }
    let mut h = HeaderMap::new();
    node.add_encoding_headers(&mut h);
    if let Some(dot) = req.uri().path().rfind('.') {
        let ext = &req.uri().path()[dot + 1..];
        if let Some(mime_type) = mime_guess::from_ext(ext).first_raw() {
            h.insert(header::CONTENT_TYPE, HeaderValue::from_static(mime_type));
        }
    }
    let f = node.into_file_entity(h)?;
    Ok(http_serve::serve(f, &req))
}

async fn serve(
    fs_dir: &Arc<dir::FsDir>,
    req: http::Request,
) -> Result<http::Response, ::std::io::Error> {
    let p = if req.uri().path() == "/" {
        "."
    } else {
        &req.uri().path()[1..]
    };
    // TODO: this should go through the same unwrapping.
    let node = Arc::clone(&fs_dir).get(p, req.headers()).await?;
    let e = match reply(req, node) {
        Ok(res) => return Ok(res),
        Err(e) => e,
    };
    let status = match e.kind() {
        ::std::io::ErrorKind::NotFound => http::StatusCode::NOT_FOUND,
        _ => http::StatusCode::INTERNAL_SERVER_ERROR,
    };
    Ok(http::Response::builder()
        .status(status)
        .body(format!("I/O error: {}", e).into())
        .unwrap())
}

#[tokio::main]
async fn main() {
    let dir: &'static Arc<dir::FsDir> =
        Box::leak(Box::new(dir::FsDir::builder().for_path(".").unwrap()));
    env_logger::init();
    let addr = ([127, 0, 0, 1], 1337).into();
    let make_svc = make_service_fn(move |_conn| {
        future::ok::<_, std::convert::Infallible>(service_fn(move |req| serve(dir, req)))
    });
    let server = hyper::Server::bind(&addr).serve(make_svc);
    println!("Serving . on http://{} with 1 thread.", server.local_addr());
    server.await.unwrap();
}
<|endoftext|>


<commit_before>use ::{DeterministicRandomId, PersistentTypeId, ListedType, PersistentlyIdentifiedType, SimulationStateData, DataHandleTrait, DataTimelineCellTrait, ExtendedTime};
use ::stewards::{simple_full as steward_module};
use self::steward_module::{TimeSteward, Event, DataTimelineCellReadGuard, DataHandle, DataTimelineCell, Accessor, EventAccessor, FutureCleanupAccessor, SnapshotAccessor, simple_timeline};
use self::simple_timeline::{SimpleTimeline, GetVarying, tracking_query, tracking_query_ref, set, unset};

pub type Coordinate = u32;
pub type NumDimensions = u32;

pub trait BoundingBoxCollisionDetectable: PersistentlyIdentifiedType {
  type Steward: TimeSteward;
  type Object: SimulationStateData + PersistentlyIdentifiedType;
  type Space; // a way to distinguish if the same object can be put in multiple collision detectors of the same type. Can easily be () if not.

  const DIMENSIONS: NumDimensions;

  // An Object generally has to store some opaque data for the collision detector.
  // It would normally include a DataHandle to a tree node.
  // These are getter and setter methods for that data.
  fn get_collision_detector_data<A: EventAccessor <Steward = Self::Steward>>(accessor: &A, object: &DataHandle<Self::Object>, space: &Self::Space)->Option<&ObjectData<Self>>>;
  fn set_collision_detector_data<A: EventAccessor <Steward = Self::Steward>>(accessor: &A, object: &DataHandle<Self::Object>, space: &Self::Space, data: Option<ObjectData<Self>>);

  fn calculate_current_bounding_box<A: EventAccessor <Steward = Self::Steward>>(accessor: &A, object: &DataHandle<Self::Object>, space: &Self::Space)->BoundingBox;
  fn when_escapes<A: EventAccessor <Steward = Self::Steward>>(accessor: &A, object: &DataHandle<Self::Object>, space: &Self::Space, BoundingBox)-><Self::Steward as TimeSteward>::Basics::Time;

  fn become_nearby<A: EventAccessor <Steward = Self::Steward>>(accessor: &A, objects: [&DataHandle<Self::Object>; 2], space: &Self::Space) {}
  fn stop_being_nearby<A: EventAccessor <Steward = Self::Steward>>(accessor: &A, objects: [&DataHandle<Self::Object>; 2], space: &Self::Space) {}
}

pub struct BoundingBox<B: BoundingBoxCollisionDetectable> {
  pub bounds: [[Coordinate; 2]; B::DIMENSIONS],
}
struct NodeBounds<B: BoundingBoxCollisionDetectable> {
  half_size_shift: u32,
  center: [Coordinate; B::DIMENSIONS],
}
fn smallest_containing_node_bounds <B: BoundingBoxCollisionDetectable> (bounds: & BoundingBox<B>)->NodeBounds <B> {
  unimplemented!()
}

#[derive (Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
struct Node<B: BoundingBoxCollisionDetectable> {
  bounds: NodeBounds<B>,
  parent: Option<DataHandle <Node <B>>>,
  larger_cousins: [[Option<DataHandle <Node <B>>>; 2]; B::DIMENSIONS],
  varying: NodeVarying <B>,
}
impl<B: BoundingBoxCollisionDetectable> PersistentlyIdentifiedType for Node<B> {
  const ID: PersistentTypeId = PersistentTypeId(B::ID.0 ^ 0x7c4c8993671ba023);
}
#[derive (Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
struct NodeVarying<B: BoundingBoxCollisionDetectable> {
  children: [Option<DataHandle <Node <B>>>; 1<<B::DIMENSIONS],
  overlapping_live_nodes: Vec<DataHandle <B::Object>>,
  objects: Vec<DataHandle <B::Object>>,
}

pub struct ObjectData<B: BoundingBoxCollisionDetectable> {
  varying: ObjectVarying<B>,
}
struct ObjectVarying<B: BoundingBoxCollisionDetectable> {
  node: DataHandle <Node <B>>,
}
pub struct BoundingBoxCollisionDetector<B: BoundingBoxCollisionDetectable> {
  root: DataHandle <Node <B>>,
}

impl<B: BoundingBoxCollisionDetectable> BoundingBoxCollisionDetector<B> {
  pub fn insert<A: EventAccessor <Steward = B::Steward>>(accessor: &A, object: &DataHandle<B::Object>, space: &B::Space, location_hint: Option <& DataHandle<B::Object>>) {

  }
  pub fn remove<A: EventAccessor <Steward = B::Steward>>(accessor: &A, object: &DataHandle<B::Object>, space: &B::Space) {

  }
  pub fn neighbors<A: EventAccessor <Steward = B::Steward>>(accessor: &A, object: &DataHandle<B::Object>, space: &B::Space) -> Iter {

  }
}

#[derive (Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct EscapesBounds<B: BoundingBoxCollisionDetectable> {}
impl<B: BoundingBoxCollisionDetectable> PersistentlyIdentifiedType for EscapesBounds<B> {
  const ID: PersistentTypeId = PersistentTypeId(B::ID.0 ^ 0xb0cdbe951b688b70);
}
impl<B: BoundingBoxCollisionDetectable> Event for EscapesBounds<B> {
  type Steward = B::Steward;
  type ExecutionData = ();
  fn execute <Accessor: EventAccessor <Steward = Self::Steward>> (&self, accessor: &mut Accessor) {

  }

  fn undo <Accessor: FutureCleanupAccessor <Steward = Self::Steward>> (&self, accessor: &mut Accessor, _: ()) {
    unimplemented!()
  }
}

impl<B: BoundingBoxCollisionDetectable> BoundingBoxCollisionDetector<B> {
  fn reposition <A: EventAccessor <Steward = B::Steward>> (accessor: &A, object: &DataHandle<B::Object>) {
    let varying = tracking_query (accessor, object.varying);
    let mut current_node = varying.node;
    let new_bounds = B::calculate_current_bounding_box (object);
    let destination_node_bounds = smallest_containing_node_bounds (new_bounds) ;
    let bigger_shift = max (current_node.bounds.half_size_shift, destination_node_bounds.half_size_shift);

    while current_node.bounds.half_size_shift < bigger_shift {
      current_node = current_node.parent.expect("All nodes except the root node have to have a parent, and we should never be trying to navigate to a node bigger than the root");
    }

    let mut destination_ancestor_bounds = destination_node_bounds;
    while destination_ancestor_bounds.half_size_shift < bigger_shift {
      destination_ancestor_bounds = parent_bounds(destination_ancestor_bounds);
    }

    while largest_single_dimension_distance (current_node.bounds, destination_ancestor_bounds) > (1 << destination_ancestor_bounds.half_size_shift) {
      destination_ancestor_bounds = parent_bounds(destination_ancestor_bounds);
      current_node = current_node.parent.expect("All nodes except the root node have to have a parent, and we should never be trying to navigate to a node bigger than the root");
    }

    if current_node.bounds != destination_ancestor_bounds {
      // they should now be the same size and half- or all-overlapping in each dimension.
    }
  }
}
<commit_msg>Started writing a simple-grid collision detector<commit_after>use ::{DeterministicRandomId, PersistentTypeId, ListedType, PersistentlyIdentifiedType, SimulationStateData, DataHandleTrait, DataTimelineCellTrait, ExtendedTime};
use ::stewards::{simple_full as steward_module};
use self::steward_module::{TimeSteward, Event, DataTimelineCellReadGuard, DataHandle, DataTimelineCell, Accessor, EventAccessor, FutureCleanupAccessor, SnapshotAccessor, simple_timeline};
use self::simple_timeline::{SimpleTimeline, GetVarying, tracking_query, tracking_query_ref, set, unset};

pub type Coordinate = u32;
pub type NumDimensions = u32;

/// If there's only one interpretation of how your objects are arranged in space, it makes sense to implement this on a unit-like struct.
pub trait Space: SimulationStateData + PersistentlyIdentifiedType {
  type Steward: TimeSteward;
  type Object: SimulationStateData + PersistentlyIdentifiedType;
  type DetectorDataPerObject: SimulationStateData;

  const DIMENSIONS: NumDimensions;

  // An Object generally has to store some opaque data for the collision detector.
  // It would normally include a DataHandle to a tree node.
  // These are getter and setter methods for that data.
  fn get_detector_data<A: EventAccessor <Steward = Self::Steward>>(&self, accessor: &A, object: &DataHandle<Self::Object>)->Option<&DetectorDataPerObject<Self>>>;
  fn set_detector_data<A: EventAccessor <Steward = Self::Steward>>(&self, accessor: &A, object: &DataHandle<Self::Object>, data: Option<DetectorDataPerObject<Self>>);

  fn current_bounding_box<A: EventAccessor <Steward = Self::Steward>>(&self, accessor: &A, object: &DataHandle<Self::Object>)->BoundingBox;
  fn when_escapes<A: EventAccessor <Steward = Self::Steward>>(&self, accessor: &A, object: &DataHandle<Self::Object>, space: &Self::Space, BoundingBox)-><Self::Steward as TimeSteward>::Basics::Time;

  fn become_neighbors<A: EventAccessor <Steward = Self::Steward>>(&self, accessor: &A, objects: [&DataHandle<Self::Object>; 2]) {}
  fn stop_being_neighbors<A: EventAccessor <Steward = Self::Steward>>(&self, accessor: &A, objects: [&DataHandle<Self::Object>; 2]) {}
}

pub trait Detector: SimulationStateData {
  type Steward: TimeSteward;
  type Object: SimulationStateData + PersistentlyIdentifiedType;
  type DetectorDataPerObject: SimulationStateData;

  pub fn insert<A: EventAccessor <Steward = Self::Steward>, S: Space <DetectorDataPerObject = Self::DetectorDataPerObject>>(accessor: &A, space: &S, object: &DataHandle<S::Object>, location_hint: Option <& DataHandle<B::Object>>);
  pub fn remove<A: EventAccessor <Steward = Self::Steward>, S: Space <DetectorDataPerObject = Self::DetectorDataPerObject>>(accessor: &A, space: &S, object: &DataHandle<S::Object>);
  pub fn changed<A: EventAccessor <Steward = Self::Steward>, S: Space <DetectorDataPerObject = Self::DetectorDataPerObject>>(accessor: &A, space: &S, object: &DataHandle<S::Object>);
  pub fn nearby_objects<A: EventAccessor <Steward = Self::Steward>, S: Space <DetectorDataPerObject = Self::DetectorDataPerObject>>(accessor: &A, space: &S, object: &DataHandle<S::Object>) ->Vec<DataHandle<S::Object>>;
}

pub struct BoundingBox<B: BoundingBoxCollisionDetectable> {
  pub bounds: [[Coordinate; 2]; B::DIMENSIONS],
}

pub mod simple_grid {
  use super::*;

  pub struct SimpleGridDetector <Steward: TimeSteward> {
    cell_size: Coordinate,
    cells: DataTimelineCell<SimpleTimeline<HashMap <[Coordinate; DIMENSIONS], Cell>>>,
  }

  struct DetectorDataPerObject {
    current_grid_bounds: BoundingBox,
    escapes_bounds_prediction: Option <<Steward as TimeSteward>::EventHandle>,
  }
  struct Cell {
    objects: Vec<Object>,
  }

  impl Detector for SimpleGridDetector {
    type Steward = Steward;
    type Object = Object;
    type DetectorDataPerObject = DetectorDataPerObject;

    insert (accessor, space, object, location_hint) {

    }

    changed (accessor, space, object) {
      let data = match space.get_detector_data (accessor, object) {None => return, Some (a) => a};
      let new_bounds = space.current_bounding_box (accessor, object);
      let new_grid_bounds = self.grid_box (new_bounds);

      let mut cells = get (accessor, self.cells);
      let mut new_neighbors =
      let mut removed_neighbors =

      for location in new_bounds.locations () {
        if let Some(cell) = cells.get_mut (location) {
          for neighbor in cell.objects {
            new_neighbors.insert (neighbor) ;
          }
          if !old_bounds.contains (location) {
            cell.objects.insert (object.clone());
          }
        }
      }
      for location in old_bounds.locations () {
        if !new_bounds.contains (location) {
          let cell = cells.entry (location).or_insert (Default::default());
          for neighbor in cell.objects {
            if !new_neighbors.contains (neighbor) {
              removed_neighbors.insert (neighbor);
            }
          }
          cell.objects.insert (object.clone());
        }
      }

      for neighbor in removed_neighbors {
        space.stop_being_neighbors (accessor, [object, neighbor]);
      }
      for neighbor in new_neighbors {
        space.become_neighbors (accessor, [object, neighbor]);
      }

    }
  }

  impl SimpleGridDetector {
    fn grid_box (&self, exact_box: & BoundingBox) -> BoundingBox {
      Array::from_fn (| dimension | Array::from_fn (| direction | {
        exact_box [dimension] [direction] + direction*(self.cell_size - 1)/self.cell_size
      }))
    }
    fn real_box_from_grid (&self, grid_box: & BoundingBox) -> BoundingBox {
      Array::from_fn (| dimension | Array::from_fn (| direction | {
        grid_box [dimension] [direction] * self.cell_size
      }))
    }
  }
}

/*
struct NodeBounds<B: BoundingBoxCollisionDetectable> {
  half_size_shift: u32,
  center: [Coordinate; B::DIMENSIONS],
}
fn smallest_containing_node_bounds <B: BoundingBoxCollisionDetectable> (bounds: & BoundingBox<B>)->NodeBounds <B> {
  unimplemented!()
}

#[derive (Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
struct Node<B: BoundingBoxCollisionDetectable> {
  bounds: NodeBounds<B>,
  parent: Option<DataHandle <Node <B>>>,
  larger_cousins: [[Option<DataHandle <Node <B>>>; 2]; B::DIMENSIONS],
  varying: NodeVarying <B>,
}
impl<B: BoundingBoxCollisionDetectable> PersistentlyIdentifiedType for Node<B> {
  const ID: PersistentTypeId = PersistentTypeId(B::ID.0 ^ 0x7c4c8993671ba023);
}
#[derive (Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
struct NodeVarying<B: BoundingBoxCollisionDetectable> {
  children: [Option<DataHandle <Node <B>>>; 1<<B::DIMENSIONS],
  overlapping_live_nodes: Vec<DataHandle <B::Object>>,
  objects: Vec<DataHandle <B::Object>>,
}

pub struct ObjectData<B: BoundingBoxCollisionDetectable> {
  varying: ObjectVarying<B>,
}
struct ObjectVarying<B: BoundingBoxCollisionDetectable> {
  node: DataHandle <Node <B>>,
}
pub struct BoundingBoxCollisionDetector<B: BoundingBoxCollisionDetectable> {
  root: DataHandle <Node <B>>,
}

impl<B: BoundingBoxCollisionDetectable> BoundingBoxCollisionDetector<B> {
  pub fn insert<A: EventAccessor <Steward = B::Steward>>(accessor: &A, object: &DataHandle<B::Object>, space: &B::Space, location_hint: Option <& DataHandle<B::Object>>) {

  }
  pub fn remove<A: EventAccessor <Steward = B::Steward>>(accessor: &A, object: &DataHandle<B::Object>, space: &B::Space) {

  }
  pub fn neighbors<A: EventAccessor <Steward = B::Steward>>(accessor: &A, object: &DataHandle<B::Object>, space: &B::Space) -> Iter {

  }
}

#[derive (Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub struct EscapesBounds<B: BoundingBoxCollisionDetectable> {}
impl<B: BoundingBoxCollisionDetectable> PersistentlyIdentifiedType for EscapesBounds<B> {
  const ID: PersistentTypeId = PersistentTypeId(B::ID.0 ^ 0xb0cdbe951b688b70);
}
impl<B: BoundingBoxCollisionDetectable> Event for EscapesBounds<B> {
  type Steward = B::Steward;
  type ExecutionData = ();
  fn execute <Accessor: EventAccessor <Steward = Self::Steward>> (&self, accessor: &mut Accessor) {

  }

  fn undo <Accessor: FutureCleanupAccessor <Steward = Self::Steward>> (&self, accessor: &mut Accessor, _: ()) {
    unimplemented!()
  }
}

impl<B: BoundingBoxCollisionDetectable> BoundingBoxCollisionDetector<B> {
  fn reposition <A: EventAccessor <Steward = B::Steward>> (accessor: &A, object: &DataHandle<B::Object>) {
    let varying = tracking_query (accessor, object.varying);
    let mut current_node = varying.node;
    let new_bounds = B::calculate_current_bounding_box (object);
    let destination_node_bounds = smallest_containing_node_bounds (new_bounds) ;
    let bigger_shift = max (current_node.bounds.half_size_shift, destination_node_bounds.half_size_shift);

    while current_node.bounds.half_size_shift < bigger_shift {
      current_node = current_node.parent.expect("All nodes except the root node have to have a parent, and we should never be trying to navigate to a node bigger than the root");
    }

    let mut destination_ancestor_bounds = destination_node_bounds;
    while destination_ancestor_bounds.half_size_shift < bigger_shift {
      destination_ancestor_bounds = parent_bounds(destination_ancestor_bounds);
    }

    while largest_single_dimension_distance (current_node.bounds, destination_ancestor_bounds) > (1 << destination_ancestor_bounds.half_size_shift) {
      destination_ancestor_bounds = parent_bounds(destination_ancestor_bounds);
      current_node = current_node.parent.expect("All nodes except the root node have to have a parent, and we should never be trying to navigate to a node bigger than the root");
    }

    if current_node.bounds != destination_ancestor_bounds {
      // they should now be the same size and half- or all-overlapping in each dimension.
    }
  }
}

*/
<|endoftext|>


<commit_before>use crate::{Duration, Time};
use itertools::Itertools;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::iter::FromIterator;

pub type MessageValue = HashMap<String, Value>;

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Value {
    Bool(bool),
    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    F32(f32),
    F64(f64),
    String(String),
    Time(Time),
    Duration(Duration),
    Array(Vec<Value>),
    Message(MessageValue),
}

impl Value {
    fn fmt_indented(&self, indentation: usize, step: usize, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Value::Bool(v) => v.fmt(f),
            Value::I8(v) => v.fmt(f),
            Value::I16(v) => v.fmt(f),
            Value::I32(v) => v.fmt(f),
            Value::I64(v) => v.fmt(f),
            Value::U8(v) => v.fmt(f),
            Value::U16(v) => v.fmt(f),
            Value::U32(v) => v.fmt(f),
            Value::U64(v) => v.fmt(f),
            Value::F32(v) => v.fmt(f),
            Value::F64(v) => v.fmt(f),
            Value::String(v) => write!(f, "{:?}", v),
            Value::Time(v) => v.fmt(f),
            Value::Duration(v) => v.fmt(f),
            Value::Array(items) => {
                for item in items {
                    writeln!(f)?;
                    write!(f, "{:indent$}- ", "", indent = indentation)?;
                    item.fmt_indented(indentation + step, step, f)?;
                }
                Ok(())
            }
            Value::Message(items) => {
                for (key, item) in items.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) {
                    writeln!(f)?;
                    write!(f, "{:indent$}{}: ", "", key, indent = indentation)?;
                    item.fmt_indented(indentation + step, step, f)?;
                }
                Ok(())
            }
        }
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.fmt_indented(0, 2, f)
    }
}

impl From<bool> for Value {
    fn from(v: bool) -> Self {
        Self::Bool(v)
    }
}

impl From<i8> for Value {
    fn from(v: i8) -> Self {
        Self::I8(v)
    }
}

impl From<i16> for Value {
    fn from(v: i16) -> Self {
        Self::I16(v)
    }
}

impl From<i32> for Value {
    fn from(v: i32) -> Self {
        Self::I32(v)
    }
}

impl From<i64> for Value {
    fn from(v: i64) -> Self {
        Self::I64(v)
    }
}

impl From<u8> for Value {
    fn from(v: u8) -> Self {
        Self::U8(v)
    }
}

impl From<u16> for Value {
    fn from(v: u16) -> Self {
        Self::U16(v)
    }
}

impl From<u32> for Value {
    fn from(v: u32) -> Self {
        Self::U32(v)
    }
}

impl From<u64> for Value {
    fn from(v: u64) -> Self {
        Self::U64(v)
    }
}

impl From<f32> for Value {
    fn from(v: f32) -> Self {
        Self::F32(v)
    }
}

impl From<f64> for Value {
    fn from(v: f64) -> Self {
        Self::F64(v)
    }
}

impl From<String> for Value {
    fn from(v: String) -> Self {
        Self::String(v)
    }
}

impl From<Time> for Value {
    fn from(v: Time) -> Self {
        Self::Time(v)
    }
}

impl From<Duration> for Value {
    fn from(v: Duration) -> Self {
        Self::Duration(v)
    }
}

impl From<Vec<Value>> for Value {
    fn from(v: Vec<Value>) -> Self {
        Self::Array(v)
    }
}

impl From<HashMap<String, Value>> for Value {
    fn from(v: HashMap<String, Value>) -> Self {
        Self::Message(v)
    }
}

impl<K: Into<String>, T: Into<Value>> FromIterator<(K, T)> for Value {
    fn from_iter<I: IntoIterator<Item = (K, T)>>(iter: I) -> Self {
        Self::Message(
            iter.into_iter()
                .map(|(key, value)| (key.into(), value.into()))
                .collect(),
        )
    }
}

impl<T: Into<Value>> FromIterator<T> for Value {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Self::Array(iter.into_iter().map(Into::into).collect())
    }
}
<commit_msg>Add convenience methods to dynamic message values<commit_after>use crate::{Duration, Time};
use itertools::Itertools;
use serde_derive::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fmt;
use std::fmt::{Display, Formatter};
use std::iter::FromIterator;

pub type MessageValue = HashMap<String, Value>;

/// Represents an arbitrary ROS message or value in it.
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Value {
    Bool(bool),
    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
    F32(f32),
    F64(f64),
    String(String),
    Time(Time),
    Duration(Duration),
    Array(Vec<Value>),
    Message(MessageValue),
}

impl Value {
    fn fmt_indented(&self, indentation: usize, step: usize, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Value::Bool(v) => v.fmt(f),
            Value::I8(v) => v.fmt(f),
            Value::I16(v) => v.fmt(f),
            Value::I32(v) => v.fmt(f),
            Value::I64(v) => v.fmt(f),
            Value::U8(v) => v.fmt(f),
            Value::U16(v) => v.fmt(f),
            Value::U32(v) => v.fmt(f),
            Value::U64(v) => v.fmt(f),
            Value::F32(v) => v.fmt(f),
            Value::F64(v) => v.fmt(f),
            Value::String(v) => write!(f, "{:?}", v),
            Value::Time(v) => v.fmt(f),
            Value::Duration(v) => v.fmt(f),
            Value::Array(items) => {
                for item in items {
                    writeln!(f)?;
                    write!(f, "{:indent$}- ", "", indent = indentation)?;
                    item.fmt_indented(indentation + step, step, f)?;
                }
                Ok(())
            }
            Value::Message(items) => {
                for (key, item) in items.iter().sorted_by(|a, b| Ord::cmp(&a.0, &b.0)) {
                    writeln!(f)?;
                    write!(f, "{:indent$}{}: ", "", key, indent = indentation)?;
                    item.fmt_indented(indentation + step, step, f)?;
                }
                Ok(())
            }
        }
    }

    /// Returns the content if `Value` is a `bool`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::Bool(true).as_bool(), Some(true));
    /// assert_eq!(Value::Bool(false).as_bool(), Some(false));
    /// assert!(Value::U32(12).as_bool().is_none());
    /// ```
    pub fn as_bool(&self) -> Option<bool> {
        if let Value::Bool(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is an `i8`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::I8(12).as_i8(), Some(12));
    /// assert!(Value::U32(12).as_i8().is_none());
    /// ```
    pub fn as_i8(&self) -> Option<i8> {
        if let Value::I8(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is an `i16`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::I16(12).as_i16(), Some(12));
    /// assert!(Value::U32(12).as_i16().is_none());
    /// ```
    pub fn as_i16(&self) -> Option<i16> {
        if let Value::I16(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is an `i32`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::I32(12).as_i32(), Some(12));
    /// assert!(Value::U32(12).as_i32().is_none());
    /// ```
    pub fn as_i32(&self) -> Option<i32> {
        if let Value::I32(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is an `i64`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::I64(12).as_i64(), Some(12));
    /// assert!(Value::U32(12).as_i64().is_none());
    /// ```
    pub fn as_i64(&self) -> Option<i64> {
        if let Value::I64(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is a `u8`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::U8(12).as_u8(), Some(12));
    /// assert!(Value::U32(12).as_u8().is_none());
    /// ```
    pub fn as_u8(&self) -> Option<u8> {
        if let Value::U8(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is a `u16`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::U16(12).as_u16(), Some(12));
    /// assert!(Value::U32(12).as_u16().is_none());
    /// ```
    pub fn as_u16(&self) -> Option<u16> {
        if let Value::U16(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is a `u32`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::U32(12).as_u32(), Some(12));
    /// assert!(Value::U16(12).as_u32().is_none());
    /// ```
    pub fn as_u32(&self) -> Option<u32> {
        if let Value::U32(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is a `u64`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::U64(12).as_u64(), Some(12));
    /// assert!(Value::U32(12).as_u64().is_none());
    /// ```
    pub fn as_u64(&self) -> Option<u64> {
        if let Value::U64(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is an `f32`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::F32(12.0).as_f32(), Some(12.0));
    /// assert!(Value::U32(12).as_f32().is_none());
    /// ```
    pub fn as_f32(&self) -> Option<f32> {
        if let Value::F32(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is an `f64`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::F64(12.0).as_f64(), Some(12.0));
    /// assert!(Value::U32(12).as_f64().is_none());
    /// ```
    pub fn as_f64(&self) -> Option<f64> {
        if let Value::F64(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns a `&str` if `Value` is a `String`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(Value::String("foo".into()).as_str(), Some("foo"));
    /// assert!(Value::U32(12).as_str().is_none());
    /// ```
    pub fn as_str(&self) -> Option<&str> {
        if let Value::String(value) = self {
            Some(value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is a `Time` struct.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::{Time, Value};
    /// assert_eq!(
    ///     Value::Time(Time::from_nanos(120)).as_time(),
    ///     Some(Time::from_nanos(120)),
    /// );
    /// assert!(Value::U32(12).as_time().is_none());
    /// ```
    pub fn as_time(&self) -> Option<Time> {
        if let Value::Time(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns the content if `Value` is a `Duration` struct.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::{Duration, Value};
    /// assert_eq!(
    ///     Value::Duration(Duration::from_nanos(120)).as_duration(),
    ///     Some(Duration::from_nanos(120)),
    /// );
    /// assert!(Value::U32(12).as_duration().is_none());
    /// ```
    pub fn as_duration(&self) -> Option<Duration> {
        if let Value::Duration(value) = self {
            Some(*value)
        } else {
            None
        }
    }

    /// Returns a reference to the content if `Value` is an array.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// assert_eq!(
    ///     Value::Array(vec![1u32.into(), 2u32.into(), 3u32.into()]).as_slice(),
    ///     Some(&[Value::U32(1), Value::U32(2), Value::U32(3)][..]),
    /// );
    /// assert!(Value::U32(12).as_slice().is_none());
    /// ```
    pub fn as_slice(&self) -> Option<&[Value]> {
        if let Value::Array(value) = self {
            Some(value)
        } else {
            None
        }
    }

    /// Returns a reference to the content if `Value` is a message.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ros_message::Value;
    /// # use std::collections::HashMap;
    /// let mut data = HashMap::<String, Value>::new();
    /// data.insert("foo".into(), true.into());
    /// data.insert("bar".into(), false.into());
    /// assert_eq!(Value::Message(data.clone()).as_map(), Some(&data));
    /// assert!(Value::U32(12).as_map().is_none());
    /// ```
    pub fn as_map(&self) -> Option<&MessageValue> {
        if let Value::Message(value) = self {
            Some(value)
        } else {
            None
        }
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.fmt_indented(0, 2, f)
    }
}

impl From<bool> for Value {
    fn from(v: bool) -> Self {
        Self::Bool(v)
    }
}

impl From<i8> for Value {
    fn from(v: i8) -> Self {
        Self::I8(v)
    }
}

impl From<i16> for Value {
    fn from(v: i16) -> Self {
        Self::I16(v)
    }
}

impl From<i32> for Value {
    fn from(v: i32) -> Self {
        Self::I32(v)
    }
}

impl From<i64> for Value {
    fn from(v: i64) -> Self {
        Self::I64(v)
    }
}

impl From<u8> for Value {
    fn from(v: u8) -> Self {
        Self::U8(v)
    }
}

impl From<u16> for Value {
    fn from(v: u16) -> Self {
        Self::U16(v)
    }
}

impl From<u32> for Value {
    fn from(v: u32) -> Self {
        Self::U32(v)
    }
}

impl From<u64> for Value {
    fn from(v: u64) -> Self {
        Self::U64(v)
    }
}

impl From<f32> for Value {
    fn from(v: f32) -> Self {
        Self::F32(v)
    }
}

impl From<f64> for Value {
    fn from(v: f64) -> Self {
        Self::F64(v)
    }
}

impl From<String> for Value {
    fn from(v: String) -> Self {
        Self::String(v)
    }
}

impl From<Time> for Value {
    fn from(v: Time) -> Self {
        Self::Time(v)
    }
}

impl From<Duration> for Value {
    fn from(v: Duration) -> Self {
        Self::Duration(v)
    }
}

impl From<Vec<Value>> for Value {
    fn from(v: Vec<Value>) -> Self {
        Self::Array(v)
    }
}

impl From<HashMap<String, Value>> for Value {
    fn from(v: HashMap<String, Value>) -> Self {
        Self::Message(v)
    }
}

impl<K: Into<String>, T: Into<Value>> FromIterator<(K, T)> for Value {
    fn from_iter<I: IntoIterator<Item = (K, T)>>(iter: I) -> Self {
        Self::Message(
            iter.into_iter()
                .map(|(key, value)| (key.into(), value.into()))
                .collect(),
        )
    }
}

impl<T: Into<Value>> FromIterator<T> for Value {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
        Self::Array(iter.into_iter().map(Into::into).collect())
    }
}
<|endoftext|>


<commit_before>//! # What is Validator
//! It useful for Form and Model validation.
//! Implementation for Validation via BTreeMap structure.
//! It consist basic validations rule, validatior, and
//! validation Result and validation Errors.
//!
//! ## How to use
//! Most common examples you can find at src/admin/models/*
pub use rustc_serialize::json::{self, Json, ToJson};
pub use rustc_serialize::json::DecoderError::*;
pub use rustc_serialize::Decodable;
use params::{Value, FromValue};
use super::render::{BaseDataMap, BaseDataMapDecoder};
use std::collections::BTreeMap;
use std::string::String;

/// Base Validator struct
#[derive(RustcDecodable, Debug)]
pub struct Validator<T> {
    /// Type of validator
    /// For example: string, bool, i64 etc.
    pub vtype: String,
    pub requiered: Option<bool>,
    pub min: Option<u32>,
    pub max: Option<u32>,
    pub default: Option<T>,
    errors: Option<ErrorValidator>,
}

/// Validation result enum.
/// Consist Values and Errors
#[derive(Debug)]
pub struct ValidateResult(BaseDataMap, ErrorValidator);
/// Array of Validatopn Results for all validatior
#[derive(Debug)]
pub struct ValidateResults(pub Vec<ValidateResult>);
// Error result aggregator
pub type ErrorsResult = Option<Vec<ErrorValidator>>;

/// Validation results methods
impl ValidateResults {
    /// Get Validation Errors result
    pub fn get_errors(&self) -> ErrorsResult {
        let &ValidateResults(ref results) = self;
        let mut errors = vec!();
        for &ValidateResult(_, ref err) in results {
            if err.errors_count.is_some() {
                errors.push(err.to_owned());
            }
        }
        if errors.len() > 0 { Some(errors) } else { None }
    }

    /// Get Validation Values result
    pub fn get_values(&self) -> BaseDataMap {
        let &ValidateResults(ref results) = self;
        let mut values: BaseDataMap = BTreeMap::new();
        for &ValidateResult(ref val, _) in results {
            values.append(&mut val.clone());
        }
        values
    }
}

/// Convert Validation Results to Json
impl ToJson for ValidateResults {
    fn to_json(&self) -> Json {
        let mut data = BTreeMap::new();
        let &ValidateResults(ref results) = self;
        for &ValidateResult(ref val, ref err) in results {
            println!("\n\tERR_CNT: {:?}", err.field.to_json());
            let mut d = BTreeMap::new();
            // Set `errors_count` attribute
            if let Some(count) = err.errors_count {
                d.insert("errors_count".to_string(), count.to_json());
            } else {
                d.insert("errors_count".to_string(), 0.to_json());
            }
            // Set `field` attribute
            d.insert("field".to_string(), err.field.to_json());
            // Set `errors` attribute
            d.insert("errors".to_string(), err.errors.to_json());
            // Set `values` attribute
            d.insert("values".to_string(), val.to_json());

            data.append(&mut d);
        }
        println!("{:?}", data);
        Json::Object(data)
    }
}

/// Validator methods
/// It depends from various additional **traits**.
impl<T: FromValue + ToJson + Decodable> Validator<T> {
    /// Init Validation rule
    pub fn new(validator_rules: BaseDataMap) -> Validator<T> {
        validator_rules.decode()
    }

    /// Main validor for all validations rules
    pub fn validate(&mut self, field: String, value: Option<&Value>) -> ValidateResult {
        let mut value: Option<Value> = if let Some(val) = value {
            Some(val.to_owned())
        } else { None };
        // Init Errors
        self.errors = Some(ErrorValidator::new(&field));

        // Invoke validators
        self.requiered(&value);
        value = self.default(&value);
println!("{:?}", value);
        let json_value: Json = match self.type_cast(&value) {
            Some(ref json_value) => json_value.to_owned(),
            None => {
                if let Some(ref mut error) = self.errors {
                    if value.is_some() {
                        let msg = format!("Field wrong type: {}", error.field);
                        error.add(msg);
                    }
                }
                Json::Null
            }
        };

        let mut err = ErrorValidator::new(&field);
        if let Some(ref err_results) = self.errors {
            err = err_results.to_owned();
        }

        ValidateResult(btreemap! {
            field.to_owned() => json_value
        }, err)
    }

    /// Requered validator
    fn requiered(&mut self, value: &Option<Value>) {
        if self.requiered.is_some() {
            if value.is_some() {
                let check_value = match *value {
                    Some(Value::String(ref value)) => {
                        !value.trim().is_empty()
                    },
                    _ => true
                };
                if check_value {
                    return ()
                }
            }
            if let Some(ref mut error) = self.errors {
                let msg = format!("Field requiered: {}", error.field);
                error.add(msg);
            }
        }
    }

    /// Default value validator
    /// Validate by type and default field
    fn default(&mut self, value: &Option<Value>) -> Option<Value> {
        if let Some(ref default_value) = self.default {
            if value.is_none() {
                return self.to_value(default_value.to_json());
            }
        }
        value.to_owned()
    }

    /// Convert value based ot specific type to Value
    pub fn to_value(&self, json_value: Json) -> Option<Value> {
        match json_value {
            Json::I64(value) => Some(Value::I64(value)),
            Json::U64(value) => Some(Value::U64(value)),
            Json::F64(value) => Some(Value::F64(value)),
            Json::String( ref value) => Some(Value::String(value.clone())),
            Json::Boolean(value) => Some(Value::Boolean(value)),
            Json::Null => Some(Value::Null),
            _ => None,
        }
    }

    // Type cast for Value.
    // Returned as Json
    fn type_cast(&self, value: &Option<Value>) -> Option<Json> {
        let val: Value;
        if let Some(name) = value.as_ref() {
            val = name.to_owned();
        } else {
            return None
        }
        match &self.vtype.as_ref() as &str {
            "array" | "vec" => {
                if let Some(val) = <Vec<String> as FromValue>::from_value(&val) {
                    Some(val.to_json())
                } else {
                    None
                }
            },
            "bool" | "boolean" => {
                if let Some(val) = <bool as FromValue>::from_value(&val) {
                    Some(Json::Boolean(val))
                } else {
                    return None;
                }
            },
            "string" | "str" => {
                if let Some(val) = <String as FromValue>::from_value(&val) {
                    Some(Json::String(val))
                } else {
                    None
                }
            },
            "u8" | "u16" | "u32" | "u64" | "usize" => {
                if let Some(val) = <u64 as FromValue>::from_value(&val) {
                    Some(Json::U64(val))
                } else {
                    None
                }
            },
            "i8" | "i16" | "i32" | "i64" | "isize" => {
                if let Some(val) = <i64 as FromValue>::from_value(&val) {
                    Some(Json::I64(val))
                } else {
                    None
                }
            },
            "f32" | "f64" => {
                if let Some(val) = <f64 as FromValue>::from_value(&val) {
                    Some(Json::F64(val))
                } else {
                    return None;
                }
            },
            _ => None,
        }
    }
}

/// Validator Errors
#[derive(RustcDecodable, Debug, Clone)]
pub struct ErrorValidator {
    pub errors: Vec<String>,
    pub errors_count: Option<u32>,
    pub field : String,
}

/// Validator Errors methods
impl ErrorValidator {
    /// Init error
    fn new(field: &String) -> Self {
        ErrorValidator {
            field: field.to_owned(),
            errors: vec!(),
            errors_count: None,
        }
    }

    /// Add error
    fn add(&mut self, error: String) {
        if self.errors_count.is_none() {
            self.errors = vec!(error);
            self.errors_count = Some(1);
        } else {
            if let Some(count) = self.errors_count {
                self.errors.push(error);
                self.errors_count = Some(count + 1);
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn new_test() {
        // Test for requiered equal
        let val_req = Validator::<String>::new(btreemap! {
            "requiered".to_string() => true.to_json(),
            "vtype".to_string() => "bool".to_json(),
        });
        assert_eq!(val_req.requiered, Some(true));

        // Test for non-panic
        Validator::<bool>::new(btreemap! {
            "default".to_string() => false.to_json(),
            "vtype".to_string() => "bool".to_json(),
        });
    }

    #[test]
    #[should_panic]
    fn new_with_wrong_type_test() {
        // It should be: Validator::<bool>
        Validator::<String>::new(btreemap! {
            "default".to_string() => false.to_json(),
            "vtype".to_string() => "bool".to_json(),
        });
    }
}
<commit_msg>Validations results to Json - as array<commit_after>//! # What is Validator
//! It useful for Form and Model validation.
//! Implementation for Validation via BTreeMap structure.
//! It consist basic validations rule, validatior, and
//! validation Result and validation Errors.
//!
//! ## How to use
//! Most common examples you can find at src/admin/models/*
pub use rustc_serialize::json::{self, Json, ToJson};
pub use rustc_serialize::json::DecoderError::*;
pub use rustc_serialize::Decodable;
use params::{Value, FromValue};
use super::render::{BaseDataMap, BaseDataMapDecoder};
use std::collections::BTreeMap;
use std::string::String;

/// Base Validator struct
#[derive(RustcDecodable, Debug)]
pub struct Validator<T> {
    /// Type of validator
    /// For example: string, bool, i64 etc.
    pub vtype: String,
    pub requiered: Option<bool>,
    pub min: Option<u32>,
    pub max: Option<u32>,
    pub default: Option<T>,
    errors: Option<ErrorValidator>,
}

/// Validation result enum.
/// Consist Values and Errors
#[derive(Debug)]
pub struct ValidateResult(BaseDataMap, ErrorValidator);
/// Array of Validatopn Results for all validatior
#[derive(Debug)]
pub struct ValidateResults(pub Vec<ValidateResult>);
// Error result aggregator
pub type ErrorsResult = Option<Vec<ErrorValidator>>;

/// Validation results methods
impl ValidateResults {
    /// Get Validation Errors result
    pub fn get_errors(&self) -> ErrorsResult {
        let &ValidateResults(ref results) = self;
        let mut errors = vec!();
        for &ValidateResult(_, ref err) in results {
            if err.errors_count.is_some() {
                errors.push(err.to_owned());
            }
        }
        if errors.len() > 0 { Some(errors) } else { None }
    }

    /// Get Validation Values result
    pub fn get_values(&self) -> BaseDataMap {
        let &ValidateResults(ref results) = self;
        let mut values: BaseDataMap = BTreeMap::new();
        for &ValidateResult(ref val, _) in results {
            values.append(&mut val.clone());
        }
        values
    }
}

/// Convert Validation Results to Json
impl ToJson for ValidateResults {
    fn to_json(&self) -> Json {
        let mut data: Vec<Json> = vec!();
        let &ValidateResults(ref results) = self;
        let mut i = 0;
        for &ValidateResult(ref val, ref err) in results {
            let mut d = BTreeMap::new();
            // Set `field` attribute
            d.insert("field".to_string(), err.field.to_json());
            // Set `errors` attribute
            d.insert("errors".to_string(), err.errors.to_json());
            // Set `values` attribute
            d.insert("values".to_string(), val.to_json());

            data.push(d.to_json());

            //data.append(&mut d);
            i = i + 1;
        }
        Json::Array(data)
    }
}

/// Validator methods
/// It depends from various additional **traits**.
impl<T: FromValue + ToJson + Decodable> Validator<T> {
    /// Init Validation rule
    pub fn new(validator_rules: BaseDataMap) -> Validator<T> {
        validator_rules.decode()
    }

    /// Main validor for all validations rules
    pub fn validate(&mut self, field: String, value: Option<&Value>) -> ValidateResult {
        let mut value: Option<Value> = if let Some(val) = value {
            Some(val.to_owned())
        } else { None };
        // Init Errors
        self.errors = Some(ErrorValidator::new(&field));

        // Invoke validators
        self.requiered(&value);
        value = self.default(&value);
println!("{:?}", value);
        let json_value: Json = match self.type_cast(&value) {
            Some(ref json_value) => json_value.to_owned(),
            None => {
                if let Some(ref mut error) = self.errors {
                    if value.is_some() {
                        let msg = format!("Field wrong type: {}", error.field);
                        error.add(msg);
                    }
                }
                Json::Null
            }
        };

        let mut err = ErrorValidator::new(&field);
        if let Some(ref err_results) = self.errors {
            err = err_results.to_owned();
        }

        ValidateResult(btreemap! {
            field.to_owned() => json_value
        }, err)
    }

    /// Requered validator
    fn requiered(&mut self, value: &Option<Value>) {
        if self.requiered.is_some() {
            if value.is_some() {
                let check_value = match *value {
                    Some(Value::String(ref value)) => {
                        !value.trim().is_empty()
                    },
                    _ => true
                };
                if check_value {
                    return ()
                }
            }
            if let Some(ref mut error) = self.errors {
                let msg = format!("Field requiered: {}", error.field);
                error.add(msg);
            }
        }
    }

    /// Default value validator
    /// Validate by type and default field
    fn default(&mut self, value: &Option<Value>) -> Option<Value> {
        if let Some(ref default_value) = self.default {
            if value.is_none() {
                return self.to_value(default_value.to_json());
            }
        }
        value.to_owned()
    }

    /// Convert value based ot specific type to Value
    pub fn to_value(&self, json_value: Json) -> Option<Value> {
        match json_value {
            Json::I64(value) => Some(Value::I64(value)),
            Json::U64(value) => Some(Value::U64(value)),
            Json::F64(value) => Some(Value::F64(value)),
            Json::String( ref value) => Some(Value::String(value.clone())),
            Json::Boolean(value) => Some(Value::Boolean(value)),
            Json::Null => Some(Value::Null),
            _ => None,
        }
    }

    // Type cast for Value.
    // Returned as Json
    fn type_cast(&self, value: &Option<Value>) -> Option<Json> {
        let val: Value;
        if let Some(name) = value.as_ref() {
            val = name.to_owned();
        } else {
            return None
        }
        match &self.vtype.as_ref() as &str {
            "array" | "vec" => {
                if let Some(val) = <Vec<String> as FromValue>::from_value(&val) {
                    Some(val.to_json())
                } else {
                    None
                }
            },
            "bool" | "boolean" => {
                if let Some(val) = <bool as FromValue>::from_value(&val) {
                    Some(Json::Boolean(val))
                } else {
                    return None;
                }
            },
            "string" | "str" => {
                if let Some(val) = <String as FromValue>::from_value(&val) {
                    Some(Json::String(val))
                } else {
                    None
                }
            },
            "u8" | "u16" | "u32" | "u64" | "usize" => {
                if let Some(val) = <u64 as FromValue>::from_value(&val) {
                    Some(Json::U64(val))
                } else {
                    None
                }
            },
            "i8" | "i16" | "i32" | "i64" | "isize" => {
                if let Some(val) = <i64 as FromValue>::from_value(&val) {
                    Some(Json::I64(val))
                } else {
                    None
                }
            },
            "f32" | "f64" => {
                if let Some(val) = <f64 as FromValue>::from_value(&val) {
                    Some(Json::F64(val))
                } else {
                    return None;
                }
            },
            _ => None,
        }
    }
}

/// Validator Errors
#[derive(RustcDecodable, Debug, Clone)]
pub struct ErrorValidator {
    pub errors: Vec<String>,
    pub errors_count: Option<u32>,
    pub field : String,
}

/// Validator Errors methods
impl ErrorValidator {
    /// Init error
    fn new(field: &String) -> Self {
        ErrorValidator {
            field: field.to_owned(),
            errors: vec!(),
            errors_count: None,
        }
    }

    /// Add error
    fn add(&mut self, error: String) {
        if self.errors_count.is_none() {
            self.errors = vec!(error);
            self.errors_count = Some(1);
        } else {
            if let Some(count) = self.errors_count {
                self.errors.push(error);
                self.errors_count = Some(count + 1);
            }
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn new_test() {
        // Test for requiered equal
        let val_req = Validator::<String>::new(btreemap! {
            "requiered".to_string() => true.to_json(),
            "vtype".to_string() => "bool".to_json(),
        });
        assert_eq!(val_req.requiered, Some(true));

        // Test for non-panic
        Validator::<bool>::new(btreemap! {
            "default".to_string() => false.to_json(),
            "vtype".to_string() => "bool".to_json(),
        });
    }

    #[test]
    #[should_panic]
    fn new_with_wrong_type_test() {
        // It should be: Validator::<bool>
        Validator::<String>::new(btreemap! {
            "default".to_string() => false.to_json(),
            "vtype".to_string() => "bool".to_json(),
        });
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate rustorm_dao;
extern crate syn;

#[macro_use]
mod column_derive;
#[macro_use]
mod dao_derive;
#[macro_use]
mod table_derive;

use proc_macro::TokenStream;

#[proc_macro_derive(FromDao)]
pub fn from_dao(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();
    let gen = dao_derive::impl_from_dao(&ast);
    gen.parse().unwrap()
}

#[proc_macro_derive(ToDao)]
pub fn to_dao(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();
    let gen = dao_derive::impl_to_dao(&ast);
    gen.parse().unwrap()
}

#[proc_macro_derive(ToTableName)]
pub fn to_table_name(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();
    let gen = table_derive::impl_to_table_name(&ast);
    gen.parse().unwrap()
}

#[proc_macro_derive(ToColumnNames)]
pub fn to_column_names(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();
    let gen = column_derive::impl_to_column_names(&ast);
    gen.parse().unwrap()
}
<commit_msg>Add cargo clippy to codegen<commit_after>#![deny(warnings)]
#![deny(clippy::all)]

extern crate proc_macro;
#[macro_use]
extern crate quote;
extern crate rustorm_dao;
extern crate syn;

#[macro_use]
mod column_derive;
#[macro_use]
mod dao_derive;
#[macro_use]
mod table_derive;

use proc_macro::TokenStream;

#[proc_macro_derive(FromDao)]
pub fn from_dao(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();
    let gen = dao_derive::impl_from_dao(&ast);
    gen.parse().unwrap()
}

#[proc_macro_derive(ToDao)]
pub fn to_dao(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();
    let gen = dao_derive::impl_to_dao(&ast);
    gen.parse().unwrap()
}

#[proc_macro_derive(ToTableName)]
pub fn to_table_name(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();
    let gen = table_derive::impl_to_table_name(&ast);
    gen.parse().unwrap()
}

#[proc_macro_derive(ToColumnNames)]
pub fn to_column_names(input: TokenStream) -> TokenStream {
    let s = input.to_string();
    let ast = syn::parse_macro_input(&s).unwrap();
    let gen = column_derive::impl_to_column_names(&ast);
    gen.parse().unwrap()
}
<|endoftext|>


<commit_before>//! Weave files will follow a file naming convention.  This determines the names of various temp
//! files and other aspects.  The SCCS conventions are not followed, because they are not save
//! (this crate will never write to a file that already exists).

use ::Result;
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions};
use std::io::ErrorKind;

/// A naming convention provides utilities needed to find the involved files, and construct
/// temporary files as part of writing the new weave.  The underlying object should keep the path
/// and base name.
pub trait NamingConvention {
    /// Create a temporary file for writing.  Upon success, returns the full path of the file, and
    /// the opened File for writing to the file.  The path should refer to a new file that did not
    /// exist prior to this call.
    fn temp_file(&self) -> Result<(PathBuf, File)>;

    /// Return the pathname of the primary file.
    fn main_file(&self) -> PathBuf;

    /// Return the pathname of the backup file.
    fn backup_file(&self) -> PathBuf;
}

/// The SimpleNaming is a NamingConvention that has a basename, with the main file having a
/// specified extension, the backup file having a ".bak" extension, and the temp files using a
/// numbered extension starting with ".0".  If the names are intended to be compressed, a ".gz"
/// suffix can also be added.
pub struct SimpleNaming {
    // The directory for the files to be written.
    path: PathBuf,
    // The string for the base filename.
    base: String,
    // The extension to use for the main name.
    ext: String,
    // Are these names to indicate compression?
    compressed: bool,
}

impl SimpleNaming {
    pub fn new<P: AsRef<Path>>(path: P, base: &str, ext: &str, compressed: bool) -> SimpleNaming {
        SimpleNaming {
            path: path.as_ref().to_path_buf(),
            base: base.to_string(),
            ext: ext.to_string(),
            compressed: compressed,
        }
    }

    pub fn make_name(&self, ext: &str) -> PathBuf {
        let name = format!("{}.{}{}", self.base, ext,
                           if self.compressed { ".gz" } else { "" });
        self.path.join(name)
    }
}

impl NamingConvention for SimpleNaming {
    fn main_file(&self) -> PathBuf {
        self.make_name(&self.ext)
    }

    fn backup_file(&self) -> PathBuf {
        self.make_name("bak")
    }

    fn temp_file(&self) -> Result<(PathBuf, File)> {
        let mut n = 0;
        loop {
            let name = self.make_name(&n.to_string());

            match OpenOptions::new().write(true).create_new(true).open(&name) {
                Ok(fd) => return Ok((name, fd)),
                Err(ref e) if e.kind() == ErrorKind::AlreadyExists => (),
                Err(e) => return Err(e.into()),
            }

            n += 1;
        }
    }
}
<commit_msg>weave: Fix small doc typo<commit_after>//! Weave files will follow a file naming convention.  This determines the names of various temp
//! files and other aspects.  The SCCS conventions are not followed, because they are not safe
//! (this crate will never write to a file that already exists).

use ::Result;
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions};
use std::io::ErrorKind;

/// A naming convention provides utilities needed to find the involved files, and construct
/// temporary files as part of writing the new weave.  The underlying object should keep the path
/// and base name.
pub trait NamingConvention {
    /// Create a temporary file for writing.  Upon success, returns the full path of the file, and
    /// the opened File for writing to the file.  The path should refer to a new file that did not
    /// exist prior to this call.
    fn temp_file(&self) -> Result<(PathBuf, File)>;

    /// Return the pathname of the primary file.
    fn main_file(&self) -> PathBuf;

    /// Return the pathname of the backup file.
    fn backup_file(&self) -> PathBuf;
}

/// The SimpleNaming is a NamingConvention that has a basename, with the main file having a
/// specified extension, the backup file having a ".bak" extension, and the temp files using a
/// numbered extension starting with ".0".  If the names are intended to be compressed, a ".gz"
/// suffix can also be added.
pub struct SimpleNaming {
    // The directory for the files to be written.
    path: PathBuf,
    // The string for the base filename.
    base: String,
    // The extension to use for the main name.
    ext: String,
    // Are these names to indicate compression?
    compressed: bool,
}

impl SimpleNaming {
    pub fn new<P: AsRef<Path>>(path: P, base: &str, ext: &str, compressed: bool) -> SimpleNaming {
        SimpleNaming {
            path: path.as_ref().to_path_buf(),
            base: base.to_string(),
            ext: ext.to_string(),
            compressed: compressed,
        }
    }

    pub fn make_name(&self, ext: &str) -> PathBuf {
        let name = format!("{}.{}{}", self.base, ext,
                           if self.compressed { ".gz" } else { "" });
        self.path.join(name)
    }
}

impl NamingConvention for SimpleNaming {
    fn main_file(&self) -> PathBuf {
        self.make_name(&self.ext)
    }

    fn backup_file(&self) -> PathBuf {
        self.make_name("bak")
    }

    fn temp_file(&self) -> Result<(PathBuf, File)> {
        let mut n = 0;
        loop {
            let name = self.make_name(&n.to_string());

            match OpenOptions::new().write(true).create_new(true).open(&name) {
                Ok(fd) => return Ok((name, fd)),
                Err(ref e) if e.kind() == ErrorKind::AlreadyExists => (),
                Err(e) => return Err(e.into()),
            }

            n += 1;
        }
    }
}
<|endoftext|>