<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{config::CargoConfig, utils::project_root, Result};
use anyhow::anyhow;
use log::{info, warn};
use std::{
    ffi::{OsStr, OsString},
    path::Path,
    process::{Command, Output, Stdio},
    time::Instant,
};

pub struct Cargo {
    inner: Command,
    pass_through_args: Vec<OsString>,
    env_additions: Vec<(OsString, OsString)>,
}

impl Cargo {
    pub fn new<S: AsRef<OsStr>>(cargo_config: &CargoConfig, command: S) -> Self {
        // run rustup to find correct toolchain
        let output = Command::new("rustup")
            .arg("which")
            .arg("--toolchain")
            .arg(&cargo_config.toolchain)
            .arg("cargo")
            .output()
            .expect("failed to execute rustup which");
        let (cargo_binary, cargo_flags) = if output.status.success() {
            (
                String::from_utf8(output.stdout)
                    .expect("error parsing rustup which output into utf8"),
                &cargo_config.flags,
            )
        } else {
            println!(
                "WARN: Rust toolchain {} not installed; falling back to legacy Cargo resolver.",
                cargo_config.toolchain,
            );
            println!(
                "WARN: Run `rustup toolchain install {}` to use the new resolver.",
                cargo_config.toolchain,
            );
            ("cargo".to_string(), &None)
        };

        println!(
            "cargo_binary = {}, cargo_flags = {:?}",
            cargo_binary, cargo_flags
        );

        let mut inner = Command::new(str::trim(&cargo_binary));
        if let Some(flags) = &cargo_flags {
            inner.arg(&flags);
        }
        inner.arg(command);
        Self {
            inner,
            pass_through_args: Vec::new(),
            env_additions: Vec::new(),
        }
    }

    pub fn all(&mut self) -> &mut Self {
        self.inner.arg("--all");
        self
    }

    pub fn workspace(&mut self) -> &mut Self {
        self.inner.arg("--workspace");
        self
    }

    pub fn all_targets(&mut self) -> &mut Self {
        self.inner.arg("--all-targets");
        self
    }

    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self {
        self.inner.current_dir(dir);
        self
    }

    pub fn packages<I, S>(&mut self, packages: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for p in packages {
            self.inner.arg("--package");
            self.inner.arg(p);
        }
        self
    }

    pub fn exclusions<I, S>(&mut self, exclusions: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for e in exclusions {
            self.inner.arg("--exclude");
            self.inner.arg(e);
        }
        self
    }

    /// Adds a series of arguments to x's target command.
    pub fn args<I, S>(&mut self, args: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        self.inner.args(args);
        self
    }

    /// Adds an argument to x's target command.
    #[allow(dead_code)]
    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
        self.inner.arg(arg);
        self
    }

    /// Adds "Pass Through" arguments to x's target command.
    /// Pass through arguments appear after a double dash " -- " and may
    /// not be handled/checked by x's target command itself, but an underlying executable.
    pub fn pass_through<I, S>(&mut self, args: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for a in args {
            self.pass_through_args.push(a.as_ref().to_owned());
        }
        self
    }

    /// Passes extra environment variables to x's target command.
    pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
    where
        I: IntoIterator<Item = (K, V)>,
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        for (key, val) in vars {
            self.env(key, val);
        }
        self
    }

    /// Passes an extra environment variable to x's target command.
    pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
    where
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        self.env_additions
            .push((key.as_ref().to_os_string(), val.as_ref().to_os_string()));
        self
    }

    pub fn run(&mut self) -> Result<()> {
        self.inner.stdout(Stdio::inherit()).stderr(Stdio::inherit());
        self.do_run(true).map(|_| ())
    }

    /// Runs this command, capturing the standard output into a `Vec<u8>`.
    /// No logging/timing will be displayed as the result of this call from x.
    pub fn run_with_output(&mut self) -> Result<Vec<u8>> {
        self.inner.stderr(Stdio::inherit());
        // Since system out hijacked don't log for this command
        self.do_run(false).map(|o| o.stdout)
    }

    /// Internal run command, where the magic happens.
    /// If log is true, any environment variable overrides will be logged, the full command will be logged,
    /// and after the command's output reaches stdout, the command will be printed again along with the time took
    /// to process the command (wallclock) in ms.
    fn do_run(&mut self, log: bool) -> Result<Output> {
        // these arguments are passed through cargo/x to underlying executable (test, clippy, etc)
        if !self.pass_through_args.is_empty() {
            self.inner.arg("--").args(&self.pass_through_args);
        }

        // once all the arguments are added to the command we can log it.
        if log {
            self.env_additions
                .iter()
                .for_each(|t| info!("Env {:?}: {:?}", t.0, t.1));
            info!("Executing: {:?}", &self.inner);
        }
        self.inner
            .envs(self.env_additions.iter().map(|(k, v)| (k, v)));
        let now = Instant::now();
        let output = self.inner.output()?;
        // once the command has been executed we log it's success or failure.
        if log {
            if output.status.success() {
                info!(
                    "Completed in {}ms: {:?}",
                    now.elapsed().as_millis(),
                    &self.inner
                );
            } else {
                warn!(
                    "Failed in {}ms: {:?}",
                    now.elapsed().as_millis(),
                    &self.inner
                );
            }
        }
        if !output.status.success() {
            return Err(anyhow!("failed to run cargo command"));
        }
        Ok(output)
    }
}

#[derive(Debug, Default)]
pub struct CargoArgs {
    pub all_targets: bool,
}

/// Represents an invocations of cargo that will call multiple other invocations of
/// cargo based on groupings implied by the contents of <workspace-root>/x.toml.
pub enum CargoCommand<'a> {
    Bench(&'a CargoConfig, &'a [OsString]),
    Check(&'a CargoConfig),
    Clippy(&'a CargoConfig, &'a [OsString]),
    Fix(&'a CargoConfig, &'a [OsString]),
    Test {
        cargo_config: &'a CargoConfig,
        direct_args: &'a [OsString],
        args: &'a [OsString],
        env: &'a [(&'a str, &'a str)],
    },
}

impl<'a> CargoCommand<'a> {
    pub fn cargo_config(&self) -> &CargoConfig {
        match self {
            CargoCommand::Bench(config, _) => config,
            CargoCommand::Check(config) => config,
            CargoCommand::Clippy(config, _) => config,
            CargoCommand::Fix(config, _) => config,
            CargoCommand::Test { cargo_config, .. } => cargo_config,
        }
    }

    pub fn run_on_local_package(&self, args: &CargoArgs) -> Result<()> {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .args(self.direct_args())
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_on_packages<I, S>(&self, packages: I, args: &CargoArgs) -> Result<()>
    where
        I: IntoIterator<Item = S> + Clone,
        S: AsRef<OsStr>,
    {
        // Early return if we have no packages to run
        if packages.clone().into_iter().count() == 0 {
            return Ok(());
        }

        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .args(self.direct_args())
            .packages(packages)
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_on_all_packages(&self, args: &CargoArgs) -> Result<()> {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .workspace()
            .args(self.direct_args())
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_with_exclusions<I, S>(&self, exclusions: I, args: &CargoArgs) -> Result<()>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .workspace()
            .args(self.direct_args())
            .exclusions(exclusions)
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn as_str(&self) -> &'static str {
        match self {
            CargoCommand::Bench(_, _) => "bench",
            CargoCommand::Check(_) => "check",
            CargoCommand::Clippy(_, _) => "clippy",
            CargoCommand::Fix(_, _) => "fix",
            CargoCommand::Test { .. } => "test",
        }
    }

    fn pass_through_args(&self) -> &[OsString] {
        match self {
            CargoCommand::Bench(_, args) => args,
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, args) => args,
            CargoCommand::Fix(_, args) => args,
            CargoCommand::Test { args, .. } => args,
        }
    }

    fn direct_args(&self) -> &[OsString] {
        match self {
            CargoCommand::Bench(_, _) => &[],
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, _) => &[],
            CargoCommand::Fix(_, _) => &[],
            CargoCommand::Test { direct_args, .. } => direct_args,
        }
    }

    pub fn get_extra_env(&self) -> &[(&str, &str)] {
        match self {
            CargoCommand::Bench(_, _) => &[],
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, _) => &[],
            CargoCommand::Fix(_, _) => &[],
            CargoCommand::Test { env, .. } => &env,
        }
    }

    fn apply_args(cargo: &mut Cargo, args: &CargoArgs) {
        if args.all_targets {
            cargo.all_targets();
        }
    }
}
<commit_msg>x: set RUSTUP_TOOLCHAIN if its not present<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{config::CargoConfig, utils::project_root, Result};
use anyhow::anyhow;
use log::{info, warn};
use std::{
    env,
    ffi::{OsStr, OsString},
    path::Path,
    process::{Command, Output, Stdio},
    time::Instant,
};

const RUST_TOOLCHAIN_VERSION: &str = include_str!("../../../rust-toolchain");
const RUSTUP_TOOLCHAIN: &str = "RUSTUP_TOOLCHAIN";

pub struct Cargo {
    inner: Command,
    pass_through_args: Vec<OsString>,
    env_additions: Vec<(OsString, OsString)>,
}

impl Cargo {
    pub fn new<S: AsRef<OsStr>>(cargo_config: &CargoConfig, command: S) -> Self {
        // run rustup to find correct toolchain
        let output = Command::new("rustup")
            .arg("which")
            .arg("--toolchain")
            .arg(&cargo_config.toolchain)
            .arg("cargo")
            .output()
            .expect("failed to execute rustup which");
        let (cargo_binary, cargo_flags) = if output.status.success() {
            (
                String::from_utf8(output.stdout)
                    .expect("error parsing rustup which output into utf8"),
                &cargo_config.flags,
            )
        } else {
            println!(
                "WARN: Rust toolchain {} not installed; falling back to legacy Cargo resolver.",
                cargo_config.toolchain,
            );
            println!(
                "WARN: Run `rustup toolchain install {}` to use the new resolver.",
                cargo_config.toolchain,
            );
            ("cargo".to_string(), &None)
        };

        println!(
            "cargo_binary = {}, cargo_flags = {:?}",
            cargo_binary, cargo_flags
        );

        let mut inner = Command::new(str::trim(&cargo_binary));
        if let Some(flags) = &cargo_flags {
            inner.arg(&flags);
        }

        // The environment is inherited for child processes so we only need to set RUSTUP_TOOLCHAIN
        // if it isn't already present in the environment
        if env::var_os(RUSTUP_TOOLCHAIN).is_none() {
            inner.env(RUSTUP_TOOLCHAIN, RUST_TOOLCHAIN_VERSION);
        }

        inner.arg(command);
        Self {
            inner,
            pass_through_args: Vec::new(),
            env_additions: Vec::new(),
        }
    }

    pub fn all(&mut self) -> &mut Self {
        self.inner.arg("--all");
        self
    }

    pub fn workspace(&mut self) -> &mut Self {
        self.inner.arg("--workspace");
        self
    }

    pub fn all_targets(&mut self) -> &mut Self {
        self.inner.arg("--all-targets");
        self
    }

    pub fn current_dir<P: AsRef<Path>>(&mut self, dir: P) -> &mut Self {
        self.inner.current_dir(dir);
        self
    }

    pub fn packages<I, S>(&mut self, packages: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for p in packages {
            self.inner.arg("--package");
            self.inner.arg(p);
        }
        self
    }

    pub fn exclusions<I, S>(&mut self, exclusions: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for e in exclusions {
            self.inner.arg("--exclude");
            self.inner.arg(e);
        }
        self
    }

    /// Adds a series of arguments to x's target command.
    pub fn args<I, S>(&mut self, args: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        self.inner.args(args);
        self
    }

    /// Adds an argument to x's target command.
    #[allow(dead_code)]
    pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Self {
        self.inner.arg(arg);
        self
    }

    /// Adds "Pass Through" arguments to x's target command.
    /// Pass through arguments appear after a double dash " -- " and may
    /// not be handled/checked by x's target command itself, but an underlying executable.
    pub fn pass_through<I, S>(&mut self, args: I) -> &mut Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        for a in args {
            self.pass_through_args.push(a.as_ref().to_owned());
        }
        self
    }

    /// Passes extra environment variables to x's target command.
    pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Self
    where
        I: IntoIterator<Item = (K, V)>,
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        for (key, val) in vars {
            self.env(key, val);
        }
        self
    }

    /// Passes an extra environment variable to x's target command.
    pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Self
    where
        K: AsRef<OsStr>,
        V: AsRef<OsStr>,
    {
        self.env_additions
            .push((key.as_ref().to_os_string(), val.as_ref().to_os_string()));
        self
    }

    pub fn run(&mut self) -> Result<()> {
        self.inner.stdout(Stdio::inherit()).stderr(Stdio::inherit());
        self.do_run(true).map(|_| ())
    }

    /// Runs this command, capturing the standard output into a `Vec<u8>`.
    /// No logging/timing will be displayed as the result of this call from x.
    pub fn run_with_output(&mut self) -> Result<Vec<u8>> {
        self.inner.stderr(Stdio::inherit());
        // Since system out hijacked don't log for this command
        self.do_run(false).map(|o| o.stdout)
    }

    /// Internal run command, where the magic happens.
    /// If log is true, any environment variable overrides will be logged, the full command will be logged,
    /// and after the command's output reaches stdout, the command will be printed again along with the time took
    /// to process the command (wallclock) in ms.
    fn do_run(&mut self, log: bool) -> Result<Output> {
        // these arguments are passed through cargo/x to underlying executable (test, clippy, etc)
        if !self.pass_through_args.is_empty() {
            self.inner.arg("--").args(&self.pass_through_args);
        }

        // once all the arguments are added to the command we can log it.
        if log {
            self.env_additions
                .iter()
                .for_each(|t| info!("Env {:?}: {:?}", t.0, t.1));
            info!("Executing: {:?}", &self.inner);
        }
        self.inner
            .envs(self.env_additions.iter().map(|(k, v)| (k, v)));
        let now = Instant::now();
        let output = self.inner.output()?;
        // once the command has been executed we log it's success or failure.
        if log {
            if output.status.success() {
                info!(
                    "Completed in {}ms: {:?}",
                    now.elapsed().as_millis(),
                    &self.inner
                );
            } else {
                warn!(
                    "Failed in {}ms: {:?}",
                    now.elapsed().as_millis(),
                    &self.inner
                );
            }
        }
        if !output.status.success() {
            return Err(anyhow!("failed to run cargo command"));
        }
        Ok(output)
    }
}

#[derive(Debug, Default)]
pub struct CargoArgs {
    pub all_targets: bool,
}

/// Represents an invocations of cargo that will call multiple other invocations of
/// cargo based on groupings implied by the contents of <workspace-root>/x.toml.
pub enum CargoCommand<'a> {
    Bench(&'a CargoConfig, &'a [OsString]),
    Check(&'a CargoConfig),
    Clippy(&'a CargoConfig, &'a [OsString]),
    Fix(&'a CargoConfig, &'a [OsString]),
    Test {
        cargo_config: &'a CargoConfig,
        direct_args: &'a [OsString],
        args: &'a [OsString],
        env: &'a [(&'a str, &'a str)],
    },
}

impl<'a> CargoCommand<'a> {
    pub fn cargo_config(&self) -> &CargoConfig {
        match self {
            CargoCommand::Bench(config, _) => config,
            CargoCommand::Check(config) => config,
            CargoCommand::Clippy(config, _) => config,
            CargoCommand::Fix(config, _) => config,
            CargoCommand::Test { cargo_config, .. } => cargo_config,
        }
    }

    pub fn run_on_local_package(&self, args: &CargoArgs) -> Result<()> {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .args(self.direct_args())
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_on_packages<I, S>(&self, packages: I, args: &CargoArgs) -> Result<()>
    where
        I: IntoIterator<Item = S> + Clone,
        S: AsRef<OsStr>,
    {
        // Early return if we have no packages to run
        if packages.clone().into_iter().count() == 0 {
            return Ok(());
        }

        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .args(self.direct_args())
            .packages(packages)
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_on_all_packages(&self, args: &CargoArgs) -> Result<()> {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .workspace()
            .args(self.direct_args())
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn run_with_exclusions<I, S>(&self, exclusions: I, args: &CargoArgs) -> Result<()>
    where
        I: IntoIterator<Item = S>,
        S: AsRef<OsStr>,
    {
        let mut cargo = Cargo::new(self.cargo_config(), self.as_str());
        Self::apply_args(&mut cargo, args);
        cargo
            .current_dir(project_root())
            .workspace()
            .args(self.direct_args())
            .exclusions(exclusions)
            .pass_through(self.pass_through_args())
            .envs(self.get_extra_env().to_owned())
            .run()
    }

    pub fn as_str(&self) -> &'static str {
        match self {
            CargoCommand::Bench(_, _) => "bench",
            CargoCommand::Check(_) => "check",
            CargoCommand::Clippy(_, _) => "clippy",
            CargoCommand::Fix(_, _) => "fix",
            CargoCommand::Test { .. } => "test",
        }
    }

    fn pass_through_args(&self) -> &[OsString] {
        match self {
            CargoCommand::Bench(_, args) => args,
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, args) => args,
            CargoCommand::Fix(_, args) => args,
            CargoCommand::Test { args, .. } => args,
        }
    }

    fn direct_args(&self) -> &[OsString] {
        match self {
            CargoCommand::Bench(_, _) => &[],
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, _) => &[],
            CargoCommand::Fix(_, _) => &[],
            CargoCommand::Test { direct_args, .. } => direct_args,
        }
    }

    pub fn get_extra_env(&self) -> &[(&str, &str)] {
        match self {
            CargoCommand::Bench(_, _) => &[],
            CargoCommand::Check(_) => &[],
            CargoCommand::Clippy(_, _) => &[],
            CargoCommand::Fix(_, _) => &[],
            CargoCommand::Test { env, .. } => &env,
        }
    }

    fn apply_args(cargo: &mut Cargo, args: &CargoArgs) {
        if args.all_targets {
            cargo.all_targets();
        }
    }
}
<|endoftext|>


<commit_before>use libc::{c_double, c_void};
use std::cmp::{Ordering};
use std::sync::{Once, ONCE_INIT};

static EXACTINIT: Once = ONCE_INIT;

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point2D {
    x: c_double,
    y: c_double,
}

impl Point2D {
    pub fn new(x: c_double, y: c_double) -> Point2D {
        Point2D { x: x, y: y }
    }
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point3D {
    x: c_double,
    y: c_double,
    z: c_double,
}

impl Point3D {
    pub fn new(x: c_double, y: c_double, z: c_double) -> Point3D {
        Point3D { x: x, y: y, z: z }
    }
}

#[link(name = "predicates")]
extern "C" {
    fn exactinit() -> c_void;
    fn orient2d(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D) -> c_double;
    fn incircle(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D, pd: *const Point2D) -> c_double;
    fn orient3d(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D) -> c_double;
    fn insphere(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D, pe: *const Point3D) -> c_double;
}

fn init_predicates() {
    EXACTINIT.call_once(|| {
        unsafe { exactinit() };
    });
}

#[derive(Debug, Eq, PartialEq)]
pub enum InCircleLocation {
    Inside,
    Outside,
    On
}

#[derive(Debug, Eq, PartialEq)]
pub enum Orientation {
    Positive,
    Negative
}

impl Orientation {
    pub fn to_f64_multiplier(&self) -> f64 {
        match *self {
            Orientation::Positive => {  1.0 },
            Orientation::Negative => { -1.0 }
        }
    }
}

pub trait InCircleTestable<P> {
    fn in_circle_test(&self, point: &P) -> Option<InCircleLocation>;
}

pub trait Orientable {
    fn orientation(&self) -> Option<Orientation>;
}

pub struct Triangle<P> {
    p1: P,
    p2: P,
    p3: P,
}

impl<P> Triangle<P> {
    pub fn new(p1: P, p2: P, p3: P) -> Triangle<P> {
        Triangle {
            p1: p1,
            p2: p2,
            p3: p3,
        }
    }
}

pub struct Tetrahedron<P> {
    p1: P,
    p2: P,
    p3: P,
    p4: P,
}

impl<P> Tetrahedron<P> {
    pub fn new(p1: P, p2: P, p3: P, p4: P) -> Tetrahedron<P> {
        Tetrahedron {
            p1: p1,
            p2: p2,
            p3: p3,
            p4: p4,
        }
    }
}

fn det_to_in_circle_location(det: f64) -> Option<InCircleLocation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(InCircleLocation::Inside) }
        Some(Ordering::Less) => { Some(InCircleLocation::Outside) }
        Some(Ordering::Equal) => { Some(InCircleLocation::On) }
        None => { None }
    }
}

fn det_to_orientation(det: f64) -> Option<Orientation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(Orientation::Positive) }
        Some(Ordering::Less) => { Some(Orientation::Negative) }
        _ => { None }
    }
}

impl Orientable for Triangle<Point2D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient2d(&self.p1, &self.p2, &self.p3) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point2D> for Triangle<Point2D> {
    fn in_circle_test(&self, point: &Point2D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { incircle(&self.p1, &self.p2, &self.p3, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

impl Orientable for Tetrahedron<Point3D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient3d(&self.p1, &self.p2, &self.p3, &self.p4) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point3D> for Tetrahedron<Point3D> {
    fn in_circle_test(&self, point: &Point3D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { insphere(&self.p1, &self.p2, &self.p3, &self.p4, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

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

    use std::f64;
    use std::f64::consts;
    use rand;
    use quickcheck::{TestResult, quickcheck, QuickCheck, StdGen};

    #[test]
    fn in_circle_2d() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);
        let d_inside = Point2D::new(0.5, 0.5);
        let d_outside = Point2D::new(2.0, 0.0);
        let d_on = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

    #[test]
    fn in_circle_2d_triangle_constructed_from_circle() {
        fn in_circle_2d_triangle_constructed_from_circle(center: (f64, f64), radius: f64, angles: (f64, f64, f64)) -> TestResult {
            if radius <= 0.0 { return TestResult::discard()};
            fn to_pnt(center: (f64, f64), radius: f64, angle: f64) -> Point2D {
                let x = center.0 + radius * angle.cos();
                let y = center.1 + radius * angle.sin();
                Point2D::new(x, y)
            }
            let p1 = to_pnt(center, radius, angles.0);
            let p2 = to_pnt(center, radius, angles.1);
            let p3 = to_pnt(center, radius, angles.2);
            let p_center = Point2D::new(center.0, center.1);

            let triangle = Triangle::new(p1, p2, p3);

            TestResult::from_bool(triangle.in_circle_test(&p_center) == Some(InCircleLocation::Inside))
        }
        quickcheck(in_circle_2d_triangle_constructed_from_circle as fn(center: (f64, f64), radius: f64, angles: (f64, f64, f64)) -> TestResult)
    }

    #[test]
    fn in_circle_2d_tetrahedron_constructed_from_sphere() {
        const DOMAIN: usize = 100;
        fn in_circle_2d_tetrahedron_constructed_from_sphere(center: (f64, f64, f64), radius: f64, angle_inputs: ((f64, f64), (f64, f64), (f64, f64), (f64, f64))) -> TestResult {
            if radius <= 0.0 { return TestResult::discard()};
            fn to_pnt(center: (f64, f64, f64), radius: f64, angle_inputs: (f64, f64)) -> Point3D {
                let domain_f64 = DOMAIN as f64;
                let u = (angle_inputs.0 + domain_f64) / (2.0 * domain_f64); // transform to random variable on [0, 1]
                let v = angle_inputs.1 / domain_f64; // transform to  random variable on [-1, 1]
                let theta = 2.0 * consts::PI * u;
                let phi = v.acos();
                let x = center.0 + radius * theta.cos() * phi.sin();
                let y = center.1 + radius * theta.sin() * phi.sin();
                let z = center.2 + radius * phi.cos();
                Point3D::new(x, y, z)
            }
            let p1 = to_pnt(center, radius, angle_inputs.0);
            let p2 = to_pnt(center, radius, angle_inputs.1);
            let p3 = to_pnt(center, radius, angle_inputs.2);
            let p4 = to_pnt(center, radius, angle_inputs.3);
            let p_center = Point3D::new(center.0, center.1, center.2);

            let tetrahedron = Tetrahedron::new(p1, p2, p3, p4);

            TestResult::from_bool(tetrahedron.in_circle_test(&p_center) == Some(InCircleLocation::Inside))
        }
        QuickCheck::new().gen(StdGen::new(rand::thread_rng(), DOMAIN)).quickcheck(
            in_circle_2d_tetrahedron_constructed_from_sphere as fn(center: (f64, f64, f64), radius: f64, angle_inputs: ((f64, f64), (f64, f64), (f64, f64), (f64, f64))) -> TestResult
        )
    }

    #[test]
    fn in_circle_2d_nan_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NAN);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_nan_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NAN);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::INFINITY);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NEG_INFINITY);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NEG_INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_3d() {
        let p1 = Point3D::new(-1.0,  1.0, -1.0);
        let p2 = Point3D::new( 1.0,  1.0, -1.0);
        let p3 = Point3D::new( 0.0, -1.0, -1.0);
        let p4 = Point3D::new( 0.0,  0.0,  1.0);
        let d_inside = Point3D::new(0.0, 0.0, 0.0);
        let d_outside = Point3D::new(10.0, 10.0, 10.0);
        let d_on = Point3D::new(0.0, 0.0, 1.0);

        let t = Tetrahedron::new(p1, p2, p3, p4);

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

}
<commit_msg>Fixed comment<commit_after>use libc::{c_double, c_void};
use std::cmp::{Ordering};
use std::sync::{Once, ONCE_INIT};

static EXACTINIT: Once = ONCE_INIT;

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point2D {
    x: c_double,
    y: c_double,
}

impl Point2D {
    pub fn new(x: c_double, y: c_double) -> Point2D {
        Point2D { x: x, y: y }
    }
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct Point3D {
    x: c_double,
    y: c_double,
    z: c_double,
}

impl Point3D {
    pub fn new(x: c_double, y: c_double, z: c_double) -> Point3D {
        Point3D { x: x, y: y, z: z }
    }
}

#[link(name = "predicates")]
extern "C" {
    fn exactinit() -> c_void;
    fn orient2d(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D) -> c_double;
    fn incircle(pa: *const Point2D, pb: *const Point2D, pc: *const Point2D, pd: *const Point2D) -> c_double;
    fn orient3d(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D) -> c_double;
    fn insphere(pa: *const Point3D, pb: *const Point3D, pc: *const Point3D, pd: *const Point3D, pe: *const Point3D) -> c_double;
}

fn init_predicates() {
    EXACTINIT.call_once(|| {
        unsafe { exactinit() };
    });
}

#[derive(Debug, Eq, PartialEq)]
pub enum InCircleLocation {
    Inside,
    Outside,
    On
}

#[derive(Debug, Eq, PartialEq)]
pub enum Orientation {
    Positive,
    Negative
}

impl Orientation {
    pub fn to_f64_multiplier(&self) -> f64 {
        match *self {
            Orientation::Positive => {  1.0 },
            Orientation::Negative => { -1.0 }
        }
    }
}

pub trait InCircleTestable<P> {
    fn in_circle_test(&self, point: &P) -> Option<InCircleLocation>;
}

pub trait Orientable {
    fn orientation(&self) -> Option<Orientation>;
}

pub struct Triangle<P> {
    p1: P,
    p2: P,
    p3: P,
}

impl<P> Triangle<P> {
    pub fn new(p1: P, p2: P, p3: P) -> Triangle<P> {
        Triangle {
            p1: p1,
            p2: p2,
            p3: p3,
        }
    }
}

pub struct Tetrahedron<P> {
    p1: P,
    p2: P,
    p3: P,
    p4: P,
}

impl<P> Tetrahedron<P> {
    pub fn new(p1: P, p2: P, p3: P, p4: P) -> Tetrahedron<P> {
        Tetrahedron {
            p1: p1,
            p2: p2,
            p3: p3,
            p4: p4,
        }
    }
}

fn det_to_in_circle_location(det: f64) -> Option<InCircleLocation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(InCircleLocation::Inside) }
        Some(Ordering::Less) => { Some(InCircleLocation::Outside) }
        Some(Ordering::Equal) => { Some(InCircleLocation::On) }
        None => { None }
    }
}

fn det_to_orientation(det: f64) -> Option<Orientation> {
    match 0.0.partial_cmp(&det) {
        Some(Ordering::Greater) => { Some(Orientation::Positive) }
        Some(Ordering::Less) => { Some(Orientation::Negative) }
        _ => { None }
    }
}

impl Orientable for Triangle<Point2D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient2d(&self.p1, &self.p2, &self.p3) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point2D> for Triangle<Point2D> {
    fn in_circle_test(&self, point: &Point2D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { incircle(&self.p1, &self.p2, &self.p3, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

impl Orientable for Tetrahedron<Point3D> {
    fn orientation(&self) -> Option<Orientation> {
        init_predicates();

        let orientation_det = unsafe { orient3d(&self.p1, &self.p2, &self.p3, &self.p4) };

        det_to_orientation(orientation_det)
    }
}

impl InCircleTestable<Point3D> for Tetrahedron<Point3D> {
    fn in_circle_test(&self, point: &Point3D) -> Option<InCircleLocation> {
        init_predicates();

        let orienation_multiplier: f64 = match self.orientation() {
            Some(p) => { p.to_f64_multiplier() },
            None => { return None; }
        };

        let incircle_det = unsafe { insphere(&self.p1, &self.p2, &self.p3, &self.p4, point) };

        det_to_in_circle_location(orienation_multiplier * incircle_det)
    }
}

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

    use std::f64;
    use std::f64::consts;
    use rand;
    use quickcheck::{TestResult, quickcheck, QuickCheck, StdGen};

    #[test]
    fn in_circle_2d() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);
        let d_inside = Point2D::new(0.5, 0.5);
        let d_outside = Point2D::new(2.0, 0.0);
        let d_on = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

    #[test]
    fn in_circle_2d_triangle_constructed_from_circle() {
        fn in_circle_2d_triangle_constructed_from_circle(center: (f64, f64), radius: f64, angles: (f64, f64, f64)) -> TestResult {
            if radius <= 0.0 { return TestResult::discard()};
            fn to_pnt(center: (f64, f64), radius: f64, angle: f64) -> Point2D {
                let x = center.0 + radius * angle.cos();
                let y = center.1 + radius * angle.sin();
                Point2D::new(x, y)
            }
            let p1 = to_pnt(center, radius, angles.0);
            let p2 = to_pnt(center, radius, angles.1);
            let p3 = to_pnt(center, radius, angles.2);
            let p_center = Point2D::new(center.0, center.1);

            let triangle = Triangle::new(p1, p2, p3);

            TestResult::from_bool(triangle.in_circle_test(&p_center) == Some(InCircleLocation::Inside))
        }
        quickcheck(in_circle_2d_triangle_constructed_from_circle as fn(center: (f64, f64), radius: f64, angles: (f64, f64, f64)) -> TestResult)
    }

    #[test]
    fn in_circle_2d_tetrahedron_constructed_from_sphere() {
        const DOMAIN: usize = 100;
        fn in_circle_2d_tetrahedron_constructed_from_sphere(center: (f64, f64, f64), radius: f64, angle_inputs: ((f64, f64), (f64, f64), (f64, f64), (f64, f64))) -> TestResult {
            if radius <= 0.0 { return TestResult::discard()};
            fn to_pnt(center: (f64, f64, f64), radius: f64, angle_inputs: (f64, f64)) -> Point3D {
                let domain_f64 = DOMAIN as f64;
                let u = (angle_inputs.0 + domain_f64) / (2.0 * domain_f64); // transform to random variable on [0, 1]
                let v = angle_inputs.1 / domain_f64; // transform to random variable on [-1, 1]
                let theta = 2.0 * consts::PI * u;
                let phi = v.acos();
                let x = center.0 + radius * theta.cos() * phi.sin();
                let y = center.1 + radius * theta.sin() * phi.sin();
                let z = center.2 + radius * phi.cos();
                Point3D::new(x, y, z)
            }
            let p1 = to_pnt(center, radius, angle_inputs.0);
            let p2 = to_pnt(center, radius, angle_inputs.1);
            let p3 = to_pnt(center, radius, angle_inputs.2);
            let p4 = to_pnt(center, radius, angle_inputs.3);
            let p_center = Point3D::new(center.0, center.1, center.2);

            let tetrahedron = Tetrahedron::new(p1, p2, p3, p4);

            TestResult::from_bool(tetrahedron.in_circle_test(&p_center) == Some(InCircleLocation::Inside))
        }
        QuickCheck::new().gen(StdGen::new(rand::thread_rng(), DOMAIN)).quickcheck(
            in_circle_2d_tetrahedron_constructed_from_sphere as fn(center: (f64, f64, f64), radius: f64, angle_inputs: ((f64, f64), (f64, f64), (f64, f64), (f64, f64))) -> TestResult
        )
    }

    #[test]
    fn in_circle_2d_nan_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NAN);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_nan_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NAN);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::INFINITY);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_test_point() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, 1.0);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, f64::NEG_INFINITY);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_2d_neg_infinity_in_triangle() {
        let p1 = Point2D::new(0.0, 0.0);
        let p2 = Point2D::new(0.0, f64::NEG_INFINITY);
        let p3 = Point2D::new(1.0, 1.0);

        let d = Point2D::new(1.0, 1.0);

        let t = Triangle::new(p1, p2, p3);

        assert_eq!(t.in_circle_test(&d), None);
    }

    #[test]
    fn in_circle_3d() {
        let p1 = Point3D::new(-1.0,  1.0, -1.0);
        let p2 = Point3D::new( 1.0,  1.0, -1.0);
        let p3 = Point3D::new( 0.0, -1.0, -1.0);
        let p4 = Point3D::new( 0.0,  0.0,  1.0);
        let d_inside = Point3D::new(0.0, 0.0, 0.0);
        let d_outside = Point3D::new(10.0, 10.0, 10.0);
        let d_on = Point3D::new(0.0, 0.0, 1.0);

        let t = Tetrahedron::new(p1, p2, p3, p4);

        assert_eq!(t.in_circle_test(&d_inside), Some(InCircleLocation::Inside));
        assert_eq!(t.in_circle_test(&d_outside), Some(InCircleLocation::Outside));
        assert_eq!(t.in_circle_test(&d_on), Some(InCircleLocation::On));
    }

}
<|endoftext|>


<commit_before>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/reader.rs                                           *
 *                                                        *
 * hprose reader for Rust.                                *
 *                                                        *
 * LastModified: Sep 13, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

use super::tags;
use super::decoder::{Decodable, Decoder};

#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {}

pub type DecodeResult<T> = Result<T, DecoderError>;

pub struct Reader {
    buf: Vec<u8>
}

impl Reader {
    #[inline]
    pub fn new(buf: Vec<u8>) -> Reader {
        Reader {
            buf: buf
        }
    }

    #[inline]
    pub fn unserialize<T: Decodable>(&mut self) -> DecodeResult<T> {
        self.read()
    }

    #[inline]
    pub fn read<T: Decodable>(&mut self) -> DecodeResult<T> {
        Decodable::decode(self)
    }
}

impl Decoder for Reader {
    type Error = DecoderError;

    fn read_nil(&mut self) -> Result<(), Self::Error> {
        unimplemented!()
    }

    fn read_bool(&mut self) -> Result<bool, Self::Error> {
        unimplemented!()
    }

    fn read_i64(&mut self) -> Result<i64, Self::Error> {
        unimplemented!()
    }

    fn read_u64(&mut self) -> Result<u64, Self::Error> {
        unimplemented!()
    }

    fn read_f32(&mut self) -> Result<f32, Self::Error> {
        unimplemented!()
    }

    fn read_f64(&mut self) -> Result<f64, Self::Error> {
        unimplemented!()
    }

    fn read_char(&mut self) -> Result<char, Self::Error> {
        unimplemented!()
    }

    fn read_str(&mut self) -> Result<String, Self::Error> {
        unimplemented!()
    }

    fn read_bytes(&mut self) -> Result<Vec<u8>, Self::Error> {
        unimplemented!()
    }

    fn read_option<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnMut(&mut Self, bool) -> Result<T, Self::Error> {
        unimplemented!()
    }

    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error> where F: FnOnce(&mut Self, usize) -> Result<T, Self::Error> {
        unimplemented!()
    }
}
<commit_msg>Added ByteReader trait.<commit_after>/**********************************************************\
|                                                          |
|                          hprose                          |
|                                                          |
| Official WebSite: http://www.hprose.com/                 |
|                   http://www.hprose.org/                 |
|                                                          |
\**********************************************************/
/**********************************************************\
 *                                                        *
 * io/reader.rs                                           *
 *                                                        *
 * hprose reader for Rust.                                *
 *                                                        *
 * LastModified: Sep 13, 2016                             *
 * Author: Chen Fei <cf@hprose.com>                       *
 *                                                        *
\**********************************************************/

use super::tags;
use super::*;

use std::io;

#[derive(Clone, PartialEq, Debug)]
pub enum ParserError {
    /// msg, line, col
    //    SyntaxError(ErrorCode, usize, usize),
    IoError(io::ErrorKind, String),
}

#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParserError(ParserError)
}

pub type DecodeResult<T> = Result<T, DecoderError>;

pub struct Reader {
    buf: Vec<u8>,
    off: usize
}

pub trait ByteReader {
    fn read_byte(&mut self) -> Result<u8, ParserError>;
}

impl Reader {
    #[inline]
    pub fn new(buf: Vec<u8>) -> Reader {
        Reader {
            buf: buf,
            off: 0
        }
    }

    #[inline]
    pub fn unserialize<T: Decodable>(&mut self) -> DecodeResult<T> {
        self.read()
    }

    #[inline]
    pub fn read<T: Decodable>(&mut self) -> DecodeResult<T> {
        Decodable::decode(self)
    }
}

#[inline]
fn io_error_to_error(io: io::Error) -> ParserError {
    ParserError::IoError(io.kind(), io.to_string())
}

impl ByteReader for Reader {
    fn read_byte(&mut self) -> Result<u8, ParserError> {
        if self.off >= self.buf.len() {
            return Err(io_error_to_error(io::Error::new(io::ErrorKind::UnexpectedEof, "")))
        }
        let b = self.buf[self.off];
        self.off += 1;
        return Ok(b)
    }
}

impl Decoder for Reader {
    type Error = DecoderError;

    fn read_nil(&mut self) -> DecodeResult<()> {
        unimplemented!()
    }

    fn read_bool(&mut self) -> DecodeResult<bool> {
        unimplemented!()
    }

    fn read_i64(&mut self) -> DecodeResult<i64> {
        unimplemented!()
    }

    fn read_u64(&mut self) -> DecodeResult<u64> {
        unimplemented!()
    }

    fn read_f32(&mut self) -> DecodeResult<f32> {
        unimplemented!()
    }

    fn read_f64(&mut self) -> DecodeResult<f64> {
        unimplemented!()
    }

    fn read_char(&mut self) -> DecodeResult<char> {
        unimplemented!()
    }

    fn read_str(&mut self) -> DecodeResult<String> {
        unimplemented!()
    }

    fn read_bytes(&mut self) -> DecodeResult<Vec<u8>> {
        unimplemented!()
    }

    fn read_option<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnMut(&mut Self, bool) -> DecodeResult<T> {
        unimplemented!()
    }

    fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T> where F: FnOnce(&mut Self, usize) -> DecodeResult<T> {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>use types::{Hash256}
use hashing::canonical_hash;
use std::iter::range_step;

fn merkle_root(values: Vec<T>) -> Hash256 {
    let mut o = vec![0; values.len()];
    o.append(values);

    for v in range_step(values - 1, 0, -1) {
        canonical_hash(v.as_bytes());
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn calculate_merkle_root() {
        let values = vec!['abc', 'lmn', 'xyz', 'o0o'];

        let test_leaf_1 = canonical_hash(values[0]);
        let test_leaf_2 = canonical_hash(values[1]);
        let test_leaf_3 = canonical_hash(values[2]);
        let test_leaf_4 = canonical_hash(values[3]);
        let test_node_1 = canonical_hash(vec![test_leaf_4, test_leaf_3]);
        let test_node_2 = canonical_hash(vec![test_leaf_2, test_leaf_1]);
        let test_root   = canonical_hash(vec![test_node_1, test_node_2]);

        let result      = merkle_root(values);
        assert_eq!(result, test_root);
    }
}
<commit_msg>feat(merkle_root): commit changes<commit_after>use types::{Hash256}
use hashing::canonical_hash;

pub fn merkle_root(values: Vec<T>) -> Hash256 {
    let mut o: Vec<&[u8]> = vec![0; values.len()];
    let mut value_hashes = vec![];
    for v in values {
       value_hashes.push(canonical_hash(v);
    }

    o.append(values);

    for i in (0..values.len() - 1).rev() {
        canonical_hash(o[i * 2] + o[i * 2 + 1]);
    }

    o[1];
}

#[cfg(test)]
mod tests {
    #[test]
    fn calculate_merkle_root() {
        let values = vec!["abc", "lmn", "xyz", "o0o"];

        let test_leaf_0 = canonical_hash(values[0]);
        let test_leaf_1 = canonical_hash(values[1]);
        let test_leaf_2 = canonical_hash(values[2]);
        let test_leaf_3 = canonical_hash(values[3]);
        let test_node_0 = canonical_hash(test_leaf_3 + test_leaf_2);
        let test_node_1 = canonical_hash(test_leaf_1 + test_leaf_0);
        let test_root   = canonical_hash(test_node_0 + test_node_0);

        let result      = merkle_root(values);
        assert_eq!(result, test_root);
    }
}
<|endoftext|>


<commit_before>
use call;
use error::GGRError;
use error::GGRResult;
use gron::ToGron;
use serde_json;
use regex;
use std::collections::HashMap;
use entities;
use gerrit::GerritAccess;
use url;

/// Interface to retrieve Changes information from gerrit server
pub struct Changes {
    call: call::Call,

    /// Query Information (`q`-parameter) like "owner:self"
    pub querylist: Option<Vec<String>>,

    /// Additional fields, like `DOWNLOAD_COMMANDS` or `CURRENT_ACTIONS`
    pub labellist: Option<Vec<String>>,
}

impl GerritAccess for Changes {
    // creates ("/a/changes", "pp=0&q="querystring"&o=label&o=label")
    fn build_url(&self) -> (String, String) {
        let mut querystring = String::from("pp=0&q=");
        if let Some(ref querylist) = self.querylist {
            let mut fragment = String::new();
            for el in querylist.iter() {
                fragment.push_str(el);
                fragment.push_str("+");
            }
            if let Some(x) = fragment.chars().last() {
                if x == '+' {
                    fragment = fragment.trim_right_matches(x).to_string();
                }
            };

            querystring = format!("{}{}", querystring, fragment);
        };

        if let Some(ref labels) = self.labellist {
            for label in labels {
                querystring = format!("{}&o={}", querystring, label);
            }
        }

        querystring = querystring.replace("//", "/");

        (String::from("/a/changes/"), querystring)
    }
}

impl Changes {
    pub fn new(url: &url::Url) -> Changes {
        Changes {
            call: call::Call::new(url),
            querylist: None,
            labellist: None,
        }
    }

    /// Returns a ChangeInfos object on success. This value comes direct from the http call and
    /// is a valid json object
    pub fn query_changes(&mut self) -> GGRResult<ChangeInfos> {
        let (path, query) = self.build_url();

        self.call.set_url_query(Some(&query));

        match self.call.get(&path) {
            Ok(cr) => {
                let body = match cr.get_body() {
                    Some(x) => x,
                    None => {
                        // no body content
                        return Ok(ChangeInfos::new());
                    }
                };
                let mut data2 = try!(String::from_utf8(body));
                data2 = data2.trim().into();

                let data5 = match serde_json::de::from_str(&data2) {
                    Ok(d) => d,
                    Err(e) => {
                        println!("error: {}",e);
                        return Err(GGRError::from(e));
                    }
                };

                let changeinfos = ChangeInfos::new_with_data(Some(data5));

                Ok(changeinfos)
            },
            Err(x) => {
                Err(GGRError::General(format!("call problem with: {} and {} ({})", path, query, x)))
            }
        }
    }
}

#[derive(Default, Debug, Deserialize)]
pub struct ChangeInfos {
    pub json: Option<serde_json::value::Value>,
    filter_key: Vec<String>,
    filter_val: Vec<String>,
}

impl ChangeInfos {
    /// creates a new ChangeInfos instance. ChangeInfos.json is None
    pub fn new() -> ChangeInfos {
        ChangeInfos {
            json: None,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// creates new ChangeInfos object with an initial ChangeInfos.json value
    pub fn new_with_data(json: Option<serde_json::value::Value>)
    -> ChangeInfos {
        ChangeInfos {
            json: json,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// add a regular expression filter for keys
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_key(&mut self, r: &str) -> &mut Self {
        self.filter_key.push(String::from(r));
        self
    }

    /// add a regular expression filter for values
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_val(&mut self, r: String) -> &mut Self {
        self.filter_val.push(r);
        self
    }

    /// reset key and value filter
    pub fn filter_reset(&mut self) -> &mut Self {
        self.filter_val.clear();
        self.filter_key.clear();
        self
    }

    pub fn as_string_reg(&self, selectors: &[String]) -> String {
        let json = self.json.clone();

        let mut grondata: Vec<u8> = Vec::new();
        let _ = json.unwrap().to_gron(&mut grondata, "");
        let mut out = String::from("");

        for line in String::from_utf8(grondata).unwrap_or(String::new()).lines() {
            let mut keyval = line.splitn(2, '=');
            let key = keyval.next().unwrap_or("").trim();
            let val = keyval.next().unwrap_or("").trim();

            for selector in selectors {
                if let Ok(re) = regex::Regex::new(selector) {
                    if re.is_match(key) {
                        out.push_str(&format!("{} {}\n", key, val));
                    }
                }
            }
        }

        out
    }

    /// prints all selectable fields os a search string
    ///
    /// returns two values. First one is the count of returned json objects and second value is a
    /// HashMap<String, usize> with all fields and gow much they occure.
    pub fn fieldslist(&self) -> (usize, HashMap<String, usize>) {
        let mut out_hmap: HashMap<String, usize> = HashMap::new();
        let mut entries = 0;

        if let Some(obj) = self.json.clone() {
            if let Some(array) = obj.as_array() {
                entries = array.len();
                for entry in array {
                    match *entry {
                        serde_json::value::Value::Object(ref x) => {
                            for key in x.keys() {
                                let counter = out_hmap.entry(key.to_owned()).or_insert(0);
                                *counter += 1;
                            }
                        }
                        _ => continue,
                    }
                }
            } else {
                println!("no array");
            }
        }

        (entries, out_hmap)
    }

    /// return the string in machinereadable format
    pub fn raw(&self) -> String {
        let json = self.json.clone();

        format!("{}", json.unwrap_or(serde_json::value::Value::String("".into())))
    }

    /// return in human readable form
    pub fn human(&self) -> String {
        let json = self.json.clone();

        serde_json::ser::to_string_pretty(&json.unwrap_or_else(|| serde_json::value::Value::String("".into()))).unwrap_or_else(|_| "problem with pretty printing".into())
    }

    pub fn to_entities(&self) -> GGRResult<Vec<entities::ChangeInfo>> {
        let json = self.raw();

        match serde_json::de::from_str(&json) {
            Ok(decode) => { Ok(decode) },
            Err(r) => {
                println!("decode error: {}", r);
                println!("json:\n{}", json);
                Err(GGRError::from(r))
            },
        }
    }

    pub fn entity_from_commit(&self, commit: &str) -> GGRResult<entities::ChangeInfo> {
        let entities = try!(self.to_entities());

        for element in entities {
            if let Some(ref revisions) = element.revisions {
                for rev in revisions.keys() {
                    if *rev == commit {
                        return Ok(element.clone());
                    }
                }
            }
        }

        Err(GGRError::General("no entity found".into()))
    }

    /// returns a HashMap with project and tip of a topic.changeset
    pub fn project_tip(&self) -> GGRResult<HashMap<String, String>> {
        let entities = try!(self.to_entities());
        // find involved projects
        let mut list_of_projects = Vec::new();
        for element in &entities {
            let project = &element.project;
            if !list_of_projects.contains(project) {
                list_of_projects.push(project.clone());
            }
        }

        // find tip of every project
        let mut project_tip: HashMap<String, String> = HashMap::new();
        for project in list_of_projects {
            // find in entities the last change of every project for this topic
            let mut list_all_parents = Vec::new();
            for element in &entities {
                if let Some(ref cur_revision) = element.current_revision {
                    if let Some(ref revisions) = element.revisions {
                        if let Some(rev) = revisions.get(cur_revision) {
                            if let Some(ref commit) = rev.commit {
                                if let Some(ref parents) = commit.parents {
                                    for p in parents {
                                        list_all_parents.push(&p.commit);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for element in &entities {
                if element.project == project {
                    if let Some(ref cur_revision) = element.current_revision {
                        if !list_all_parents.contains(&cur_revision) {
                            // a tip commit is never a parent for a topic
                            project_tip.insert(project, cur_revision.clone());
                            break;
                        }
                    }
                }
            }
        }

        Ok(project_tip)
    }
}

<commit_msg>remove empty lines in query changes output<commit_after>
use call;
use error::GGRError;
use error::GGRResult;
use gron::ToGron;
use serde_json;
use regex;
use std::collections::HashMap;
use entities;
use gerrit::GerritAccess;
use url;

/// Interface to retrieve Changes information from gerrit server
pub struct Changes {
    call: call::Call,

    /// Query Information (`q`-parameter) like "owner:self"
    pub querylist: Option<Vec<String>>,

    /// Additional fields, like `DOWNLOAD_COMMANDS` or `CURRENT_ACTIONS`
    pub labellist: Option<Vec<String>>,
}

impl GerritAccess for Changes {
    // creates ("/a/changes", "pp=0&q="querystring"&o=label&o=label")
    fn build_url(&self) -> (String, String) {
        let mut querystring = String::from("pp=0&q=");
        if let Some(ref querylist) = self.querylist {
            let mut fragment = String::new();
            for el in querylist.iter() {
                fragment.push_str(el);
                fragment.push_str("+");
            }
            if let Some(x) = fragment.chars().last() {
                if x == '+' {
                    fragment = fragment.trim_right_matches(x).to_string();
                }
            };

            querystring = format!("{}{}", querystring, fragment);
        };

        if let Some(ref labels) = self.labellist {
            for label in labels {
                querystring = format!("{}&o={}", querystring, label);
            }
        }

        querystring = querystring.replace("//", "/");

        (String::from("/a/changes/"), querystring)
    }
}

impl Changes {
    pub fn new(url: &url::Url) -> Changes {
        Changes {
            call: call::Call::new(url),
            querylist: None,
            labellist: None,
        }
    }

    /// Returns a ChangeInfos object on success. This value comes direct from the http call and
    /// is a valid json object
    pub fn query_changes(&mut self) -> GGRResult<ChangeInfos> {
        let (path, query) = self.build_url();

        self.call.set_url_query(Some(&query));

        match self.call.get(&path) {
            Ok(cr) => {
                let body = match cr.get_body() {
                    Some(x) => x,
                    None => {
                        // no body content
                        return Ok(ChangeInfos::new());
                    }
                };
                let mut data2 = try!(String::from_utf8(body));
                data2 = data2.trim().into();

                let data5 = match serde_json::de::from_str(&data2) {
                    Ok(d) => d,
                    Err(e) => {
                        println!("error: {}",e);
                        return Err(GGRError::from(e));
                    }
                };

                let changeinfos = ChangeInfos::new_with_data(Some(data5));

                Ok(changeinfos)
            },
            Err(x) => {
                Err(GGRError::General(format!("call problem with: {} and {} ({})", path, query, x)))
            }
        }
    }
}

#[derive(Default, Debug, Deserialize)]
pub struct ChangeInfos {
    pub json: Option<serde_json::value::Value>,
    filter_key: Vec<String>,
    filter_val: Vec<String>,
}

impl ChangeInfos {
    /// creates a new ChangeInfos instance. ChangeInfos.json is None
    pub fn new() -> ChangeInfos {
        ChangeInfos {
            json: None,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// creates new ChangeInfos object with an initial ChangeInfos.json value
    pub fn new_with_data(json: Option<serde_json::value::Value>)
    -> ChangeInfos {
        ChangeInfos {
            json: json,
            filter_key: Vec::new(),
            filter_val: Vec::new(),
        }
    }

    /// add a regular expression filter for keys
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_key(&mut self, r: &str) -> &mut Self {
        self.filter_key.push(String::from(r));
        self
    }

    /// add a regular expression filter for values
    ///
    /// The filter needs to be resetted through `filter_reset`.
    pub fn filter_val(&mut self, r: String) -> &mut Self {
        self.filter_val.push(r);
        self
    }

    /// reset key and value filter
    pub fn filter_reset(&mut self) -> &mut Self {
        self.filter_val.clear();
        self.filter_key.clear();
        self
    }

    pub fn as_string_reg(&self, selectors: &[String]) -> String {
        let json = self.json.clone();

        let mut grondata: Vec<u8> = Vec::new();
        let _ = json.unwrap().to_gron(&mut grondata, "");
        let mut out = String::from("");

        for line in String::from_utf8(grondata).unwrap_or(String::new()).lines() {
            let mut keyval = line.splitn(2, '=');
            let key = keyval.next().unwrap_or("").trim();
            let val = keyval.next().unwrap_or("").trim();

            // remove empty lines
            if key.is_empty() { continue };

            for selector in selectors {
                if let Ok(re) = regex::Regex::new(selector) {
                    if re.is_match(key) {
                        out.push_str(&format!("{} {}\n", key, val));
                    }
                }
            }
        }

        out
    }

    /// prints all selectable fields os a search string
    ///
    /// returns two values. First one is the count of returned json objects and second value is a
    /// HashMap<String, usize> with all fields and gow much they occure.
    pub fn fieldslist(&self) -> (usize, HashMap<String, usize>) {
        let mut out_hmap: HashMap<String, usize> = HashMap::new();
        let mut entries = 0;

        if let Some(obj) = self.json.clone() {
            if let Some(array) = obj.as_array() {
                entries = array.len();
                for entry in array {
                    match *entry {
                        serde_json::value::Value::Object(ref x) => {
                            for key in x.keys() {
                                let counter = out_hmap.entry(key.to_owned()).or_insert(0);
                                *counter += 1;
                            }
                        }
                        _ => continue,
                    }
                }
            } else {
                println!("no array");
            }
        }

        (entries, out_hmap)
    }

    /// return the string in machinereadable format
    pub fn raw(&self) -> String {
        let json = self.json.clone();

        format!("{}", json.unwrap_or(serde_json::value::Value::String("".into())))
    }

    /// return in human readable form
    pub fn human(&self) -> String {
        let json = self.json.clone();

        serde_json::ser::to_string_pretty(&json.unwrap_or_else(|| serde_json::value::Value::String("".into()))).unwrap_or_else(|_| "problem with pretty printing".into())
    }

    pub fn to_entities(&self) -> GGRResult<Vec<entities::ChangeInfo>> {
        let json = self.raw();

        match serde_json::de::from_str(&json) {
            Ok(decode) => { Ok(decode) },
            Err(r) => {
                println!("decode error: {}", r);
                println!("json:\n{}", json);
                Err(GGRError::from(r))
            },
        }
    }

    pub fn entity_from_commit(&self, commit: &str) -> GGRResult<entities::ChangeInfo> {
        let entities = try!(self.to_entities());

        for element in entities {
            if let Some(ref revisions) = element.revisions {
                for rev in revisions.keys() {
                    if *rev == commit {
                        return Ok(element.clone());
                    }
                }
            }
        }

        Err(GGRError::General("no entity found".into()))
    }

    /// returns a HashMap with project and tip of a topic.changeset
    pub fn project_tip(&self) -> GGRResult<HashMap<String, String>> {
        let entities = try!(self.to_entities());
        // find involved projects
        let mut list_of_projects = Vec::new();
        for element in &entities {
            let project = &element.project;
            if !list_of_projects.contains(project) {
                list_of_projects.push(project.clone());
            }
        }

        // find tip of every project
        let mut project_tip: HashMap<String, String> = HashMap::new();
        for project in list_of_projects {
            // find in entities the last change of every project for this topic
            let mut list_all_parents = Vec::new();
            for element in &entities {
                if let Some(ref cur_revision) = element.current_revision {
                    if let Some(ref revisions) = element.revisions {
                        if let Some(rev) = revisions.get(cur_revision) {
                            if let Some(ref commit) = rev.commit {
                                if let Some(ref parents) = commit.parents {
                                    for p in parents {
                                        list_all_parents.push(&p.commit);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            for element in &entities {
                if element.project == project {
                    if let Some(ref cur_revision) = element.current_revision {
                        if !list_all_parents.contains(&cur_revision) {
                            // a tip commit is never a parent for a topic
                            project_tip.insert(project, cur_revision.clone());
                            break;
                        }
                    }
                }
            }
        }

        Ok(project_tip)
    }
}

<|endoftext|>


<commit_before>fn main() {
    let x = ~{mut a: ~10, b: ~20};
    match x {
      ~{a: ref mut a, b: ref mut b} => {
        assert **a == 10; (*x).a = ~30; assert **a == 30;
      }
    }
}
<commit_msg>test: Fix alt-implicit-copy-unique. rs=me<commit_after>fn main() {
    let x = ~{mut a: ~10, b: ~20};
    match x {
      ~{a: ref mut a, b: ref b} => {
        assert **a == 10; (*x).a = ~30; assert **a == 30;
      }
    }
}
<|endoftext|>


<commit_before>macro_rules! hash_func {
    ($ctx:expr, $update:expr, $convert:expr) => {
        pub fn hash(path: &PathBuf) -> String {
            let mut file = File::open(path).unwrap();
            let mut buffer = vec![0; 1024];

            let mut ctx = $ctx;
            loop {
                let read = file.read(&mut buffer[..]).unwrap();

                if read == 0 {
                    break;
                }

                $update(&mut ctx, &buffer, read);
            }

            $convert(ctx)
        }
    }
}
<commit_msg>Bump buffer size to 4096<commit_after>macro_rules! hash_func {
    ($ctx:expr, $update:expr, $convert:expr) => {
        pub fn hash(path: &PathBuf) -> String {
            let mut file = File::open(path).unwrap();
            let mut buffer = vec![0; 4096];

            let mut ctx = $ctx;
            loop {
                let read = file.read(&mut buffer[..]).unwrap();

                if read == 0 {
                    break;
                }

                $update(&mut ctx, &buffer, read);
            }

            $convert(ctx)
        }
    }
}
<|endoftext|>


<commit_before>// src/controllers/users_controller.rs

/// Users Controller

// Import
// External
use ::chrono::{DateTime, Duration, Local};
use ::nickel::{JsonBody, Request};
use ::bson::Bson;
use ::bson::oid::ObjectId;
use ::std::default::Default;
use ::crypto::sha2::Sha256;
use ::jwt::{Header, Registered, Token};
use ::rustc_serialize::hex::ToHex;
// Utilities
use ::common::api_result::ApiResult;
use ::common::config::Config;
use ::common::data_access::ServerData;
use ::common::session as Session;
// DAO
use ::dao::dao_manager::DAOManager;
// Models
use ::models::user_model::{InUserModel, LoginUserModel, OutUserModel, UserModel};

#[derive(Clone)]
pub struct UsersController{
    dao_manager: DAOManager,
    config: Config
}

impl UsersController{

    pub fn new(dao_manager: DAOManager, config: Config) -> UsersController{
        UsersController{
            dao_manager: dao_manager,
            config: config
        }
    }

    /// Find All Users
    /// ToDo: Remove this endpoint for security
    ///
    /// # Arguments
    /// &self
    ///
    /// # Returns
    /// `ApiResult<Vec<UserModel>>` - ApiResult including a vector of users
    pub fn find_all(&self) -> ApiResult<Vec<OutUserModel>, ()>{
        match self.dao_manager.get_user_dao(){
            Ok(dao) => {
                info!("Fetch all Users");
                let users = dao.find(None);

                ApiResult::Success{result:users}
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end find_all

    /// Create New User
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    ///
    /// # Returns
    /// `ApiResult<OutUserModel>` - ApiResult including the created user
    pub fn create(&self, req: &mut Request<ServerData>) -> ApiResult<OutUserModel, OutUserModel>{
        match self.dao_manager.get_user_dao(){
            Ok(dao) => {

                match req.json_as::<InUserModel>(){
                    Ok(in_user) => {
                        // Validate User
                        let validation_result = in_user.validate_new(self.dao_manager.get_user_dao().unwrap());
                        if validation_result.is_valid(){
                            let mut user = UserModel::new(in_user);
                            // Save User
                            match dao.create(&user){
                                Ok(result) => {
                                    // Set user ID
                                    match result.inserted_id{
                                        Some(id_wrapper) => {
                                            match id_wrapper{
                                                Bson::ObjectId(id) => user.set_id(id),
                                                _ => {}
                                            }
                                        },
                                        None => {}
                                    }

                                    ApiResult::Success{result:OutUserModel::new(user)}
                                },
                                Err(e) => {
                                    error!("{}",e);
                                    ApiResult::Failure{msg:"Unable to create user"}
                                }
                            }
                        }else{
                            ApiResult::Invalid{validation:validation_result, request:OutUserModel::from_in_user(in_user)}
                        }
                    },
                    Err(e) => {
                        error!("{}",e);
                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end create

    /// Modify User
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    ///
    /// # Returns
    /// `ApiResult<OutUserModel>` - ApiResult including the modified user
    pub fn modify(&self, req: &mut Request<ServerData>) -> ApiResult<OutUserModel, OutUserModel>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        match self.dao_manager.get_user_dao(){
            Ok(dao) => {

                match req.json_as::<InUserModel>(){
                    Ok(in_user) => {
                        // Validate User
                        let validation_result = in_user.validate_existing();
                        if validation_result.is_valid(){
                            let user = UserModel::new(in_user);
                            // Save User
                            match dao.update(user_id, &user){
                                Ok(result) => {
                                    if result.acknowledged && result.modified_count > 0 {
                                        ApiResult::Success{result:OutUserModel::new(user)}
                                    }else{
                                        ApiResult::Failure{msg:"Update failed."}
                                    }
                                },
                                Err(e) => {
                                    error!("{}",e);
                                    ApiResult::Failure{msg:"Unable to save user"}
                                }
                            }
                        }else{
                            ApiResult::Invalid{validation:validation_result, request:OutUserModel::from_in_user(in_user)}
                        }
                    },
                    Err(e) => {
                        error!("{}",e);
                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end modify

    /// Log In
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    ///
    /// # Returns
    /// `ApiResult<OutUserModel>` - ApiResult including the logged in user if login successful
    pub fn login(&self, req: &mut Request<ServerData>) -> ApiResult<LoginUserModel, LoginUserModel>{
        match self.dao_manager.get_user_dao(){
            Ok(dao) => {
                // parse input
                match req.json_as::<InUserModel>(){
                    Ok(in_user) => {

                        // validate (require email and password)
                        let validation_result = in_user.login_validate();
                        if validation_result.is_valid() {
                            let filter = doc!{
                                "email" => { in_user.email.unwrap() }
                            };

                            if let Some(found_user) = dao.find_one(Some(filter), None){
                                // Found user for email
                                if found_user.verify_password(in_user.password.unwrap()) {
                                    // Passwords match

                                    //Create a signed JASON Web Token (JWT) for authentication
                                    let header: Header = Default::default();

                                    // Define claims
                                    let claims = create_auth_claims(&self.config, found_user.get_id().unwrap().to_hex());

                                    let token = Token::new(header, claims);

                                    // Sign the token
                                    if let Some(ref auth_secret) = self.config.auth.auth_secret{
                                        match token.signed(auth_secret.as_bytes(), Sha256::new()){
                                            Ok(jwt) => {
                                                return ApiResult::Success{result:LoginUserModel::new(found_user, jwt)};
                                            }
                                            Err(e) => {
                                                error!("Login Error. Unable to sign JWT Token: {:?}.", e);
                                            }
                                        }
                                    }else{
                                        error!("Login Error. Unable to sign JWT Toke. No auth_secret key.");
                                    }
                                    return ApiResult::Failure{msg:"Unable to sign token for authentication."};
                                }
                            }
                            ApiResult::Failure{msg:"Invalid email address or password."}
                        }else{
                            ApiResult::Invalid{validation:validation_result, request:LoginUserModel::from_in_user(in_user)}
                        }
                    },
                    Err(e) => {
                        error!("{}",e);
                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end login

    /// Get current user details
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    ///
    /// # Returns
    /// `ApiResult<OutUserModel>` - ApiResult including the logged in user
    pub fn get_account(&self, req: &mut Request<ServerData>) -> ApiResult<OutUserModel, ()>{
        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        match self.dao_manager.get_user_dao(){
            Ok(dao) => {
                match ObjectId::with_string(user_id.as_str()){
                    Ok(id) => {
                        let filter = doc! {
                            "_id" => id
                        };

                        if let Some(user) = dao.find_one(Some(filter), None){
                            ApiResult::Success{result:OutUserModel::new(user)}
                        }else{
                            ApiResult::Failure{msg:"Unable to find user."}
                        }
                    },
                    Err(e) => {
                        error!("{}", e);
                        ApiResult::Failure{msg:"Failed to find user. Invalid ID."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end get_account

}// end impl UsersController

/// Get JWT auth claims for token
///
/// # Arguments
/// id - String The users ID
///
/// # Returns
/// `Registered` - The claims for the JWT token
fn create_auth_claims(config: &Config, id: String) -> Registered{
    let mut iss = String::new();
    let mut exp_duration = 1;// default expiration duration to 1 minute
    if let Some(ref claim_iss) = config.auth.claim_iss{
        iss = claim_iss.clone();
    }
    if let Some(ref exp_dur) = config.auth.exp_duration{
        exp_duration = exp_dur.clone();
    }
    let iat: DateTime<Local> = Local::now();
    let exp: DateTime<Local> = Local::now() + Duration::minutes(exp_duration);
    let claims = Registered {
        iss: Some(iss),
        sub: Some(id),
        exp: Some(exp.timestamp() as u64),
        iat: Some(iat.timestamp() as u64),
        ..Default::default()
    };
    claims
}// end create_auth_claims
<commit_msg>Clarify Return status for user modification when no updates necessary<commit_after>// src/controllers/users_controller.rs

/// Users Controller

// Import
// External
use ::chrono::{DateTime, Duration, Local};
use ::nickel::{JsonBody, Request};
use ::bson::Bson;
use ::bson::oid::ObjectId;
use ::std::default::Default;
use ::crypto::sha2::Sha256;
use ::jwt::{Header, Registered, Token};
use ::rustc_serialize::hex::ToHex;
// Utilities
use ::common::api_result::ApiResult;
use ::common::config::Config;
use ::common::data_access::ServerData;
use ::common::session as Session;
// DAO
use ::dao::dao_manager::DAOManager;
// Models
use ::models::user_model::{InUserModel, LoginUserModel, OutUserModel, UserModel};

#[derive(Clone)]
pub struct UsersController{
    dao_manager: DAOManager,
    config: Config
}

impl UsersController{

    pub fn new(dao_manager: DAOManager, config: Config) -> UsersController{
        UsersController{
            dao_manager: dao_manager,
            config: config
        }
    }

    /// Find All Users
    /// ToDo: Remove this endpoint for security
    ///
    /// # Arguments
    /// &self
    ///
    /// # Returns
    /// `ApiResult<Vec<UserModel>>` - ApiResult including a vector of users
    pub fn find_all(&self) -> ApiResult<Vec<OutUserModel>, ()>{
        match self.dao_manager.get_user_dao(){
            Ok(dao) => {
                info!("Fetch all Users");
                let users = dao.find(None);

                ApiResult::Success{result:users}
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end find_all

    /// Create New User
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    ///
    /// # Returns
    /// `ApiResult<OutUserModel>` - ApiResult including the created user
    pub fn create(&self, req: &mut Request<ServerData>) -> ApiResult<OutUserModel, OutUserModel>{
        match self.dao_manager.get_user_dao(){
            Ok(dao) => {

                match req.json_as::<InUserModel>(){
                    Ok(in_user) => {
                        // Validate User
                        let validation_result = in_user.validate_new(self.dao_manager.get_user_dao().unwrap());
                        if validation_result.is_valid(){
                            let mut user = UserModel::new(in_user);
                            // Save User
                            match dao.create(&user){
                                Ok(result) => {
                                    // Set user ID
                                    match result.inserted_id{
                                        Some(id_wrapper) => {
                                            match id_wrapper{
                                                Bson::ObjectId(id) => user.set_id(id),
                                                _ => {}
                                            }
                                        },
                                        None => {}
                                    }

                                    ApiResult::Success{result:OutUserModel::new(user)}
                                },
                                Err(e) => {
                                    error!("{}",e);
                                    ApiResult::Failure{msg:"Unable to create user"}
                                }
                            }
                        }else{
                            ApiResult::Invalid{validation:validation_result, request:OutUserModel::from_in_user(in_user)}
                        }
                    },
                    Err(e) => {
                        error!("{}",e);
                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end create

    /// Modify User
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    ///
    /// # Returns
    /// `ApiResult<OutUserModel>` - ApiResult including the modified user
    pub fn modify(&self, req: &mut Request<ServerData>) -> ApiResult<OutUserModel, OutUserModel>{

        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        match self.dao_manager.get_user_dao(){
            Ok(dao) => {

                match req.json_as::<InUserModel>(){
                    Ok(in_user) => {
                        // Validate User
                        let validation_result = in_user.validate_existing();
                        if validation_result.is_valid(){
                            let user = UserModel::new(in_user);
                            // Save User
                            match dao.update(user_id, &user){
                                Ok(result) => {
                                    if result.acknowledged && result.matched_count > 0  && result.modified_count == 0 {
                                        //Update found match, but no changes were needed to existing data
                                        ApiResult::Success{
                                            result:OutUserModel{
                                                id: None,
                                                first_name: None,
                                                last_name: None,
                                                email: None
                                            }
                                        }
                                    } else if result.acknowledged && result.matched_count > 0 && result.modified_count > 0 {
                                        //Update successful
                                        ApiResult::Success{result:OutUserModel::new(user)}
                                    }else{
                                        ApiResult::Failure{msg:"Update failed."}
                                    }
                                },
                                Err(e) => {
                                    error!("{}",e);
                                    ApiResult::Failure{msg:"Unable to save user"}
                                }
                            }
                        }else{
                            ApiResult::Invalid{validation:validation_result, request:OutUserModel::from_in_user(in_user)}
                        }
                    },
                    Err(e) => {
                        error!("{}",e);
                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end modify

    /// Log In
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    ///
    /// # Returns
    /// `ApiResult<OutUserModel>` - ApiResult including the logged in user if login successful
    pub fn login(&self, req: &mut Request<ServerData>) -> ApiResult<LoginUserModel, LoginUserModel>{
        match self.dao_manager.get_user_dao(){
            Ok(dao) => {
                // parse input
                match req.json_as::<InUserModel>(){
                    Ok(in_user) => {

                        // validate (require email and password)
                        let validation_result = in_user.login_validate();
                        if validation_result.is_valid() {
                            let filter = doc!{
                                "email" => { in_user.email.unwrap() }
                            };

                            if let Some(found_user) = dao.find_one(Some(filter), None){
                                // Found user for email
                                if found_user.verify_password(in_user.password.unwrap()) {
                                    // Passwords match

                                    //Create a signed JASON Web Token (JWT) for authentication
                                    let header: Header = Default::default();

                                    // Define claims
                                    let claims = create_auth_claims(&self.config, found_user.get_id().unwrap().to_hex());

                                    let token = Token::new(header, claims);

                                    // Sign the token
                                    if let Some(ref auth_secret) = self.config.auth.auth_secret{
                                        match token.signed(auth_secret.as_bytes(), Sha256::new()){
                                            Ok(jwt) => {
                                                return ApiResult::Success{result:LoginUserModel::new(found_user, jwt)};
                                            }
                                            Err(e) => {
                                                error!("Login Error. Unable to sign JWT Token: {:?}.", e);
                                            }
                                        }
                                    }else{
                                        error!("Login Error. Unable to sign JWT Toke. No auth_secret key.");
                                    }
                                    return ApiResult::Failure{msg:"Unable to sign token for authentication."};
                                }
                            }
                            ApiResult::Failure{msg:"Invalid email address or password."}
                        }else{
                            ApiResult::Invalid{validation:validation_result, request:LoginUserModel::from_in_user(in_user)}
                        }
                    },
                    Err(e) => {
                        error!("{}",e);
                        ApiResult::Failure{msg:"Invalid format. Unable to parse data."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end login

    /// Get current user details
    ///
    /// # Arguments
    /// &self
    /// req - nickel::Request
    ///
    /// # Returns
    /// `ApiResult<OutUserModel>` - ApiResult including the logged in user
    pub fn get_account(&self, req: &mut Request<ServerData>) -> ApiResult<OutUserModel, ()>{
        let user_id = match Session::get_session_id(req){
            Ok(id) => id,
            Err(e) => {
                error!("{}",e.get_message().to_string());
                return ApiResult::Failure{msg:"Unable to retrieve session data."};
            }
        };

        match self.dao_manager.get_user_dao(){
            Ok(dao) => {
                match ObjectId::with_string(user_id.as_str()){
                    Ok(id) => {
                        let filter = doc! {
                            "_id" => id
                        };

                        if let Some(user) = dao.find_one(Some(filter), None){
                            ApiResult::Success{result:OutUserModel::new(user)}
                        }else{
                            ApiResult::Failure{msg:"Unable to find user."}
                        }
                    },
                    Err(e) => {
                        error!("{}", e);
                        ApiResult::Failure{msg:"Failed to find user. Invalid ID."}
                    }
                }
            },
            Err(e) => {
                error!("{}",e.get_message().to_string());
                ApiResult::Failure{msg:"Unable to interact with database"}
            }
        }
    }// end get_account

}// end impl UsersController

/// Get JWT auth claims for token
///
/// # Arguments
/// id - String The users ID
///
/// # Returns
/// `Registered` - The claims for the JWT token
fn create_auth_claims(config: &Config, id: String) -> Registered{
    let mut iss = String::new();
    let mut exp_duration = 1;// default expiration duration to 1 minute
    if let Some(ref claim_iss) = config.auth.claim_iss{
        iss = claim_iss.clone();
    }
    if let Some(ref exp_dur) = config.auth.exp_duration{
        exp_duration = exp_dur.clone();
    }
    let iat: DateTime<Local> = Local::now();
    let exp: DateTime<Local> = Local::now() + Duration::minutes(exp_duration);
    let claims = Registered {
        iss: Some(iss),
        sub: Some(id),
        exp: Some(exp.timestamp() as u64),
        iat: Some(iat.timestamp() as u64),
        ..Default::default()
    };
    claims
}// end create_auth_claims
<|endoftext|>