<commit_before>use core::prelude::*;
use alloc::boxed::Box;
use collections::string::String;
use core::{ptr, mem, raw, fmt};
//use core::ptr::RawMutPtr;
//use core::any::{Any, AnyRefExt};
use core::any::Any;
use core::fmt::{Show, Writer};
use core::iter;
use libc::{c_void, c_char};
use core::borrow::{Cow, IntoCow};
use collections::vec::Vec;
use std::str;

use jni::{jobject, jclass, jmethodID, jfieldID, JNIEnv, jint, jstring, jvalue, JNINativeMethod, JavaVM};
#[cfg(target_word_size = "64")] use jni::jlong;
use jni_constants::*;

use glinit::GLInit;
use drawevent::Events;
use glcommon::MString;
use libc::types::os::arch::posix88::pid_t;

use std;

extern "C" {
    pub fn gettid() -> pid_t;
}

#[macro_use]
mod macros;
pub mod texturethread;
pub mod android_bitmap;
pub mod gldataclasses;
pub mod motionevent;

#[cfg(not(target_word_size = "64"))]
#[allow(non_camel_case_types)]
pub type jpointer = jint;
#[cfg(target_word_size = "64")]
#[allow(non_camel_case_types)]
pub type jpointer = jlong;

struct CaseClass {
    constructor: jmethodID,
    class: jclass,
}

static mut GL_EXCEPTION: CaseClass = CaseClass { constructor: 0 as jmethodID, class: 0 as jclass };

struct GLInitEvents<'a> {
    glinit: GLInit<'a>,
    events: Events<'a>,
    jni_undo_callback: JNIUndoCallback,
    owning_thread: pid_t,
    //lua: LuaInterpolatorState<LuaCallbackType>,
}

#[deriving(Copy)]
pub struct JNIUndoCallback {
    callback_obj: jobject,
    callback_method: jmethodID,
}

pub struct JNICallbackClosure<'a> {
    undo_callback: &'a JNIUndoCallback,
    env: *mut JNIEnv,
}

impl JNIUndoCallback {
    pub unsafe fn new(env: *mut JNIEnv, obj: jobject) -> JNIUndoCallback {
        let obj = ((**env).NewGlobalRef)(env, obj);
        let objclass = ((**env).GetObjectClass)(env, obj);
        let method = ((**env).GetMethodID)(env, objclass, cstr!("undoBufferChanged"), cstr!("(I)V"));
        JNIUndoCallback { callback_obj: obj, callback_method: method }
    }

    pub unsafe fn call(&self, env: *mut JNIEnv, new_undo_size: i32) {
        ((**env).CallVoidMethod)(env, self.callback_obj, self.callback_method, new_undo_size as jint);
    }

    pub unsafe fn destroy(self, env: *mut JNIEnv) {
        ((**env).DeleteGlobalRef)(env, self.callback_obj);
    }
    pub fn create_closure(&self, env: *mut JNIEnv) -> JNICallbackClosure {
        JNICallbackClosure { undo_callback: self, env: env }
    }
}

impl CaseClass {
    pub unsafe fn new(env: *mut JNIEnv, name: *const c_char, sig: *const c_char) -> CaseClass {
        let class = ((**env).FindClass)(env, name);
        let constructor = ((**env).GetMethodID)(env, class, cstr!("<init>"), sig);
        let globalclass = ((**env).NewGlobalRef)(env, class);

        CaseClass { constructor: constructor, class: globalclass }
    }
    pub unsafe fn construct(&self, env: *mut JNIEnv, arg: &mut [jvalue]) -> jobject {
        ((**env).NewObjectA)(env, self.class, self.constructor, arg.as_mut_ptr())
    }
    pub unsafe fn destroy(&mut self, env: *mut JNIEnv) {
        ((**env).DeleteGlobalRef)(env, self.class);
    }
}

unsafe fn get_string(env: *mut JNIEnv, string: jstring) -> Option<String> {
    let string = try_opt!(string.as_mut());
    let c = try_opt!(((**env).GetStringChars)(env, string, ptr::null_mut()).as_ref());
    let len = ((**env).GetStringLength)(env, string);
    let strslice: &[u16] = mem::transmute(raw::Slice { data: c, len: len as uint });
    let ruststr = String::from_utf16(strslice);
    ((**env).ReleaseStringChars)(env, string as jstring, strslice.as_ptr());
    match ruststr {
        Ok(s) => Some(s),
        Err(_) => None,
    }
}

unsafe fn get_mstring(env: *mut JNIEnv, string: jstring) -> Option<MString> {
    match get_string(env, string) {
        Some(s) => Some(s.into_cow()),
        None => None,
    }
}

unsafe fn str_to_jstring(env: *mut JNIEnv, s: &str) -> jstring {
    let u16msg: Vec<u16> = s.utf16_units().collect();
    ((**env).NewString)(env, u16msg.as_ptr(), u16msg.len() as i32)
}

pub unsafe fn register_classmethods(env: *mut JNIEnv, classname: *const i8, methods: &[JNINativeMethod]) {
    let class = ((**env).FindClass)(env, classname);
    ((**env).RegisterNatives)(env, class, methods.as_ptr(), methods.len() as i32);
}

fn get_safe_data<'a>(data: jpointer) -> &'a mut GLInitEvents<'a> {
    unsafe {
        let data: &'a mut GLInitEvents<'a> = mem::transmute(data);
        assert_eq!(gettid(), data.owning_thread);
        data
    }
}

#[cfg(not(target_word_size = "64"))]
#[inline(always)]
unsafe fn get_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    ((**env).GetIntField)(env, obj, field)
}
#[cfg(target_word_size = "64")]
#[inline(always)]
unsafe fn get_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    ((**env).GetLongField)(env, obj, field)
}

//#[cfg(target_word_size = "32")]
//#[inline(always)]
//fn set_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    //((**env).SetIntField)(env, obj, field)
//}
//#[cfg(target_word_size = "64")]
//#[inline(always)]
//fn set_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    //((**env).SetLongField)(env, obj, field)
//}

fn on_unwind(msg: &(Any + Send), file: &'static str, line: uint) {
    //use core::fmt::FormatWriter;
    // as far as I know there's no way to identify traits that can be cast to Show at runtime
    if let Some(s) = msg.downcast_ref::<&Show>() {
        loge!("fatal error in {}:{} as &Show: {:?}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<Box<Show>>() {
        loge!("fatal error in {}:{} as Box<Show>: {:?}", file, line, &**s);
    } else if let Some(s) = msg.downcast_ref::<&str>() {
        loge!("fatal error in {}:{} as &str: {}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<String>() {
        loge!("fatal error in {}:{} as String: {}", file, line, s);
    //} else if let Some(s) = msg.downcast_ref::<Cow<'static, String, &str>>() {
        //loge!("fatal error in {}:{} as MaybeOwned: {}", file, line, s);
    } else {
        loge!("fatal error in {}:{}: unknown error message type {:?}!", file, line, msg.get_type_id());
        loge!("Printing start:");
        unsafe {
            let mut line = String::new();

            let width = 32;
            let raw::TraitObject { data: msgptr, vtable: _ } = mem::transmute(msg);
            let msgslice: &[u8] = mem::transmute(raw::Slice { data: msgptr as *const (), len: 1000 });
            let poscounter = iter::count(msgptr as u32, width as u32);
            for (chunk, pos) in msgslice.chunks(width).zip(poscounter) {
                {
                    let _ = write!(&mut line, "{:08x}: ", pos);
                    for byte in chunk.iter() {
                        let _ = write!(&mut line, "{} ", byte);
                    }
                }
                loge!("{}", line);
                line.clear();
            }
        }
    }
    // Unwinding always fails, but not before messing up android's crash report backtrace.
    // So, commit suicide before that can happen.
    unsafe {
        let null: *mut u16 = ptr::null_mut();
        *null = 0xdead;
    }
}

#[allow(non_snake_case, unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn JNI_OnLoad(vm: *mut JavaVM, reserved: *mut c_void) -> jint {
    logi!("jni onload!!");
    let mut env: *mut c_void = ptr::null_mut();
    if ((**vm).GetEnv)(vm, (&mut env as *mut *mut c_void), JNI_VERSION_1_6) != JNI_OK {
        return -1;
    }
    let env = env as *mut JNIEnv;
    logi!("got environment!: {:?}", env);

    texturethread::init(env);
    texturethread::init(env);
    android_bitmap::init(env);
    gldataclasses::init(env);
    motionevent::init(env);

    GL_EXCEPTION = CaseClass::new(env, cstr!("com/github/wartman4404/gldraw/GLException"), cstr!("(Ljava/lang/String;)V"));

    //rustrt::init(1, ["rustjni".as_ptr()].as_ptr());
    std::rt::unwind::register(on_unwind);

    logi!("finished jni_onload");
    JNI_VERSION_1_2
}

#[allow(non_snake_case, unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn JNI_OnUnload(vm: *mut JavaVM, reserved: *mut c_void) {
    logi!("jni onload!!");
    let mut env: *mut c_void = ptr::null_mut();
    if ((**vm).GetEnv)(vm, (&mut env as *mut *mut c_void), JNI_VERSION_1_6) != JNI_OK {
        return;
    }
    let env = env as *mut JNIEnv;
    texturethread::destroy(env);
    texturethread::destroy(env);
    android_bitmap::destroy(env);
    gldataclasses::destroy(env);
    motionevent::destroy(env);
    GL_EXCEPTION.destroy(env);
}
<commit_msg>import fixes for utf16_units<commit_after>// cannot use core::prelude and still import StrExt needed for utf16_units
use std::prelude::v1::*;
use core::{ptr, mem, raw, fmt};
use core::any::Any;
use core::fmt::Show;
use core::fmt::Writer as FormatWriter;
use core::iter;
use libc::{c_void, c_char};
use core::borrow::{Cow, IntoCow};

use jni::{jobject, jclass, jmethodID, jfieldID, JNIEnv, jint, jstring, jvalue, JNINativeMethod, JavaVM};
#[cfg(target_word_size = "64")] use jni::jlong;
use jni_constants::*;

use glinit::GLInit;
use drawevent::Events;
use glcommon::MString;
use libc::types::os::arch::posix88::pid_t;

use std;

extern "C" {
    pub fn gettid() -> pid_t;
}

#[macro_use]
mod macros;
pub mod texturethread;
pub mod android_bitmap;
pub mod gldataclasses;
pub mod motionevent;

#[cfg(not(target_word_size = "64"))]
#[allow(non_camel_case_types)]
pub type jpointer = jint;
#[cfg(target_word_size = "64")]
#[allow(non_camel_case_types)]
pub type jpointer = jlong;

struct CaseClass {
    constructor: jmethodID,
    class: jclass,
}

static mut GL_EXCEPTION: CaseClass = CaseClass { constructor: 0 as jmethodID, class: 0 as jclass };

struct GLInitEvents<'a> {
    glinit: GLInit<'a>,
    events: Events<'a>,
    jni_undo_callback: JNIUndoCallback,
    owning_thread: pid_t,
    //lua: LuaInterpolatorState<LuaCallbackType>,
}

#[deriving(Copy)]
pub struct JNIUndoCallback {
    callback_obj: jobject,
    callback_method: jmethodID,
}

pub struct JNICallbackClosure<'a> {
    undo_callback: &'a JNIUndoCallback,
    env: *mut JNIEnv,
}

impl JNIUndoCallback {
    pub unsafe fn new(env: *mut JNIEnv, obj: jobject) -> JNIUndoCallback {
        let obj = ((**env).NewGlobalRef)(env, obj);
        let objclass = ((**env).GetObjectClass)(env, obj);
        let method = ((**env).GetMethodID)(env, objclass, cstr!("undoBufferChanged"), cstr!("(I)V"));
        JNIUndoCallback { callback_obj: obj, callback_method: method }
    }

    pub unsafe fn call(&self, env: *mut JNIEnv, new_undo_size: i32) {
        ((**env).CallVoidMethod)(env, self.callback_obj, self.callback_method, new_undo_size as jint);
    }

    pub unsafe fn destroy(self, env: *mut JNIEnv) {
        ((**env).DeleteGlobalRef)(env, self.callback_obj);
    }
    pub fn create_closure(&self, env: *mut JNIEnv) -> JNICallbackClosure {
        JNICallbackClosure { undo_callback: self, env: env }
    }
}

impl CaseClass {
    pub unsafe fn new(env: *mut JNIEnv, name: *const c_char, sig: *const c_char) -> CaseClass {
        let class = ((**env).FindClass)(env, name);
        let constructor = ((**env).GetMethodID)(env, class, cstr!("<init>"), sig);
        let globalclass = ((**env).NewGlobalRef)(env, class);

        CaseClass { constructor: constructor, class: globalclass }
    }
    pub unsafe fn construct(&self, env: *mut JNIEnv, arg: &mut [jvalue]) -> jobject {
        ((**env).NewObjectA)(env, self.class, self.constructor, arg.as_mut_ptr())
    }
    pub unsafe fn destroy(&mut self, env: *mut JNIEnv) {
        ((**env).DeleteGlobalRef)(env, self.class);
    }
}

unsafe fn get_string(env: *mut JNIEnv, string: jstring) -> Option<String> {
    let string = try_opt!(string.as_mut());
    let c = try_opt!(((**env).GetStringChars)(env, string, ptr::null_mut()).as_ref());
    let len = ((**env).GetStringLength)(env, string);
    let strslice: &[u16] = mem::transmute(raw::Slice { data: c, len: len as uint });
    let ruststr = String::from_utf16(strslice);
    ((**env).ReleaseStringChars)(env, string as jstring, strslice.as_ptr());
    match ruststr {
        Ok(s) => Some(s),
        Err(_) => None,
    }
}

unsafe fn get_mstring(env: *mut JNIEnv, string: jstring) -> Option<MString> {
    match get_string(env, string) {
        Some(s) => Some(s.into_cow()),
        None => None,
    }
}

unsafe fn str_to_jstring(env: *mut JNIEnv, s: &str) -> jstring {
    let u16msg: Vec<u16> = s.utf16_units().collect();
    ((**env).NewString)(env, u16msg.as_ptr(), u16msg.len() as i32)
}

pub unsafe fn register_classmethods(env: *mut JNIEnv, classname: *const i8, methods: &[JNINativeMethod]) {
    let class = ((**env).FindClass)(env, classname);
    ((**env).RegisterNatives)(env, class, methods.as_ptr(), methods.len() as i32);
}

fn get_safe_data<'a>(data: jpointer) -> &'a mut GLInitEvents<'a> {
    unsafe {
        let data: &'a mut GLInitEvents<'a> = mem::transmute(data);
        assert_eq!(gettid(), data.owning_thread);
        data
    }
}

#[cfg(not(target_word_size = "64"))]
#[inline(always)]
unsafe fn get_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    ((**env).GetIntField)(env, obj, field)
}
#[cfg(target_word_size = "64")]
#[inline(always)]
unsafe fn get_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    ((**env).GetLongField)(env, obj, field)
}

//#[cfg(target_word_size = "32")]
//#[inline(always)]
//fn set_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    //((**env).SetIntField)(env, obj, field)
//}
//#[cfg(target_word_size = "64")]
//#[inline(always)]
//fn set_jpointer(env: *mut JNIEnv, obj: jobject, field: jfieldID) -> jpointer {
    //((**env).SetLongField)(env, obj, field)
//}

fn on_unwind(msg: &(Any + Send), file: &'static str, line: uint) {
    //use core::fmt::FormatWriter;
    // as far as I know there's no way to identify traits that can be cast to Show at runtime
    if let Some(s) = msg.downcast_ref::<&Show>() {
        loge!("fatal error in {}:{} as &Show: {:?}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<Box<Show>>() {
        loge!("fatal error in {}:{} as Box<Show>: {:?}", file, line, &**s);
    } else if let Some(s) = msg.downcast_ref::<&str>() {
        loge!("fatal error in {}:{} as &str: {}", file, line, s);
    } else if let Some(s) = msg.downcast_ref::<String>() {
        loge!("fatal error in {}:{} as String: {}", file, line, s);
    //} else if let Some(s) = msg.downcast_ref::<Cow<'static, String, &str>>() {
        //loge!("fatal error in {}:{} as MaybeOwned: {}", file, line, s);
    } else {
        loge!("fatal error in {}:{}: unknown error message type {:?}!", file, line, msg.get_type_id());
        loge!("Printing start:");
        unsafe {
            let mut line = String::new();

            let width = 32;
            let raw::TraitObject { data: msgptr, vtable: _ } = mem::transmute(msg);
            let msgslice: &[u8] = mem::transmute(raw::Slice { data: msgptr as *const (), len: 1000 });
            let poscounter = iter::count(msgptr as u32, width as u32);
            for (chunk, pos) in msgslice.chunks(width).zip(poscounter) {
                {
                    let _ = write!(&mut line, "{:08x}: ", pos);
                    for byte in chunk.iter() {
                        let _ = write!(&mut line, "{} ", byte);
                    }
                }
                loge!("{}", line);
                line.clear();
            }
        }
    }
    // Unwinding always fails, but not before messing up android's crash report backtrace.
    // So, commit suicide before that can happen.
    unsafe {
        let null: *mut u16 = ptr::null_mut();
        *null = 0xdead;
    }
}

#[allow(non_snake_case, unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn JNI_OnLoad(vm: *mut JavaVM, reserved: *mut c_void) -> jint {
    logi!("jni onload!!");
    let mut env: *mut c_void = ptr::null_mut();
    if ((**vm).GetEnv)(vm, (&mut env as *mut *mut c_void), JNI_VERSION_1_6) != JNI_OK {
        return -1;
    }
    let env = env as *mut JNIEnv;
    logi!("got environment!: {:?}", env);

    texturethread::init(env);
    texturethread::init(env);
    android_bitmap::init(env);
    gldataclasses::init(env);
    motionevent::init(env);

    GL_EXCEPTION = CaseClass::new(env, cstr!("com/github/wartman4404/gldraw/GLException"), cstr!("(Ljava/lang/String;)V"));

    //rustrt::init(1, ["rustjni".as_ptr()].as_ptr());
    std::rt::unwind::register(on_unwind);

    logi!("finished jni_onload");
    JNI_VERSION_1_2
}

#[allow(non_snake_case, unused_variables)]
#[no_mangle]
pub unsafe extern "C" fn JNI_OnUnload(vm: *mut JavaVM, reserved: *mut c_void) {
    logi!("jni onload!!");
    let mut env: *mut c_void = ptr::null_mut();
    if ((**vm).GetEnv)(vm, (&mut env as *mut *mut c_void), JNI_VERSION_1_6) != JNI_OK {
        return;
    }
    let env = env as *mut JNIEnv;
    texturethread::destroy(env);
    texturethread::destroy(env);
    android_bitmap::destroy(env);
    gldataclasses::destroy(env);
    motionevent::destroy(env);
    GL_EXCEPTION.destroy(env);
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::path::Path;

use serde::ser;

use crate::util::{CargoResult, CargoResultExt, Config, RustfixDiagnosticServer};

/// Configuration information for a rustc build.
#[derive(Debug)]
pub struct BuildConfig {
    /// The target arch triple.
    /// Default: host arch.
    pub requested_target: Option<String>,
    /// Number of rustc jobs to run in parallel.
    pub jobs: u32,
    /// `true` if we are building for release.
    pub release: bool,
    /// The mode we are compiling in.
    pub mode: CompileMode,
    /// `true` to print stdout in JSON format (for machine reading).
    pub message_format: MessageFormat,
    /// Force Cargo to do a full rebuild and treat each target as changed.
    pub force_rebuild: bool,
    /// Output a build plan to stdout instead of actually compiling.
    pub build_plan: bool,
    /// Use Cargo itself as the wrapper around rustc, only used for `cargo fix`.
    pub cargo_as_rustc_wrapper: bool,
    /// Extra env vars to inject into rustc commands.
    pub extra_rustc_env: Vec<(String, String)>,
    /// Extra args to inject into rustc commands.
    pub extra_rustc_args: Vec<String>,
    pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
}

impl BuildConfig {
    /// Parses all config files to learn about build configuration. Currently
    /// configured options are:
    ///
    /// * `build.jobs`
    /// * `build.target`
    /// * `target.$target.ar`
    /// * `target.$target.linker`
    /// * `target.$target.libfoo.metadata`
    pub fn new(
        config: &Config,
        jobs: Option<u32>,
        requested_target: &Option<String>,
        mode: CompileMode,
    ) -> CargoResult<BuildConfig> {
        let requested_target = match requested_target {
            &Some(ref target) if target.ends_with(".json") => {
                let path = Path::new(target).canonicalize().chain_err(|| {
                    failure::format_err!("Target path {:?} is not a valid file", target)
                })?;
                Some(
                    path.into_os_string()
                        .into_string()
                        .map_err(|_| failure::format_err!("Target path is not valid unicode"))?,
                )
            }
            other => other.clone(),
        };
        if let Some(ref s) = requested_target {
            if s.trim().is_empty() {
                failure::bail!("target was empty")
            }
        }
        let cfg_target = config.get_string("build.target")?.map(|s| s.val);
        let target = requested_target.or(cfg_target);

        if jobs == Some(0) {
            failure::bail!("jobs must be at least 1")
        }
        if jobs.is_some() && config.jobserver_from_env().is_some() {
            config.shell().warn(
                "a `-j` argument was passed to Cargo but Cargo is \
                 also configured with an external jobserver in \
                 its environment, ignoring the `-j` parameter",
            )?;
        }
        let cfg_jobs: Option<u32> = config.get("build.jobs")?;
        let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32);
        Ok(BuildConfig {
            requested_target: target,
            jobs,
            release: false,
            mode,
            message_format: MessageFormat::Human,
            force_rebuild: false,
            build_plan: false,
            cargo_as_rustc_wrapper: false,
            extra_rustc_env: Vec::new(),
            extra_rustc_args: Vec::new(),
            rustfix_diagnostic_server: RefCell::new(None),
        })
    }

    pub fn json_messages(&self) -> bool {
        self.message_format == MessageFormat::Json
    }

    pub fn test(&self) -> bool {
        self.mode == CompileMode::Test || self.mode == CompileMode::Bench
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MessageFormat {
    Human,
    Json,
    Short,
}

/// The general "mode" for what to do.
/// This is used for two purposes. The commands themselves pass this in to
/// `compile_ws` to tell it the general execution strategy. This influences
/// the default targets selected. The other use is in the `Unit` struct
/// to indicate what is being done with a specific target.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum CompileMode {
    /// A target being built for a test.
    Test,
    /// Building a target with `rustc` (lib or bin).
    Build,
    /// Building a target with `rustc` to emit `rmeta` metadata only. If
    /// `test` is true, then it is also compiled with `--test` to check it like
    /// a test.
    Check { test: bool },
    /// Used to indicate benchmarks should be built. This is not used in
    /// `Target`, because it is essentially the same as `Test` (indicating
    /// `--test` should be passed to rustc) and by using `Test` instead it
    /// allows some de-duping of Units to occur.
    Bench,
    /// A target that will be documented with `rustdoc`.
    /// If `deps` is true, then it will also document all dependencies.
    Doc { deps: bool },
    /// A target that will be tested with `rustdoc`.
    Doctest,
    /// A marker for Units that represent the execution of a `build.rs` script.
    RunCustomBuild,
}

impl ser::Serialize for CompileMode {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        use self::CompileMode::*;
        match *self {
            Test => "test".serialize(s),
            Build => "build".serialize(s),
            Check { .. } => "check".serialize(s),
            Bench => "bench".serialize(s),
            Doc { .. } => "doc".serialize(s),
            Doctest => "doctest".serialize(s),
            RunCustomBuild => "run-custom-build".serialize(s),
        }
    }
}

impl CompileMode {
    /// Returns `true` if the unit is being checked.
    pub fn is_check(self) -> bool {
        match self {
            CompileMode::Check { .. } => true,
            _ => false,
        }
    }

    /// Returns `true` if this is a doc or doc test. Be careful using this.
    /// Although both run rustdoc, the dependencies for those two modes are
    /// very different.
    pub fn is_doc(self) -> bool {
        match self {
            CompileMode::Doc { .. } | CompileMode::Doctest => true,
            _ => false,
        }
    }

    /// Returns `true` if this is any type of test (test, benchmark, doc test, or
    /// check test).
    pub fn is_any_test(self) -> bool {
        match self {
            CompileMode::Test
            | CompileMode::Bench
            | CompileMode::Check { test: true }
            | CompileMode::Doctest => true,
            _ => false,
        }
    }

    /// Returns `true` if this is the *execution* of a `build.rs` script.
    pub fn is_run_custom_build(self) -> bool {
        self == CompileMode::RunCustomBuild
    }

    /// List of all modes (currently used by `cargo clean -p` for computing
    /// all possible outputs).
    pub fn all_modes() -> &'static [CompileMode] {
        static ALL: [CompileMode; 9] = [
            CompileMode::Test,
            CompileMode::Build,
            CompileMode::Check { test: true },
            CompileMode::Check { test: false },
            CompileMode::Bench,
            CompileMode::Doc { deps: true },
            CompileMode::Doc { deps: false },
            CompileMode::Doctest,
            CompileMode::RunCustomBuild,
        ];
        &ALL
    }
}
<commit_msg>Auto merge of #6778 - phil-opp:canonicalize-config-target, r=alexcrichton<commit_after>use std::cell::RefCell;
use std::path::Path;

use serde::ser;

use crate::util::{CargoResult, CargoResultExt, Config, RustfixDiagnosticServer};

/// Configuration information for a rustc build.
#[derive(Debug)]
pub struct BuildConfig {
    /// The target arch triple.
    /// Default: host arch.
    pub requested_target: Option<String>,
    /// Number of rustc jobs to run in parallel.
    pub jobs: u32,
    /// `true` if we are building for release.
    pub release: bool,
    /// The mode we are compiling in.
    pub mode: CompileMode,
    /// `true` to print stdout in JSON format (for machine reading).
    pub message_format: MessageFormat,
    /// Force Cargo to do a full rebuild and treat each target as changed.
    pub force_rebuild: bool,
    /// Output a build plan to stdout instead of actually compiling.
    pub build_plan: bool,
    /// Use Cargo itself as the wrapper around rustc, only used for `cargo fix`.
    pub cargo_as_rustc_wrapper: bool,
    /// Extra env vars to inject into rustc commands.
    pub extra_rustc_env: Vec<(String, String)>,
    /// Extra args to inject into rustc commands.
    pub extra_rustc_args: Vec<String>,
    pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
}

impl BuildConfig {
    /// Parses all config files to learn about build configuration. Currently
    /// configured options are:
    ///
    /// * `build.jobs`
    /// * `build.target`
    /// * `target.$target.ar`
    /// * `target.$target.linker`
    /// * `target.$target.libfoo.metadata`
    pub fn new(
        config: &Config,
        jobs: Option<u32>,
        requested_target: &Option<String>,
        mode: CompileMode,
    ) -> CargoResult<BuildConfig> {
        let requested_target = match requested_target {
            &Some(ref target) if target.ends_with(".json") => {
                let path = Path::new(target).canonicalize().chain_err(|| {
                    failure::format_err!("Target path {:?} is not a valid file", target)
                })?;
                Some(
                    path.into_os_string()
                        .into_string()
                        .map_err(|_| failure::format_err!("Target path is not valid unicode"))?,
                )
            }
            other => other.clone(),
        };
        if let Some(ref s) = requested_target {
            if s.trim().is_empty() {
                failure::bail!("target was empty")
            }
        }
        let cfg_target = match config.get_string("build.target")? {
            Some(ref target) if target.val.ends_with(".json") => {
                let path = target.definition.root(config).join(&target.val);
                let path_string = path
                    .into_os_string()
                    .into_string()
                    .map_err(|_| failure::format_err!("Target path is not valid unicode"));
                Some(path_string?)
            }
            other => other.map(|t| t.val),
        };
        let target = requested_target.or(cfg_target);

        if jobs == Some(0) {
            failure::bail!("jobs must be at least 1")
        }
        if jobs.is_some() && config.jobserver_from_env().is_some() {
            config.shell().warn(
                "a `-j` argument was passed to Cargo but Cargo is \
                 also configured with an external jobserver in \
                 its environment, ignoring the `-j` parameter",
            )?;
        }
        let cfg_jobs: Option<u32> = config.get("build.jobs")?;
        let jobs = jobs.or(cfg_jobs).unwrap_or(::num_cpus::get() as u32);
        Ok(BuildConfig {
            requested_target: target,
            jobs,
            release: false,
            mode,
            message_format: MessageFormat::Human,
            force_rebuild: false,
            build_plan: false,
            cargo_as_rustc_wrapper: false,
            extra_rustc_env: Vec::new(),
            extra_rustc_args: Vec::new(),
            rustfix_diagnostic_server: RefCell::new(None),
        })
    }

    pub fn json_messages(&self) -> bool {
        self.message_format == MessageFormat::Json
    }

    pub fn test(&self) -> bool {
        self.mode == CompileMode::Test || self.mode == CompileMode::Bench
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MessageFormat {
    Human,
    Json,
    Short,
}

/// The general "mode" for what to do.
/// This is used for two purposes. The commands themselves pass this in to
/// `compile_ws` to tell it the general execution strategy. This influences
/// the default targets selected. The other use is in the `Unit` struct
/// to indicate what is being done with a specific target.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum CompileMode {
    /// A target being built for a test.
    Test,
    /// Building a target with `rustc` (lib or bin).
    Build,
    /// Building a target with `rustc` to emit `rmeta` metadata only. If
    /// `test` is true, then it is also compiled with `--test` to check it like
    /// a test.
    Check { test: bool },
    /// Used to indicate benchmarks should be built. This is not used in
    /// `Target`, because it is essentially the same as `Test` (indicating
    /// `--test` should be passed to rustc) and by using `Test` instead it
    /// allows some de-duping of Units to occur.
    Bench,
    /// A target that will be documented with `rustdoc`.
    /// If `deps` is true, then it will also document all dependencies.
    Doc { deps: bool },
    /// A target that will be tested with `rustdoc`.
    Doctest,
    /// A marker for Units that represent the execution of a `build.rs` script.
    RunCustomBuild,
}

impl ser::Serialize for CompileMode {
    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        use self::CompileMode::*;
        match *self {
            Test => "test".serialize(s),
            Build => "build".serialize(s),
            Check { .. } => "check".serialize(s),
            Bench => "bench".serialize(s),
            Doc { .. } => "doc".serialize(s),
            Doctest => "doctest".serialize(s),
            RunCustomBuild => "run-custom-build".serialize(s),
        }
    }
}

impl CompileMode {
    /// Returns `true` if the unit is being checked.
    pub fn is_check(self) -> bool {
        match self {
            CompileMode::Check { .. } => true,
            _ => false,
        }
    }

    /// Returns `true` if this is a doc or doc test. Be careful using this.
    /// Although both run rustdoc, the dependencies for those two modes are
    /// very different.
    pub fn is_doc(self) -> bool {
        match self {
            CompileMode::Doc { .. } | CompileMode::Doctest => true,
            _ => false,
        }
    }

    /// Returns `true` if this is any type of test (test, benchmark, doc test, or
    /// check test).
    pub fn is_any_test(self) -> bool {
        match self {
            CompileMode::Test
            | CompileMode::Bench
            | CompileMode::Check { test: true }
            | CompileMode::Doctest => true,
            _ => false,
        }
    }

    /// Returns `true` if this is the *execution* of a `build.rs` script.
    pub fn is_run_custom_build(self) -> bool {
        self == CompileMode::RunCustomBuild
    }

    /// List of all modes (currently used by `cargo clean -p` for computing
    /// all possible outputs).
    pub fn all_modes() -> &'static [CompileMode] {
        static ALL: [CompileMode; 9] = [
            CompileMode::Test,
            CompileMode::Build,
            CompileMode::Check { test: true },
            CompileMode::Check { test: false },
            CompileMode::Bench,
            CompileMode::Doc { deps: true },
            CompileMode::Doc { deps: false },
            CompileMode::Doctest,
            CompileMode::RunCustomBuild,
        ];
        &ALL
    }
}
<|endoftext|>


<commit_before>use std::f32::consts::PI;
use std::sync::{Arc, Mutex, mpsc::{Sender, Receiver, TryRecvError}};

use cgmath::{Point3, Vector3, Vector4, prelude::*};

use glium::Rect;

use rand::{self, prelude::*};

use camera::Camera;
use material::Material;
use pt_renderer::{Intersect, Ray, RenderCoordinator};
use scene::Scene;
use triangle::{Hit, RTTriangle};

const EPSILON: f32 = 1e-5;

pub struct RenderWorker {
    scene: Arc<Scene>,
    camera: Camera,
    coordinator: Arc<Mutex<RenderCoordinator>>,
    message_rx: Receiver<()>,
    result_tx: Sender<(Rect, Vec<f32>)>,
}

impl RenderWorker {
    pub fn new(scene: Arc<Scene>, camera: Camera, coordinator: Arc<Mutex<RenderCoordinator>>,
               message_rx: Receiver<()>, result_tx: Sender<(Rect, Vec<f32>)>) -> RenderWorker {
        RenderWorker {
            scene, camera, coordinator,
            message_rx, result_tx,
        }
    }

    pub fn run(&self) {
        let (width, height) = {
            let coordinator = self.coordinator.lock().unwrap();
            (coordinator.width, coordinator.height)
        };
        let clip_to_world = self.camera.get_world_to_clip().invert().unwrap();
        loop {
            match self.message_rx.try_recv() {
                Err(TryRecvError::Empty) => (),
                Ok(_) => return,
                Err(TryRecvError::Disconnected) => {
                    println!("Threads were not properly stopped before disconnecting channel!");
                    return;
                }
            }
            if let Some(rect) = self.coordinator.lock().unwrap().next_block() {
                let mut block = vec![0.0f32; (3 * rect.width * rect.height) as usize];
                for h in 0..rect.height {
                    for w in 0..rect.width {
                        let clip_x = 2.0 * (rect.left + w) as f32 / width as f32 - 1.0;
                        let clip_y = 2.0 * (rect.bottom + h) as f32 / height as f32 - 1.0;
                        let clip_p = Vector4::new(clip_x, clip_y, 1.0, 1.0);
                        let world_p = clip_to_world * clip_p;
                        let dir = ((world_p / world_p.w).truncate() - self.camera.pos.to_vec())
                            .normalize();
                        let ray = Ray::new(self.camera.pos, dir, 100.0);
                        let c = self.trace_ray(&ray, 0);
                        let pixel_i = 3 * (h * rect.width + w) as usize;
                        block[pixel_i]     = c.x;
                        block[pixel_i + 1] = c.y;
                        block[pixel_i + 2] = c.z;
                    }
                }
                self.result_tx.send((rect, block)).expect("Receiver closed!");
            } else {
                return;
            }
        }
    }

    fn trace_ray(&self, ray: &Ray, bounce: u32) -> Vector3<f32> {
        let mut c = Vector3::zero();
        if let Some(hit) = self.find_hit(&ray) {
            let material = &self.scene.materials[hit.tri.material_i];
            let mut normal = hit.normal();
            // Flip the normal if its pointing to the opposite side from the hit
            if normal.dot(ray.dir) > 0.0 {
                normal *= -1.0;
            }
            if bounce == 0 {
                if let Some(emissive) = material.emissive {
                    c += normal.dot(-ray.dir).max(0.0) * emissive;
                }
            }
            let (light, light_pos, light_normal, light_pdf) = self.sample_light();
            let bump_pos = hit.pos() + EPSILON * normal;
            let hit_to_light = light_pos - bump_pos;
            let light_dir = hit_to_light.normalize();
            let shadow_ray = Ray::new(bump_pos, light_dir, hit_to_light.magnitude() - EPSILON);
            if shadow_ray.length > 0.1 && self.find_hit(&shadow_ray).is_none() {
                let cos_l = light_normal.dot(-light_dir).max(0.0);
                let cos_t = normal.dot(light_dir).max(0.0);
                let light_material = &self.scene.materials[light.material_i];
                let emissive = light_material.emissive.expect("Light wasn't emissive");
                c += emissive.mul_element_wise(self.brdf(&ray, &shadow_ray, material))
                    * cos_l * cos_t / (hit_to_light.magnitude2() * light_pdf);
            }
            if bounce < 10 {
                let (new_dir, pdf) = self.sample_dir(normal);
                let new_ray = Ray::new(bump_pos, new_dir, 100.0);
                c += normal.dot(new_dir) * self.brdf(&ray, &new_ray, material)
                    .mul_element_wise(self.trace_ray(&new_ray, bounce + 1)) / pdf;
            }
        }
        c
    }

    fn brdf(&self, _in_ray: &Ray, _out_ray: &Ray, material: &Material) -> Vector3<f32> {
        material.diffuse / PI
    }

    fn sample_dir(&self, normal: Vector3<f32>) -> (Vector3<f32>, f32) {
        let dir = 2.0 * PI * rand::random::<f32>();
        let length: f32 = rand::random();
        let x = length * dir.cos();
        let y = length * dir.sin();
        let z = (1.0 - length.powi(2)).sqrt();
        let nx = if normal.x.abs() > normal.y.abs() {
            Vector3::new(normal.z, 0.0, -normal.x).normalize()
        } else {
            Vector3::new(0.0, -normal.z, normal.y).normalize()
        };
        let ny = normal.cross(nx);
        (x * nx + y * ny + z * normal, z / PI)
    }

    pub fn sample_light(&self) -> (&RTTriangle, Point3<f32>, Vector3<f32>, f32) {
        if self.scene.lights.is_empty() {
            panic!("Rendered scene has no lights!");
        } else {
            let i = rand::thread_rng().gen_range(0, self.scene.lights.len());
            let light = &self.scene.lights[i];
            let pdf = 1.0 / (self.scene.lights.len() as f32 * light.area());
            let (point, normal) = light.random_point();
            (light, point, normal, pdf)
        }
    }

    fn find_hit(&self, ray: &Ray) -> Option<Hit> {
        let bvh = &self.scene.bvh;
        let mut node_stack = Vec::new();
        node_stack.push((bvh.root(), 0.0f32));
        let mut closest_hit: Option<Hit> = None;
        while let Some((node, t)) = node_stack.pop() {
            // We've already found closer hit
            if closest_hit.as_ref().map_or(false, |hit| hit.t <= t) { continue }
            if node.is_leaf() {
                for tri in &self.scene.triangles[node.start_i..node.end_i] {
                    if let Some(hit) = tri.intersect(&ray) {
                        if let Some(closest) = closest_hit.take() {
                            if hit.t < closest.t {
                                closest_hit = Some(hit);
                            } else {
                                closest_hit = Some(closest);
                            }
                        } else {
                            closest_hit = Some(hit);
                        }
                    }
                }
            } else {
                // TODO: put closest hit on top of the stack
                let (left, right) = bvh.get_children(node).expect("Non leaf node had no child nodes!");
                if let Some(t_left) = left.intersect(&ray) {
                    node_stack.push((left, t_left));
                }
                if let Some(t_right) = right.intersect(&ray) {
                    node_stack.push((right, t_right));
                }
            }
        }
        closest_hit
    }
}
<commit_msg>Choose samples randomly within a pixel<commit_after>use std::f32::consts::PI;
use std::sync::{Arc, Mutex, mpsc::{Sender, Receiver, TryRecvError}};

use cgmath::{Point3, Vector3, Vector4, prelude::*};

use glium::Rect;

use rand::{self, prelude::*};

use camera::Camera;
use material::Material;
use pt_renderer::{Intersect, Ray, RenderCoordinator};
use scene::Scene;
use triangle::{Hit, RTTriangle};

const EPSILON: f32 = 1e-5;

pub struct RenderWorker {
    scene: Arc<Scene>,
    camera: Camera,
    coordinator: Arc<Mutex<RenderCoordinator>>,
    message_rx: Receiver<()>,
    result_tx: Sender<(Rect, Vec<f32>)>,
}

impl RenderWorker {
    pub fn new(scene: Arc<Scene>, camera: Camera, coordinator: Arc<Mutex<RenderCoordinator>>,
               message_rx: Receiver<()>, result_tx: Sender<(Rect, Vec<f32>)>) -> RenderWorker {
        RenderWorker {
            scene, camera, coordinator,
            message_rx, result_tx,
        }
    }

    pub fn run(&self) {
        let (width, height) = {
            let coordinator = self.coordinator.lock().unwrap();
            (coordinator.width, coordinator.height)
        };
        let clip_to_world = self.camera.get_world_to_clip().invert().unwrap();
        loop {
            match self.message_rx.try_recv() {
                Err(TryRecvError::Empty) => (),
                Ok(_) => return,
                Err(TryRecvError::Disconnected) => {
                    println!("Threads were not properly stopped before disconnecting channel!");
                    return;
                }
            }
            if let Some(rect) = self.coordinator.lock().unwrap().next_block() {
                let mut block = vec![0.0f32; (3 * rect.width * rect.height) as usize];
                for h in 0..rect.height {
                    for w in 0..rect.width {
                        let dx: f32 = rand::random();
                        let dy: f32 = rand::random();
                        let clip_x = 2.0 * ((rect.left + w) as f32 + dx) / width as f32 - 1.0;
                        let clip_y = 2.0 * ((rect.bottom + h) as f32 + dy) / height as f32 - 1.0;
                        let clip_p = Vector4::new(clip_x, clip_y, 1.0, 1.0);
                        let world_p = clip_to_world * clip_p;
                        let dir = ((world_p / world_p.w).truncate() - self.camera.pos.to_vec())
                            .normalize();
                        let ray = Ray::new(self.camera.pos, dir, 100.0);
                        let c = self.trace_ray(&ray, 0);
                        let pixel_i = 3 * (h * rect.width + w) as usize;
                        block[pixel_i]     = c.x;
                        block[pixel_i + 1] = c.y;
                        block[pixel_i + 2] = c.z;
                    }
                }
                self.result_tx.send((rect, block)).expect("Receiver closed!");
            } else {
                return;
            }
        }
    }

    fn trace_ray(&self, ray: &Ray, bounce: u32) -> Vector3<f32> {
        let mut c = Vector3::zero();
        if let Some(hit) = self.find_hit(&ray) {
            let material = &self.scene.materials[hit.tri.material_i];
            let mut normal = hit.normal();
            // Flip the normal if its pointing to the opposite side from the hit
            if normal.dot(ray.dir) > 0.0 {
                normal *= -1.0;
            }
            if bounce == 0 {
                if let Some(emissive) = material.emissive {
                    c += normal.dot(-ray.dir).max(0.0) * emissive;
                }
            }
            let (light, light_pos, light_normal, light_pdf) = self.sample_light();
            let bump_pos = hit.pos() + EPSILON * normal;
            let hit_to_light = light_pos - bump_pos;
            let light_dir = hit_to_light.normalize();
            let shadow_ray = Ray::new(bump_pos, light_dir, hit_to_light.magnitude() - EPSILON);
            if shadow_ray.length > 0.1 && self.find_hit(&shadow_ray).is_none() {
                let cos_l = light_normal.dot(-light_dir).max(0.0);
                let cos_t = normal.dot(light_dir).max(0.0);
                let light_material = &self.scene.materials[light.material_i];
                let emissive = light_material.emissive.expect("Light wasn't emissive");
                c += emissive.mul_element_wise(self.brdf(&ray, &shadow_ray, material))
                    * cos_l * cos_t / (hit_to_light.magnitude2() * light_pdf);
            }
            if bounce < 10 {
                let (new_dir, pdf) = self.sample_dir(normal);
                let new_ray = Ray::new(bump_pos, new_dir, 100.0);
                c += normal.dot(new_dir) * self.brdf(&ray, &new_ray, material)
                    .mul_element_wise(self.trace_ray(&new_ray, bounce + 1)) / pdf;
            }
        }
        c
    }

    fn brdf(&self, _in_ray: &Ray, _out_ray: &Ray, material: &Material) -> Vector3<f32> {
        material.diffuse / PI
    }

    fn sample_dir(&self, normal: Vector3<f32>) -> (Vector3<f32>, f32) {
        let dir = 2.0 * PI * rand::random::<f32>();
        let length: f32 = rand::random();
        let x = length * dir.cos();
        let y = length * dir.sin();
        let z = (1.0 - length.powi(2)).sqrt();
        let nx = if normal.x.abs() > normal.y.abs() {
            Vector3::new(normal.z, 0.0, -normal.x).normalize()
        } else {
            Vector3::new(0.0, -normal.z, normal.y).normalize()
        };
        let ny = normal.cross(nx);
        (x * nx + y * ny + z * normal, z / PI)
    }

    pub fn sample_light(&self) -> (&RTTriangle, Point3<f32>, Vector3<f32>, f32) {
        if self.scene.lights.is_empty() {
            panic!("Rendered scene has no lights!");
        } else {
            let i = rand::thread_rng().gen_range(0, self.scene.lights.len());
            let light = &self.scene.lights[i];
            let pdf = 1.0 / (self.scene.lights.len() as f32 * light.area());
            let (point, normal) = light.random_point();
            (light, point, normal, pdf)
        }
    }

    fn find_hit(&self, ray: &Ray) -> Option<Hit> {
        let bvh = &self.scene.bvh;
        let mut node_stack = Vec::new();
        node_stack.push((bvh.root(), 0.0f32));
        let mut closest_hit: Option<Hit> = None;
        while let Some((node, t)) = node_stack.pop() {
            // We've already found closer hit
            if closest_hit.as_ref().map_or(false, |hit| hit.t <= t) { continue }
            if node.is_leaf() {
                for tri in &self.scene.triangles[node.start_i..node.end_i] {
                    if let Some(hit) = tri.intersect(&ray) {
                        if let Some(closest) = closest_hit.take() {
                            if hit.t < closest.t {
                                closest_hit = Some(hit);
                            } else {
                                closest_hit = Some(closest);
                            }
                        } else {
                            closest_hit = Some(hit);
                        }
                    }
                }
            } else {
                // TODO: put closest hit on top of the stack
                let (left, right) = bvh.get_children(node).expect("Non leaf node had no child nodes!");
                if let Some(t_left) = left.intersect(&ray) {
                    node_stack.push((left, t_left));
                }
                if let Some(t_right) = right.intersect(&ray) {
                    node_stack.push((right, t_right));
                }
            }
        }
        closest_hit
    }
}
<|endoftext|>


<commit_before>use std::ops::{Deref, DerefMut, Mul};
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};

#[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer};
#[cfg(feature = "serde-serialize")]
use serde::ser::SerializeSeq;
#[cfg(feature = "serde-serialize")]
use serde::de::{SeqAccess, Visitor, Error};
#[cfg(feature = "serde-serialize")]
use std::mem;
#[cfg(feature = "serde-serialize")]
use std::marker::PhantomData;

#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;

use typenum::Prod;
use generic_array::{ArrayLength, GenericArray};

use core::Scalar;
use core::dimension::{DimName, U1};
use core::storage::{Storage, StorageMut, Owned, OwnedStorage};
use core::allocator::Allocator;
use core::default_allocator::DefaultAllocator;

/*
 *
 * Static Storage.
 *
 */
/// A array-based statically sized matrix data storage.
#[repr(C)]
pub struct MatrixArray<N, R, C>
where R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    data: GenericArray<N, Prod<R::Value, C::Value>>
}

impl<N, R, C> Hash for MatrixArray<N, R, C>
where N: Hash,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.data[..].hash(state)
    }
}

impl<N, R, C> Deref for MatrixArray<N, R, C>
where R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {
    type Target = GenericArray<N, Prod<R::Value, C::Value>>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<N, R, C> DerefMut for MatrixArray<N, R, C>
where R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.data
    }
}

impl<N, R, C> Debug for MatrixArray<N, R, C>
where N: Debug,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.data.fmt(fmt)
    }
}

impl<N, R, C> Copy for MatrixArray<N, R, C>
    where N: Copy,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N>,
          GenericArray<N, Prod<R::Value, C::Value>> : Copy
{ }

impl<N, R, C> Clone for MatrixArray<N, R, C>
    where N: Clone,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn clone(&self) -> Self {
        MatrixArray {
            data: self.data.clone()
        }
    }
}

impl<N, R, C> Eq for MatrixArray<N, R, C>
    where N: Eq,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
}

impl<N, R, C> PartialEq for MatrixArray<N, R, C>
    where N: PartialEq,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn eq(&self, right: &Self) -> bool {
        self.data  == right.data
    }
}

unsafe impl<N, R, C> Storage<N, R, C> for MatrixArray<N, R, C>
    where N: Scalar,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    type RStride = U1;
    type CStride = R;
    type Alloc   = DefaultAllocator;

    #[inline]
    fn into_owned(self) -> Owned<N, R, C, Self::Alloc> {
        self
    }

    #[inline]
    fn clone_owned(&self) -> Owned<N, R, C, Self::Alloc> {
        let it = self.iter().cloned();

        Self::Alloc::allocate_from_iterator(self.shape().0, self.shape().1, it)
    }

    #[inline]
    fn ptr(&self) -> *const N {
        self[..].as_ptr()
    }

    #[inline]
    fn shape(&self) -> (R, C) {
        (R::name(), C::name())
    }

    #[inline]
    fn strides(&self) -> (Self::RStride, Self::CStride) {
        (Self::RStride::name(), Self::CStride::name())
    }
}

unsafe impl<N, R, C> StorageMut<N, R, C> for MatrixArray<N, R, C>
    where N: Scalar,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn ptr_mut(&mut self) -> *mut N {
        self[..].as_mut_ptr()
    }
}

unsafe impl<N, R, C> OwnedStorage<N, R, C> for MatrixArray<N, R, C>
    where N: Scalar,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn as_slice(&self) -> &[N] {
        &self[..]
    }

    #[inline]
    fn as_mut_slice(&mut self) -> &mut [N] {
        &mut self[..]
    }
}

/*
 *
 * Allocation-less serde impls.
 *
 */
// XXX: open an issue for GenericArray so that it implements serde traits?
#[cfg(feature = "serde-serialize")]
impl<N, R, C> Serialize for MatrixArray<N, R, C>
where N: Scalar + Serialize,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
            let mut serializer = serializer.serialize_seq(Some(R::dim() * C::dim()))?;

            for e in self.iter() {
                serializer.serialize_element(e)?;
            }

            serializer.end()
        }
}

#[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Deserialize<'a> for MatrixArray<N, R, C>
where N: Scalar + Deserialize<'a>,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'a> {
            deserializer.deserialize_seq(MatrixArrayVisitor::new())
        }
}

#[cfg(feature = "serde-serialize")]
/// A visitor that produces a matrix array.
struct MatrixArrayVisitor<N, R, C> {
    marker: PhantomData<(N, R, C)>
}

#[cfg(feature = "serde-serialize")]
impl<N, R, C> MatrixArrayVisitor<N, R, C>
where N: Scalar,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    /// Construct a new sequence visitor.
    pub fn new() -> Self {
        MatrixArrayVisitor {
            marker: PhantomData,
        }
    }
}

#[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Visitor<'a> for MatrixArrayVisitor<N, R, C>
where N: Scalar + Deserialize<'a>,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    type Value = MatrixArray<N, R, C>;

    fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
        formatter.write_str("a matrix array")
    }

    #[inline]
    fn visit_seq<V>(self, mut visitor: V) -> Result<MatrixArray<N, R, C>, V::Error>
        where V: SeqAccess<'a> {

        let mut out: Self::Value = unsafe { mem::uninitialized() };
        let mut curr = 0;

        while let Some(value) = try!(visitor.next_element()) {
            out[curr] = value;
            curr += 1;
        }

        if curr == R::dim() * C::dim() {
            Ok(out)
        }
        else {
            Err(V::Error::invalid_length(curr, &self))
        }
    }
}

#[cfg(feature = "abomonation-serialize")]
impl<N, R, C> Abomonation for MatrixArray<N, R, C>
    where R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N>,
          N: Abomonation
{
    unsafe fn entomb(&self, writer: &mut Vec<u8>) {
        self.data.as_slice().entomb(writer)
    }

    unsafe fn embalm(&mut self) {
        self.data.as_slice().embalm()
    }

    unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
        self.data.as_slice().exhume(bytes)
    }
}
<commit_msg>Provide safer Abomonation impl for matrix arrays<commit_after>use std::ops::{Deref, DerefMut, Mul};
use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};

#[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer};
#[cfg(feature = "serde-serialize")]
use serde::ser::SerializeSeq;
#[cfg(feature = "serde-serialize")]
use serde::de::{SeqAccess, Visitor, Error};
#[cfg(feature = "serde-serialize")]
use std::mem;
#[cfg(feature = "serde-serialize")]
use std::marker::PhantomData;

#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;

use typenum::Prod;
use generic_array::{ArrayLength, GenericArray};

use core::Scalar;
use core::dimension::{DimName, U1};
use core::storage::{Storage, StorageMut, Owned, OwnedStorage};
use core::allocator::Allocator;
use core::default_allocator::DefaultAllocator;

/*
 *
 * Static Storage.
 *
 */
/// A array-based statically sized matrix data storage.
#[repr(C)]
pub struct MatrixArray<N, R, C>
where R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    data: GenericArray<N, Prod<R::Value, C::Value>>
}

impl<N, R, C> Hash for MatrixArray<N, R, C>
where N: Hash,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.data[..].hash(state)
    }
}

impl<N, R, C> Deref for MatrixArray<N, R, C>
where R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {
    type Target = GenericArray<N, Prod<R::Value, C::Value>>;

    #[inline]
    fn deref(&self) -> &Self::Target {
        &self.data
    }
}

impl<N, R, C> DerefMut for MatrixArray<N, R, C>
where R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.data
    }
}

impl<N, R, C> Debug for MatrixArray<N, R, C>
where N: Debug,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.data.fmt(fmt)
    }
}

impl<N, R, C> Copy for MatrixArray<N, R, C>
    where N: Copy,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N>,
          GenericArray<N, Prod<R::Value, C::Value>> : Copy
{ }

impl<N, R, C> Clone for MatrixArray<N, R, C>
    where N: Clone,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn clone(&self) -> Self {
        MatrixArray {
            data: self.data.clone()
        }
    }
}

impl<N, R, C> Eq for MatrixArray<N, R, C>
    where N: Eq,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
}

impl<N, R, C> PartialEq for MatrixArray<N, R, C>
    where N: PartialEq,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn eq(&self, right: &Self) -> bool {
        self.data  == right.data
    }
}

unsafe impl<N, R, C> Storage<N, R, C> for MatrixArray<N, R, C>
    where N: Scalar,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    type RStride = U1;
    type CStride = R;
    type Alloc   = DefaultAllocator;

    #[inline]
    fn into_owned(self) -> Owned<N, R, C, Self::Alloc> {
        self
    }

    #[inline]
    fn clone_owned(&self) -> Owned<N, R, C, Self::Alloc> {
        let it = self.iter().cloned();

        Self::Alloc::allocate_from_iterator(self.shape().0, self.shape().1, it)
    }

    #[inline]
    fn ptr(&self) -> *const N {
        self[..].as_ptr()
    }

    #[inline]
    fn shape(&self) -> (R, C) {
        (R::name(), C::name())
    }

    #[inline]
    fn strides(&self) -> (Self::RStride, Self::CStride) {
        (Self::RStride::name(), Self::CStride::name())
    }
}

unsafe impl<N, R, C> StorageMut<N, R, C> for MatrixArray<N, R, C>
    where N: Scalar,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn ptr_mut(&mut self) -> *mut N {
        self[..].as_mut_ptr()
    }
}

unsafe impl<N, R, C> OwnedStorage<N, R, C> for MatrixArray<N, R, C>
    where N: Scalar,
          R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N> {
    #[inline]
    fn as_slice(&self) -> &[N] {
        &self[..]
    }

    #[inline]
    fn as_mut_slice(&mut self) -> &mut [N] {
        &mut self[..]
    }
}

/*
 *
 * Allocation-less serde impls.
 *
 */
// XXX: open an issue for GenericArray so that it implements serde traits?
#[cfg(feature = "serde-serialize")]
impl<N, R, C> Serialize for MatrixArray<N, R, C>
where N: Scalar + Serialize,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
            let mut serializer = serializer.serialize_seq(Some(R::dim() * C::dim()))?;

            for e in self.iter() {
                serializer.serialize_element(e)?;
            }

            serializer.end()
        }
}

#[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Deserialize<'a> for MatrixArray<N, R, C>
where N: Scalar + Deserialize<'a>,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'a> {
            deserializer.deserialize_seq(MatrixArrayVisitor::new())
        }
}

#[cfg(feature = "serde-serialize")]
/// A visitor that produces a matrix array.
struct MatrixArrayVisitor<N, R, C> {
    marker: PhantomData<(N, R, C)>
}

#[cfg(feature = "serde-serialize")]
impl<N, R, C> MatrixArrayVisitor<N, R, C>
where N: Scalar,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    /// Construct a new sequence visitor.
    pub fn new() -> Self {
        MatrixArrayVisitor {
            marker: PhantomData,
        }
    }
}

#[cfg(feature = "serde-serialize")]
impl<'a, N, R, C> Visitor<'a> for MatrixArrayVisitor<N, R, C>
where N: Scalar + Deserialize<'a>,
      R: DimName,
      C: DimName,
      R::Value: Mul<C::Value>,
      Prod<R::Value, C::Value>: ArrayLength<N> {

    type Value = MatrixArray<N, R, C>;

    fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
        formatter.write_str("a matrix array")
    }

    #[inline]
    fn visit_seq<V>(self, mut visitor: V) -> Result<MatrixArray<N, R, C>, V::Error>
        where V: SeqAccess<'a> {

        let mut out: Self::Value = unsafe { mem::uninitialized() };
        let mut curr = 0;

        while let Some(value) = try!(visitor.next_element()) {
            out[curr] = value;
            curr += 1;
        }

        if curr == R::dim() * C::dim() {
            Ok(out)
        }
        else {
            Err(V::Error::invalid_length(curr, &self))
        }
    }
}

#[cfg(feature = "abomonation-serialize")]
impl<N, R, C> Abomonation for MatrixArray<N, R, C>
    where R: DimName,
          C: DimName,
          R::Value: Mul<C::Value>,
          Prod<R::Value, C::Value>: ArrayLength<N>,
          N: Abomonation
{
    unsafe fn entomb(&self, writer: &mut Vec<u8>) {
        for element in self.data.as_slice() {
            element.entomb(writer);
        }
    }

    unsafe fn embalm(&mut self) {
        for element in self.data.as_mut_slice() {
            element.embalm();
        }
    }

    unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
        for element in self.data.as_mut_slice() {
            let temp = bytes;
            bytes = if let Some(remainder) = element.exhume(temp) {
                remainder
            } else {
                return None;
            }
        }
        Some(bytes)
    }
}
<|endoftext|>


<commit_before>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use std::fmt;
use std::env;
use hyper;
use hyper::status::StatusCode;
use hyper::client::response::Response as HyperResponse;
use hyper::HttpError;
use mime;
use rustc_serialize::json;
use errors::Kind as DelivError;
use std::error;
use std::io::prelude::*;
use errors::{DeliveryError, Kind};
use token::TokenStore;
use utils::say::{sayln};

mod headers;
pub mod token;
pub mod change;

#[derive(Debug)]
enum HProto {
    HTTP,
    HTTPS
}

impl fmt::Display for HProto {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let s = match self {
            &HProto::HTTP => "http",
            &HProto::HTTPS => "https"
        };
        write!(f, "{}", s)
    }
}

// impl string::ToString for HProto {
//     fn fmt(&self) -> String {
//         let s = match self {
//             &HProto::HTTP => "http",
//             &HProto::HTTPS => "https"
//         };
//         String::new(s)
//     }
// }

#[derive(Debug)]
pub struct APIClient {
    proto: HProto,
    host: String,
    enterprise: String,
    auth: Option<APIAuth>
}

impl APIClient {

    /// Create a new `APIClient` using HTTP attached to the enterprise
    /// given by `ent`.
    pub fn new_http(host: &str, ent: &str) -> APIClient {
        APIClient::new(HProto::HTTP, host, ent)
    }

    /// Create a new `APIClient` using HTTPS attached to the
    /// enterprise given by `ent`.
    pub fn new_https(host: &str, ent: &str) -> APIClient {
        APIClient::new(HProto::HTTPS, host, ent)
    }

    fn new(proto: HProto, host: &str, ent: &str) -> APIClient {
        APIClient {
            proto: proto,
            host: String::from_str(host),
            enterprise: String::from_str(ent),
            auth: None
        }
    }

    pub fn get_auth_from_home(&mut self, server: &str, ent: &str, user: &str) -> Result<APIAuth, DeliveryError> {
        match TokenStore::from_home() {
            Ok(tstore) => {
                APIAuth::from_token_store(tstore, server, ent, user)
            },
            Err(e) => Err(e)
        }
    }

    pub fn set_auth(&mut self, auth: APIAuth) {
        self.auth = Some(auth);
    }

    pub fn api_url(&self, path: &str) -> String {
        format!("{}://{}/api/v0/e/{}/{}",
                self.proto, self.host, self.enterprise, path)
    }

    pub fn project_exists(&self,
                          org: &str,
                          proj: &str) -> bool {

        let path = format!("orgs/{}/projects/{}", org, proj);
        match self.get(&path) {
            Ok(res) => {
                match res.status {
                    StatusCode::Ok => {
                        return true;
                    },
                    _ => {
                        return false;
                    }
                }
            },
            Err(e) => {
                sayln("red", &format!("project_exists: HttpError: {:?}", e));
                return false;
            }
        }
    }

    pub fn create_project(&self,
                          org: &str,
                          proj: &str) -> Result<HyperResponse, DelivError> {
        let path = format!("orgs/{}/projects", org);
        // FIXME: we'd like to use the native struct->json stuff, but
        // seeing link issues.
        let payload = format!("{{\"name\":\"{}\"}}", proj);
        match self.post(&path, &payload) {
            Ok(mut res) => {
                match res.status {
                    StatusCode::Created =>
                        Ok(res),
                    _ => {
                        let mut detail = String::new();
                        let e = match res.read_to_string(&mut detail) {
                            Ok(_) => Ok(detail),
                            Err(e) => Err(e)
                        };
                        Err(DelivError::ApiError(res.status, e))
                    }
                }
            },
            Err(e) => Err(DelivError::HttpError(e))
        }
    }

    pub fn create_pipeline(&self,
                           org: &str,
                           proj: &str,
                           pipe: &str) -> Result<HyperResponse, DelivError> {
        let path = format!("orgs/{}/projects/{}/pipelines", org, proj);
        // FIXME: we'd like to use the native struct->json stuff, but
        // seeing link issues.
        let base_branch = "master";
        let payload = format!("{{\"name\":\"{}\",\"base\":\"{}\"}}",
                              pipe, base_branch);
        match self.post(&path, &payload) {
            Ok(mut res) => {
                match res.status {
                    StatusCode::Created =>
                        Ok(res),
                    _ => {
                        let mut detail = String::new();
                        let e = match res.read_to_string(&mut detail) {
                            Ok(_) => Ok(detail),
                            Err(e) => Err(e)
                        };
                        Err(DelivError::ApiError(res.status, e))
                    }
                }
            },
            Err(e) => Err(DelivError::HttpError(e))
        }
    }

    pub fn get(&self, path: &str) -> Result<HyperResponse, HttpError> {
        let url = self.api_url(path);
        let mut client = hyper::Client::new();
        let req = client.get(&url);
        let req = req.header(self.json_content());
        let req = match self.auth {
            Some(ref auth) => {
                let (deliv_user, deliv_token) = auth.auth_headers();
                req.header(deliv_user).header(deliv_token)
            },
            None => req
        };
        req.send()
    }

    pub fn post(&self,
                path: &str,
                payload: &str) -> Result<HyperResponse, HttpError> {
        let url = self.api_url(path);
        let mut client = hyper::Client::new();
        let req = client.post(&url);
        let req = req.header(self.json_content());
        let req = match self.auth {
            Some(ref auth) => {
                let (deliv_user, deliv_token) = auth.auth_headers();
                req.header(deliv_user).header(deliv_token)
            },
            None => req
        };
        if !payload.is_empty() {
            req.body(payload).send()
        } else {
            req.send()
        }
    }

    pub fn put(&self,
               path: &str,
               payload: &str) -> Result<HyperResponse, HttpError> {
        let url = self.api_url(path);
        let mut client = hyper::Client::new();
        let req = client.put(url.as_ref());
        let req = req.header(self.json_content());
        let req = match self.auth {
            Some(ref auth) => {
                let (deliv_user, deliv_token) = auth.auth_headers();
                req.header(deliv_user).header(deliv_token)
            },
            None => req
        };
        if !payload.is_empty() {
            req.body(payload).send()
        } else {
            req.send()
        }
    }

    pub fn parse_json(result: Result<HyperResponse, hyper::HttpError>) -> Result<json::Json, DeliveryError> {
        let body = match result {
            Ok(mut b) => {
                let mut body_string = String::new();
                let _x = try!(b.read_to_string(&mut body_string));
                body_string
            },
            Err(e) => return Err(DeliveryError{kind: Kind::HttpError(e),
                                               detail: None})
        };
        Ok(try!(json::Json::from_str(&body)))
    }

    pub fn extract_pretty_json<T: error::Error>(
        result: Result<HyperResponse, T>) -> Result<String, String> {
        let body = match result {
            Ok(mut b) => {
                let mut body_string = String::new();
                match b.read_to_string(&mut body_string) {
                    Ok(_) => body_string,
                    Err(e) => {
                        debug!("extract_pretty_json: {}", e);
                        return Err(String::from_str("response read failed"))
                    }
                }
            },
            Err(e) => {
                debug!("extract_pretty_json: HttpError: {}", e.description());
                return Err(String::from_str("HTTP Error"))
            }
        };
        let json = match json::Json::from_str(&body) {
            Ok(j) => j,
            Err(_) => {
                return Err(String::from_str("invalid JSON"))
            }
        };
        Ok(format!("{}", json.pretty()))
    }

    fn json_content(&self) -> hyper::header::ContentType {
        let mime = mime::Mime(mime::TopLevel::Application,
                              mime::SubLevel::Json, vec![]);
        hyper::header::ContentType(mime)
    }

}

#[derive(Debug)]
pub struct APIAuth {
    user: String,
    token: String
}

impl APIAuth {
    pub fn from_env() -> APIAuth {
        let token = env::var("TOKEN").ok().expect("env missing TOKEN");
        let user = env::var("DEL_USER").ok().expect("env missing DEL_USER");
        APIAuth { user: user, token: token }
    }

    pub fn from_token_store(tstore: TokenStore,
                            server: &str, ent: &str,
                            user: &str) -> Result<APIAuth, DeliveryError> {
        match tstore.lookup(server, ent, user) {
            Some(token) => {
                Ok(APIAuth{ user: String::from_str(user),
                             token: String::from_str(token)})
            },
            None => {
                let msg = format!("server: {}, ent: {}, user: {}",
                                  server, ent, user);
                Err(DeliveryError{ kind: Kind::NoToken,
                                   detail: Some(msg)})
            }
        }
    }

    pub fn user(&self) -> String {
        self.user.clone()
    }

    pub fn token(&self) -> String {
        self.token.clone()
    }

    pub fn auth_headers(&self) -> (headers::ChefDeliveryUser,
                                   headers::ChefDeliveryToken) {
        (headers::ChefDeliveryUser(self.user.clone()),
         headers::ChefDeliveryToken(self.token.clone()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::TokenStore;
    use std::env;
    use tempdir::TempDir;
    use utils::path_join_many::PathJoinMany;

    #[test]
    fn api_auth() {
        fake_test_env();
        let auth = APIAuth::from_env();
        println!("got auth user: {}, token: {}",
                 auth.user, auth.token);
        assert_eq!("pete", auth.user);
        assert!(auth.token.len() > 4);
    }

    #[test]
    fn http_api_url_test() {
        let mut client = APIClient::new_http("localhost:4343",
                                         "Chef");
        fake_test_env();
        let auth = APIAuth::from_env();
        client.set_auth(auth);
        let url = client.api_url("foo/bar");
        assert_eq!("http://localhost:4343/api/v0/e/Chef/foo/bar", url)
    }

    #[test]
    fn https_api_url_test() {
        let mut client = APIClient::new_https("localhost:4343",
                                          "Chef");
        fake_test_env();
        let auth = APIAuth::from_env();
        client.set_auth(auth);
        let url = client.api_url("foo/bar");
        assert_eq!("https://localhost:4343/api/v0/e/Chef/foo/bar", url)
    }

    fn fake_test_env() {
        env::set_var("DEL_USER", "pete");
        env::set_var("TOKEN", "deadbeefcafe");
    }

    #[test]
    fn from_empty_token_store_test() {
        let tempdir = TempDir::new("t1").ok().expect("TempDir failed");
        let path = tempdir.path();
        let tfile = path.join_many(&["api-tokens"]);
        let tstore = TokenStore::from_file(&tfile).ok().expect("tstore sad");

        // token store is empty so we expect an Err()
        let from_empty = APIAuth::from_token_store(tstore,
                                                   "127.0.0.1", "acme", "bob");
        assert_eq!(true, from_empty.or_else(|e| {
            let msg = "server: 127.0.0.1, ent: acme, user: bob";
            assert_eq!(msg, e.detail().unwrap());
            Err(e)
        }).is_err());
    }

    #[test]
    fn from_non_empty_token_store_test() {
        let tempdir = TempDir::new("t1").ok().expect("TempDir failed");
        let path = tempdir.path();
        let tfile = path.join_many(&["api-tokens"]);
        let mut tstore = TokenStore::from_file(&tfile).ok().expect("tstore sad");
        let write_result = tstore.write_token("127.0.0.1", "acme", "bob",
                                              "beefbeef");
        assert_eq!(true, write_result.is_ok());
        let auth = APIAuth::from_token_store(tstore, "127.0.0.1", "acme", "bob");
        assert_eq!(true,
                   auth.and_then(|a| {
                       assert_eq!("bob", a.user());
                       assert_eq!("beefbeef", a.token());
                       Ok(a)
                   }).is_ok());
    }
}
<commit_msg>Compat fix for rustup<commit_after>//
// Copyright:: Copyright (c) 2015 Chef Software, Inc.
// License:: Apache License, Version 2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

use std::fmt;
use std::env;
use hyper;
use hyper::status::StatusCode;
use hyper::client::response::Response as HyperResponse;
use hyper::HttpError;
use mime;
use rustc_serialize::json;
use errors::Kind as DelivError;
use std::error;
use std::io::prelude::*;
use errors::{DeliveryError, Kind};
use token::TokenStore;
use utils::say::{sayln};

mod headers;
pub mod token;
pub mod change;

#[derive(Debug)]
enum HProto {
    HTTP,
    HTTPS
}

impl fmt::Display for HProto {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let s = match self {
            &HProto::HTTP => "http",
            &HProto::HTTPS => "https"
        };
        write!(f, "{}", s)
    }
}

// impl string::ToString for HProto {
//     fn fmt(&self) -> String {
//         let s = match self {
//             &HProto::HTTP => "http",
//             &HProto::HTTPS => "https"
//         };
//         String::new(s)
//     }
// }

#[derive(Debug)]
pub struct APIClient {
    proto: HProto,
    host: String,
    enterprise: String,
    auth: Option<APIAuth>
}

impl APIClient {

    /// Create a new `APIClient` using HTTP attached to the enterprise
    /// given by `ent`.
    pub fn new_http(host: &str, ent: &str) -> APIClient {
        APIClient::new(HProto::HTTP, host, ent)
    }

    /// Create a new `APIClient` using HTTPS attached to the
    /// enterprise given by `ent`.
    pub fn new_https(host: &str, ent: &str) -> APIClient {
        APIClient::new(HProto::HTTPS, host, ent)
    }

    fn new(proto: HProto, host: &str, ent: &str) -> APIClient {
        APIClient {
            proto: proto,
            host: String::from_str(host),
            enterprise: String::from_str(ent),
            auth: None
        }
    }

    pub fn get_auth_from_home(&mut self, server: &str, ent: &str, user: &str) -> Result<APIAuth, DeliveryError> {
        match TokenStore::from_home() {
            Ok(tstore) => {
                APIAuth::from_token_store(tstore, server, ent, user)
            },
            Err(e) => Err(e)
        }
    }

    pub fn set_auth(&mut self, auth: APIAuth) {
        self.auth = Some(auth);
    }

    pub fn api_url(&self, path: &str) -> String {
        format!("{}://{}/api/v0/e/{}/{}",
                self.proto, self.host, self.enterprise, path)
    }

    pub fn project_exists(&self,
                          org: &str,
                          proj: &str) -> bool {

        let path = format!("orgs/{}/projects/{}", org, proj);
        match self.get(&path) {
            Ok(res) => {
                match res.status {
                    StatusCode::Ok => {
                        return true;
                    },
                    _ => {
                        return false;
                    }
                }
            },
            Err(e) => {
                sayln("red", &format!("project_exists: HttpError: {:?}", e));
                return false;
            }
        }
    }

    pub fn create_project(&self,
                          org: &str,
                          proj: &str) -> Result<HyperResponse, DelivError> {
        let path = format!("orgs/{}/projects", org);
        // FIXME: we'd like to use the native struct->json stuff, but
        // seeing link issues.
        let payload = format!("{{\"name\":\"{}\"}}", proj);
        match self.post(&path, &payload) {
            Ok(mut res) => {
                match res.status {
                    StatusCode::Created =>
                        Ok(res),
                    _ => {
                        let mut detail = String::new();
                        let e = match res.read_to_string(&mut detail) {
                            Ok(_) => Ok(detail),
                            Err(e) => Err(e)
                        };
                        Err(DelivError::ApiError(res.status, e))
                    }
                }
            },
            Err(e) => Err(DelivError::HttpError(e))
        }
    }

    pub fn create_pipeline(&self,
                           org: &str,
                           proj: &str,
                           pipe: &str) -> Result<HyperResponse, DelivError> {
        let path = format!("orgs/{}/projects/{}/pipelines", org, proj);
        // FIXME: we'd like to use the native struct->json stuff, but
        // seeing link issues.
        let base_branch = "master";
        let payload = format!("{{\"name\":\"{}\",\"base\":\"{}\"}}",
                              pipe, base_branch);
        match self.post(&path, &payload) {
            Ok(mut res) => {
                match res.status {
                    StatusCode::Created =>
                        Ok(res),
                    _ => {
                        let mut detail = String::new();
                        let e = match res.read_to_string(&mut detail) {
                            Ok(_) => Ok(detail),
                            Err(e) => Err(e)
                        };
                        Err(DelivError::ApiError(res.status, e))
                    }
                }
            },
            Err(e) => Err(DelivError::HttpError(e))
        }
    }

    pub fn get(&self, path: &str) -> Result<HyperResponse, HttpError> {
        let url = self.api_url(path);
        let mut client = hyper::Client::new();
        let req = client.get(&url);
        let req = req.header(self.json_content());
        let req = match self.auth {
            Some(ref auth) => {
                let (deliv_user, deliv_token) = auth.auth_headers();
                req.header(deliv_user).header(deliv_token)
            },
            None => req
        };
        req.send()
    }

    pub fn post(&self,
                path: &str,
                payload: &str) -> Result<HyperResponse, HttpError> {
        let url = self.api_url(path);
        let mut client = hyper::Client::new();
        let req = client.post(&url);
        let req = req.header(self.json_content());
        let req = match self.auth {
            Some(ref auth) => {
                let (deliv_user, deliv_token) = auth.auth_headers();
                req.header(deliv_user).header(deliv_token)
            },
            None => req
        };
        if !payload.is_empty() {
            req.body(payload).send()
        } else {
            req.send()
        }
    }

    pub fn put(&self,
               path: &str,
               payload: &str) -> Result<HyperResponse, HttpError> {
        let url = self.api_url(path);
        let mut client = hyper::Client::new();
        let req = client.put(&url);
        let req = req.header(self.json_content());
        let req = match self.auth {
            Some(ref auth) => {
                let (deliv_user, deliv_token) = auth.auth_headers();
                req.header(deliv_user).header(deliv_token)
            },
            None => req
        };
        if !payload.is_empty() {
            req.body(payload).send()
        } else {
            req.send()
        }
    }

    pub fn parse_json(result: Result<HyperResponse, hyper::HttpError>) -> Result<json::Json, DeliveryError> {
        let body = match result {
            Ok(mut b) => {
                let mut body_string = String::new();
                let _x = try!(b.read_to_string(&mut body_string));
                body_string
            },
            Err(e) => return Err(DeliveryError{kind: Kind::HttpError(e),
                                               detail: None})
        };
        Ok(try!(json::Json::from_str(&body)))
    }

    pub fn extract_pretty_json<T: error::Error>(
        result: Result<HyperResponse, T>) -> Result<String, String> {
        let body = match result {
            Ok(mut b) => {
                let mut body_string = String::new();
                match b.read_to_string(&mut body_string) {
                    Ok(_) => body_string,
                    Err(e) => {
                        debug!("extract_pretty_json: {}", e);
                        return Err(String::from_str("response read failed"))
                    }
                }
            },
            Err(e) => {
                debug!("extract_pretty_json: HttpError: {}", e.description());
                return Err(String::from_str("HTTP Error"))
            }
        };
        let json = match json::Json::from_str(&body) {
            Ok(j) => j,
            Err(_) => {
                return Err(String::from_str("invalid JSON"))
            }
        };
        Ok(format!("{}", json.pretty()))
    }

    fn json_content(&self) -> hyper::header::ContentType {
        let mime = mime::Mime(mime::TopLevel::Application,
                              mime::SubLevel::Json, vec![]);
        hyper::header::ContentType(mime)
    }

}

#[derive(Debug)]
pub struct APIAuth {
    user: String,
    token: String
}

impl APIAuth {
    pub fn from_env() -> APIAuth {
        let token = env::var("TOKEN").ok().expect("env missing TOKEN");
        let user = env::var("DEL_USER").ok().expect("env missing DEL_USER");
        APIAuth { user: user, token: token }
    }

    pub fn from_token_store(tstore: TokenStore,
                            server: &str, ent: &str,
                            user: &str) -> Result<APIAuth, DeliveryError> {
        match tstore.lookup(server, ent, user) {
            Some(token) => {
                Ok(APIAuth{ user: String::from_str(user),
                             token: String::from_str(token)})
            },
            None => {
                let msg = format!("server: {}, ent: {}, user: {}",
                                  server, ent, user);
                Err(DeliveryError{ kind: Kind::NoToken,
                                   detail: Some(msg)})
            }
        }
    }

    pub fn user(&self) -> String {
        self.user.clone()
    }

    pub fn token(&self) -> String {
        self.token.clone()
    }

    pub fn auth_headers(&self) -> (headers::ChefDeliveryUser,
                                   headers::ChefDeliveryToken) {
        (headers::ChefDeliveryUser(self.user.clone()),
         headers::ChefDeliveryToken(self.token.clone()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::TokenStore;
    use std::env;
    use tempdir::TempDir;
    use utils::path_join_many::PathJoinMany;

    #[test]
    fn api_auth() {
        fake_test_env();
        let auth = APIAuth::from_env();
        println!("got auth user: {}, token: {}",
                 auth.user, auth.token);
        assert_eq!("pete", auth.user);
        assert!(auth.token.len() > 4);
    }

    #[test]
    fn http_api_url_test() {
        let mut client = APIClient::new_http("localhost:4343",
                                         "Chef");
        fake_test_env();
        let auth = APIAuth::from_env();
        client.set_auth(auth);
        let url = client.api_url("foo/bar");
        assert_eq!("http://localhost:4343/api/v0/e/Chef/foo/bar", url)
    }

    #[test]
    fn https_api_url_test() {
        let mut client = APIClient::new_https("localhost:4343",
                                          "Chef");
        fake_test_env();
        let auth = APIAuth::from_env();
        client.set_auth(auth);
        let url = client.api_url("foo/bar");
        assert_eq!("https://localhost:4343/api/v0/e/Chef/foo/bar", url)
    }

    fn fake_test_env() {
        env::set_var("DEL_USER", "pete");
        env::set_var("TOKEN", "deadbeefcafe");
    }

    #[test]
    fn from_empty_token_store_test() {
        let tempdir = TempDir::new("t1").ok().expect("TempDir failed");
        let path = tempdir.path();
        let tfile = path.join_many(&["api-tokens"]);
        let tstore = TokenStore::from_file(&tfile).ok().expect("tstore sad");

        // token store is empty so we expect an Err()
        let from_empty = APIAuth::from_token_store(tstore,
                                                   "127.0.0.1", "acme", "bob");
        assert_eq!(true, from_empty.or_else(|e| {
            let msg = "server: 127.0.0.1, ent: acme, user: bob";
            assert_eq!(msg, e.detail().unwrap());
            Err(e)
        }).is_err());
    }

    #[test]
    fn from_non_empty_token_store_test() {
        let tempdir = TempDir::new("t1").ok().expect("TempDir failed");
        let path = tempdir.path();
        let tfile = path.join_many(&["api-tokens"]);
        let mut tstore = TokenStore::from_file(&tfile).ok().expect("tstore sad");
        let write_result = tstore.write_token("127.0.0.1", "acme", "bob",
                                              "beefbeef");
        assert_eq!(true, write_result.is_ok());
        let auth = APIAuth::from_token_store(tstore, "127.0.0.1", "acme", "bob");
        assert_eq!(true,
                   auth.and_then(|a| {
                       assert_eq!("bob", a.user());
                       assert_eq!("beefbeef", a.token());
                       Ok(a)
                   }).is_ok());
    }
}
<|endoftext|>