<commit_before>extern crate libc;
extern crate llvm_sys;

use std::ffi::{CString, CStr};

use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::target_machine::*;
use llvm_sys::target::*;
use llvm_sys::core as llvm;

// This should only be used for static strings
macro_rules! c_str_to_str {
    ($s:expr) => {
        ::std::str::from_utf8(CStr::from_ptr($s).to_bytes()).unwrap()
    }
}

// LLVM Wrappers

pub struct Context {
    pub context: LLVMContextRef
}

impl Context {
    pub fn new() -> Self {
        let context = unsafe {
            llvm::LLVMContextCreate()
        };
        Context { context: context }
    }

    pub fn create_builder(&self) -> Builder {
        let builder = unsafe {
            llvm::LLVMCreateBuilderInContext(self.context)
        };
        Builder { builder: builder }
    }

    pub fn module_create_with_name(&self, name: &str) -> Module {
        let c_name = CString::new(name).unwrap();
        let module = unsafe {
            llvm::LLVMModuleCreateWithNameInContext(c_name.as_ptr(), self.context)
        };
        Module { module: module }
    }

    pub fn void_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMVoidTypeInContext(self.context)
        }
    }

    pub fn int32_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt32TypeInContext(self.context)
        }
    }

    pub fn int16_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt16TypeInContext(self.context)
        }
    }

    pub fn int8_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt8TypeInContext(self.context)
        }
    }

    pub fn int1_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt1TypeInContext(self.context)
        }
    }

    pub fn const_bool(&self, val: bool) -> LLVMValueRef {
        let ty = self.int1_type();
        const_int(ty, val as u64, false)
    }

    pub fn append_basic_block(&self, func: LLVMValueRef, name: &str) -> LLVMBasicBlockRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMAppendBasicBlockInContext(self.context, func, c_name.as_ptr())
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMContextDispose(self.context);
        }
    }
}

// No `Drop` impl is needed as this is disposed of when the associated context is disposed
pub struct Module {
    pub module: LLVMModuleRef
}

impl Module {
    pub fn dump(&self) {
        unsafe {
            llvm::LLVMDumpModule(self.module)
        }
    }

    pub fn add_function(&mut self, func_ty: LLVMTypeRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMAddFunction(self.module, c_name.as_ptr(), func_ty)
        }
    }

    pub fn get_named_function(&mut self, name: &str) -> Option<LLVMValueRef> {
        let c_name = CString::new(name).unwrap();
        let res = unsafe {
            llvm::LLVMGetNamedFunction(self.module, c_name.as_ptr())
        };

        if res.is_null() {
            None
        } else {
            Some(res)
        }
    }
}

pub struct Builder {
    pub builder: LLVMBuilderRef
}

impl Builder {
    pub fn position_at_end(&mut self, basic_block: LLVMBasicBlockRef) {
        unsafe {
            llvm::LLVMPositionBuilderAtEnd(self.builder, basic_block);
        }
    }

    pub fn build_ret(&mut self, ret_val: LLVMValueRef) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildRet(self.builder, ret_val)
        }
    }

    pub fn build_ret_void(&self) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildRetVoid(self.builder)
        }
    }

    pub fn build_alloca(&mut self, ty: LLVMTypeRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildAlloca(self.builder, ty, c_name.as_ptr())
        }
    }

    pub fn build_store(&mut self, val: LLVMValueRef, ptr: LLVMValueRef) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildStore(self.builder, val, ptr)
        }
    }

    pub fn build_load(&mut self, ptr: LLVMValueRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildLoad(self.builder, ptr, c_name.as_ptr())
        }
    }

    pub fn build_call(&mut self, func: LLVMValueRef, mut args: Vec<LLVMValueRef>,
                      name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildCall(self.builder, func, args.as_mut_ptr(), args.len() as u32,
                                c_name.as_ptr())
        }
    }

    pub fn build_add(&mut self, lhs: LLVMValueRef, rhs: LLVMValueRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildAdd(self.builder, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_sub(&mut self, lhs: LLVMValueRef, rhs: LLVMValueRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildSub(self.builder, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_mul(&mut self, lhs: LLVMValueRef, rhs: LLVMValueRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildMul(self.builder, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_sdiv(&mut self, lhs: LLVMValueRef, rhs: LLVMValueRef,
                      name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildSDiv(self.builder, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_icmp(&mut self, op: LLVMIntPredicate, lhs: LLVMValueRef, rhs: LLVMValueRef,
                      name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildICmp(self.builder, op, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_global_string(&self, s: &str, name: &str) -> LLVMValueRef {
        let c_s = CString::new(s).unwrap();
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildGlobalString(self.builder, c_s.as_ptr(), c_name.as_ptr())
        }
    }

    pub fn build_in_bounds_gep(&self, ptr: LLVMValueRef, mut indices: Vec<LLVMValueRef>,
                               name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildInBoundsGEP(self.builder, ptr, indices.as_mut_ptr(),
                                       indices.len() as u32, c_name.as_ptr())
        }
    }

    pub fn build_cond_br(&self, cond: LLVMValueRef, then: LLVMBasicBlockRef,
                         else_: LLVMBasicBlockRef) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildCondBr(self.builder, cond, then, else_)
        }
    }

    pub fn build_br(&self, dest: LLVMBasicBlockRef) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildBr(self.builder, dest)
        }
    }

}

impl Drop for Builder {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeBuilder(self.builder);
        }
    }
}

pub fn const_int(ty: LLVMTypeRef, val: u64, signed: bool) -> LLVMValueRef {
    unsafe {
        llvm::LLVMConstInt(ty, val, signed as i32)
    }
}

pub fn function_type(ret_ty: LLVMTypeRef, mut param_types: Vec<LLVMTypeRef>,
                     is_var_args: bool) -> LLVMTypeRef {
    unsafe {
        llvm::LLVMFunctionType(ret_ty, param_types.as_mut_ptr(), param_types.len() as u32,
                               is_var_args as i32)
    }
}

pub fn pointer_type(ty: LLVMTypeRef, address_space: u32) -> LLVMTypeRef {
    unsafe {
        llvm::LLVMPointerType(ty, address_space)
    }
}

pub fn get_first_param(func: LLVMValueRef) -> Option<LLVMValueRef> {
    let res = unsafe {
        llvm::LLVMGetFirstParam(func)
    };
    // TODO: We should replace this API with a safe iterator in the future
    if res.is_null() {
        None
    } else {
        Some(res)
    }
}

pub fn get_next_param(param: LLVMValueRef) -> Option<LLVMValueRef> {
    let res = unsafe {
        llvm::LLVMGetNextParam(param)
    };
    // TODO: We should replace this API with a safe iterator in the future
    if res.is_null() {
        None
    } else {
        Some(res)
    }
}

pub fn set_value_name(val: LLVMValueRef, name: &str) {
    let c_name = CString::new(name).unwrap();
    unsafe {
        llvm::LLVMSetValueName(val, c_name.as_ptr());
    }
}

pub fn create_pass_manager() -> LLVMPassManagerRef {
    unsafe {
        llvm::LLVMCreatePassManager()
    }
}

pub fn print_module_to_file(module: &Module, path: &str) -> Result<(), &'static str> {
    let c_path = CString::new(path).unwrap();
    let mut em: usize = 0;
    let em_ptr: *mut usize = &mut em;
    unsafe {
        llvm::LLVMPrintModuleToFile(module.module, c_path.as_ptr(), em_ptr as *mut *mut i8);
        if em == 0 { // no error message was set
            Ok(())
        } else {
            Err(c_str_to_str!(em as *const i8))
        }
    }
}

pub fn print_module_to_string<'a>(module: &'a Module) -> String {
    unsafe {
        let c_str = llvm::LLVMPrintModuleToString(module.module);
        let len = libc::strlen(c_str);
        String::from_raw_parts(c_str as *mut u8, (len + 1) as usize, (len + 1) as usize)
    }
}

pub fn get_target_from_name(name: &str) -> Option<LLVMTargetRef> {
    let c_name = CString::new(name).unwrap();
    let res = unsafe {
        LLVMGetTargetFromName(c_name.as_ptr())
    };

    if res.is_null() {
        None
    } else {
        Some(res)
    }
}

pub fn create_target_machine(target: LLVMTargetRef, triple: &str, cpu: &str, features: &str,
                             level: LLVMCodeGenOptLevel, reloc: LLVMRelocMode,
                             model: LLVMCodeModel) -> LLVMTargetMachineRef {
    let c_triple = CString::new(triple).unwrap();
    let c_cpu = CString::new(cpu).unwrap();
    let c_features = CString::new(features).unwrap();
    unsafe {
        LLVMCreateTargetMachine(target, c_triple.as_ptr(), c_cpu.as_ptr(),
                                c_features.as_ptr(), level, reloc, model)
    }
}

pub fn target_machine_emit_to_file(target: LLVMTargetMachineRef, module: &mut Module, path: &str,
                                   file_type: LLVMCodeGenFileType) -> Result<(), &'static str> {
    let c_path = CString::new(path).unwrap();
    let mut em: usize = 0;
    let em_ptr: *mut usize = &mut em;
    unsafe {
        LLVMTargetMachineEmitToFile(target, module.module, c_path.as_ptr() as *mut i8,
                                    file_type, em_ptr as *mut *mut i8);
        if em == 0 { // no error message was set
            Ok(())
        } else {
            Err(c_str_to_str!(em as *const i8))
        }
    }
}

pub fn initialize_native_target() {
    unsafe {
        LLVM_InitializeNativeTarget();
    }
}

pub fn initialize_native_asm_printer() {
    unsafe {
        LLVM_InitializeNativeAsmPrinter();
    }
}

pub fn get_default_target_triple<'a>() -> &'a str {
    unsafe {
        c_str_to_str!(LLVMGetDefaultTargetTriple())
    }
}
<commit_msg>Add int64 type<commit_after>extern crate libc;
extern crate llvm_sys;

use std::ffi::{CString, CStr};

use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::target_machine::*;
use llvm_sys::target::*;
use llvm_sys::core as llvm;

// This should only be used for static strings
macro_rules! c_str_to_str {
    ($s:expr) => {
        ::std::str::from_utf8(CStr::from_ptr($s).to_bytes()).unwrap()
    }
}

// LLVM Wrappers

pub struct Context {
    pub context: LLVMContextRef
}

impl Context {
    pub fn new() -> Self {
        let context = unsafe {
            llvm::LLVMContextCreate()
        };
        Context { context: context }
    }

    pub fn create_builder(&self) -> Builder {
        let builder = unsafe {
            llvm::LLVMCreateBuilderInContext(self.context)
        };
        Builder { builder: builder }
    }

    pub fn module_create_with_name(&self, name: &str) -> Module {
        let c_name = CString::new(name).unwrap();
        let module = unsafe {
            llvm::LLVMModuleCreateWithNameInContext(c_name.as_ptr(), self.context)
        };
        Module { module: module }
    }

    pub fn void_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMVoidTypeInContext(self.context)
        }
    }

    pub fn int64_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt64TypeInContext(self.context)
        }
    }

    pub fn int32_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt32TypeInContext(self.context)
        }
    }

    pub fn int16_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt16TypeInContext(self.context)
        }
    }

    pub fn int8_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt8TypeInContext(self.context)
        }
    }

    pub fn int1_type(&self) -> LLVMTypeRef {
        unsafe {
            llvm::LLVMInt1TypeInContext(self.context)
        }
    }

    pub fn const_bool(&self, val: bool) -> LLVMValueRef {
        let ty = self.int1_type();
        const_int(ty, val as u64, false)
    }

    pub fn append_basic_block(&self, func: LLVMValueRef, name: &str) -> LLVMBasicBlockRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMAppendBasicBlockInContext(self.context, func, c_name.as_ptr())
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMContextDispose(self.context);
        }
    }
}

// No `Drop` impl is needed as this is disposed of when the associated context is disposed
pub struct Module {
    pub module: LLVMModuleRef
}

impl Module {
    pub fn dump(&self) {
        unsafe {
            llvm::LLVMDumpModule(self.module)
        }
    }

    pub fn add_function(&mut self, func_ty: LLVMTypeRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMAddFunction(self.module, c_name.as_ptr(), func_ty)
        }
    }

    pub fn get_named_function(&mut self, name: &str) -> Option<LLVMValueRef> {
        let c_name = CString::new(name).unwrap();
        let res = unsafe {
            llvm::LLVMGetNamedFunction(self.module, c_name.as_ptr())
        };

        if res.is_null() {
            None
        } else {
            Some(res)
        }
    }
}

pub struct Builder {
    pub builder: LLVMBuilderRef
}

impl Builder {
    pub fn position_at_end(&mut self, basic_block: LLVMBasicBlockRef) {
        unsafe {
            llvm::LLVMPositionBuilderAtEnd(self.builder, basic_block);
        }
    }

    pub fn build_ret(&mut self, ret_val: LLVMValueRef) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildRet(self.builder, ret_val)
        }
    }

    pub fn build_ret_void(&self) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildRetVoid(self.builder)
        }
    }

    pub fn build_alloca(&mut self, ty: LLVMTypeRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildAlloca(self.builder, ty, c_name.as_ptr())
        }
    }

    pub fn build_store(&mut self, val: LLVMValueRef, ptr: LLVMValueRef) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildStore(self.builder, val, ptr)
        }
    }

    pub fn build_load(&mut self, ptr: LLVMValueRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildLoad(self.builder, ptr, c_name.as_ptr())
        }
    }

    pub fn build_call(&mut self, func: LLVMValueRef, mut args: Vec<LLVMValueRef>,
                      name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildCall(self.builder, func, args.as_mut_ptr(), args.len() as u32,
                                c_name.as_ptr())
        }
    }

    pub fn build_add(&mut self, lhs: LLVMValueRef, rhs: LLVMValueRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildAdd(self.builder, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_sub(&mut self, lhs: LLVMValueRef, rhs: LLVMValueRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildSub(self.builder, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_mul(&mut self, lhs: LLVMValueRef, rhs: LLVMValueRef, name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildMul(self.builder, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_sdiv(&mut self, lhs: LLVMValueRef, rhs: LLVMValueRef,
                      name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildSDiv(self.builder, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_icmp(&mut self, op: LLVMIntPredicate, lhs: LLVMValueRef, rhs: LLVMValueRef,
                      name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildICmp(self.builder, op, lhs, rhs, c_name.as_ptr())
        }
    }

    pub fn build_global_string(&self, s: &str, name: &str) -> LLVMValueRef {
        let c_s = CString::new(s).unwrap();
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildGlobalString(self.builder, c_s.as_ptr(), c_name.as_ptr())
        }
    }

    pub fn build_in_bounds_gep(&self, ptr: LLVMValueRef, mut indices: Vec<LLVMValueRef>,
                               name: &str) -> LLVMValueRef {
        let c_name = CString::new(name).unwrap();
        unsafe {
            llvm::LLVMBuildInBoundsGEP(self.builder, ptr, indices.as_mut_ptr(),
                                       indices.len() as u32, c_name.as_ptr())
        }
    }

    pub fn build_cond_br(&self, cond: LLVMValueRef, then: LLVMBasicBlockRef,
                         else_: LLVMBasicBlockRef) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildCondBr(self.builder, cond, then, else_)
        }
    }

    pub fn build_br(&self, dest: LLVMBasicBlockRef) -> LLVMValueRef {
        unsafe {
            llvm::LLVMBuildBr(self.builder, dest)
        }
    }

}

impl Drop for Builder {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMDisposeBuilder(self.builder);
        }
    }
}

pub fn const_int(ty: LLVMTypeRef, val: u64, signed: bool) -> LLVMValueRef {
    unsafe {
        llvm::LLVMConstInt(ty, val, signed as i32)
    }
}

pub fn function_type(ret_ty: LLVMTypeRef, mut param_types: Vec<LLVMTypeRef>,
                     is_var_args: bool) -> LLVMTypeRef {
    unsafe {
        llvm::LLVMFunctionType(ret_ty, param_types.as_mut_ptr(), param_types.len() as u32,
                               is_var_args as i32)
    }
}

pub fn pointer_type(ty: LLVMTypeRef, address_space: u32) -> LLVMTypeRef {
    unsafe {
        llvm::LLVMPointerType(ty, address_space)
    }
}

pub fn get_first_param(func: LLVMValueRef) -> Option<LLVMValueRef> {
    let res = unsafe {
        llvm::LLVMGetFirstParam(func)
    };
    // TODO: We should replace this API with a safe iterator in the future
    if res.is_null() {
        None
    } else {
        Some(res)
    }
}

pub fn get_next_param(param: LLVMValueRef) -> Option<LLVMValueRef> {
    let res = unsafe {
        llvm::LLVMGetNextParam(param)
    };
    // TODO: We should replace this API with a safe iterator in the future
    if res.is_null() {
        None
    } else {
        Some(res)
    }
}

pub fn set_value_name(val: LLVMValueRef, name: &str) {
    let c_name = CString::new(name).unwrap();
    unsafe {
        llvm::LLVMSetValueName(val, c_name.as_ptr());
    }
}

pub fn create_pass_manager() -> LLVMPassManagerRef {
    unsafe {
        llvm::LLVMCreatePassManager()
    }
}

pub fn print_module_to_file(module: &Module, path: &str) -> Result<(), &'static str> {
    let c_path = CString::new(path).unwrap();
    let mut em: usize = 0;
    let em_ptr: *mut usize = &mut em;
    unsafe {
        llvm::LLVMPrintModuleToFile(module.module, c_path.as_ptr(), em_ptr as *mut *mut i8);
        if em == 0 { // no error message was set
            Ok(())
        } else {
            Err(c_str_to_str!(em as *const i8))
        }
    }
}

pub fn print_module_to_string<'a>(module: &'a Module) -> String {
    unsafe {
        let c_str = llvm::LLVMPrintModuleToString(module.module);
        let len = libc::strlen(c_str);
        String::from_raw_parts(c_str as *mut u8, (len + 1) as usize, (len + 1) as usize)
    }
}

pub fn get_target_from_name(name: &str) -> Option<LLVMTargetRef> {
    let c_name = CString::new(name).unwrap();
    let res = unsafe {
        LLVMGetTargetFromName(c_name.as_ptr())
    };

    if res.is_null() {
        None
    } else {
        Some(res)
    }
}

pub fn create_target_machine(target: LLVMTargetRef, triple: &str, cpu: &str, features: &str,
                             level: LLVMCodeGenOptLevel, reloc: LLVMRelocMode,
                             model: LLVMCodeModel) -> LLVMTargetMachineRef {
    let c_triple = CString::new(triple).unwrap();
    let c_cpu = CString::new(cpu).unwrap();
    let c_features = CString::new(features).unwrap();
    unsafe {
        LLVMCreateTargetMachine(target, c_triple.as_ptr(), c_cpu.as_ptr(),
                                c_features.as_ptr(), level, reloc, model)
    }
}

pub fn target_machine_emit_to_file(target: LLVMTargetMachineRef, module: &mut Module, path: &str,
                                   file_type: LLVMCodeGenFileType) -> Result<(), &'static str> {
    let c_path = CString::new(path).unwrap();
    let mut em: usize = 0;
    let em_ptr: *mut usize = &mut em;
    unsafe {
        LLVMTargetMachineEmitToFile(target, module.module, c_path.as_ptr() as *mut i8,
                                    file_type, em_ptr as *mut *mut i8);
        if em == 0 { // no error message was set
            Ok(())
        } else {
            Err(c_str_to_str!(em as *const i8))
        }
    }
}

pub fn initialize_native_target() {
    unsafe {
        LLVM_InitializeNativeTarget();
    }
}

pub fn initialize_native_asm_printer() {
    unsafe {
        LLVM_InitializeNativeAsmPrinter();
    }
}

pub fn get_default_target_triple<'a>() -> &'a str {
    unsafe {
        c_str_to_str!(LLVMGetDefaultTargetTriple())
    }
}
<|endoftext|>


<commit_before>//! Runtime support for the async/await syntax for futures.
//!
//! This crate serves as a masquerade over the `futures` crate itself,
//! reexporting all of its contents. It's intended that you'll do:
//!
//! ```
//! extern crate futures_await as futures;
//! ```
//!
//! This crate adds a `prelude` module which contains various traits as well as
//! the `async` and `await` macros you'll likely want to use.
//!
//! See the crates's README for more information about usage.

#![feature(conservative_impl_trait)]
#![feature(generator_trait)]
#![feature(use_extern_macros)]
#![feature(never_type)]
#![feature(on_unimplemented)]

extern crate futures_async_macro; // the compiler lies that this has no effect
extern crate futures_await_macro;
extern crate futures;

pub use futures::*;

pub mod prelude {
    pub use {Future, Stream, Sink, Poll, Async, AsyncSink, StartSend};
    pub use {IntoFuture};
    pub use futures_async_macro::{async, async_stream, async_block, async_stream_block};
    pub use futures_await_macro::{await, stream_yield};
}

/// A hidden module that's the "runtime support" for the async/await syntax.
///
/// The `async` attribute and the `await` macro both assume that they can find
/// this module and use its contents. All of their dependencies are defined or
/// reexported here in one way shape or form.
///
/// This module has absolutely not stability at all. All contents may change at
/// any time without notice. Do not use this module in your code if you wish
/// your code to be stable.
#[doc(hidden)]
pub mod __rt {
    pub use std::boxed::Box;
    pub use std::option::Option::{Some, None};
    pub use std::result::Result::{Ok, Err, self};
    pub use std::ops::Generator;

    use futures::Poll;
    use futures::{Future, Async, Stream};
    use std::ops::GeneratorState;

    pub trait MyFuture<T: IsResult>: Future<Item=T::Ok, Error = T::Err> {}

    pub trait MyStream<T, U: IsResult<Ok=()>>: Stream<Item=T, Error=U::Err> {}

    impl<F, T> MyFuture<T> for F
        where F: Future<Item = T::Ok, Error = T::Err > + ?Sized,
              T: IsResult
    {}

    impl<F, T, U> MyStream<T, U> for F
        where F: Stream<Item = T, Error = U::Err> + ?Sized,
              U: IsResult<Ok=()>
    {}

    #[rustc_on_unimplemented = "async functions must return a `Result` or \
                                a typedef of `Result`"]
    pub trait IsResult {
        type Ok;
        type Err;

        fn into_result(self) -> Result<Self::Ok, Self::Err>;
    }
    impl<T, E> IsResult for Result<T, E> {
        type Ok = T;
        type Err = E;

        fn into_result(self) -> Result<Self::Ok, Self::Err> { self }
    }

    pub trait IsAsync {
        type Item;

        fn into_async(self) -> Async<Self::Item>;
    }
    impl<T> IsAsync for Async<T> {
        type Item = T;

        fn into_async(self) -> Async<Self::Item> { self }
    }

    pub fn diverge<T>() -> T { loop {} }

    /// Small shim to translate from a generator to a future.
    ///
    /// This is the translation layer from the generator/coroutine protocol to
    /// the futures protocol.
    struct GenFuture<T>(T);

    /// Small shim to translate from a generator to a stream.
    struct GenStream<T>(T);

    pub fn gen<T>(gen: T) -> impl MyFuture<T::Return>
        where T: Generator<Yield = Async<!>>,
              T::Return: IsResult,
    {
        GenFuture(gen)
    }

    pub fn gen_stream<T, U>(gen: T) -> impl MyStream<U, T::Return>
        where T: Generator,
              T::Yield: IsAsync,
              <T::Yield as IsAsync>::Item: IsResult<Ok = U>,
              T::Return: IsResult<
                  Ok = (),
                  Err = <<T::Yield as IsAsync>::Item as IsResult>::Err
              >,
    {
        GenStream(gen)
    }

    impl<T> Future for GenFuture<T>
        where T: Generator<Yield = Async<!>>,
              T::Return: IsResult,
    {
        type Item = <T::Return as IsResult>::Ok;
        type Error = <T::Return as IsResult>::Err;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.0.resume() {
                GeneratorState::Yielded(Async::NotReady)
                    => Ok(Async::NotReady),
                GeneratorState::Complete(e)
                    => e.into_result().map(Async::Ready),
            }
        }
    }

    impl<T> Stream for GenStream<T>
        where T: Generator,
              T::Yield: IsAsync,
              <T::Yield as IsAsync>::Item: IsResult,
              T::Return: IsResult<
                  Ok = (),
                  Err = <<T::Yield as IsAsync>::Item as IsResult>::Err
              >,
    {
        type Item = <<T::Yield as IsAsync>::Item as IsResult>::Ok;
        type Error = <<T::Yield as IsAsync>::Item as IsResult>::Err;

        fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
            match self.0.resume() {
                GeneratorState::Yielded(e) => match e.into_async() {
                    Async::NotReady
                        => Ok(Async::NotReady),
                    Async::Ready(e)
                        => e.into_result().map(|e| Async::Ready(Some(e))),
                },
                GeneratorState::Complete(e)
                    => e.into_result().map(|()| Async::Ready(None)),
            }
        }
    }
}
<commit_msg>Allow polling stream again after returning a final error<commit_after>//! Runtime support for the async/await syntax for futures.
//!
//! This crate serves as a masquerade over the `futures` crate itself,
//! reexporting all of its contents. It's intended that you'll do:
//!
//! ```
//! extern crate futures_await as futures;
//! ```
//!
//! This crate adds a `prelude` module which contains various traits as well as
//! the `async` and `await` macros you'll likely want to use.
//!
//! See the crates's README for more information about usage.

#![feature(conservative_impl_trait)]
#![feature(generator_trait)]
#![feature(use_extern_macros)]
#![feature(never_type)]
#![feature(on_unimplemented)]

extern crate futures_async_macro; // the compiler lies that this has no effect
extern crate futures_await_macro;
extern crate futures;

pub use futures::*;

pub mod prelude {
    pub use {Future, Stream, Sink, Poll, Async, AsyncSink, StartSend};
    pub use {IntoFuture};
    pub use futures_async_macro::{async, async_stream, async_block, async_stream_block};
    pub use futures_await_macro::{await, stream_yield};
}

/// A hidden module that's the "runtime support" for the async/await syntax.
///
/// The `async` attribute and the `await` macro both assume that they can find
/// this module and use its contents. All of their dependencies are defined or
/// reexported here in one way shape or form.
///
/// This module has absolutely not stability at all. All contents may change at
/// any time without notice. Do not use this module in your code if you wish
/// your code to be stable.
#[doc(hidden)]
pub mod __rt {
    pub use std::boxed::Box;
    pub use std::option::Option::{Some, None};
    pub use std::result::Result::{Ok, Err, self};
    pub use std::ops::Generator;

    use futures::Poll;
    use futures::{Future, Async, Stream};
    use std::ops::GeneratorState;

    pub trait MyFuture<T: IsResult>: Future<Item=T::Ok, Error = T::Err> {}

    pub trait MyStream<T, U: IsResult<Ok=()>>: Stream<Item=T, Error=U::Err> {}

    impl<F, T> MyFuture<T> for F
        where F: Future<Item = T::Ok, Error = T::Err > + ?Sized,
              T: IsResult
    {}

    impl<F, T, U> MyStream<T, U> for F
        where F: Stream<Item = T, Error = U::Err> + ?Sized,
              U: IsResult<Ok=()>
    {}

    #[rustc_on_unimplemented = "async functions must return a `Result` or \
                                a typedef of `Result`"]
    pub trait IsResult {
        type Ok;
        type Err;

        fn into_result(self) -> Result<Self::Ok, Self::Err>;
    }
    impl<T, E> IsResult for Result<T, E> {
        type Ok = T;
        type Err = E;

        fn into_result(self) -> Result<Self::Ok, Self::Err> { self }
    }

    pub trait IsAsync {
        type Item;

        fn into_async(self) -> Async<Self::Item>;
    }
    impl<T> IsAsync for Async<T> {
        type Item = T;

        fn into_async(self) -> Async<Self::Item> { self }
    }

    pub fn diverge<T>() -> T { loop {} }

    /// Small shim to translate from a generator to a future.
    ///
    /// This is the translation layer from the generator/coroutine protocol to
    /// the futures protocol.
    struct GenFuture<T>(T);

    /// Small shim to translate from a generator to a stream.
    struct GenStream<T> {
        gen: T,
        done: bool,
    }

    pub fn gen<T>(gen: T) -> impl MyFuture<T::Return>
        where T: Generator<Yield = Async<!>>,
              T::Return: IsResult,
    {
        GenFuture(gen)
    }

    pub fn gen_stream<T, U>(gen: T) -> impl MyStream<U, T::Return>
        where T: Generator,
              T::Yield: IsAsync,
              <T::Yield as IsAsync>::Item: IsResult<Ok = U>,
              T::Return: IsResult<
                  Ok = (),
                  Err = <<T::Yield as IsAsync>::Item as IsResult>::Err
              >,
    {
        GenStream { gen, done: false }
    }

    impl<T> Future for GenFuture<T>
        where T: Generator<Yield = Async<!>>,
              T::Return: IsResult,
    {
        type Item = <T::Return as IsResult>::Ok;
        type Error = <T::Return as IsResult>::Err;

        fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
            match self.0.resume() {
                GeneratorState::Yielded(Async::NotReady)
                    => Ok(Async::NotReady),
                GeneratorState::Complete(e)
                    => e.into_result().map(Async::Ready),
            }
        }
    }

    impl<T> Stream for GenStream<T>
        where T: Generator,
              T::Yield: IsAsync,
              <T::Yield as IsAsync>::Item: IsResult,
              T::Return: IsResult<
                  Ok = (),
                  Err = <<T::Yield as IsAsync>::Item as IsResult>::Err
              >,
    {
        type Item = <<T::Yield as IsAsync>::Item as IsResult>::Ok;
        type Error = <<T::Yield as IsAsync>::Item as IsResult>::Err;

        fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
            if self.done { return Ok(Async::Ready(None)) }
            match self.gen.resume() {
                GeneratorState::Yielded(e) => match e.into_async() {
                    Async::NotReady
                        => Ok(Async::NotReady),
                    Async::Ready(e)
                        => e.into_result().map(|e| Async::Ready(Some(e))),
                },
                GeneratorState::Complete(e) => {
                    self.done = true;
                    e.into_result().map(|()| Async::Ready(None))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Watchexec: the library
//!
//! This is the library version of the CLI tool [watchexec]. The tool is
//! implemented with this library, but the purpose of the watchexec project is
//! to deliver the CLI tool, instead of focusing on the library interface first
//! and foremost. **For this reason, semver guarantees do _not_ apply to this
//! library.** Please use exact version matching, as this API may break even
//! between patch point releases. This policy may change in the future.
//!
//! [watchexec]: https://github.com/watchexec/watchexec

#![forbid(
    clippy::pedantic,
    clippy::nursery,
    deprecated,
    intra_doc_link_resolution_failure,
    clippy::option_unwrap_used,
    clippy::result_unwrap_used
)]
#![deny(unsafe_code, clippy::missing_const_for_fn, clippy::redundant_clone)]
#![allow(
    clippy::default_trait_access,
    clippy::cognitive_complexity,
    clippy::too_many_lines
)]

#[macro_use]
extern crate clap;
#[macro_use]
extern crate derive_builder;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;

pub mod cli;
pub mod error;
mod gitignore;
mod ignore;
mod notification_filter;
pub mod pathop;
mod process;
pub mod run;
mod signal;
mod watcher;

pub use cli::{Args, ArgsBuilder};
pub use run::{run, watch, Handler};
<commit_msg>Revise clippy lints to avoid breakage<commit_after>//! Watchexec: the library
//!
//! This is the library version of the CLI tool [watchexec]. The tool is
//! implemented with this library, but the purpose of the watchexec project is
//! to deliver the CLI tool, instead of focusing on the library interface first
//! and foremost. **For this reason, semver guarantees do _not_ apply to this
//! library.** Please use exact version matching, as this API may break even
//! between patch point releases. This policy may change in the future.
//!
//! [watchexec]: https://github.com/watchexec/watchexec

#![forbid(deprecated)]
#![warn(
    clippy::all,
    clippy::missing_const_for_fn,
    clippy::option_unwrap_used,
    clippy::result_unwrap_used,
    intra_doc_link_resolution_failure
)]

#[macro_use]
extern crate clap;
#[macro_use]
extern crate derive_builder;
#[macro_use]
extern crate log;
#[macro_use]
extern crate lazy_static;

pub mod cli;
pub mod error;
mod gitignore;
mod ignore;
mod notification_filter;
pub mod pathop;
mod process;
pub mod run;
mod signal;
mod watcher;

pub use cli::{Args, ArgsBuilder};
pub use run::{run, watch, Handler};
<|endoftext|>


<commit_before>extern crate libc;

use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, RawFd};

mod ffi;

macro_rules! unsafe_try {
    ( $x:expr ) => {
        try!($crate::to_result(unsafe { $x }))
    };
}

#[derive(Clone)]
pub struct ChildPTY {
    fd: libc::c_int
}

#[derive(Clone)]
pub struct Child {
    pid: libc::pid_t,
    pty: Option<ChildPTY>
}

impl Child {
    pub fn pid(&self) -> libc::pid_t {
        self.pid
    }

    pub fn pty(&self) -> Option<&ChildPTY> {
        self.pty.as_ref()
    }

    pub fn pty_mut(&mut self) -> Option<&mut ChildPTY> {
        self.pty.as_mut()
    }

    pub fn wait(&mut self) -> i32 {
        let mut status = 0 as libc::c_int;

        unsafe { libc::waitpid(self.pid, &mut status, 0) };

        match self.pty {
            Some(ref pty) => pty.close(),
            None          => unreachable!()
        }

        status as i32
    }
}

impl ChildPTY {
    pub fn close(&self) {
        unsafe { libc::close(self.as_raw_fd()) };
    }
}

impl AsRawFd for ChildPTY {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl Read for ChildPTY {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match to_result(unsafe {
            libc::read(self.fd,
                       buf.as_mut_ptr() as *mut libc::c_void,
                       buf.len() as libc::size_t)
        }) {
            Ok(nread) => Ok(nread as usize),
            Err(_)    => Ok(0 as usize)
        }
    }
}

impl Write for ChildPTY {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let ret = unsafe_try!(
            libc::write(self.fd,
                        buf.as_ptr() as *const libc::c_void,
                        buf.len() as libc::size_t)
        );

        Ok(ret as usize)
    }

    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

pub fn fork() -> io::Result<Child>
{
    let pty_master = try!(open_ptm());
    let pid        = unsafe_try!(libc::fork());

    if pid == 0 {
        try!(attach_pts(pty_master));

        Ok(Child { pid: pid, pty: None })
    }
    else {
        Ok(Child { pid: pid, pty: Some(ChildPTY { fd: pty_master }) })
    }
}

fn open_ptm() -> io::Result<libc::c_int> {
    let pty_master = unsafe_try!(ffi::posix_openpt(libc::O_RDWR));

    unsafe_try!(ffi::grantpt(pty_master));
    unsafe_try!(ffi::unlockpt(pty_master));

    Ok(pty_master)
}

fn attach_pts(pty_master: libc::c_int) -> io::Result<()> {
    let pts_name = unsafe { ffi::ptsname(pty_master) };

    if (pts_name as *const i32) == std::ptr::null() {
        return Err(io::Error::last_os_error())
    }

    unsafe_try!(libc::close(pty_master));
    unsafe_try!(libc::setsid());

    let pty_slave = unsafe_try!(libc::open(pts_name, libc::O_RDWR, 0));

    unsafe_try!(libc::dup2(pty_slave, libc::STDIN_FILENO));
    unsafe_try!(libc::dup2(pty_slave, libc::STDOUT_FILENO));
    unsafe_try!(libc::dup2(pty_slave, libc::STDERR_FILENO));

    unsafe_try!(libc::close(pty_slave));

    Ok(())
}

// XXX use <T: Neg<Output=T> + One + PartialEq> trait instead
trait CReturnValue { fn as_c_return_value_is_error(&self) -> bool; }

macro_rules! impl_as_c_return_value_is_error {
    () => {
        fn as_c_return_value_is_error(&self) -> bool { *self == -1 }
    }
}

impl CReturnValue for i32 { impl_as_c_return_value_is_error!(); }
impl CReturnValue for i64 { impl_as_c_return_value_is_error!(); }

#[inline]
fn to_result<T: CReturnValue>(r: T) -> io::Result<T> {
    if r.as_c_return_value_is_error() {
        Err(io::Error::last_os_error())
    } else {
        Ok(r)
    }
}

#[cfg(test)]
mod tests {
    extern crate libc;

    use std::ffi::CString;
    use std::io::{Read, Write};
    use std::process::{Command, Stdio};
    use std::ptr;
    use std::string::String;
    use super::fork;

    #[test]
    fn it_fork_with_new_pty() {
        let mut child = fork().unwrap();

        if child.pid() == 0 {
            let mut ptrs = [CString::new("tty").unwrap().as_ptr(), ptr::null()];

            unsafe { libc::execvp(*ptrs.as_ptr(), ptrs.as_mut_ptr()) };
        }
        else {
            let mut pty    = child.pty_mut().unwrap();
            let mut string = String::new();

            match pty.read_to_string(&mut string) {
                Ok(_)  => {
                    let output = Command::new("tty").stdin(Stdio::inherit()).output().unwrap().stdout;

                    let parent_tty = String::from_utf8_lossy(&output);
                    let child_tty  = string.trim();

                    assert!(child_tty != "");
                    assert!(child_tty != parent_tty);

                    let mut parent_tty_dir: Vec<&str> = parent_tty.split("/").collect();
                    let mut child_tty_dir:  Vec<&str> = child_tty.split("/").collect();

                    parent_tty_dir.pop();
                    child_tty_dir.pop();

                    assert_eq!(parent_tty_dir, child_tty_dir);
                },
                Err(e) => panic!("{}", e)
            }
        }

        child.wait();
    }

    #[test]
    fn it_can_read_write() {
        let mut child = fork().unwrap();

        if child.pid() == 0 {
            let mut ptrs = [CString::new("bash").unwrap().as_ptr(), ptr::null()];

            print!(" "); // FIXME I'm not sure but this is needed to prevent read-block.

            unsafe { libc::execvp(*ptrs.as_ptr(), ptrs.as_mut_ptr()) };
        }
        else {
            let mut pty = child.pty_mut().unwrap();
            let _       = pty.write("echo readme!\n".to_string().as_bytes());

            let mut string = String::new();

            match pty.read_to_string(&mut string) {
                Ok(_)  => {
                    assert!(string.contains("readme!"));
                },
                Err(e) => panic!("{}", e)
            }

            let _ = pty.write("exit\n".to_string().as_bytes());
        }

        child.wait();
    }
}
<commit_msg>Unnecessary mut<commit_after>extern crate libc;

use std::io::{self, Read, Write};
use std::os::unix::io::{AsRawFd, RawFd};

mod ffi;

macro_rules! unsafe_try {
    ( $x:expr ) => {
        try!($crate::to_result(unsafe { $x }))
    };
}

#[derive(Clone)]
pub struct ChildPTY {
    fd: libc::c_int
}

#[derive(Clone)]
pub struct Child {
    pid: libc::pid_t,
    pty: Option<ChildPTY>
}

impl Child {
    pub fn pid(&self) -> libc::pid_t {
        self.pid
    }

    pub fn pty(&self) -> Option<&ChildPTY> {
        self.pty.as_ref()
    }

    pub fn pty_mut(&mut self) -> Option<&mut ChildPTY> {
        self.pty.as_mut()
    }

    pub fn wait(&self) -> i32 {
        let mut status = 0 as libc::c_int;

        unsafe { libc::waitpid(self.pid, &mut status, 0) };

        match self.pty {
            Some(ref pty) => pty.close(),
            None          => unreachable!()
        }

        status as i32
    }
}

impl ChildPTY {
    pub fn close(&self) {
        unsafe { libc::close(self.as_raw_fd()) };
    }
}

impl AsRawFd for ChildPTY {
    fn as_raw_fd(&self) -> RawFd {
        self.fd
    }
}

impl Read for ChildPTY {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match to_result(unsafe {
            libc::read(self.fd,
                       buf.as_mut_ptr() as *mut libc::c_void,
                       buf.len() as libc::size_t)
        }) {
            Ok(nread) => Ok(nread as usize),
            Err(_)    => Ok(0 as usize)
        }
    }
}

impl Write for ChildPTY {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let ret = unsafe_try!(
            libc::write(self.fd,
                        buf.as_ptr() as *const libc::c_void,
                        buf.len() as libc::size_t)
        );

        Ok(ret as usize)
    }

    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

pub fn fork() -> io::Result<Child>
{
    let pty_master = try!(open_ptm());
    let pid        = unsafe_try!(libc::fork());

    if pid == 0 {
        try!(attach_pts(pty_master));

        Ok(Child { pid: pid, pty: None })
    }
    else {
        Ok(Child { pid: pid, pty: Some(ChildPTY { fd: pty_master }) })
    }
}

fn open_ptm() -> io::Result<libc::c_int> {
    let pty_master = unsafe_try!(ffi::posix_openpt(libc::O_RDWR));

    unsafe_try!(ffi::grantpt(pty_master));
    unsafe_try!(ffi::unlockpt(pty_master));

    Ok(pty_master)
}

fn attach_pts(pty_master: libc::c_int) -> io::Result<()> {
    let pts_name = unsafe { ffi::ptsname(pty_master) };

    if (pts_name as *const i32) == std::ptr::null() {
        return Err(io::Error::last_os_error())
    }

    unsafe_try!(libc::close(pty_master));
    unsafe_try!(libc::setsid());

    let pty_slave = unsafe_try!(libc::open(pts_name, libc::O_RDWR, 0));

    unsafe_try!(libc::dup2(pty_slave, libc::STDIN_FILENO));
    unsafe_try!(libc::dup2(pty_slave, libc::STDOUT_FILENO));
    unsafe_try!(libc::dup2(pty_slave, libc::STDERR_FILENO));

    unsafe_try!(libc::close(pty_slave));

    Ok(())
}

// XXX use <T: Neg<Output=T> + One + PartialEq> trait instead
trait CReturnValue { fn as_c_return_value_is_error(&self) -> bool; }

macro_rules! impl_as_c_return_value_is_error {
    () => {
        fn as_c_return_value_is_error(&self) -> bool { *self == -1 }
    }
}

impl CReturnValue for i32 { impl_as_c_return_value_is_error!(); }
impl CReturnValue for i64 { impl_as_c_return_value_is_error!(); }

#[inline]
fn to_result<T: CReturnValue>(r: T) -> io::Result<T> {
    if r.as_c_return_value_is_error() {
        Err(io::Error::last_os_error())
    } else {
        Ok(r)
    }
}

#[cfg(test)]
mod tests {
    extern crate libc;

    use std::ffi::CString;
    use std::io::{Read, Write};
    use std::process::{Command, Stdio};
    use std::ptr;
    use std::string::String;
    use super::fork;

    #[test]
    fn it_fork_with_new_pty() {
        let mut child = fork().unwrap();

        if child.pid() == 0 {
            let mut ptrs = [CString::new("tty").unwrap().as_ptr(), ptr::null()];

            unsafe { libc::execvp(*ptrs.as_ptr(), ptrs.as_mut_ptr()) };
        }
        else {
            let mut pty    = child.pty_mut().unwrap();
            let mut string = String::new();

            match pty.read_to_string(&mut string) {
                Ok(_)  => {
                    let output = Command::new("tty").stdin(Stdio::inherit()).output().unwrap().stdout;

                    let parent_tty = String::from_utf8_lossy(&output);
                    let child_tty  = string.trim();

                    assert!(child_tty != "");
                    assert!(child_tty != parent_tty);

                    let mut parent_tty_dir: Vec<&str> = parent_tty.split("/").collect();
                    let mut child_tty_dir:  Vec<&str> = child_tty.split("/").collect();

                    parent_tty_dir.pop();
                    child_tty_dir.pop();

                    assert_eq!(parent_tty_dir, child_tty_dir);
                },
                Err(e) => panic!("{}", e)
            }
        }

        child.wait();
    }

    #[test]
    fn it_can_read_write() {
        let mut child = fork().unwrap();

        if child.pid() == 0 {
            let mut ptrs = [CString::new("bash").unwrap().as_ptr(), ptr::null()];

            print!(" "); // FIXME I'm not sure but this is needed to prevent read-block.

            unsafe { libc::execvp(*ptrs.as_ptr(), ptrs.as_mut_ptr()) };
        }
        else {
            let mut pty = child.pty_mut().unwrap();
            let _       = pty.write("echo readme!\n".to_string().as_bytes());

            let mut string = String::new();

            match pty.read_to_string(&mut string) {
                Ok(_)  => {
                    assert!(string.contains("readme!"));
                },
                Err(e) => panic!("{}", e)
            }

            let _ = pty.write("exit\n".to_string().as_bytes());
        }

        child.wait();
    }
}
<|endoftext|>


<commit_before>extern crate futures;

use futures::{Async, AsyncSink, Poll, Sink, StartSend};

/// Encapsulate errors from both Sinks
pub enum RouterSinkError<A, B> {
    Left(A),
    Right(B),
}

/// Marker to decide which route the item has to take
pub enum Route<A, B> {
    Left(A),
    Right(B),
}

/// A sink capable of routing incoming items to one of two sinks
pub struct RouterSink<A, B> {
    left_sink: A,
    right_sink: B,
}

/// Poll the given sink and map the error to an appropriate type with
/// the given conversion function
fn poll_complete<S, F, E>(sink: &mut S, f: F) -> Poll<(), E>
    where S: Sink,
          F: Fn(S::SinkError) -> E
{
    match sink.poll_complete() {
            Ok(Async::Ready(x)) => Ok(Async::Ready(x)),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(e) => Err(e),
        }
        .map_err(f)
}

/// Start sending an item on the given sink, map the item back to its route
/// if `NotReady` and map the error to an appropriate type
/// with the given conversion function
fn start_send<S, F, E, G, I>(sink: &mut S, item: S::SinkItem, f: F, g: G) -> StartSend<I, E>
    where S: Sink,
          F: Fn(S::SinkError) -> E,
          G: Fn(S::SinkItem) -> I
{
    sink.start_send(item)
        .map(|x| match x {
                 AsyncSink::Ready => AsyncSink::Ready,
                 AsyncSink::NotReady(x) => AsyncSink::NotReady(g(x)),
             })
        .map_err(f)
}

impl<A, B> RouterSink<A, B> {
    /// Create a new RouterrSink for the two given sinks
    pub fn new(left_sink: A, right_sink: B) -> RouterSink<A, B> {
        RouterSink {
            left_sink,
            right_sink,
        }
    }
}

impl<A, B> Sink for RouterSink<A, B>
    where A: Sink,
          B: Sink
{
    type SinkItem = Route<A::SinkItem, B::SinkItem>;
    type SinkError = RouterSinkError<A::SinkError, B::SinkError>;

    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        match item {
            Route::Left(x) => {
                start_send(&mut self.left_sink, x, RouterSinkError::Left, Route::Left)
            }
            Route::Right(x) => {
                start_send(&mut self.right_sink,
                           x,
                           RouterSinkError::Right,
                           Route::Right)
            }
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        match (poll_complete(&mut self.left_sink, RouterSinkError::Left),
               poll_complete(&mut self.right_sink, RouterSinkError::Right)) {
            (Ok(Async::Ready(())), Ok(Async::Ready(()))) => Ok(Async::Ready(())),
            (Err(e), _) | (_, Err(e)) => Err(e),
            (Ok(Async::NotReady), _) |
            (_, Ok(Async::NotReady)) => Ok(Async::NotReady),
        }
    }
}
<commit_msg>test: add test cases<commit_after>extern crate futures;

use futures::{Async, AsyncSink, Poll, Sink, StartSend};

/// Encapsulate errors from both Sinks
pub enum RouterSinkError<A, B> {
    Left(A),
    Right(B),
}

/// Marker to decide which route the item has to take
pub enum Route<A, B> {
    Left(A),
    Right(B),
}

/// A sink capable of routing incoming items to one of two sinks
pub struct RouterSink<A, B> {
    left_sink: A,
    right_sink: B,
}

/// Poll the given sink and map the error to an appropriate type with
/// the given conversion function
fn poll_complete<S, F, E>(sink: &mut S, f: F) -> Poll<(), E>
    where S: Sink,
          F: Fn(S::SinkError) -> E
{
    match sink.poll_complete() {
            Ok(Async::Ready(x)) => Ok(Async::Ready(x)),
            Ok(Async::NotReady) => Ok(Async::NotReady),
            Err(e) => Err(e),
        }
        .map_err(f)
}

/// Start sending an item on the given sink, map the item back to its route
/// if `NotReady` and map the error to an appropriate type
/// with the given conversion function
fn start_send<S, F, E, G, I>(sink: &mut S, item: S::SinkItem, f: F, g: G) -> StartSend<I, E>
    where S: Sink,
          F: Fn(S::SinkError) -> E,
          G: Fn(S::SinkItem) -> I
{
    sink.start_send(item)
        .map(|x| match x {
                 AsyncSink::Ready => AsyncSink::Ready,
                 AsyncSink::NotReady(x) => AsyncSink::NotReady(g(x)),
             })
        .map_err(f)
}

impl<A, B> RouterSink<A, B> {
    /// Create a new RouterrSink for the two given sinks
    pub fn new(left_sink: A, right_sink: B) -> RouterSink<A, B> {
        RouterSink {
            left_sink,
            right_sink,
        }
    }
}

impl<A, B> Sink for RouterSink<A, B>
    where A: Sink,
          B: Sink
{
    type SinkItem = Route<A::SinkItem, B::SinkItem>;
    type SinkError = RouterSinkError<A::SinkError, B::SinkError>;

    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        match item {
            Route::Left(x) => {
                start_send(&mut self.left_sink, x, RouterSinkError::Left, Route::Left)
            }
            Route::Right(x) => {
                start_send(&mut self.right_sink,
                           x,
                           RouterSinkError::Right,
                           Route::Right)
            }
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        match (poll_complete(&mut self.left_sink, RouterSinkError::Left),
               poll_complete(&mut self.right_sink, RouterSinkError::Right)) {
            (Ok(Async::Ready(())), Ok(Async::Ready(()))) => Ok(Async::Ready(())),
            (Err(e), _) | (_, Err(e)) => Err(e),
            (Ok(Async::NotReady), _) |
            (_, Ok(Async::NotReady)) => Ok(Async::NotReady),
        }
    }
}

#[cfg(test)]
mod test {
    use super::{Route, RouterSink, RouterSinkError};
    use futures::{Future, stream, Stream};

    #[test]
    fn poll_all() {
        let a: Vec<u32> = Vec::new();
        let b: Vec<u32> = Vec::new();

        let input: Vec<Result<_, ()>> = vec![Ok(Route::Left(23)), Ok(Route::Right(42))];
        let stream = stream::iter(input);

        let router = RouterSink::new(a, b);

        match stream
                  .map_err(|_| RouterSinkError::Left(()))
                  .forward(router)
                  .wait() {
            Ok((_, router)) => {
                assert_eq!(router.left_sink[0], 23);
                assert_eq!(router.right_sink[0], 42);
            }
            Err(_) => assert!(false),
        }
    }

    #[test]
    fn poll_err() {
        let a: Vec<u32> = Vec::new();
        let b: Vec<u32> = Vec::new();

        let input = vec![Ok(Route::Left(23)), Err(())];
        let stream = stream::iter(input);

        let router = RouterSink::new(a, b);

        assert_eq!(true,
                   stream
                       .map_err(|_| RouterSinkError::Left(()))
                       .forward(router)
                       .wait()
                       .is_err());
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
#![feature(concat_idents)]
#![allow(improper_ctypes)]

extern crate libc;
extern crate num;

pub use eigenvalues::*;
pub use general_eigenvalues::*;
pub use least_squares::*;
pub use linear_equations::*;

#[macro_use]
mod prefix;
mod scalar;
mod types;
mod util;
pub mod ll;
pub mod error;
pub mod matrix;
pub mod linear_equations;
pub mod least_squares;
pub mod eigenvalues;
pub mod general_eigenvalues;
<commit_msg>Reexport matrix<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
#![feature(concat_idents)]
#![allow(improper_ctypes)]

extern crate libc;
extern crate num;

pub use matrix::Matrix;
pub use eigenvalues::*;
pub use general_eigenvalues::*;
pub use least_squares::*;
pub use linear_equations::*;

#[macro_use]
mod prefix;
mod scalar;
mod types;
mod util;
pub mod ll;
pub mod error;
pub mod matrix;
pub mod linear_equations;
pub mod least_squares;
pub mod eigenvalues;
pub mod general_eigenvalues;
<|endoftext|>


<commit_before>extern crate libc;
extern crate openexr_sys;

use std::mem;
use std::slice;
use std::iter;
use std::path::Path;
use std::collections::HashMap;
use std::ffi::CString;

use libc::{c_char, c_int, c_float};

use openexr_sys as cexr;

pub use openexr_sys::CEXR_PixelType as PixelType;
pub use openexr_sys::CEXR_CompressionMethod as CompressionMethod;
pub use openexr_sys::CEXR_LineOrder as LineOrder;

// ------------------------------------------------------------------------------

pub struct Box2i {
    pub min: (i32, i32),
    pub max: (i32, i32),
}

// ------------------------------------------------------------------------------

pub unsafe trait EXRPixelData: Copy + Into<f64> {
    fn exr_pixel_data_type() -> PixelType;
}

unsafe impl EXRPixelData for u32 {
    fn exr_pixel_data_type() -> PixelType {
        PixelType::U32
    }
}

unsafe impl EXRPixelData for f32 {
    fn exr_pixel_data_type() -> PixelType {
        PixelType::F32
    }
}

// ------------------------------------------------------------------------------

pub unsafe trait EXRPixelStruct: Copy {
    /// Returns the number if channels in the data
    fn channel_count() -> usize;

    /// Returns an array of the types and byte offsets of the channels in the data
    fn channel_descriptions() -> &'static [(PixelType, usize)];
}

unsafe impl EXRPixelStruct for (f32, f32) {
    fn channel_count() -> usize {
        2
    }

    fn channel_descriptions() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 2] = [(PixelType::F32, 0), (PixelType::F32, 4)];
        &TYPES
    }
}

unsafe impl EXRPixelStruct for (f32, f32, f32) {
    fn channel_count() -> usize {
        3
    }

    fn channel_descriptions() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 3] =
            [(PixelType::F32, 0), (PixelType::F32, 4), (PixelType::F32, 8)];
        &TYPES
    }
}

unsafe impl EXRPixelStruct for (f32, f32, f32, f32) {
    fn channel_count() -> usize {
        4
    }

    fn channel_descriptions() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 4] =
            [(PixelType::F32, 0), (PixelType::F32, 4), (PixelType::F32, 8), (PixelType::F32, 12)];
        &TYPES
    }
}

// ------------------------------------------------------------------------------

#[derive(Copy, Clone)]
pub struct Channel {
    pub pixel_type: PixelType,
    pub subsampling: (u32, u32), /* If set to 1, every pixel, if set to 2, every
                                  * other pixel, if 3, every third, etc. */
    pub p_linear: bool, /* Hint to lossy compression methods that indicates whether
                         * human perception of the quantity represented by this channel
                         * is closer to linear or closer to logarithmic. */
}

impl Channel {
    pub fn with_type(pixel_type: PixelType) -> Channel {
        Channel {
            pixel_type: pixel_type,
            subsampling: (1, 1),
            p_linear: true,
        }
    }
}

// ------------------------------------------------------------------------------

#[derive(Copy, Clone)]
pub struct SliceDescription {
    pub pixel_type: PixelType,
    pub start: usize,
    pub stride: (usize, usize),
    pub subsampling: (usize, usize),
    pub tile_coords: (bool, bool),
}

pub struct FrameBuffer<'a> {
    dimensions: (usize, usize),
    channels: HashMap<&'a str, (usize, SliceDescription, f64)>,
    buffers: Vec<&'a mut [u8]>,
}

impl<'a> FrameBuffer<'a> {
    pub fn new(width: usize, height: usize) -> FrameBuffer<'a> {
        FrameBuffer {
            dimensions: (width, height),
            channels: HashMap::new(),
            buffers: Vec::new(),
        }
    }

    pub fn add_slice<T: EXRPixelData>(&mut self, data: &'a mut [T], name: &'a str, default: T) {
        if data.len() < (self.dimensions.0 * self.dimensions.1) {
            panic!("Attempted to add too small slice to FrameBuffer.");
        }

        self.add_interleaved_slice(data, &[(name, default)]);
    }

    pub fn add_interleaved_slice<T: EXRPixelData>(&mut self,
                                                  data: &'a mut [T],
                                                  channels: &[(&'a str, T)]) {
        if channels.len() == 0 {
            panic!("Attempted to add slice without channels to FrameBuffer.");
        }
        if (data.len() / channels.len()) < (self.dimensions.0 * self.dimensions.1) {
            panic!("Attempted to add too small slice to FrameBuffer.");
        }

        // Insert channels
        let width = self.dimensions.0;
        for (i, &(name, default)) in channels.iter().enumerate() {
            self.channels.insert(name,
                                 (self.buffers.len(),
                                  SliceDescription {
                                     pixel_type: T::exr_pixel_data_type(),
                                     start: mem::size_of::<T>() * i,
                                     stride: (mem::size_of::<T>(),
                                              mem::size_of::<T>() * width * channels.len()),
                                     subsampling: (1, 1),
                                     tile_coords: (false, false),
                                 },
                                  default.into()));
        }

        // Add buffer
        let p = data.as_mut_ptr();
        let l = data.len() * mem::size_of::<T>();
        let pd = unsafe { slice::from_raw_parts_mut(p as *mut u8, l) };
        self.buffers.push(pd);
    }

    pub fn add_structured_slice<T: EXRPixelStruct>(&mut self,
                                                   data: &'a mut [T],
                                                   channels: &[(&'a str, f64)]) {
        unsafe {
            self.add_structured_slice_unsafe(data, channels, T::channel_descriptions());
        }
    }

    pub unsafe fn add_structured_slice_unsafe<T: EXRPixelStruct>(&mut self,
                                                                 data: &'a mut [T],
                                                                 channels: &[(&'a str, f64)],
                                                                 channel_descriptions: &[(PixelType,
                                                                                usize)]) {
        if data.len() < (self.dimensions.0 * self.dimensions.1) {
            panic!("Attempted to add too small slice to FrameBuffer.");
        }
        if channels.len() == 0 {
            panic!("Attempted to add slice without channels to FrameBuffer.");
        }
        if channels.len() != channel_descriptions.len() {
            panic!("Number of channels doesn't match number of channel descriptions.");
        }
        for &(pixel_type, byte_offset) in channel_descriptions.iter() {
            if (pixel_type.data_size() + byte_offset) > mem::size_of::<T>() {
                panic!("Structured data description violates data bounds of type.");
            }
        }

        // Insert channels
        let width = self.dimensions.0;
        for (&(name, default), &(pixel_type, byte_offset)) in
            iter::Iterator::zip(channels.iter(), channel_descriptions.iter()) {
            self.channels.insert(name,
                                 (self.buffers.len(),
                                  SliceDescription {
                                     pixel_type: pixel_type,
                                     start: byte_offset,
                                     stride: (mem::size_of::<T>(), mem::size_of::<T>() * width),
                                     subsampling: (1, 1),
                                     tile_coords: (false, false),
                                 },
                                  default.into()));
        }

        // Add buffer
        let p = data.as_mut_ptr();
        let l = data.len() * mem::size_of::<T>();
        let pd = slice::from_raw_parts_mut(p as *mut u8, l);
        self.buffers.push(pd);
    }

    pub unsafe fn add_raw_slice(&mut self,
                                data: &'a mut [u8],
                                descriptions: &[(&'a str, SliceDescription, f64)]) {
        // Make sure we're not creating any duplicate channels.
        // We check this ahead of time instead of in the same loop as inserting the channels
        // so that the FrameBuffer state remains valid.
        // TODO: more error checking, specifically checking to make sure 'data' is large
        // enough for all of the described slices.
        for &(name, _, _) in descriptions {
            if self.channels.contains_key(name) {
                // TODO: return an Err instead of a panicing
                panic!("Cannot have two of the same channel name in a FrameBuffer.");
            }
        }

        // Insert channels
        for &(name, desc, default) in descriptions {
            self.channels.insert(name, (self.buffers.len(), desc, default));
        }

        // Add buffer
        self.buffers.push(data);
    }
}

// ------------------------------------------------------------------------------

pub struct ExrWriterBuilder<'a> {
    path: &'a Path,
    display_window: Box2i,
    data_window: Box2i,
    pixel_aspect_ratio: f32,
    screen_window_center: (f32, f32),
    screen_window_width: f32,
    line_order: LineOrder,
    compression_method: CompressionMethod,
    channels: HashMap<String, Channel>,
}

impl<'a> ExrWriterBuilder<'a> {
    pub fn new(path: &'a Path) -> ExrWriterBuilder<'a> {
        ExrWriterBuilder {
            path: path,
            display_window: Box2i {
                min: (0, 0),
                max: (0, 0),
            },
            data_window: Box2i {
                min: (0, 0),
                max: (0, 0),
            },
            pixel_aspect_ratio: 1.0,
            screen_window_center: (0.0, 0.0),
            screen_window_width: 1.0,
            line_order: LineOrder::IncreasingY,
            compression_method: CompressionMethod::ZIP,
            channels: HashMap::new(),
        }
    }

    pub fn display_window(mut self, min: (i32, i32), max: (i32, i32)) -> ExrWriterBuilder<'a> {
        self.display_window = Box2i {
            min: min,
            max: max,
        };
        self
    }

    pub fn data_window(mut self, min: (i32, i32), max: (i32, i32)) -> ExrWriterBuilder<'a> {
        self.data_window = Box2i {
            min: min,
            max: max,
        };
        self
    }

    pub fn pixel_aspect_ratio(mut self, par: f32) -> ExrWriterBuilder<'a> {
        self.pixel_aspect_ratio = par;
        self
    }

    pub fn screen_window_center(mut self, swc: (f32, f32)) -> ExrWriterBuilder<'a> {
        self.screen_window_center = swc;
        self
    }

    pub fn screen_window_width(mut self, sww: f32) -> ExrWriterBuilder<'a> {
        self.screen_window_width = sww;
        self
    }

    pub fn line_order(mut self, lo: LineOrder) -> ExrWriterBuilder<'a> {
        self.line_order = lo;
        self
    }

    pub fn compression_method(mut self, cm: CompressionMethod) -> ExrWriterBuilder<'a> {
        self.compression_method = cm;
        self
    }

    pub fn insert_channel(mut self, name: &str, channel: Channel) -> ExrWriterBuilder<'a> {
        self.channels.insert(name.to_string(), channel);
        self
    }

    pub fn open(self) -> ExrWriter {
        // Build the header
        let header = {
            let mut header = unsafe {
                cexr::CEXR_Header_new(self.display_window.min.0 as c_int,
                                      self.display_window.min.1 as c_int,
                                      self.display_window.max.0 as c_int,
                                      self.display_window.max.1 as c_int,
                                      self.data_window.min.0 as c_int,
                                      self.data_window.min.1 as c_int,
                                      self.data_window.max.0 as c_int,
                                      self.data_window.max.1 as c_int,
                                      self.pixel_aspect_ratio as c_float,
                                      self.screen_window_center.0,
                                      self.screen_window_center.1,
                                      self.screen_window_width,
                                      self.line_order,
                                      self.compression_method)
            };
            for (name, channel) in &self.channels {
                let n = CString::new(name.as_bytes()).unwrap();
                let c = cexr::CEXR_Channel {
                    pixel_type: channel.pixel_type,
                    x_sampling: channel.subsampling.0 as c_int,
                    y_sampling: channel.subsampling.1 as c_int,
                    p_linear: if channel.p_linear {
                        1 as c_int
                    } else {
                        0 as c_int
                    },
                };
                unsafe { cexr::CEXR_Header_insert_channel(&mut header, n.as_ptr(), c) };
            }
            header
        };

        ExrWriter {
            handle: unsafe {
                cexr::CEXR_OutputFile_new(CString::new(self.path.to_str().unwrap().as_bytes())
                                              .unwrap()
                                              .as_ptr(),
                                          &header,
                                          1)
            },
        }
    }
}

// ------------------------------------------------------------------------------
pub struct ExrWriter {
    handle: cexr::CEXR_OutputFile,
}

impl Drop for ExrWriter {
    fn drop(&mut self) {
        unsafe { cexr::CEXR_OutputFile_delete(&mut self.handle) };
    }
}

impl ExrWriter {
    pub fn write_pixels(&mut self, frame_buffer: &mut FrameBuffer) {
        // Build the frame buffer.
        let mut cexr_fb = {
            let mut cexr_fb = unsafe { cexr::CEXR_FrameBuffer_new() };
            for (&name, &(buf_index, desc, default)) in frame_buffer.channels.iter() {
                let n = CString::new(name.as_bytes()).unwrap();
                let buf_ptr = unsafe {
                    frame_buffer.buffers[buf_index].as_mut_ptr().offset(desc.start as isize)
                } as *mut c_char;
                unsafe {
                    cexr::CEXR_FrameBuffer_insert_slice(&mut cexr_fb,
                                                        n.as_ptr(),
                                                        desc.pixel_type,
                                                        buf_ptr,
                                                        desc.stride.0,
                                                        desc.stride.1,
                                                        desc.subsampling.0 as i32,
                                                        desc.subsampling.1 as i32,
                                                        default,
                                                        desc.tile_coords.0 as i32,
                                                        desc.tile_coords.1 as i32)
                };
            }
            cexr_fb
        };

        // Set the frame buffer.
        unsafe { cexr::CEXR_OutputFile_set_frame_buffer(&mut self.handle, &mut cexr_fb) };

        // Write the pixel data.
        unsafe {
            cexr::CEXR_OutputFile_write_pixels(&mut self.handle, frame_buffer.dimensions.1 as i32)
        };

        // Destroy the framebuffer
        unsafe { cexr::CEXR_FrameBuffer_delete(&mut cexr_fb) };
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        println!("woo hoo!");
    }
}
<commit_msg>Added a bit of documentation, and some skeleton code for EXRReader.<commit_after>extern crate libc;
extern crate openexr_sys;

use std::mem;
use std::slice;
use std::iter;
use std::path::Path;
use std::collections::HashMap;
use std::ffi::CString;

use libc::{c_char, c_int, c_float};

use openexr_sys as cexr;

pub use openexr_sys::CEXR_PixelType as PixelType;
pub use openexr_sys::CEXR_CompressionMethod as CompressionMethod;
pub use openexr_sys::CEXR_LineOrder as LineOrder;

// ------------------------------------------------------------------------------

pub struct Box2i {
    pub min: (i32, i32),
    pub max: (i32, i32),
}

// ------------------------------------------------------------------------------

/// A trait for types that can be bit-for-bit copied as OpenEXR pixel data with
/// valid semantics.
pub unsafe trait EXRPixelData: Copy + Into<f64> {
    fn exr_pixel_data_type() -> PixelType;
}

unsafe impl EXRPixelData for u32 {
    fn exr_pixel_data_type() -> PixelType {
        PixelType::U32
    }
}

unsafe impl EXRPixelData for f32 {
    fn exr_pixel_data_type() -> PixelType {
        PixelType::F32
    }
}

// ------------------------------------------------------------------------------

/// A trait for types that can be interpreted as a set of pixel channels.
pub unsafe trait EXRPixelStruct: Copy {
    /// Returns the number if channels in the data
    fn channel_count() -> usize;

    /// Returns an array of the types and byte offsets of the channels in the data
    fn channel_descriptions() -> &'static [(PixelType, usize)];
}

unsafe impl EXRPixelStruct for (f32, f32) {
    fn channel_count() -> usize {
        2
    }

    fn channel_descriptions() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 2] = [(PixelType::F32, 0), (PixelType::F32, 4)];
        &TYPES
    }
}

unsafe impl EXRPixelStruct for (f32, f32, f32) {
    fn channel_count() -> usize {
        3
    }

    fn channel_descriptions() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 3] =
            [(PixelType::F32, 0), (PixelType::F32, 4), (PixelType::F32, 8)];
        &TYPES
    }
}

unsafe impl EXRPixelStruct for (f32, f32, f32, f32) {
    fn channel_count() -> usize {
        4
    }

    fn channel_descriptions() -> &'static [(PixelType, usize)] {
        static TYPES: [(PixelType, usize); 4] =
            [(PixelType::F32, 0), (PixelType::F32, 4), (PixelType::F32, 8), (PixelType::F32, 12)];
        &TYPES
    }
}

// ------------------------------------------------------------------------------

/// Describes a channel of an image (e.g. the red channel, alpha channel, an
/// arbitrary data channel) as stored on disk.  It is used for communication in
/// the API's, and doesn't actually contain any image data itself.
#[derive(Copy, Clone)]
pub struct Channel {
    pub pixel_type: PixelType,
    pub subsampling: (u32, u32), /* If set to 1, every pixel, if set to 2, every
                                  * other pixel, if 3, every third, etc. */
    pub p_linear: bool, /* Hint to lossy compression methods that indicates whether
                         * human perception of the quantity represented by this channel
                         * is closer to linear or closer to logarithmic. */
}

impl Channel {
    pub fn with_type(pixel_type: PixelType) -> Channel {
        Channel {
            pixel_type: pixel_type,
            subsampling: (1, 1),
            p_linear: true,
        }
    }
}

/// Describes a channel of an image as stored in memory.  It is used for
/// communication in the API's, and doesn't actually contain any image
/// data itself.
#[derive(Copy, Clone)]
pub struct SliceDescription {
    pub pixel_type: PixelType,
    pub subsampling: (u32, u32),
    pub start: usize,
    pub stride: (usize, usize),
    pub tile_coords: (bool, bool),
}

// ------------------------------------------------------------------------------

/// Points to and describes the in-memory storage for all channels of an
/// EXR image.  This is passed to readers and writers so they know where to
/// read/write image data in memory.
pub struct FrameBuffer<'a> {
    dimensions: (usize, usize),
    channels: HashMap<&'a str, (usize, SliceDescription, f64)>,
    buffers: Vec<&'a mut [u8]>,
}

impl<'a> FrameBuffer<'a> {
    pub fn new(width: usize, height: usize) -> FrameBuffer<'a> {
        FrameBuffer {
            dimensions: (width, height),
            channels: HashMap::new(),
            buffers: Vec::new(),
        }
    }

    pub fn add_slice<T: EXRPixelData>(&mut self, data: &'a mut [T], name: &'a str, default: T) {
        if data.len() < (self.dimensions.0 * self.dimensions.1) {
            panic!("Attempted to add too small slice to FrameBuffer.");
        }

        self.add_interleaved_slice(data, &[(name, default)]);
    }

    pub fn add_interleaved_slice<T: EXRPixelData>(&mut self,
                                                  data: &'a mut [T],
                                                  channels: &[(&'a str, T)]) {
        if channels.len() == 0 {
            panic!("Attempted to add slice without channels to FrameBuffer.");
        }
        if (data.len() / channels.len()) < (self.dimensions.0 * self.dimensions.1) {
            panic!("Attempted to add too small slice to FrameBuffer.");
        }

        // Insert channels
        let width = self.dimensions.0;
        for (i, &(name, default)) in channels.iter().enumerate() {
            self.channels.insert(name,
                                 (self.buffers.len(),
                                  SliceDescription {
                                     pixel_type: T::exr_pixel_data_type(),
                                     subsampling: (1, 1),
                                     start: mem::size_of::<T>() * i,
                                     stride: (mem::size_of::<T>(),
                                              mem::size_of::<T>() * width * channels.len()),
                                     tile_coords: (false, false),
                                 },
                                  default.into()));
        }

        // Add buffer
        let p = data.as_mut_ptr();
        let l = data.len() * mem::size_of::<T>();
        let pd = unsafe { slice::from_raw_parts_mut(p as *mut u8, l) };
        self.buffers.push(pd);
    }

    pub fn add_structured_slice<T: EXRPixelStruct>(&mut self,
                                                   data: &'a mut [T],
                                                   channels: &[(&'a str, f64)]) {
        unsafe {
            self.add_structured_slice_unsafe(data, channels, T::channel_descriptions());
        }
    }

    pub unsafe fn add_structured_slice_unsafe<T: EXRPixelStruct>(&mut self,
                                                                 data: &'a mut [T],
                                                                 channels: &[(&'a str, f64)],
                                                                 channel_descriptions: &[(PixelType,
                                                                                usize)]) {
        if data.len() < (self.dimensions.0 * self.dimensions.1) {
            panic!("Attempted to add too small slice to FrameBuffer.");
        }
        if channels.len() == 0 {
            panic!("Attempted to add slice without channels to FrameBuffer.");
        }
        if channels.len() != channel_descriptions.len() {
            panic!("Number of channels doesn't match number of channel descriptions.");
        }
        for &(pixel_type, byte_offset) in channel_descriptions.iter() {
            if (pixel_type.data_size() + byte_offset) > mem::size_of::<T>() {
                panic!("Structured data description violates data bounds of type.");
            }
        }

        // Insert channels
        let width = self.dimensions.0;
        for (&(name, default), &(pixel_type, byte_offset)) in
            iter::Iterator::zip(channels.iter(), channel_descriptions.iter()) {
            self.channels.insert(name,
                                 (self.buffers.len(),
                                  SliceDescription {
                                     pixel_type: pixel_type,
                                     subsampling: (1, 1),
                                     start: byte_offset,
                                     stride: (mem::size_of::<T>(), mem::size_of::<T>() * width),
                                     tile_coords: (false, false),
                                 },
                                  default.into()));
        }

        // Add buffer
        let p = data.as_mut_ptr();
        let l = data.len() * mem::size_of::<T>();
        let pd = slice::from_raw_parts_mut(p as *mut u8, l);
        self.buffers.push(pd);
    }

    pub unsafe fn add_raw_slice(&mut self,
                                data: &'a mut [u8],
                                descriptions: &[(&'a str, SliceDescription, f64)]) {
        // Make sure we're not creating any duplicate channels.
        // We check this ahead of time instead of in the same loop as inserting the channels
        // so that the FrameBuffer state remains valid.
        // TODO: more error checking, specifically checking to make sure 'data' is large
        // enough for all of the described slices.
        for &(name, _, _) in descriptions {
            if self.channels.contains_key(name) {
                // TODO: return an Err instead of a panicing
                panic!("Cannot have two of the same channel name in a FrameBuffer.");
            }
        }

        // Insert channels
        for &(name, desc, default) in descriptions {
            self.channels.insert(name, (self.buffers.len(), desc, default));
        }

        // Add buffer
        self.buffers.push(data);
    }
}

// ------------------------------------------------------------------------------

/// A builder for an exr writer.  Once everything is set up, use open() to create
/// the final EXRWriter.
pub struct ExrWriterBuilder<'a> {
    path: &'a Path,
    display_window: Box2i,
    data_window: Box2i,
    pixel_aspect_ratio: f32,
    screen_window_center: (f32, f32),
    screen_window_width: f32,
    line_order: LineOrder,
    compression_method: CompressionMethod,
    channels: HashMap<String, Channel>,
}

impl<'a> ExrWriterBuilder<'a> {
    pub fn new(path: &'a Path) -> ExrWriterBuilder<'a> {
        ExrWriterBuilder {
            path: path,
            display_window: Box2i {
                min: (0, 0),
                max: (0, 0),
            },
            data_window: Box2i {
                min: (0, 0),
                max: (0, 0),
            },
            pixel_aspect_ratio: 1.0,
            screen_window_center: (0.0, 0.0),
            screen_window_width: 1.0,
            line_order: LineOrder::IncreasingY,
            compression_method: CompressionMethod::ZIP,
            channels: HashMap::new(),
        }
    }

    pub fn display_window(mut self, min: (i32, i32), max: (i32, i32)) -> ExrWriterBuilder<'a> {
        self.display_window = Box2i {
            min: min,
            max: max,
        };
        self
    }

    pub fn data_window(mut self, min: (i32, i32), max: (i32, i32)) -> ExrWriterBuilder<'a> {
        self.data_window = Box2i {
            min: min,
            max: max,
        };
        self
    }

    pub fn pixel_aspect_ratio(mut self, par: f32) -> ExrWriterBuilder<'a> {
        self.pixel_aspect_ratio = par;
        self
    }

    pub fn screen_window_center(mut self, swc: (f32, f32)) -> ExrWriterBuilder<'a> {
        self.screen_window_center = swc;
        self
    }

    pub fn screen_window_width(mut self, sww: f32) -> ExrWriterBuilder<'a> {
        self.screen_window_width = sww;
        self
    }

    pub fn line_order(mut self, lo: LineOrder) -> ExrWriterBuilder<'a> {
        self.line_order = lo;
        self
    }

    pub fn compression_method(mut self, cm: CompressionMethod) -> ExrWriterBuilder<'a> {
        self.compression_method = cm;
        self
    }

    pub fn insert_channel(mut self, name: &str, channel: Channel) -> ExrWriterBuilder<'a> {
        self.channels.insert(name.to_string(), channel);
        self
    }

    pub fn open(self) -> ExrWriter {
        // Build the header
        let header = {
            let mut header = unsafe {
                cexr::CEXR_Header_new(self.display_window.min.0 as c_int,
                                      self.display_window.min.1 as c_int,
                                      self.display_window.max.0 as c_int,
                                      self.display_window.max.1 as c_int,
                                      self.data_window.min.0 as c_int,
                                      self.data_window.min.1 as c_int,
                                      self.data_window.max.0 as c_int,
                                      self.data_window.max.1 as c_int,
                                      self.pixel_aspect_ratio as c_float,
                                      self.screen_window_center.0,
                                      self.screen_window_center.1,
                                      self.screen_window_width,
                                      self.line_order,
                                      self.compression_method)
            };
            for (name, channel) in &self.channels {
                let n = CString::new(name.as_bytes()).unwrap();
                let c = cexr::CEXR_Channel {
                    pixel_type: channel.pixel_type,
                    x_sampling: channel.subsampling.0 as c_int,
                    y_sampling: channel.subsampling.1 as c_int,
                    p_linear: if channel.p_linear {
                        1 as c_int
                    } else {
                        0 as c_int
                    },
                };
                unsafe { cexr::CEXR_Header_insert_channel(&mut header, n.as_ptr(), c) };
            }
            header
        };

        ExrWriter {
            handle: unsafe {
                cexr::CEXR_OutputFile_new(CString::new(self.path.to_str().unwrap().as_bytes())
                                              .unwrap()
                                              .as_ptr(),
                                          &header,
                                          1)
            },
        }
    }
}

// ------------------------------------------------------------------------------
pub struct ExrWriter {
    handle: cexr::CEXR_OutputFile,
}

impl Drop for ExrWriter {
    fn drop(&mut self) {
        unsafe { cexr::CEXR_OutputFile_delete(&mut self.handle) };
    }
}

impl ExrWriter {
    pub fn write_pixels(&mut self, frame_buffer: &mut FrameBuffer) {
        // Build the C frame buffer from the given frame buffer.
        let mut cexr_fb = {
            let mut cexr_fb = unsafe { cexr::CEXR_FrameBuffer_new() };
            for (&name, &(buf_index, desc, default)) in frame_buffer.channels.iter() {
                let n = CString::new(name.as_bytes()).unwrap();
                let buf_ptr = unsafe {
                    frame_buffer.buffers[buf_index].as_mut_ptr().offset(desc.start as isize)
                } as *mut c_char;
                unsafe {
                    cexr::CEXR_FrameBuffer_insert_slice(&mut cexr_fb,
                                                        n.as_ptr(),
                                                        desc.pixel_type,
                                                        buf_ptr,
                                                        desc.stride.0,
                                                        desc.stride.1,
                                                        desc.subsampling.0 as i32,
                                                        desc.subsampling.1 as i32,
                                                        default,
                                                        desc.tile_coords.0 as i32,
                                                        desc.tile_coords.1 as i32)
                };
            }
            cexr_fb
        };

        // Set the C frame buffer.
        unsafe { cexr::CEXR_OutputFile_set_frame_buffer(&mut self.handle, &mut cexr_fb) };

        // Write the pixel data.
        unsafe {
            cexr::CEXR_OutputFile_write_pixels(&mut self.handle, frame_buffer.dimensions.1 as i32)
        };

        // Destroy the C framebuffer
        unsafe { cexr::CEXR_FrameBuffer_delete(&mut cexr_fb) };
    }
}

// ------------------------------------------------------------------------------
pub struct ExrReader {
    handle: cexr::CEXR_InputFile,
}

impl Drop for ExrReader {
    fn drop(&mut self) {
        unsafe { cexr::CEXR_InputFile_delete(&mut self.handle) };
    }
}

// ------------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
        println!("woo hoo!");
    }
}
<|endoftext|>