<commit_before>#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

extern crate libc;

use std::ffi::CStr;

pub const PKG_VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn check_version() {
    let raw_version = unsafe { CStr::from_ptr(HELIX_RUNTIME_VERSION) };
    let version = raw_version.to_str().expect("HELIX_RUNTIME_VERSION must be defined");

    if PKG_VERSION != version {
        panic!("libcsys-ruby version ({}) doesn't match helix_runtime version ({}).", PKG_VERSION, version);
    }
}

pub type void = libc::c_void;
pub type c_func = *const void;
pub type c_string = *const libc::c_char;
// pub type c_func = extern "C" fn(...);

#[repr(C)]
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
pub struct ID(*mut void);

#[repr(C)]
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct VALUE(*mut void);

#[repr(C)]
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct RubyException(isize);

impl RubyException {
    pub fn new() -> RubyException {
        RubyException(0)
    }

    pub fn empty() -> RubyException {
        RubyException(0)
    }

    pub fn for_tag(tag: isize) -> RubyException {
        RubyException(tag)
    }
}

pub const EMPTY_EXCEPTION: RubyException = RubyException(0);

#[repr(C)]
pub enum st_retval {
    ST_CONTINUE,
    ST_STOP,
    ST_DELETE,
    // ST_CHECK
}

#[cfg_attr(windows, link(name="helix-runtime"))]
extern "C" {
    #[link_name = "HELIX_RUNTIME_VERSION"]
    pub static HELIX_RUNTIME_VERSION: c_string;

    #[link_name = "HELIX_Qfalse"]
    pub static Qfalse: VALUE;

    #[link_name = "HELIX_Qtrue"]
    pub static Qtrue: VALUE;

    #[link_name = "HELIX_Qnil"]
    pub static Qnil: VALUE;

    #[link_name = "HELIX_PRIsVALUE"]
    pub static PRIsVALUE: c_string;

    #[link_name = "HELIX_SPRINTF_TO_S"]
    pub static SPRINTF_TO_S: c_string;

    #[link_name = "HELIX_SPRINTF_INSPECT"]
    pub static SPRINTF_INSPECT: c_string;

    #[link_name = "rb_cObject"]
    pub static rb_cObject: VALUE;

    #[link_name = "rb_eRuntimeError"]
    pub static rb_eRuntimeError: VALUE;

    #[link_name = "rb_eTypeError"]
    pub static rb_eTypeError: VALUE;

    #[link_name = "HELIX_RSTRING_LEN"]
    pub fn RSTRING_LEN(string: VALUE) -> isize;

    #[link_name = "HELIX_RSTRING_PTR"]
    pub fn RSTRING_PTR(string: VALUE) -> c_string;

    #[link_name = "HELIX_rb_utf8_str_new"]
    pub fn rb_utf8_str_new(string: c_string, len: libc::c_long) -> VALUE;

    #[link_name = "HELIX_RARRAY_LEN"]
    pub fn RARRAY_LEN(array: VALUE) -> isize;

    #[link_name = "HELIX_RARRAY_PTR"]
    pub fn RARRAY_PTR(array: VALUE) -> *mut VALUE;

    #[link_name = "HELIX_RARRAY_CONST_PTR"]
    pub fn RARRAY_CONST_PTR(array: VALUE) -> *const VALUE;

    #[link_name = "HELIX_RHASH_SIZE"]
    pub fn RHASH_SIZE(hash: VALUE) -> isize;

    #[link_name = "HELIX_RB_TYPE_P"]
    pub fn RB_TYPE_P(val: VALUE, rb_type: isize) -> bool;

    #[link_name = "HELIX_TYPE"]
    pub fn TYPE(val: VALUE) -> isize;

    pub fn rb_check_type(v: VALUE, rb_type: isize);

    #[link_name = "HELIX_NUM2U64"]
    pub fn NUM2U64(v: VALUE) -> u64;

    #[link_name = "HELIX_U642NUM"]
    pub fn U642NUM(num: u64) -> VALUE;

    #[link_name = "HELIX_NUM2I64"]
    pub fn NUM2I64(v: VALUE) -> i64;

    #[link_name = "HELIX_I642NUM"]
    pub fn I642NUM(num: i64) -> VALUE;

    #[link_name = "HELIX_NUM2U32"]
    pub fn NUM2U32(v: VALUE) -> u32;

    #[link_name = "HELIX_U322NUM"]
    pub fn U322NUM(num: u32) -> VALUE;

    #[link_name = "HELIX_NUM2I32"]
    pub fn NUM2I32(v: VALUE) -> i32;

    #[link_name = "HELIX_I322NUM"]
    pub fn I322NUM(num: i32) -> VALUE;

    #[link_name = "HELIX_NUM2F64"]
    pub fn NUM2F64(v: VALUE) -> f64;

    #[link_name = "HELIX_F642NUM"]
    pub fn F642NUM(num: f64) -> VALUE;

    #[link_name = "HELIX_T_STRING"]
    pub static T_STRING: isize;

    #[link_name = "HELIX_T_ARRAY"]
    pub static T_ARRAY: isize;

    #[link_name = "HELIX_T_HASH"]
    pub static T_HASH: isize;

    #[link_name = "HELIX_T_TRUE"]
    pub static T_TRUE: isize;

    #[link_name = "HELIX_T_FALSE"]
    pub static T_FALSE: isize;

    #[link_name = "HELIX_T_SYMBOL"]
    pub static T_SYMBOL: isize;

    #[link_name = "HELIX_T_FIXNUM"]
    pub static T_FIXNUM: isize;

    #[link_name = "HELIX_T_FLOAT"]
    pub static T_FLOAT: isize;

    #[link_name = "HELIX_T_BIGNUM"]
    pub static T_BIGNUM: isize;

    // unknown if working?
    // fn rb_define_variable(name: c_string, value: *const VALUE);
    pub fn rb_obj_class(obj: VALUE) -> VALUE;
    pub fn rb_obj_classname(obj: VALUE) -> c_string;
    pub fn rb_const_get(class: VALUE, name: ID) -> VALUE;
    pub fn rb_define_global_const(name: c_string, value: VALUE);
    pub fn rb_define_module(name: c_string) -> VALUE;
    pub fn rb_define_module_under(namespace: VALUE, name: c_string) -> VALUE;
    pub fn rb_define_class(name: c_string, superclass: VALUE) -> VALUE;
    pub fn rb_define_class_under(namespace: VALUE, name: c_string, superclass: VALUE) -> VALUE;
    pub fn rb_define_alloc_func(klass: VALUE, func: extern "C" fn(klass: VALUE) -> VALUE);
    pub fn rb_define_method(class: VALUE, name: c_string, func: c_func, arity: isize);
    pub fn rb_define_singleton_method(class: VALUE, name: c_string, func: c_func, arity: isize);
    pub fn rb_sprintf(specifier: c_string, ...) -> VALUE;
    pub fn rb_inspect(value: VALUE) -> VALUE;
    pub fn rb_intern(string: c_string) -> ID;
    pub fn rb_intern_str(string: VALUE) -> ID;
    pub fn rb_sym2id(symbol: VALUE) -> ID;
    pub fn rb_id2sym(id: ID) -> VALUE;
    pub fn rb_id2str(id: ID) -> VALUE;
    pub fn rb_ary_new_capa(capa: isize) -> VALUE;
    pub fn rb_ary_entry(ary: VALUE, offset: isize) -> VALUE;
    pub fn rb_ary_push(ary: VALUE, item: VALUE) -> VALUE;
    pub fn rb_hash_new() -> VALUE;
    pub fn rb_hash_aset(hash: VALUE, key: VALUE, value: VALUE) -> VALUE;
    pub fn rb_hash_foreach(hash: VALUE, f: extern "C" fn(key: VALUE, value: VALUE, farg: *mut void) -> st_retval, farg: *mut void);

    pub fn rb_raise(exc: VALUE, string: c_string, ...) -> !;
    pub fn rb_jump_tag(state: RubyException) -> !;
    pub fn rb_protect(try: extern "C" fn(v: *mut void) -> VALUE,
                      arg: *mut void,
                      state: *mut RubyException)
                      -> VALUE;

    #[link_name = "HELIX_Data_Wrap_Struct"]
    pub fn Data_Wrap_Struct(klass: VALUE, mark: extern "C" fn(*mut void), free: extern "C" fn(*mut void), data: *mut void) -> VALUE;

    #[link_name = "HELIX_Data_Get_Struct_Value"]
    pub fn Data_Get_Struct_Value(obj: VALUE) -> *mut void;

    #[link_name = "HELIX_Data_Set_Struct_Value"]
    pub fn Data_Set_Struct_Value(obj: VALUE, data: *mut void);
}
<commit_msg>Expose `T_DATA` in libcruby<commit_after>#![allow(non_snake_case)]
#![allow(non_camel_case_types)]

extern crate libc;

use std::ffi::CStr;

pub const PKG_VERSION: &'static str = env!("CARGO_PKG_VERSION");

pub fn check_version() {
    let raw_version = unsafe { CStr::from_ptr(HELIX_RUNTIME_VERSION) };
    let version = raw_version.to_str().expect("HELIX_RUNTIME_VERSION must be defined");

    if PKG_VERSION != version {
        panic!("libcsys-ruby version ({}) doesn't match helix_runtime version ({}).", PKG_VERSION, version);
    }
}

pub type void = libc::c_void;
pub type c_func = *const void;
pub type c_string = *const libc::c_char;
// pub type c_func = extern "C" fn(...);

#[repr(C)]
#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)]
pub struct ID(*mut void);

#[repr(C)]
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct VALUE(*mut void);

#[repr(C)]
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
pub struct RubyException(isize);

impl RubyException {
    pub fn new() -> RubyException {
        RubyException(0)
    }

    pub fn empty() -> RubyException {
        RubyException(0)
    }

    pub fn for_tag(tag: isize) -> RubyException {
        RubyException(tag)
    }
}

pub const EMPTY_EXCEPTION: RubyException = RubyException(0);

#[repr(C)]
pub enum st_retval {
    ST_CONTINUE,
    ST_STOP,
    ST_DELETE,
    // ST_CHECK
}

#[cfg_attr(windows, link(name="helix-runtime"))]
extern "C" {
    #[link_name = "HELIX_RUNTIME_VERSION"]
    pub static HELIX_RUNTIME_VERSION: c_string;

    #[link_name = "HELIX_Qfalse"]
    pub static Qfalse: VALUE;

    #[link_name = "HELIX_Qtrue"]
    pub static Qtrue: VALUE;

    #[link_name = "HELIX_Qnil"]
    pub static Qnil: VALUE;

    #[link_name = "HELIX_PRIsVALUE"]
    pub static PRIsVALUE: c_string;

    #[link_name = "HELIX_SPRINTF_TO_S"]
    pub static SPRINTF_TO_S: c_string;

    #[link_name = "HELIX_SPRINTF_INSPECT"]
    pub static SPRINTF_INSPECT: c_string;

    #[link_name = "rb_cObject"]
    pub static rb_cObject: VALUE;

    #[link_name = "rb_eRuntimeError"]
    pub static rb_eRuntimeError: VALUE;

    #[link_name = "rb_eTypeError"]
    pub static rb_eTypeError: VALUE;

    #[link_name = "HELIX_RSTRING_LEN"]
    pub fn RSTRING_LEN(string: VALUE) -> isize;

    #[link_name = "HELIX_RSTRING_PTR"]
    pub fn RSTRING_PTR(string: VALUE) -> c_string;

    #[link_name = "HELIX_rb_utf8_str_new"]
    pub fn rb_utf8_str_new(string: c_string, len: libc::c_long) -> VALUE;

    #[link_name = "HELIX_RARRAY_LEN"]
    pub fn RARRAY_LEN(array: VALUE) -> isize;

    #[link_name = "HELIX_RARRAY_PTR"]
    pub fn RARRAY_PTR(array: VALUE) -> *mut VALUE;

    #[link_name = "HELIX_RARRAY_CONST_PTR"]
    pub fn RARRAY_CONST_PTR(array: VALUE) -> *const VALUE;

    #[link_name = "HELIX_RHASH_SIZE"]
    pub fn RHASH_SIZE(hash: VALUE) -> isize;

    #[link_name = "HELIX_RB_TYPE_P"]
    pub fn RB_TYPE_P(val: VALUE, rb_type: isize) -> bool;

    #[link_name = "HELIX_TYPE"]
    pub fn TYPE(val: VALUE) -> isize;

    pub fn rb_check_type(v: VALUE, rb_type: isize);

    #[link_name = "HELIX_NUM2U64"]
    pub fn NUM2U64(v: VALUE) -> u64;

    #[link_name = "HELIX_U642NUM"]
    pub fn U642NUM(num: u64) -> VALUE;

    #[link_name = "HELIX_NUM2I64"]
    pub fn NUM2I64(v: VALUE) -> i64;

    #[link_name = "HELIX_I642NUM"]
    pub fn I642NUM(num: i64) -> VALUE;

    #[link_name = "HELIX_NUM2U32"]
    pub fn NUM2U32(v: VALUE) -> u32;

    #[link_name = "HELIX_U322NUM"]
    pub fn U322NUM(num: u32) -> VALUE;

    #[link_name = "HELIX_NUM2I32"]
    pub fn NUM2I32(v: VALUE) -> i32;

    #[link_name = "HELIX_I322NUM"]
    pub fn I322NUM(num: i32) -> VALUE;

    #[link_name = "HELIX_NUM2F64"]
    pub fn NUM2F64(v: VALUE) -> f64;

    #[link_name = "HELIX_F642NUM"]
    pub fn F642NUM(num: f64) -> VALUE;

    #[link_name = "HELIX_T_STRING"]
    pub static T_STRING: isize;

    #[link_name = "HELIX_T_ARRAY"]
    pub static T_ARRAY: isize;

    #[link_name = "HELIX_T_HASH"]
    pub static T_HASH: isize;

    #[link_name = "HELIX_T_TRUE"]
    pub static T_TRUE: isize;

    #[link_name = "HELIX_T_FALSE"]
    pub static T_FALSE: isize;

    #[link_name = "HELIX_T_SYMBOL"]
    pub static T_SYMBOL: isize;

    #[link_name = "HELIX_T_FIXNUM"]
    pub static T_FIXNUM: isize;

    #[link_name = "HELIX_T_FLOAT"]
    pub static T_FLOAT: isize;

    #[link_name = "HELIX_T_BIGNUM"]
    pub static T_BIGNUM: isize;

    #[link_name = "HELIX_T_DATA"]
    pub static T_DATA: isize;

    // unknown if working?
    // fn rb_define_variable(name: c_string, value: *const VALUE);
    pub fn rb_obj_class(obj: VALUE) -> VALUE;
    pub fn rb_obj_classname(obj: VALUE) -> c_string;
    pub fn rb_const_get(class: VALUE, name: ID) -> VALUE;
    pub fn rb_define_global_const(name: c_string, value: VALUE);
    pub fn rb_define_module(name: c_string) -> VALUE;
    pub fn rb_define_module_under(namespace: VALUE, name: c_string) -> VALUE;
    pub fn rb_define_class(name: c_string, superclass: VALUE) -> VALUE;
    pub fn rb_define_class_under(namespace: VALUE, name: c_string, superclass: VALUE) -> VALUE;
    pub fn rb_define_alloc_func(klass: VALUE, func: extern "C" fn(klass: VALUE) -> VALUE);
    pub fn rb_define_method(class: VALUE, name: c_string, func: c_func, arity: isize);
    pub fn rb_define_singleton_method(class: VALUE, name: c_string, func: c_func, arity: isize);
    pub fn rb_sprintf(specifier: c_string, ...) -> VALUE;
    pub fn rb_inspect(value: VALUE) -> VALUE;
    pub fn rb_intern(string: c_string) -> ID;
    pub fn rb_intern_str(string: VALUE) -> ID;
    pub fn rb_sym2id(symbol: VALUE) -> ID;
    pub fn rb_id2sym(id: ID) -> VALUE;
    pub fn rb_id2str(id: ID) -> VALUE;
    pub fn rb_ary_new_capa(capa: isize) -> VALUE;
    pub fn rb_ary_entry(ary: VALUE, offset: isize) -> VALUE;
    pub fn rb_ary_push(ary: VALUE, item: VALUE) -> VALUE;
    pub fn rb_hash_new() -> VALUE;
    pub fn rb_hash_aset(hash: VALUE, key: VALUE, value: VALUE) -> VALUE;
    pub fn rb_hash_foreach(hash: VALUE, f: extern "C" fn(key: VALUE, value: VALUE, farg: *mut void) -> st_retval, farg: *mut void);

    pub fn rb_raise(exc: VALUE, string: c_string, ...) -> !;
    pub fn rb_jump_tag(state: RubyException) -> !;
    pub fn rb_protect(try: extern "C" fn(v: *mut void) -> VALUE,
                      arg: *mut void,
                      state: *mut RubyException)
                      -> VALUE;

    #[link_name = "HELIX_Data_Wrap_Struct"]
    pub fn Data_Wrap_Struct(klass: VALUE, mark: extern "C" fn(*mut void), free: extern "C" fn(*mut void), data: *mut void) -> VALUE;

    #[link_name = "HELIX_Data_Get_Struct_Value"]
    pub fn Data_Get_Struct_Value(obj: VALUE) -> *mut void;

    #[link_name = "HELIX_Data_Set_Struct_Value"]
    pub fn Data_Set_Struct_Value(obj: VALUE, data: *mut void);
}
<|endoftext|>


<commit_before>#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private, quote)]

extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;

use rustc_plugin::Registry;
use syntax::ast::{FnDecl, Ident, ItemKind, LitKind, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::codemap::Span;
use syntax::symbol::Symbol;

fn get_js_name(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem) -> String {
    let meta_items = meta_item.meta_item_list().unwrap_or_else(|| {
        ecx.struct_span_err(span, "incorrect use of napi_callback attribute")
            .help("usage: #[napi_callback(\"jsFunctionName\")]")
            .emit();
        ecx.span_fatal(span, "invalid attribute usage");
    });

    if meta_items.len() != 1 {
        ecx.struct_span_err(span, "incorrect use of napi_callback attribute")
            .help("usage: #[napi_callback(\"jsFunctionName\")]")
            .emit();
        ecx.span_fatal(span, "attribute requires exactly one argument");
    }

    let name_meta_item = &meta_items[0];

    let name = name_meta_item
        .literal()
        .and_then(|literal| match literal.node {
            LitKind::Str(ref s, _) => Some(s.as_str()),
            _ => None,
        })
        .unwrap_or_else(|| {
            ecx.span_fatal(
                name_meta_item.span(),
                "attribute argument must be a string",
            );
        });

    String::from(&*name)
}

struct Function {
    pub ident: Ident,
    pub decl: FnDecl,
}

impl Function {
    fn from_annotatable(
        ecx: &mut ExtCtxt,
        annotated: &Annotatable,
    ) -> Function {
        let report_error = |span| {
            ecx.span_fatal(
                span,
                "napi_callback attribute can only be used on \
                functions, but was applied to this item.",
            );
        };

        match *annotated {
            Annotatable::Item(ref item) => {
                match item.node {
                    ItemKind::Fn(ref decl, ..) => Function {
                        ident: item.ident,
                        decl: decl.clone().unwrap(),
                    },
                    _ => report_error(item.span),
                }
            }
            Annotatable::TraitItem(ref item) => report_error(item.span),
            Annotatable::ImplItem(ref item) => report_error(item.span),
        }
    }
}

fn create_napi_callback(ecx: &mut ExtCtxt, function: &Function) -> Annotatable {
    let fn_ident = function.ident;
    let extern_fn_name = format!("napi_rs_cb_{}", fn_ident.name);
    let extern_fn_ident = Ident::from_str(extern_fn_name.as_str());

    Annotatable::Item(
        quote_item!(ecx,
            #[no_mangle]
            pub extern "C" fn $extern_fn_ident(
                env: ::napi::sys::napi_env,
                info: ::napi::sys::napi_callback_info,
            ) -> ::napi::sys::napi_value {
                let result: ::napi::NapiResult<::napi::sys::napi_value> =
                    $fn_ident(env, info);

                match result {
                    Ok(value) => return value,
                    Err(error) => {
                        if let Some(exception) = error.exception {
                            unsafe {
                                ::napi::sys::napi_throw(env, exception);
                            }
                        } else {
                            let message = format!("{}", &error);
                            let c_string = std::ffi::CString::new(
                                message,
                            ).unwrap();

                            unsafe {
                                ::napi::sys::napi_throw_error(
                                    env,
                                    std::ptr::null(),
                                    c_string.as_ptr(),
                                );
                            }
                        }

                        unsafe {
                            let mut result: napi_value =
                                std::mem::uninitialized();
                            ::napi::sys::napi_get_undefined(env, &mut result);
                            result
                        }
                    }
                }
            }
        ).unwrap(),
    )
}

pub fn napi_callback_decorator(
    ecx: &mut ExtCtxt,
    span: Span,
    meta_item: &MetaItem,
    annotated: Annotatable,
) -> Vec<Annotatable> {
    let js_name = get_js_name(ecx, span, meta_item);
    let function = Function::from_annotatable(ecx, &annotated);

    let mut output = Vec::new();

    output.push(create_napi_callback(ecx, &function));
    output.push(annotated);

    output
}

#[plugin_registrar]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_syntax_extension(
        Symbol::intern("napi_callback"),
        SyntaxExtension::MultiModifier(Box::new(napi_callback_decorator)),
    );
}
<commit_msg>fix(codegen): don't panic on nulls in error messages<commit_after>#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private, quote)]

extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;

use rustc_plugin::Registry;
use syntax::ast::{FnDecl, Ident, ItemKind, LitKind, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::codemap::Span;
use syntax::symbol::Symbol;

fn get_js_name(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem) -> String {
    let meta_items = meta_item.meta_item_list().unwrap_or_else(|| {
        ecx.struct_span_err(span, "incorrect use of napi_callback attribute")
            .help("usage: #[napi_callback(\"jsFunctionName\")]")
            .emit();
        ecx.span_fatal(span, "invalid attribute usage");
    });

    if meta_items.len() != 1 {
        ecx.struct_span_err(span, "incorrect use of napi_callback attribute")
            .help("usage: #[napi_callback(\"jsFunctionName\")]")
            .emit();
        ecx.span_fatal(span, "attribute requires exactly one argument");
    }

    let name_meta_item = &meta_items[0];

    let name = name_meta_item
        .literal()
        .and_then(|literal| match literal.node {
            LitKind::Str(ref s, _) => Some(s.as_str()),
            _ => None,
        })
        .unwrap_or_else(|| {
            ecx.span_fatal(
                name_meta_item.span(),
                "attribute argument must be a string",
            );
        });

    String::from(&*name)
}

struct Function {
    pub ident: Ident,
    pub decl: FnDecl,
}

impl Function {
    fn from_annotatable(
        ecx: &mut ExtCtxt,
        annotated: &Annotatable,
    ) -> Function {
        let report_error = |span| {
            ecx.span_fatal(
                span,
                "napi_callback attribute can only be used on \
                functions, but was applied to this item.",
            );
        };

        match *annotated {
            Annotatable::Item(ref item) => {
                match item.node {
                    ItemKind::Fn(ref decl, ..) => Function {
                        ident: item.ident,
                        decl: decl.clone().unwrap(),
                    },
                    _ => report_error(item.span),
                }
            }
            Annotatable::TraitItem(ref item) => report_error(item.span),
            Annotatable::ImplItem(ref item) => report_error(item.span),
        }
    }
}

fn create_napi_callback(ecx: &mut ExtCtxt, function: &Function) -> Annotatable {
    let fn_ident = function.ident;
    let extern_fn_name = format!("napi_rs_cb_{}", fn_ident.name);
    let extern_fn_ident = Ident::from_str(extern_fn_name.as_str());

    Annotatable::Item(
        quote_item!(ecx,
            #[no_mangle]
            pub extern "C" fn $extern_fn_ident(
                env: ::napi::sys::napi_env,
                info: ::napi::sys::napi_callback_info,
            ) -> ::napi::sys::napi_value {
                let result: ::napi::NapiResult<::napi::sys::napi_value> =
                    $fn_ident(env, info);

                match result {
                    Ok(value) => return value,
                    Err(error) => {
                        if let Some(exception) = error.exception {
                            unsafe {
                                ::napi::sys::napi_throw(env, exception);
                            }
                        } else {
                            use std::error::Error;

                            let message = format!("{}", &error);
                            let c_string = std::ffi::CString::new(message)
                                .unwrap_or_else(|_| {
                                    std::ffi::CString::new(
                                        error.description(),
                                    ).unwrap()
                                });

                            unsafe {
                                ::napi::sys::napi_throw_error(
                                    env,
                                    std::ptr::null(),
                                    c_string.as_ptr(),
                                );
                            }
                        }

                        unsafe {
                            let mut result: napi_value =
                                std::mem::uninitialized();
                            ::napi::sys::napi_get_undefined(env, &mut result);
                            result
                        }
                    }
                }
            }
        ).unwrap(),
    )
}

pub fn napi_callback_decorator(
    ecx: &mut ExtCtxt,
    span: Span,
    meta_item: &MetaItem,
    annotated: Annotatable,
) -> Vec<Annotatable> {
    let js_name = get_js_name(ecx, span, meta_item);
    let function = Function::from_annotatable(ecx, &annotated);

    let mut output = Vec::new();

    output.push(create_napi_callback(ecx, &function));
    output.push(annotated);

    output
}

#[plugin_registrar]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_syntax_extension(
        Symbol::intern("napi_callback"),
        SyntaxExtension::MultiModifier(Box::new(napi_callback_decorator)),
    );
}
<|endoftext|>


<commit_before>use std::cell::Cell;

use super::behaviors::FocusBehavior;
use crate::{
    prelude::*,
    shell::{Key, KeyEvent},
};

/// The `TextBoxState` handles the text processing of the `TextBox` widget.
#[derive(Default)]
pub struct TextBoxState {
    text: RefCell<String16>,
    focused: Cell<bool>,
    updated: Cell<bool>,
    selection_start: Cell<usize>,
    selection_length: Cell<usize>,
    cursor_x: Cell<f64>,
}

impl TextBoxState {
    // fn click(&self, point: Point) {
    //     println!("Clicked text box point: ({}, {})", point.x, point.y);
    // }

    fn update_selection_start(&self, selection: i32) {
        self.selection_start
            .set(selection.max(0).min(self.text.borrow().len() as i32) as usize);
    }

    fn update_text(&self, key_event: KeyEvent) -> bool {
        if !self.focused.get() {
            return false;
        }

        if !key_event.text.is_empty() {
            (*self.text.borrow_mut()).insert_str(self.selection_start.get(), &key_event.text);
            self.update_selection_start(self.selection_start.get() as i32 + 1);
        } else {
            match key_event.key {
                Key::Left => {
                    self.update_selection_start(self.selection_start.get() as i32 - 1);
                    self.selection_length.set(0);
                }
                Key::Right => {
                    self.update_selection_start(self.selection_start.get() as i32 + 1);
                    self.selection_length.set(0);
                }
                Key::Backspace => {
                    if self.text.borrow().len() > 0 {
                        if self.selection_start.get() > 0 {
                            for _ in 0..(self.selection_length.get() + 1) {
                                (*self.text.borrow_mut()).remove(self.selection_start.get() - 1);
                            }
                            self.update_selection_start(self.selection_start.get() as i32 - 1);
                        }
                    }
                }
                Key::Delete => {
                    let len = self.text.borrow().len();
                    if len > 0 {
                        if self.selection_start.get() < len {
                            for _ in 0..(self.selection_length.get() + 1) {
                                (*self.text.borrow_mut()).remove(self.selection_start.get());
                            }
                            self.update_selection_start(self.selection_start.get() as i32);
                        }
                    }
                }
                _ => {}
            }
        }

        self.updated.set(true);

        true
    }
}

impl State for TextBoxState {
    fn update(&self, context: &mut Context<'_>) {
        let mut widget = context.widget();

        self.focused.set(widget.get::<Focused>().0);

        if let Some(text) = widget.try_get_mut::<Text>() {
            if text.0 != *self.text.borrow() {
                if self.updated.get() {
                    text.0 = self.text.borrow().clone();
                } else {
                    let text_length = self.text.borrow().len();
                    let origin_text_length = String16::from(text.0.to_string().as_str()).len();
                    let delta = text_length as i32 - origin_text_length as i32;

                    *self.text.borrow_mut() = String16::from(text.0.to_string().as_str());

                    // adjust cursor position after label is changed from outside
                    if text_length < origin_text_length {
                        self.update_selection_start(self.selection_start.get() as i32 - delta);
                    } else {
                        self.update_selection_start(self.selection_start.get() as i32 + delta);
                    }
                }

                self.updated.set(false);
            }
        }

        if let Some(selection) = widget.try_get_mut::<TextSelection>() {
            selection.0.start_index = self.selection_start.get();
            selection.0.length = self.selection_length.get();
        }

        if widget.get::<Text>().0.is_empty() {
            add_selector_to_widget("water-mark", &mut widget);
        } else {
            remove_selector_from_widget("water-mark", &mut widget);
        }
    }

    fn update_post_layout(&self, context: &mut Context<'_>) {
        let mut cursor_x_delta = 0.0;
        let mut scroll_viewer_width = 0.0;

        {
            let scroll_viewer = context.child_by_id("scroll_viewer");

            if let Some(bounds) = scroll_viewer.unwrap().try_get_mut::<Bounds>() {
                scroll_viewer_width = bounds.width();
            }
        }

        // maybe not use scroll viewer here

        // Adjust offset of text and cursor if cursor position is out of bounds

        {
            let mut cursor = context.child_by_id("cursor").unwrap();

            if let Some(margin) = cursor.try_get_mut::<Margin>() {
                if margin.left() < 0.0 || margin.left() > scroll_viewer_width {
                    cursor_x_delta = self.cursor_x.get() - margin.left();
                    margin.set_left(self.cursor_x.get());
                }
                self.cursor_x.set(margin.left());
            }

            if let Some(bounds) = cursor.try_get_mut::<Bounds>() {
                bounds.set_x(self.cursor_x.get());
            }
        }

        if cursor_x_delta != 0.0 {
            {
                let text_block = context.child_by_id("text_block");

                if let Some(bounds) = text_block.unwrap().try_get_mut::<Bounds>() {
                    bounds.set_x(bounds.x() + cursor_x_delta);
                }
            }

            if let Some(offset) = context.widget().try_get_mut::<Offset>() {
                (offset.0).x += cursor_x_delta;
            }
        }
    }
}

widget!(
    /// The `TextBox` widget represents a single line text input widget.
    ///
    /// * CSS element: `text-box`
    TextBox<TextBoxState>: KeyDownHandler {
        /// Sets or shares the text property.
        text: Text,

        /// Sets or shares the placeholder text property.
        placeholder: WaterMark,

        /// Sets or shares the text selection property.
        selection: TextSelection,

        /// Sets or shares the foreground property.
        foreground: Foreground,

        /// Sets or share the font size property.
        font_size: FontSize,

        /// Sets or shares the font property.
        font: Font,

        /// Sets or shares the background property.
        background: Background,

        /// Sets or shares the border radius property.
        border_radius: BorderRadius,

        /// Sets or shares the border thickness property.
        border_thickness: BorderThickness,

        /// Sets or shares the border brush property.
        border_brush: BorderBrush,

        /// Sets or shares the padding property.
        padding: Padding,

        /// Sets or shares the text offset property.
        offset: Offset,

         /// Sets or shares the focused property.
        focused: Focused,

        /// Sets or shares the css selector property.
        selector: Selector
    }
);

impl Template for TextBox {
    fn template(self, id: Entity, context: &mut BuildContext) -> Self {
        let state = self.clone_state();

        self.name("TextBox")
            .selector("text-box")
            .text("")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(fonts::FONT_SIZE_12)
            .font("Roboto Regular")
            .selection(TextSelectionValue::default())
            .offset(0.0)
            .padding(4.0)
            .background(colors::LYNCH_COLOR)
            .border_brush("transparent")
            .border_thickness(0.0)
            .border_radius(2.0)
            .size(128.0, 32.0)
            .focused(false)
            .child(
                FocusBehavior::create()
                    .enabled(id)
                    .focused(id)
                    .selector(id)
                    .child(
                        Container::create()
                            .background(id)
                            .border_radius(id)
                            .border_thickness(id)
                            .border_brush(id)
                            .padding(id)
                            .child(
                                Grid::create()
                                    .child(
                                        ScrollViewer::create()
                                            .selector(SelectorValue::default().id("scroll_viewer"))
                                            .offset(id)
                                            .scroll_mode(("None", "None"))
                                            .child(
                                                TextBlock::create()
                                                    .selector(
                                                        SelectorValue::default()
                                                            .clone()
                                                            .id("text_block"),
                                                    )
                                                    .vertical_alignment("Center")
                                                    .foreground(id)
                                                    .text(id)
                                                    .font(id)
                                                    .font_size(id)
                                                    .attach_by_source::<WaterMark>(id)
                                                    .build(context),
                                            )
                                            .build(context),
                                    )
                                    .child(
                                        Cursor::create()
                                            .selector(SelectorValue::from("cursor").id("cursor"))
                                            .margin(0.0)
                                            .horizontal_alignment("Start")
                                            .text(id)
                                            .font(id)
                                            .font_size(id)
                                            .offset(id)
                                            .focused(id)
                                            .selection(id)
                                            .build(context),
                                    )
                                    .build(context),
                            )
                            .build(context),
                    )
                    .build(context),
            )
            .on_key_down(move |event: KeyEvent| -> bool { state.update_text(event) })
    }
}
<commit_msg>Fix watermark style switch.<commit_after>use std::cell::Cell;

use super::behaviors::FocusBehavior;
use crate::{
    prelude::*,
    shell::{Key, KeyEvent},
};

/// The `TextBoxState` handles the text processing of the `TextBox` widget.
#[derive(Default)]
pub struct TextBoxState {
    text: RefCell<String16>,
    focused: Cell<bool>,
    updated: Cell<bool>,
    selection_start: Cell<usize>,
    selection_length: Cell<usize>,
    cursor_x: Cell<f64>,
}

impl TextBoxState {
    // fn click(&self, point: Point) {
    //     println!("Clicked text box point: ({}, {})", point.x, point.y);
    // }

    fn update_selection_start(&self, selection: i32) {
        self.selection_start
            .set(selection.max(0).min(self.text.borrow().len() as i32) as usize);
    }

    fn update_text(&self, key_event: KeyEvent) -> bool {
        if !self.focused.get() {
            return false;
        }

        if !key_event.text.is_empty() {
            (*self.text.borrow_mut()).insert_str(self.selection_start.get(), &key_event.text);
            self.update_selection_start(self.selection_start.get() as i32 + 1);
        } else {
            match key_event.key {
                Key::Left => {
                    self.update_selection_start(self.selection_start.get() as i32 - 1);
                    self.selection_length.set(0);
                }
                Key::Right => {
                    self.update_selection_start(self.selection_start.get() as i32 + 1);
                    self.selection_length.set(0);
                }
                Key::Backspace => {
                    if self.text.borrow().len() > 0 {
                        if self.selection_start.get() > 0 {
                            for _ in 0..(self.selection_length.get() + 1) {
                                (*self.text.borrow_mut()).remove(self.selection_start.get() - 1);
                            }
                            self.update_selection_start(self.selection_start.get() as i32 - 1);
                        }
                    }
                }
                Key::Delete => {
                    let len = self.text.borrow().len();
                    if len > 0 {
                        if self.selection_start.get() < len {
                            for _ in 0..(self.selection_length.get() + 1) {
                                (*self.text.borrow_mut()).remove(self.selection_start.get());
                            }
                            self.update_selection_start(self.selection_start.get() as i32);
                        }
                    }
                }
                _ => {}
            }
        }

        self.updated.set(true);

        true
    }
}

impl State for TextBoxState {
    fn update(&self, context: &mut Context<'_>) {
        let mut widget = context.widget();

        self.focused.set(widget.get::<Focused>().0);

        if let Some(text) = widget.try_get_mut::<Text>() {
            if text.0 != *self.text.borrow() {
                if self.updated.get() {
                    text.0 = self.text.borrow().clone();
                } else {
                    let text_length = self.text.borrow().len();
                    let origin_text_length = String16::from(text.0.to_string().as_str()).len();
                    let delta = text_length as i32 - origin_text_length as i32;

                    *self.text.borrow_mut() = String16::from(text.0.to_string().as_str());

                    // adjust cursor position after label is changed from outside
                    if text_length < origin_text_length {
                        self.update_selection_start(self.selection_start.get() as i32 - delta);
                    } else {
                        self.update_selection_start(self.selection_start.get() as i32 + delta);
                    }
                }

                self.updated.set(false);
            }
        }

        if let Some(selection) = widget.try_get_mut::<TextSelection>() {
            selection.0.start_index = self.selection_start.get();
            selection.0.length = self.selection_length.get();
        }

        if widget.get::<Text>().0.is_empty() {
            add_selector_to_widget("water-mark", &mut widget);
        } else {
            remove_selector_from_widget("water-mark", &mut widget);
        }

        context.update_theme_properties(context.entity);
    }

    fn update_post_layout(&self, context: &mut Context<'_>) {
        let mut cursor_x_delta = 0.0;
        let mut scroll_viewer_width = 0.0;

        {
            let scroll_viewer = context.child_by_id("scroll_viewer");

            if let Some(bounds) = scroll_viewer.unwrap().try_get_mut::<Bounds>() {
                scroll_viewer_width = bounds.width();
            }
        }

        // maybe not use scroll viewer here

        // Adjust offset of text and cursor if cursor position is out of bounds

        {
            let mut cursor = context.child_by_id("cursor").unwrap();

            if let Some(margin) = cursor.try_get_mut::<Margin>() {
                if margin.left() < 0.0 || margin.left() > scroll_viewer_width {
                    cursor_x_delta = self.cursor_x.get() - margin.left();
                    margin.set_left(self.cursor_x.get());
                }
                self.cursor_x.set(margin.left());
            }

            if let Some(bounds) = cursor.try_get_mut::<Bounds>() {
                bounds.set_x(self.cursor_x.get());
            }
        }

        if cursor_x_delta != 0.0 {
            {
                let text_block = context.child_by_id("text_block");

                if let Some(bounds) = text_block.unwrap().try_get_mut::<Bounds>() {
                    bounds.set_x(bounds.x() + cursor_x_delta);
                }
            }

            if let Some(offset) = context.widget().try_get_mut::<Offset>() {
                (offset.0).x += cursor_x_delta;
            }
        }
    }
}

widget!(
    /// The `TextBox` widget represents a single line text input widget.
    ///
    /// * CSS element: `text-box`
    TextBox<TextBoxState>: KeyDownHandler {
        /// Sets or shares the text property.
        text: Text,

        /// Sets or shares the placeholder text property.
        placeholder: WaterMark,

        /// Sets or shares the text selection property.
        selection: TextSelection,

        /// Sets or shares the foreground property.
        foreground: Foreground,

        /// Sets or share the font size property.
        font_size: FontSize,

        /// Sets or shares the font property.
        font: Font,

        /// Sets or shares the background property.
        background: Background,

        /// Sets or shares the border radius property.
        border_radius: BorderRadius,

        /// Sets or shares the border thickness property.
        border_thickness: BorderThickness,

        /// Sets or shares the border brush property.
        border_brush: BorderBrush,

        /// Sets or shares the padding property.
        padding: Padding,

        /// Sets or shares the text offset property.
        offset: Offset,

         /// Sets or shares the focused property.
        focused: Focused,

        /// Sets or shares the css selector property.
        selector: Selector
    }
);

impl Template for TextBox {
    fn template(self, id: Entity, context: &mut BuildContext) -> Self {
        let state = self.clone_state();

        self.name("TextBox")
            .selector("text-box")
            .text("")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(fonts::FONT_SIZE_12)
            .font("Roboto Regular")
            .selection(TextSelectionValue::default())
            .offset(0.0)
            .padding(4.0)
            .background(colors::LYNCH_COLOR)
            .border_brush("transparent")
            .border_thickness(0.0)
            .border_radius(2.0)
            .size(128.0, 32.0)
            .focused(false)
            .child(
                FocusBehavior::create()
                    .enabled(id)
                    .focused(id)
                    .selector(id)
                    .child(
                        Container::create()
                            .background(id)
                            .border_radius(id)
                            .border_thickness(id)
                            .border_brush(id)
                            .padding(id)
                            .child(
                                Grid::create()
                                    .child(
                                        ScrollViewer::create()
                                            .selector(SelectorValue::default().id("scroll_viewer"))
                                            .offset(id)
                                            .scroll_mode(("None", "None"))
                                            .child(
                                                TextBlock::create()
                                                    .selector(
                                                        SelectorValue::default()
                                                            .clone()
                                                            .id("text_block"),
                                                    )
                                                    .vertical_alignment("Center")
                                                    .foreground(id)
                                                    .text(id)
                                                    .font(id)
                                                    .font_size(id)
                                                    .attach_by_source::<WaterMark>(id)
                                                    .build(context),
                                            )
                                            .build(context),
                                    )
                                    .child(
                                        Cursor::create()
                                            .selector(SelectorValue::from("cursor").id("cursor"))
                                            .margin(0.0)
                                            .horizontal_alignment("Start")
                                            .text(id)
                                            .font(id)
                                            .font_size(id)
                                            .offset(id)
                                            .focused(id)
                                            .selection(id)
                                            .build(context),
                                    )
                                    .build(context),
                            )
                            .build(context),
                    )
                    .build(context),
            )
            .on_key_down(move |event: KeyEvent| -> bool { state.update_text(event) })
    }
}
<|endoftext|>


<commit_before>use std::io::{fs, UserRWX, File};
use std::io::fs::PathExtensions;
use std::os;

use support::{execs, paths, cargo_dir, ResultTest};
use hamcrest::{assert_that, existing_file, existing_dir, is_not};

use cargo::util::{process, ProcessBuilder};

fn setup() {
}

fn my_process(s: &str) -> ProcessBuilder {
    process(s)
        .cwd(paths::root())
        .env("HOME", Some(paths::home()))
}

fn cargo_process(s: &str) -> ProcessBuilder {
    process(cargo_dir().join("cargo")).arg(s)
        .cwd(paths::root())
        .env("HOME", Some(paths::home()))
}

test!(simple_lib {
    os::setenv("USER", "foo");
    assert_that(cargo_process("new").arg("foo").arg("--no-git"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/lib.rs"), existing_file());
    assert_that(&paths::root().join("foo/.gitignore"), is_not(existing_file()));

    assert_that(cargo_process("build").cwd(paths::root().join("foo")),
                execs().with_status(0));
})

test!(simple_bin {
    os::setenv("USER", "foo");
    assert_that(cargo_process("new").arg("foo").arg("--bin"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/main.rs"), existing_file());

    assert_that(cargo_process("build").cwd(paths::root().join("foo")),
                execs().with_status(0));
    assert_that(&paths::root().join(format!("foo/target/foo{}",
                                            os::consts::EXE_SUFFIX)),
                existing_file());
})

test!(simple_git {
    os::setenv("USER", "foo");
    assert_that(cargo_process("new").arg("foo"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/lib.rs"), existing_file());
    assert_that(&paths::root().join("foo/.git"), existing_dir());
    assert_that(&paths::root().join("foo/.gitignore"), existing_file());

    assert_that(cargo_process("build").cwd(paths::root().join("foo")),
                execs().with_status(0));
})

test!(simple_travis {
    os::setenv("USER", "foo");
    assert_that(cargo_process("new").arg("foo").arg("--travis"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/lib.rs"), existing_file());
    assert_that(&paths::root().join("foo/.travis.yml"), existing_file());

    assert_that(cargo_process("build").cwd(paths::root().join("foo")),
                execs().with_status(0));
})

test!(no_argument {
    assert_that(cargo_process("new"),
                execs().with_status(1)
                       .with_stderr("Invalid arguments.
Usage:
    cargo new [options] <path>
    cargo new -h | --help
"));
})

test!(existing {
    let dst = paths::root().join("foo");
    fs::mkdir(&dst, UserRWX).assert();
    assert_that(cargo_process("new").arg("foo"),
                execs().with_status(101)
                       .with_stderr(format!("Destination `{}` already exists\n",
                                            dst.display())));
})

test!(finds_author_user {
    assert_that(cargo_process("new").arg("foo").env("USER", Some("foo")),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let toml = File::open(&toml).read_to_string().assert();
    assert!(toml.as_slice().contains(r#"authors = ["foo"]"#));
})

test!(finds_author_git {
    my_process("git").args(["config", "--global", "user.name", "bar"])
                     .exec().assert();
    my_process("git").args(["config", "--global", "user.email", "baz"])
                     .exec().assert();
    assert_that(cargo_process("new").arg("foo").env("USER", Some("foo")),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let toml = File::open(&toml).read_to_string().assert();
    assert!(toml.as_slice().contains(r#"authors = ["bar <baz>"]"#));
})

test!(author_prefers_cargo {
    my_process("git").args(["config", "--global", "user.name", "bar"])
                     .exec().assert();
    my_process("git").args(["config", "--global", "user.email", "baz"])
                     .exec().assert();
    let root = paths::root();
    fs::mkdir(&root.join(".cargo"), UserRWX).assert();
    File::create(&root.join(".cargo/config")).write_str(r#"
        [cargo-new]
        name = "new-foo"
        email = "new-bar"
        git = false
    "#).assert();

    assert_that(cargo_process("new").arg("foo").env("USER", Some("foo")),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let toml = File::open(&toml).read_to_string().assert();
    assert!(toml.as_slice().contains(r#"authors = ["new-foo <new-bar>"]"#));
    assert!(!root.join("foo/.gitignore").exists());
})

test!(git_prefers_command_line {
    let root = paths::root();
    fs::mkdir(&root.join(".cargo"), UserRWX).assert();
    File::create(&root.join(".cargo/config")).write_str(r#"
        [cargo-new]
        git = false
        name = "foo"
        email = "bar"
    "#).assert();

    assert_that(cargo_process("new").arg("foo").arg("--git")
                                    .env("USER", Some("foo")),
                execs().with_status(0));
    assert!(root.join("foo/.gitignore").exists());
})
<commit_msg>auto merge of #631 : alexcrichton/cargo/issue-514, r=brson<commit_after>use std::io::{fs, UserRWX, File, TempDir};
use std::io::fs::PathExtensions;
use std::os;

use support::{execs, paths, cargo_dir, ResultTest};
use hamcrest::{assert_that, existing_file, existing_dir, is_not};

use cargo::util::{process, ProcessBuilder};

fn setup() {
}

fn my_process(s: &str) -> ProcessBuilder {
    process(s)
        .cwd(paths::root())
        .env("HOME", Some(paths::home()))
}

fn cargo_process(s: &str) -> ProcessBuilder {
    process(cargo_dir().join("cargo")).arg(s)
        .cwd(paths::root())
        .env("HOME", Some(paths::home()))
}

test!(simple_lib {
    os::setenv("USER", "foo");
    assert_that(cargo_process("new").arg("foo").arg("--no-git"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/lib.rs"), existing_file());
    assert_that(&paths::root().join("foo/.gitignore"), is_not(existing_file()));

    assert_that(cargo_process("build").cwd(paths::root().join("foo")),
                execs().with_status(0));
})

test!(simple_bin {
    os::setenv("USER", "foo");
    assert_that(cargo_process("new").arg("foo").arg("--bin"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/main.rs"), existing_file());

    assert_that(cargo_process("build").cwd(paths::root().join("foo")),
                execs().with_status(0));
    assert_that(&paths::root().join(format!("foo/target/foo{}",
                                            os::consts::EXE_SUFFIX)),
                existing_file());
})

test!(simple_git {
    os::setenv("USER", "foo");
    assert_that(cargo_process("new").arg("foo"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/lib.rs"), existing_file());
    assert_that(&paths::root().join("foo/.git"), existing_dir());
    assert_that(&paths::root().join("foo/.gitignore"), existing_file());

    assert_that(cargo_process("build").cwd(paths::root().join("foo")),
                execs().with_status(0));
})

test!(simple_travis {
    os::setenv("USER", "foo");
    assert_that(cargo_process("new").arg("foo").arg("--travis"),
                execs().with_status(0));

    assert_that(&paths::root().join("foo"), existing_dir());
    assert_that(&paths::root().join("foo/Cargo.toml"), existing_file());
    assert_that(&paths::root().join("foo/src/lib.rs"), existing_file());
    assert_that(&paths::root().join("foo/.travis.yml"), existing_file());

    assert_that(cargo_process("build").cwd(paths::root().join("foo")),
                execs().with_status(0));
})

test!(no_argument {
    assert_that(cargo_process("new"),
                execs().with_status(1)
                       .with_stderr("Invalid arguments.
Usage:
    cargo new [options] <path>
    cargo new -h | --help
"));
})

test!(existing {
    let dst = paths::root().join("foo");
    fs::mkdir(&dst, UserRWX).assert();
    assert_that(cargo_process("new").arg("foo"),
                execs().with_status(101)
                       .with_stderr(format!("Destination `{}` already exists\n",
                                            dst.display())));
})

test!(finds_author_user {
    // Use a temp dir to make sure we don't pick up .cargo/config somewhere in
    // the hierarchy
    let td = TempDir::new("cargo").unwrap();
    assert_that(cargo_process("new").arg("foo").env("USER", Some("foo"))
                                    .cwd(td.path().clone()),
                execs().with_status(0));

    let toml = td.path().join("foo/Cargo.toml");
    let toml = File::open(&toml).read_to_string().assert();
    assert!(toml.as_slice().contains(r#"authors = ["foo"]"#));
})

test!(finds_author_git {
    my_process("git").args(["config", "--global", "user.name", "bar"])
                     .exec().assert();
    my_process("git").args(["config", "--global", "user.email", "baz"])
                     .exec().assert();
    assert_that(cargo_process("new").arg("foo").env("USER", Some("foo")),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let toml = File::open(&toml).read_to_string().assert();
    assert!(toml.as_slice().contains(r#"authors = ["bar <baz>"]"#));
})

test!(author_prefers_cargo {
    my_process("git").args(["config", "--global", "user.name", "bar"])
                     .exec().assert();
    my_process("git").args(["config", "--global", "user.email", "baz"])
                     .exec().assert();
    let root = paths::root();
    fs::mkdir(&root.join(".cargo"), UserRWX).assert();
    File::create(&root.join(".cargo/config")).write_str(r#"
        [cargo-new]
        name = "new-foo"
        email = "new-bar"
        git = false
    "#).assert();

    assert_that(cargo_process("new").arg("foo").env("USER", Some("foo")),
                execs().with_status(0));

    let toml = paths::root().join("foo/Cargo.toml");
    let toml = File::open(&toml).read_to_string().assert();
    assert!(toml.as_slice().contains(r#"authors = ["new-foo <new-bar>"]"#));
    assert!(!root.join("foo/.gitignore").exists());
})

test!(git_prefers_command_line {
    let root = paths::root();
    fs::mkdir(&root.join(".cargo"), UserRWX).assert();
    File::create(&root.join(".cargo/config")).write_str(r#"
        [cargo-new]
        git = false
        name = "foo"
        email = "bar"
    "#).assert();

    assert_that(cargo_process("new").arg("foo").arg("--git")
                                    .env("USER", Some("foo")),
                execs().with_status(0));
    assert!(root.join("foo/.gitignore").exists());
})
<|endoftext|>


<commit_before>use backend::Backend;

/// The row trait which is used for [`FromSqlRow`][]. Apps should not need to
/// concern themselves with this trait.
///
/// [`FromSqlRow`]: ../types/trait.FromSqlRow.html
pub trait Row<DB: Backend> {
    fn take(&mut self) -> Option<&DB::RawValue>;
    fn next_is_null(&self, count: usize) -> bool;

    fn advance(&mut self, count: usize) {
        for _ in 0..count {
            self.take();
        }
    }
}
<commit_msg>Document the `row` module<commit_after>//! Contains the `Row` trait

use backend::Backend;

/// The row trait which is used for [`FromSqlRow`][]. Apps should not need to
/// concern themselves with this trait.
///
/// [`FromSqlRow`]: ../types/trait.FromSqlRow.html
pub trait Row<DB: Backend> {
    /// Returns the value of the next column in the row.
    fn take(&mut self) -> Option<&DB::RawValue>;

    /// Returns whether the next `count` columns are all `NULL`.
    fn next_is_null(&self, count: usize) -> bool;

    /// Skips the next `count` columns. This method must be called if you are
    /// choosing not to call `take` as a result of `next_is_null` returning
    /// `true`.
    fn advance(&mut self, count: usize) {
        for _ in 0..count {
            self.take();
        }
    }
}
<|endoftext|>


<commit_before>struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

// This one can be elided.
fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

// Q: Why do I need a lifetime here?
pub fn join_iters<'a, T: Iterator>(vecs: T) -> Vec<u8>
        where T::Item: IntoIterator<Item=&'a u8> {
    vecs.flat_map(|b| b.into_iter())
        .cloned()
        .collect()
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();

    let ints = vec![vec![78, 43, 1],
                    vec![1, 45, 66, 2],
                    vec![99, 8, 20]];

    assert_eq!(first_five(&name), "Andre");

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);

    assert_eq!(join_iters(ints.iter()), vec![78, 43, 1, 1, 45, 66, 2, 99, 8, 20]);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - Question: Why can't Rust ensure/infer/elide this scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<commit_msg>Added unit type to allow returning a vec of borrowed types<commit_after>#[derive(PartialEq, Eq, Debug)]
struct Age(u8);

struct Person<'a> {
    name: &'static str,
    parent: Option<&'a Person<'a>>,
}

impl<'a> Person<'a> {
    fn new(name: &'static str, parent: Option<&'a Person<'a>>) -> Person<'a> {
        Person{name: name, parent: parent}
    }

    fn parents_name(&self) -> Option<&'static str> {
        match self.parent {
            Some(p) => Some(p.name),
            None => None,
        }
    }
}

// This one can be elided.
fn first_five<'a>(value: &'a String) -> &'a str {
    &value[..5]
}

// Here we are promising Rust that all of the borrowed u8's
// live for the same scope.
// Q: Why do I need a lifetime here?
fn join_iters<'a, T: Iterator>(vecs: T) -> Vec<&'a Age>
        where T::Item: IntoIterator<Item=&'a Age> {
    vecs.flat_map(|b| b.into_iter())
        .collect()
}

#[test]
fn it_works() {
    let jane = Person::new("Jane", None);
    let tom = Person::new("Tom", Some(&jane));
    let name = "Andrew".to_owned();
    let a = 43;
    let ints = vec![vec![Age(90), Age(80)],
                    vec![Age(2)]];

    assert_eq!(first_five(&name), "Andre");

    assert_eq!(tom.name, "Tom");
    assert_eq!(jane.name, "Jane");
    assert_eq!(tom.parent.unwrap().name, "Jane");
    assert_eq!(tom.parents_name(), Some("Jane"));
    assert_eq!(jane.parents_name(), None);

    assert_eq!(join_iters(ints.iter()), vec![&Age(90), &Age(80), &Age(2)]);
}

// - We are making a promise to the compiler that all of these things live for atleast the same scope.
// - We are not asking the compiler to "create a lifetime". We are just telling it to complain if we
//   don't do what we say we are doing.
// - Why? Because this allows Rust to ensure we cannot cause common memory allocation bugs. It does
//   this at compile time. It's a zero-cost abstraction because there is no runtime penalty.
// - It makes code look "uglier". But this is the wrong mindset for writing systems-level programs.
//   The emphasis here is on safety, not expressiveness.
// - Question: Why can't Rust ensure/infer/elide this scenario? Surely any reference to a Parent
//   must *always* live for the same or a bigger scope???
//   - There is an open RFC for this
//   - It may be complex to implement and/or slow down compilation
//   - Eliding in more cases may prevent newcomer Rust programmers from ever encountering
//     lifetimes, which could have a negative impact in the long run. Pedagogy!
<|endoftext|>


<commit_before>#![crate_name = "rboy"]

#![feature(io, std_misc, core, os, env)]

#[macro_use]
extern crate log;

extern crate getopts;

extern crate sdl2;

extern crate rboy;

use rboy::device::Device;
use std::time::Duration;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};
use std::old_io::timer;

static SCALE: usize = 2;
static EXITCODE_INCORRECTOPTIONS: i32 = 1;
static EXITCODE_CPULOADFAILS: i32 = 2;

#[cfg(not(test))]
fn set_exit_status(exitcode: i32)
{
	std::env::set_exit_status(exitcode);
}

fn main() {
	let mut opts = getopts::Options::new();
	opts.optflag("s", "serial", "Output serial to stdout");
	opts.optflag("c", "classic", "Force Classic mode");

	let string_args = std::env::args().map(|v| v.into_string().unwrap()).collect::<Vec<_>>();

	let matches = match opts.parse(&string_args[1..]) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f); return }
	};

	let filename = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		let mut info_start = string_args[0].clone();
		info_start.push_str(" <filename>");
		println!("{}", opts.usage(info_start.as_slice()));
		set_exit_status(EXITCODE_INCORRECTOPTIONS);
		return;
	};

	sdl2::init(sdl2::INIT_VIDEO);
	let window = match sdl2::video::Window::new("RBoy - A gameboy in Rust",
												sdl2::video::WindowPos::PosUndefined,
												sdl2::video::WindowPos::PosUndefined,
												160*SCALE as i32,
												144*SCALE as i32,
												sdl2::video::WindowFlags::empty()) {
		Ok(window) => window,
		Err(err) => panic!("failed to open window: {}", err),
	};
	let renderer = match sdl2::render::Renderer::from_window(window, sdl2::render::RenderDriverIndex::Auto, sdl2::render::ACCELERATED) {
		Ok(screen) => screen,
		Err(err) => panic!("failed to open screen: {}", err),
	};

	let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
	let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
	let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
	let arc = Arc::new(RwLock::new(rawscreen));
	let arc2 = arc.clone();

	let cpuloop_thread = std::thread::Thread::scoped(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, filename.as_slice(), &matches));

	let mut timer = timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));

	'main : loop {
		let _ = periodic.recv();
		match sdl_rx.try_recv() {
			Err(Disconnected) => { break 'main },
			Ok(_) => recalculate_screen(&renderer, &arc),
			Err(Empty) => {},
		}
		'event : loop {
			match sdl2::event::poll_event() {
				sdl2::event::Event::Quit { .. } => break 'main,
				sdl2::event::Event::None => break 'event,
				sdl2::event::Event::KeyDown { keycode: sdl2::keycode::KeyCode::Escape, .. }
					=> break 'main,
				sdl2::event::Event::KeyDown { keycode: sdl2::keycode::KeyCode::LShift, .. }
					=> { let _ = sdl_tx.send(GBEvent::SpeedUp); },
				sdl2::event::Event::KeyUp { keycode: sdl2::keycode::KeyCode::LShift, .. }
					=> { let _ = sdl_tx.send(GBEvent::SlowDown); },
				sdl2::event::Event::KeyDown { keycode: sdlkey, .. } => {
					match sdl_to_keypad(sdlkey) {
						Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
						None => {},
					}
				},
				sdl2::event::Event::KeyUp { keycode: sdlkey, .. } => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
						None => {},
					}
				},
				_ => {}
			}
		}
	}

	drop(sdl_tx); // Disconnect such that the cpuloop will exit
	let _ = cpuloop_thread.join();
}

fn sdl_to_keypad(key: sdl2::keycode::KeyCode) -> Option<rboy::KeypadKey> {
	match key {
		sdl2::keycode::KeyCode::Z => Some(rboy::KeypadKey::A),
		sdl2::keycode::KeyCode::X => Some(rboy::KeypadKey::B),
		sdl2::keycode::KeyCode::Up => Some(rboy::KeypadKey::Up),
		sdl2::keycode::KeyCode::Down => Some(rboy::KeypadKey::Down),
		sdl2::keycode::KeyCode::Left => Some(rboy::KeypadKey::Left),
		sdl2::keycode::KeyCode::Right => Some(rboy::KeypadKey::Right),
		sdl2::keycode::KeyCode::Space => Some(rboy::KeypadKey::Select),
		sdl2::keycode::KeyCode::Return => Some(rboy::KeypadKey::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl2::render::Renderer, arc: &Arc<RwLock<Vec<u8>>>) {
	let mut drawer = screen.drawer();
	drawer.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF));
	drawer.clear();

	let data =  arc.read().unwrap().clone();
	for y in range(0, 144) {
		for x in range(0, 160) {
			drawer.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
															data[y*160*3 + x*3 + 1],
															data[y*160*3 + x*3 + 2]));
			drawer.draw_rect(sdl2::rect::Rect::new((x*SCALE) as i32, (y*SCALE) as i32, SCALE as i32, SCALE as i32));
		}
	}
	drawer.present();
}

enum GBEvent {
	KeyUp(rboy::KeypadKey),
	KeyDown(rboy::KeypadKey),
	SpeedUp,
	SlowDown,
}

fn cpuloop(cpu_tx: &Sender<u32>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, filename: &str, matches: &getopts::Matches) {
	let opt_c = match matches.opt_present("classic") {
		true => Device::new(filename),
		false => Device::new_cgb(filename),
	};
	let mut c = match opt_c
	{
		Some(cpu) => { cpu },
		None => { error!("Could not get a valid gameboy"); set_exit_status(EXITCODE_CPULOADFAILS); return; },
	};
	c.set_stdout(matches.opt_present("serial"));

	let mut timer = timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));
	let mut limit_speed = true;

	let waitticks = (4194.304f32 * 4.0) as u32;

	let mut ticks = 0;
	'cpuloop: loop {
		while ticks < waitticks {
			ticks += c.do_cycle();
			if c.check_and_reset_gpu_updated() {
				let mut data = arc.write().unwrap();
				let gpu_data = c.get_gpu_data();
				for i in range(0, data.len()) { data[i] = gpu_data[i]; }
				if cpu_tx.send(0).is_err() { break 'cpuloop };
			}
		}
		ticks -= waitticks;
		if limit_speed { let _ = periodic.recv(); }

		match cpu_rx.try_recv() {
			Ok(event) => match event {
				GBEvent::KeyUp(key) => c.keyup(key),
				GBEvent::KeyDown(key) => c.keydown(key),
				GBEvent::SpeedUp => limit_speed = false,
				GBEvent::SlowDown => limit_speed = true,
			},
			Err(Empty) => {},
			Err(Disconnected) => { break },
		};
	}
}
<commit_msg>Fix getting the os args<commit_after>#![crate_name = "rboy"]

#![feature(io, std_misc, core, env)]

#[macro_use]
extern crate log;

extern crate getopts;

extern crate sdl2;

extern crate rboy;

use rboy::device::Device;
use std::time::Duration;
use std::sync::{Arc,RwLock};
use std::sync::mpsc::{Sender,Receiver};
use std::sync::mpsc::TryRecvError::{Disconnected,Empty};
use std::old_io::timer;

static SCALE: usize = 2;
static EXITCODE_INCORRECTOPTIONS: i32 = 1;
static EXITCODE_CPULOADFAILS: i32 = 2;

#[cfg(not(test))]
fn set_exit_status(exitcode: i32)
{
	std::env::set_exit_status(exitcode);
}

fn main() {
	let mut opts = getopts::Options::new();
	opts.optflag("s", "serial", "Output serial to stdout");
	opts.optflag("c", "classic", "Force Classic mode");

	let args: Vec<_> = std::env::args().collect();

	let matches = match opts.parse(&args[1..]) {
		Ok(m) => { m }
		Err(f) => { println!("{}", f); return }
	};

	let filename = if !matches.free.is_empty() {
		matches.free[0].clone()
	} else {
		let mut info_start = args[0].clone();
		info_start.push_str(" <filename>");
		println!("{}", opts.usage(info_start.as_slice()));
		set_exit_status(EXITCODE_INCORRECTOPTIONS);
		return;
	};

	sdl2::init(sdl2::INIT_VIDEO);
	let window = match sdl2::video::Window::new("RBoy - A gameboy in Rust",
												sdl2::video::WindowPos::PosUndefined,
												sdl2::video::WindowPos::PosUndefined,
												160*SCALE as i32,
												144*SCALE as i32,
												sdl2::video::WindowFlags::empty()) {
		Ok(window) => window,
		Err(err) => panic!("failed to open window: {}", err),
	};
	let renderer = match sdl2::render::Renderer::from_window(window, sdl2::render::RenderDriverIndex::Auto, sdl2::render::ACCELERATED) {
		Ok(screen) => screen,
		Err(err) => panic!("failed to open screen: {}", err),
	};

	let (sdl_tx, cpu_rx) = std::sync::mpsc::channel();
	let (cpu_tx, sdl_rx) = std::sync::mpsc::channel();
	let rawscreen = ::std::iter::repeat(0u8).take(160*144*3).collect();
	let arc = Arc::new(RwLock::new(rawscreen));
	let arc2 = arc.clone();

	let cpuloop_thread = std::thread::Thread::scoped(move|| cpuloop(&cpu_tx, &cpu_rx, arc2, filename.as_slice(), &matches));

	let mut timer = timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));

	'main : loop {
		let _ = periodic.recv();
		match sdl_rx.try_recv() {
			Err(Disconnected) => { break 'main },
			Ok(_) => recalculate_screen(&renderer, &arc),
			Err(Empty) => {},
		}
		'event : loop {
			match sdl2::event::poll_event() {
				sdl2::event::Event::Quit { .. } => break 'main,
				sdl2::event::Event::None => break 'event,
				sdl2::event::Event::KeyDown { keycode: sdl2::keycode::KeyCode::Escape, .. }
					=> break 'main,
				sdl2::event::Event::KeyDown { keycode: sdl2::keycode::KeyCode::LShift, .. }
					=> { let _ = sdl_tx.send(GBEvent::SpeedUp); },
				sdl2::event::Event::KeyUp { keycode: sdl2::keycode::KeyCode::LShift, .. }
					=> { let _ = sdl_tx.send(GBEvent::SlowDown); },
				sdl2::event::Event::KeyDown { keycode: sdlkey, .. } => {
					match sdl_to_keypad(sdlkey) {
						Some(key) =>  { let _ = sdl_tx.send(GBEvent::KeyDown(key)); },
						None => {},
					}
				},
				sdl2::event::Event::KeyUp { keycode: sdlkey, .. } => {
					match sdl_to_keypad(sdlkey) {
						Some(key) => { let _ = sdl_tx.send(GBEvent::KeyUp(key)); },
						None => {},
					}
				},
				_ => {}
			}
		}
	}

	drop(sdl_tx); // Disconnect such that the cpuloop will exit
	let _ = cpuloop_thread.join();
}

fn sdl_to_keypad(key: sdl2::keycode::KeyCode) -> Option<rboy::KeypadKey> {
	match key {
		sdl2::keycode::KeyCode::Z => Some(rboy::KeypadKey::A),
		sdl2::keycode::KeyCode::X => Some(rboy::KeypadKey::B),
		sdl2::keycode::KeyCode::Up => Some(rboy::KeypadKey::Up),
		sdl2::keycode::KeyCode::Down => Some(rboy::KeypadKey::Down),
		sdl2::keycode::KeyCode::Left => Some(rboy::KeypadKey::Left),
		sdl2::keycode::KeyCode::Right => Some(rboy::KeypadKey::Right),
		sdl2::keycode::KeyCode::Space => Some(rboy::KeypadKey::Select),
		sdl2::keycode::KeyCode::Return => Some(rboy::KeypadKey::Start),
		_ => None,
	}
}

fn recalculate_screen(screen: &sdl2::render::Renderer, arc: &Arc<RwLock<Vec<u8>>>) {
	let mut drawer = screen.drawer();
	drawer.set_draw_color(sdl2::pixels::Color::RGB(0xFF, 0xFF, 0xFF));
	drawer.clear();

	let data =  arc.read().unwrap().clone();
	for y in range(0, 144) {
		for x in range(0, 160) {
			drawer.set_draw_color(sdl2::pixels::Color::RGB(data[y*160*3 + x*3 + 0],
															data[y*160*3 + x*3 + 1],
															data[y*160*3 + x*3 + 2]));
			drawer.draw_rect(sdl2::rect::Rect::new((x*SCALE) as i32, (y*SCALE) as i32, SCALE as i32, SCALE as i32));
		}
	}
	drawer.present();
}

enum GBEvent {
	KeyUp(rboy::KeypadKey),
	KeyDown(rboy::KeypadKey),
	SpeedUp,
	SlowDown,
}

fn cpuloop(cpu_tx: &Sender<u32>, cpu_rx: &Receiver<GBEvent>, arc: Arc<RwLock<Vec<u8>>>, filename: &str, matches: &getopts::Matches) {
	let opt_c = match matches.opt_present("classic") {
		true => Device::new(filename),
		false => Device::new_cgb(filename),
	};
	let mut c = match opt_c
	{
		Some(cpu) => { cpu },
		None => { error!("Could not get a valid gameboy"); set_exit_status(EXITCODE_CPULOADFAILS); return; },
	};
	c.set_stdout(matches.opt_present("serial"));

	let mut timer = timer::Timer::new().unwrap();
	let periodic = timer.periodic(Duration::milliseconds(8));
	let mut limit_speed = true;

	let waitticks = (4194.304f32 * 4.0) as u32;

	let mut ticks = 0;
	'cpuloop: loop {
		while ticks < waitticks {
			ticks += c.do_cycle();
			if c.check_and_reset_gpu_updated() {
				let mut data = arc.write().unwrap();
				let gpu_data = c.get_gpu_data();
				for i in range(0, data.len()) { data[i] = gpu_data[i]; }
				if cpu_tx.send(0).is_err() { break 'cpuloop };
			}
		}
		ticks -= waitticks;
		if limit_speed { let _ = periodic.recv(); }

		match cpu_rx.try_recv() {
			Ok(event) => match event {
				GBEvent::KeyUp(key) => c.keyup(key),
				GBEvent::KeyDown(key) => c.keydown(key),
				GBEvent::SpeedUp => limit_speed = false,
				GBEvent::SlowDown => limit_speed = true,
			},
			Err(Empty) => {},
			Err(Disconnected) => { break },
		};
	}
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;

use entity::{Entity, EntityType};

pub fn load_configuration(path: &str,
                          func: &Fn(&str) -> Vec<Entity>) -> Vec<Entity> {
    func(read_file_contents(path).as_str())
}

fn read_file_contents(path: &str) -> String {
    let mut contents = String::new();
    File::open(path)
        .expect(format!("File not found: {}", path).as_str())
        .read_to_string(&mut contents)
        .expect(format!("Unable to read file: {}", path).as_str());
    contents
}

pub fn hero_apply_item(hero: Entity, item: Entity) -> Result<Entity, String> {
    if !hero.is_type(EntityType::Hero) &&
        !item.is_type(EntityType::Item) {
        return Result::Err(String::from(
            "Must provide Hero and Item arguments, in that order"
        ));
    }
    Result::Ok(hero + item)
}

<commit_msg>Fix possible business issue<commit_after>use std::fs::File;
use std::io::prelude::*;

use entity::{Entity, EntityType};

pub fn load_configuration(path: &str,
                          func: &Fn(&str) -> Vec<Entity>) -> Vec<Entity> {
    func(read_file_contents(path).as_str())
}

fn read_file_contents(path: &str) -> String {
    let mut contents = String::new();
    File::open(path)
        .expect(format!("File not found: {}", path).as_str())
        .read_to_string(&mut contents)
        .expect(format!("Unable to read file: {}", path).as_str());
    contents
}

pub fn hero_apply_item(hero: Entity, item: Entity) -> Result<Entity, String> {
    if hero.is_type(EntityType::Hero) && item.is_type(EntityType::Item) {
        return Result::Ok(hero + item);
    }
    Result::Err(String::from(
        "Must provide Hero and Item arguments, in that order"
    ))
}

<|endoftext|>


<commit_before>extern crate git2;

use std::process::{Command, exit};
use self::git2::{Repository, Error, ErrorCode};

/// Gets the current branch.
///
/// # Examples
///
/// ```
/// let repo = try!(Repository::open("."));
/// let branchname = try!(branch(&repo));
/// ```
pub fn branch<'a>(repo: &'a Repository) -> Result<String, Error> {
    let head = match repo.head() {
        Ok(head) => Some(head),
            Err(ref e) if e.code() == ErrorCode::UnbornBranch ||
                          e.code() == ErrorCode::NotFound
                       => None,
            Err(e) => return Err(e),
    };
    let branchref = head.as_ref().and_then(|h| h.shorthand());
    let branchname = branchref.unwrap_or("HEAD (no branch)").to_string();

    Ok(branchname)
}

pub fn checkout(target_branch: &str) {
    let output = Command::new("git")
                         .arg("checkout")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Checking out {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

pub fn pull(target_remote: &str, target_branch: &str) {
    let output = Command::new("git")
                         .arg("pull")
                         .arg("--quiet")
                         .arg("--rebase=preserve")
                         .arg(target_remote)
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Pulling {} {} ...", target_remote, target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

pub fn rebase(target_branch: &str) {
    let output = Command::new("git")
                         .arg("rebase")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Rebasing {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}
<commit_msg>Fix indentation<commit_after>extern crate git2;

use std::process::{Command, exit};
use self::git2::{Repository, Error, ErrorCode};

/// Gets the current branch.
///
/// # Examples
///
/// ```
/// let repo = try!(Repository::open("."));
/// let branchname = try!(branch(&repo));
/// ```
pub fn branch<'a>(repo: &'a Repository) -> Result<String, Error> {
    let head = match repo.head() {
        Ok(head) => Some(head),
        Err(ref e) if e.code() == ErrorCode::UnbornBranch ||
                      e.code() == ErrorCode::NotFound
                   => None,
        Err(e) => return Err(e),
    };
    let branchref = head.as_ref().and_then(|h| h.shorthand());
    let branchname = branchref.unwrap_or("HEAD (no branch)").to_string();

    Ok(branchname)
}

pub fn checkout(target_branch: &str) {
    let output = Command::new("git")
                         .arg("checkout")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Checking out {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

pub fn pull(target_remote: &str, target_branch: &str) {
    let output = Command::new("git")
                         .arg("pull")
                         .arg("--quiet")
                         .arg("--rebase=preserve")
                         .arg(target_remote)
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Pulling {} {} ...", target_remote, target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}

pub fn rebase(target_branch: &str) {
    let output = Command::new("git")
                         .arg("rebase")
                         .arg(target_branch)
                         .output()
                         .unwrap_or_else(|e| {
                            panic!("failed to execute process: {}", e) });
    let status_code = output.status.code();

    println!("Rebasing {} ...", target_branch);

    match status_code {
        Some(0) => println!("{}", String::from_utf8_lossy(&output.stdout)),
        Some(_) => {
             println!("{}", String::from_utf8_lossy(&output.stderr));
             exit(status_code.unwrap());
        }
        None => println!("Something wrong happened"),
    }
}
<|endoftext|>