<commit_before>extern crate llvm_sys;

use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::str;
use self::llvm_sys::core::*;
use self::llvm_sys::analysis::*;
use self::llvm_sys::execution_engine::*;
use self::llvm_sys::prelude::*;
use self::llvm_sys::target::*;
//use self::llvm_sys::transforms::scalar::*;
use syntax::ast::op::*;
use syntax::ast::expr::*;
use syntax::ast::literals::*;

// Struct to keep track of data needed to build IR
pub struct Context {
    context: LLVMContextRef,
    module: LLVMModuleRef,
    builder: LLVMBuilderRef,
    execution_engine: LLVMExecutionEngineRef,
    fn_pass_manager: LLVMPassManagerRef,
    named_values: HashMap<String, LLVMValueRef>,
}

impl Context {
    pub unsafe fn new(module_name: &str) -> Context {
        LLVM_InitializeNativeTarget();
        LLVM_InitializeNativeAsmPrinter();
        LLVM_InitializeNativeAsmParser();
        LLVMLinkInInterpreter();

        let context = LLVMContextCreate();
        let module = LLVMModuleCreateWithNameInContext(c_str_ptr(module_name), context);
        let builder = LLVMCreateBuilderInContext(context);
        let named_values = HashMap::new();
        let mut execution_engine = 0 as LLVMExecutionEngineRef;
        let mut error_msg = 0 as *mut i8;

        if LLVMCreateExecutionEngineForModule(&mut execution_engine, module, &mut error_msg) == 1 {
            panic!("{}", str::from_utf8(CStr::from_ptr(error_msg).to_bytes()).unwrap())
        }

        let fn_pass_manager = LLVMCreateFunctionPassManagerForModule(module);
        let target_data = LLVMGetExecutionEngineTargetData(execution_engine);
        let data_layout = LLVMCopyStringRepOfTargetData(target_data);
        LLVMSetDataLayout(module, data_layout);
        LLVMAddTargetData(target_data, fn_pass_manager);
        LLVMDisposeMessage(data_layout);

        // Add desired passes to pass manager here
//        LLVMAddInstructionCombiningPass(fn_pass_manager);

        LLVMInitializeFunctionPassManager(fn_pass_manager);

        Context {
            context: context,
            module: module,
            builder: builder,
            execution_engine: execution_engine,
            fn_pass_manager: fn_pass_manager,
            named_values: named_values,
        }
    }

    // Dump the IR to stdout
    pub unsafe fn dump(&self) {
        LLVMDumpModule(self.module);
    }

    // Verifies that the llvm code is valid. Optionally prints
    // the error message, else abort.
    pub unsafe fn verify(&self) {
        let action = LLVMVerifierFailureAction::LLVMPrintMessageAction;
        let msg = vec![c_str_ptr("")];

        LLVMVerifyModule(self.module, action, msg.as_ptr() as *mut _);
        LLVMDisposeMessage(msg[0] as *mut _);
    }

    pub unsafe fn run(&self) -> u64 {
        let main = LLVMGetNamedFunction(self.module, c_str_ptr("main"));
        let result = LLVMRunFunction(self.execution_engine, main, 0, 0 as *mut LLVMGenericValueRef);

        LLVMGenericValueToInt(result, 1)
    }

    // Struct getters
    pub fn get_context(&self) -> LLVMContextRef {
        self.context
    }

    pub fn get_module(&self) -> LLVMModuleRef {
        self.module
    }

    pub fn get_builder(&self) -> LLVMBuilderRef {
        self.builder
    }

    pub fn clear_values(&mut self) {
        self.named_values.clear();
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposePassManager(self.fn_pass_manager);
//            LLVMDisposeExecutionEngine(self.execution_engine); // signal 4s for some reason
            LLVMDisposeBuilder(self.builder);
            LLVMDisposeModule(self.module);
            LLVMContextDispose(self.context);
        }
    }
}

pub trait CodeGen {
    unsafe fn gen_code(&self, context: &mut Context) -> Option<LLVMValueRef>;
}

impl CodeGen for ExprWrapper {
    unsafe fn gen_code(&self, context: &mut Context) -> Option<LLVMValueRef> {
        self.get_expr().gen_code(context)
    }
}

impl CodeGen for Expr {
    unsafe fn gen_code(&self, context: &mut Context) -> Option<LLVMValueRef> {
        match *self {
            Expr::Block(ref vec) => {
                let mut gen = None;

                for expr in vec {
                    gen = expr.gen_code(context);
                }

                gen
            },
            Expr::Ident(ref name) => {
                match context.named_values.get(name) {
                    Some(val) => Some(*val),
                    None => {
                        println!("Error: Unknown variable named {}", name);

                        None
                    }
                }
            },
            Expr::Literal(ref literal_type) => {
                match literal_type {
                    &Literals::UTF8String(ref val) => {
                        // Types
                        let array_type1 = LLVMArrayType(LLVMInt8TypeInContext(context.get_context()), val.len() as u32);
                        // let string_struct_type = LLVMGetNamedGlobal(context.get_module(), c_str_ptr("struct.string"));
                        // if string_struct_type.is_null() {
                        //     println!("TMP Error: Cannot find builtin string type!");
                        // }
                        let i8_type = LLVMInt8TypeInContext(context.get_context());
                        let i8_ptr_type = LLVMPointerType(i8_type, 0);
                        let i32_type = LLVMInt32TypeInContext(context.get_context());
                        let i64_type = LLVMInt64TypeInContext(context.get_context());
                        // let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                        //               LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];

                        // Values
                        let len = LLVMConstInt(i64_type, val.len() as u64, 0);

                        // Make a global string constant and assign the value:
                        let const_str_var = LLVMAddGlobal(context.get_module(), array_type1, c_str_ptr("str"));
                        let mut chars = Vec::new();
                        for chr in val.bytes() {
                            chars.push(LLVMConstInt(i8_type, chr as u64, 0));
                        }

                        let const_str_array = LLVMConstArray(i8_type, chars.as_ptr() as *mut _, chars.len() as u32);
                        LLVMSetInitializer(const_str_var, const_str_array);
                        LLVMSetGlobalConstant(const_str_var, 1);

                        let args = vec![LLVMConstInt(i32_type, 0, 0), LLVMConstInt(i32_type, 0, 0)];
                        let allocated_str_ptr = LLVMBuildAlloca(context.get_builder(), i8_ptr_type, c_str_ptr("a"));
                        let mallocated_ptr = LLVMBuildMalloc(context.get_builder(), i8_type, c_str_ptr("m"));

                        LLVMSetTailCall(mallocated_ptr, 0);
                        LLVMBuildStore(context.get_builder(), mallocated_ptr, allocated_str_ptr);

                        let element_ptr = LLVMBuildGEP(context.get_builder(), const_str_var, args.as_ptr() as *mut _, 2, c_str_ptr(""));
                        LLVMBuildStore(context.get_builder(), element_ptr, allocated_str_ptr);

                        let loaded_ptr = LLVMBuildLoad(context.get_builder(), allocated_str_ptr, c_str_ptr("l"));
                        // String type generated here should eventually be preloaded type
                        let string_type_fields = vec![LLVMPointerType(i8_type, 0), i64_type];
                        let string_type = LLVMStructTypeInContext(context.get_context(), string_type_fields.as_ptr() as *mut _, 2, 0);
                        let undef = LLVMGetUndef(string_type);

                        let i = LLVMBuildInsertValue(context.get_builder(), undef, loaded_ptr, 0, c_str_ptr("i"));
                        Some(LLVMBuildInsertValue(context.get_builder(), i, len, 1, c_str_ptr("i")))
                    },
                    &Literals::I32Num(ref val) => {
                        let ty = LLVMInt32TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val as u64, 1))
                    },
                    &Literals::I64Num(ref val) => {
                        let ty = LLVMInt64TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val as u64, 1))
                    },
                    &Literals::U32Num(ref val) => {
                        let ty = LLVMInt32TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val as u64, 0))
                    },
                    &Literals::U64Num(ref val) => {
                        let ty = LLVMInt64TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val, 0))
                    },
                    &Literals::F32Num(ref val) => {
                        let ty = LLVMFloatTypeInContext(context.get_context());
                        Some(LLVMConstReal(ty, *val as f64))
                    },
                    &Literals::F64Num(ref val) => {
                        let ty = LLVMDoubleTypeInContext(context.get_context());
                        Some(LLVMConstReal(ty, *val))
                    },
                    &Literals::Bool(ref val) => {
                        let ty = LLVMInt1TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val as u64, 0))
                    },
                    _ => {
                        println!("Error: Codegen unimplemented for {:?}", literal_type);
                        None
                    }
                }
            },
            Expr::FnCall(ref name, ref args) => {
                let function = LLVMGetNamedFunction(context.module, c_str_ptr(name));

                if function.is_null() {
                    // TODO: Add standardized error message writing?
                    println!("Error: Function {} not found.", name);
                    return None;
                }

                let arg_count = LLVMCountParams(function) as usize;

                if arg_count != args.len() {
                    println!("Error: Function {} requires {} argument(s), {} given.", name, arg_count, args.len());
                    return None;
                }

                let mut arg_values = Vec::new();

                for arg in args {
                    match arg.gen_code(context) {
                        Some(value) => arg_values.push(value),
                        None => {
                            println!("Fatal Error: Argument {:?} codegen failed!", arg);
                            return None
                        }
                    }
                }

                // Void functions don't get saved return values
                let ret_var = if LLVMGetReturnType(LLVMGetElementType(LLVMTypeOf(function))) == LLVMVoidTypeInContext(context.context) {
                    c_str_ptr("")
                } else {
                    let mut tmp = name.to_string();
                    tmp.push_str("tmp");

                    c_str_ptr(&tmp)
                };

                Some(LLVMBuildCall(context.builder, function, arg_values.as_ptr() as *mut _, arg_values.len() as u32, ret_var))
            },
            Expr::InfixOp(ref op, ref lhs_exprwrapper, ref rhs_exprwrapper) => {
                let (lhs_val, rhs_val) = (lhs_exprwrapper.gen_code(context), rhs_exprwrapper.gen_code(context));

                match *op {
                    InfixOp::Add => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator add")
                    },
                    InfixOp::Sub => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator sub")
                    },
                    InfixOp::Div => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator div")
                    },
                    InfixOp::Mul => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator mul")
                    },
                    InfixOp::Mod => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator mod")
                    },
                    InfixOp::Pow => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator pow")
                    },
                    InfixOp::Equ => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator equ")

                    },
                }
            },
            Expr::UnaryOp(ref op, ref expr) => {
                match *op {
                    // I think Negate would be easier to handle by replacing it with multiply * -1 in the parser
                    UnaryOp::Negate => panic!("Codegen error: Negation not supported in codegen."),
                    UnaryOp::Not => match expr.gen_code(context) {
                        Some(val) => Some(LLVMBuildNot(context.get_builder(), val, c_str_ptr("nottmp"))),
                        None => None
                    }
                }
            },
            Expr::NoOp => None,
            _ => None
        }
    }
}

// Helper function
pub fn c_str_ptr(rust_str: &str) -> *const i8 {
    match CString::new(rust_str.as_bytes()) {
        Ok(string) => string,
        Err(err) => panic!(err)
    }.as_ptr()
}
<commit_msg>Started writing code gen for infix ops<commit_after>extern crate llvm_sys;

use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::str;
use self::llvm_sys::core::*;
use self::llvm_sys::analysis::*;
use self::llvm_sys::execution_engine::*;
use self::llvm_sys::prelude::*;
use self::llvm_sys::target::*;
//use self::llvm_sys::transforms::scalar::*;
use syntax::ast::op::*;
use syntax::ast::expr::*;
use syntax::ast::literals::*;

// Struct to keep track of data needed to build IR
pub struct Context {
    context: LLVMContextRef,
    module: LLVMModuleRef,
    builder: LLVMBuilderRef,
    execution_engine: LLVMExecutionEngineRef,
    fn_pass_manager: LLVMPassManagerRef,
    named_values: HashMap<String, LLVMValueRef>,
}

impl Context {
    pub unsafe fn new(module_name: &str) -> Context {
        LLVM_InitializeNativeTarget();
        LLVM_InitializeNativeAsmPrinter();
        LLVM_InitializeNativeAsmParser();
        LLVMLinkInInterpreter();

        let context = LLVMContextCreate();
        let module = LLVMModuleCreateWithNameInContext(c_str_ptr(module_name), context);
        let builder = LLVMCreateBuilderInContext(context);
        let named_values = HashMap::new();
        let mut execution_engine = 0 as LLVMExecutionEngineRef;
        let mut error_msg = 0 as *mut i8;

        if LLVMCreateExecutionEngineForModule(&mut execution_engine, module, &mut error_msg) == 1 {
            panic!("{}", str::from_utf8(CStr::from_ptr(error_msg).to_bytes()).unwrap())
        }

        let fn_pass_manager = LLVMCreateFunctionPassManagerForModule(module);
        let target_data = LLVMGetExecutionEngineTargetData(execution_engine);
        let data_layout = LLVMCopyStringRepOfTargetData(target_data);
        LLVMSetDataLayout(module, data_layout);
        LLVMAddTargetData(target_data, fn_pass_manager);
        LLVMDisposeMessage(data_layout);

        // Add desired passes to pass manager here
//        LLVMAddInstructionCombiningPass(fn_pass_manager);

        LLVMInitializeFunctionPassManager(fn_pass_manager);

        Context {
            context: context,
            module: module,
            builder: builder,
            execution_engine: execution_engine,
            fn_pass_manager: fn_pass_manager,
            named_values: named_values,
        }
    }

    // Dump the IR to stdout
    pub unsafe fn dump(&self) {
        LLVMDumpModule(self.module);
    }

    // Verifies that the llvm code is valid. Optionally prints
    // the error message, else abort.
    pub unsafe fn verify(&self) {
        let action = LLVMVerifierFailureAction::LLVMPrintMessageAction;
        let msg = vec![c_str_ptr("")];

        LLVMVerifyModule(self.module, action, msg.as_ptr() as *mut _);
        LLVMDisposeMessage(msg[0] as *mut _);
    }

    pub unsafe fn run(&self) -> u64 {
        let main = LLVMGetNamedFunction(self.module, c_str_ptr("main"));
        let result = LLVMRunFunction(self.execution_engine, main, 0, 0 as *mut LLVMGenericValueRef);

        LLVMGenericValueToInt(result, 1)
    }

    // Struct getters
    pub fn get_context(&self) -> LLVMContextRef {
        self.context
    }

    pub fn get_module(&self) -> LLVMModuleRef {
        self.module
    }

    pub fn get_builder(&self) -> LLVMBuilderRef {
        self.builder
    }

    pub fn clear_values(&mut self) {
        self.named_values.clear();
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        unsafe {
            LLVMDisposePassManager(self.fn_pass_manager);
//            LLVMDisposeExecutionEngine(self.execution_engine); // signal 4s for some reason
            LLVMDisposeBuilder(self.builder);
            LLVMDisposeModule(self.module);
            LLVMContextDispose(self.context);
        }
    }
}

pub trait CodeGen {
    unsafe fn gen_code(&self, context: &mut Context) -> Option<LLVMValueRef>;
}

impl CodeGen for ExprWrapper {
    unsafe fn gen_code(&self, context: &mut Context) -> Option<LLVMValueRef> {
        self.get_expr().gen_code(context)
    }
}

impl CodeGen for Expr {
    unsafe fn gen_code(&self, context: &mut Context) -> Option<LLVMValueRef> {
        match *self {
            Expr::Block(ref vec) => {
                let mut gen = None;

                for expr in vec {
                    gen = expr.gen_code(context);
                }

                gen
            },
            Expr::Ident(ref name) => {
                match context.named_values.get(name) {
                    Some(val) => Some(*val),
                    None => {
                        println!("Error: Unknown variable named {}", name);

                        None
                    }
                }
            },
            Expr::Literal(ref literal_type) => {
                match literal_type {
                    &Literals::UTF8String(ref val) => {
                        // Types
                        let array_type1 = LLVMArrayType(LLVMInt8TypeInContext(context.get_context()), val.len() as u32);
                        // let string_struct_type = LLVMGetNamedGlobal(context.get_module(), c_str_ptr("struct.string"));
                        // if string_struct_type.is_null() {
                        //     println!("TMP Error: Cannot find builtin string type!");
                        // }
                        let i8_type = LLVMInt8TypeInContext(context.get_context());
                        let i8_ptr_type = LLVMPointerType(i8_type, 0);
                        let i32_type = LLVMInt32TypeInContext(context.get_context());
                        let i64_type = LLVMInt64TypeInContext(context.get_context());
                        // let string_type_fields = vec![LLVMInt32TypeInContext(context.get_context()),
                        //               LLVMPointerType(LLVMInt8TypeInContext(context.get_context()), 0)];

                        // Values
                        let len = LLVMConstInt(i64_type, val.len() as u64, 0);

                        // Make a global string constant and assign the value:
                        let const_str_var = LLVMAddGlobal(context.get_module(), array_type1, c_str_ptr("str"));
                        let mut chars = Vec::new();
                        for chr in val.bytes() {
                            chars.push(LLVMConstInt(i8_type, chr as u64, 0));
                        }

                        let const_str_array = LLVMConstArray(i8_type, chars.as_ptr() as *mut _, chars.len() as u32);
                        LLVMSetInitializer(const_str_var, const_str_array);
                        LLVMSetGlobalConstant(const_str_var, 1);

                        let args = vec![LLVMConstInt(i32_type, 0, 0), LLVMConstInt(i32_type, 0, 0)];
                        let allocated_str_ptr = LLVMBuildAlloca(context.get_builder(), i8_ptr_type, c_str_ptr("a"));
                        let mallocated_ptr = LLVMBuildMalloc(context.get_builder(), i8_type, c_str_ptr("m"));

                        LLVMSetTailCall(mallocated_ptr, 0);
                        LLVMBuildStore(context.get_builder(), mallocated_ptr, allocated_str_ptr);

                        let element_ptr = LLVMBuildGEP(context.get_builder(), const_str_var, args.as_ptr() as *mut _, 2, c_str_ptr(""));
                        LLVMBuildStore(context.get_builder(), element_ptr, allocated_str_ptr);

                        let loaded_ptr = LLVMBuildLoad(context.get_builder(), allocated_str_ptr, c_str_ptr("l"));
                        // String type generated here should eventually be preloaded type
                        let string_type_fields = vec![LLVMPointerType(i8_type, 0), i64_type];
                        let string_type = LLVMStructTypeInContext(context.get_context(), string_type_fields.as_ptr() as *mut _, 2, 0);
                        let undef = LLVMGetUndef(string_type);

                        let i = LLVMBuildInsertValue(context.get_builder(), undef, loaded_ptr, 0, c_str_ptr("i"));
                        Some(LLVMBuildInsertValue(context.get_builder(), i, len, 1, c_str_ptr("i")))
                    },
                    &Literals::I32Num(ref val) => {
                        let ty = LLVMInt32TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val as u64, 1))
                    },
                    &Literals::I64Num(ref val) => {
                        let ty = LLVMInt64TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val as u64, 1))
                    },
                    &Literals::U32Num(ref val) => {
                        let ty = LLVMInt32TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val as u64, 0))
                    },
                    &Literals::U64Num(ref val) => {
                        let ty = LLVMInt64TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val, 0))
                    },
                    &Literals::F32Num(ref val) => {
                        let ty = LLVMFloatTypeInContext(context.get_context());
                        Some(LLVMConstReal(ty, *val as f64))
                    },
                    &Literals::F64Num(ref val) => {
                        let ty = LLVMDoubleTypeInContext(context.get_context());
                        Some(LLVMConstReal(ty, *val))
                    },
                    &Literals::Bool(ref val) => {
                        let ty = LLVMInt1TypeInContext(context.get_context());
                        Some(LLVMConstInt(ty, *val as u64, 0))
                    },
                    _ => {
                        println!("Error: Codegen unimplemented for {:?}", literal_type);
                        None
                    }
                }
            },
            Expr::FnCall(ref name, ref args) => {
                let function = LLVMGetNamedFunction(context.module, c_str_ptr(name));

                if function.is_null() {
                    // TODO: Add standardized error message writing?
                    println!("Error: Function {} not found.", name);
                    return None;
                }

                let arg_count = LLVMCountParams(function) as usize;

                if arg_count != args.len() {
                    println!("Error: Function {} requires {} argument(s), {} given.", name, arg_count, args.len());
                    return None;
                }

                let mut arg_values = Vec::new();

                for arg in args {
                    match arg.gen_code(context) {
                        Some(value) => arg_values.push(value),
                        None => {
                            println!("Fatal Error: Argument {:?} codegen failed!", arg);
                            return None
                        }
                    }
                }

                // Void functions don't get saved return values
                let ret_var = if LLVMGetReturnType(LLVMGetElementType(LLVMTypeOf(function))) == LLVMVoidTypeInContext(context.context) {
                    c_str_ptr("")
                } else {
                    let mut tmp = name.to_string();
                    tmp.push_str("tmp");

                    c_str_ptr(&tmp)
                };

                Some(LLVMBuildCall(context.builder, function, arg_values.as_ptr() as *mut _, arg_values.len() as u32, ret_var))
            },
            Expr::InfixOp(ref op, ref lhs_exprwrapper, ref rhs_exprwrapper) => {
                let (lhs_val, rhs_val) =  match (lhs_exprwrapper.gen_code(context), rhs_exprwrapper.gen_code(context)) {
                    (Some(val1), Some(val2)) => (val1, val2),
                    (Some(_), None) => unreachable!("CodeGen Error: InfixOp only LHS contains value"),
                    (None, Some(_)) => unreachable!("CodeGen Error: InfixOp only RHS contains value"),
                    (None, None) => unreachable!("CodeGen Error: InfixOp has no values")
                };

                match *op { // Needs testing, what happens when adding diff types? LLVM error? Is that SA's job?
                    InfixOp::Add => match (lhs_val, rhs_val) {
                        _ => Some(LLVMBuildAdd(context.get_builder(), lhs_val, rhs_val, c_str_ptr("add")))
                    },
                    InfixOp::Sub => match (lhs_val, rhs_val) {
                        _ => Some(LLVMBuildSub(context.get_builder(), lhs_val, rhs_val, c_str_ptr("sub")))
                    },
                    InfixOp::Div => match (lhs_val, rhs_val) {
                        // LLVMBuildFDiv, LLVMBuildSDiv, LLVMBuildUDiv
                        _ => panic!("Unimplemented infix operator div")
                    },
                    InfixOp::Mul => match (lhs_val, rhs_val) {
                        _ => Some(LLVMBuildMul(context.get_builder(), lhs_val, rhs_val, c_str_ptr("mul")))
                    },
                    InfixOp::Mod => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator mod")
                    },
                    InfixOp::Pow => match (lhs_val, rhs_val) {
                        _ => panic!("Unimplemented infix operator pow")
                    },
                    InfixOp::Equ => match (lhs_val, rhs_val) {
                        // LLVMBuildICmp, LLVMBuildFCmp?
                        _ => panic!("Unimplemented infix operator equ")

                    },
                }
            },
            Expr::UnaryOp(ref op, ref expr) => { // Needs further testing
                match *op {
                    UnaryOp::Negate => match expr.gen_code(context) {
                        Some(val) => Some(LLVMBuildNeg(context.get_builder(), val, c_str_ptr("neg"))),
                        None => None
                    },
                    UnaryOp::Not => match expr.gen_code(context) {
                        Some(val) => Some(LLVMBuildNot(context.get_builder(), val, c_str_ptr("not"))),
                        None => None
                    }
                }
            },
            Expr::NoOp => None,
            _ => None
        }
    }
}

// Helper function
pub fn c_str_ptr(rust_str: &str) -> *const i8 {
    match CString::new(rust_str.as_bytes()) {
        Ok(string) => string,
        Err(err) => panic!(err)
    }.as_ptr()
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};

use analysis;
use analysis::namespaces::MAIN;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use writer::primitives;

use stripper_interface as stripper;
use stripper_interface::Type as SType;
use stripper_interface::TypeStruct;
use stripper_interface::{FILE, /*FILE_COMMENT, */MOD_COMMENT};

mod format;

trait FunctionTraitType {
    fn functions(&self) -> &Vec<Function>;
    fn name(&self) -> &str;
}

macro_rules! impl_function_trait_type {
    ($ty:ident) => {
        impl FunctionTraitType for $ty {
            fn functions(&self) -> &Vec<Function> {
                &self.functions
            }

            fn name(&self) -> &str {
                &self.name
            }
        }
    }
}

impl_function_trait_type!(Class);
impl_function_trait_type!(Interface);

trait ToStripperType {
    fn convert(&self) -> stripper::TypeStruct;
    fn doc(&self) -> Option<String>;
    fn doc_deprecated(&self) -> Option<String>;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn convert(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }

            fn doc(&self) -> Option<String> {
                self.doc.clone()
            }

            fn doc_deprecated(&self) -> Option<String> {
                self.doc_deprecated.clone()
            }
        }
    }
}

impl_to_stripper_type!(Alias, Struct);
impl_to_stripper_type!(Constant, Const);
impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Type);
impl_to_stripper_type!(Field, Variant);
impl_to_stripper_type!(Union, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Interface, Trait);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Namespace, Mod);
impl_to_stripper_type!(Parameter, Variant);

pub fn generate(env: &Env) {
    let path =  env.config.target_path.join("doc.cmts");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_doc(w, &env));
}

fn generate_doc(mut w: &mut Write, env: &Env) -> Result<()> {
    try!(writeln!(w, "{}*", FILE));

    let namespace = env.library.namespace(MAIN);
    for obj in env.config.objects.values() {
        if !obj.status.need_generate() {
            continue;
        }

        let info = analysis::object::class(env, obj)
            .or_else(|| analysis::object::interface(env, obj));
        let class_analysis = match info {
            Some(info) => info,
            None => continue,
        };
        let has_trait = class_analysis.has_children;

        try!(handle_type(w, &env.library.type_(class_analysis.type_id), None, has_trait,
                         true, &env));
    }

    for ty in namespace.types.iter().filter_map(|t| t.as_ref()) {
        try!(handle_type(&mut w, &ty, None, false, false, &env));
    }
    Ok(())
}

fn handle_type(w: &mut Write, ty: &LType, parent: Option<Box<TypeStruct>>,
               has_trait: bool, handle_structs: bool,
               env: &Env) -> Result<()> {
    match *ty {
        LType::Alias(ref a) => create_sub_doc(w, a, parent, env),
        LType::Enumeration(ref e) => create_enum_doc(w, &e, parent, env),
        LType::Function(ref f) => create_fn_doc(w, &f, parent, env),
        LType::Interface(ref i) if handle_structs => create_class_doc(w, i, parent, has_trait,
                                                                      env),
        LType::Class(ref c) if handle_structs => create_class_doc(w, c, parent, has_trait,
                                                                  env),
        _ => Ok(()),
    }
}

fn create_class_doc<T: FunctionTraitType + ToStripperType>(w: &mut Write, class: &T,
                                                           parent: Option<Box<TypeStruct>>,
                                                           has_trait: bool,
                                                           env: &Env)
                                                          -> Result<()> {
    let tabs : String = primitives::tabs(compute_indent(&parent));
    let mut ty = class.convert();
    ty.parent = parent;

    //try!(writeln!(w, "{}src/auto/{}.rs", FILE, module_name(&class.name())));
    if class.doc().is_some() || class.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, ty));
    }

    if let Some(ref class_doc) = class.doc() {
        try!(write_lines(w, &class_doc, &tabs, env));
    }
    if let Some(ref class_doc) = class.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &class_doc, &tabs, env));
    }

    for function in class.functions().iter() {
        if function.parameters.iter().any(|p| p.instance_parameter) == false {
            try!(create_fn_doc(w, &function, Some(Box::new(ty.clone())), env));
        }
    }
    if has_trait {
        ty.ty = SType::Trait;
        ty.name = format!("{}Ext", class.convert().name);

        for function in class.functions().iter() {
            if function.parameters.iter().any(|p| p.instance_parameter) {
                try!(create_fn_doc(w, &function, Some(Box::new(ty.clone())), env));
            }
        }
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, enum_: &Enumeration,
                   parent: Option<Box<TypeStruct>>,
                   env: &Env) -> Result<()> {
    let indent = compute_indent(&parent);
    let mut ty = enum_.convert();
    ty.parent = parent;
    let tabs : String = primitives::tabs(indent);

    if enum_.doc().is_some() || enum_.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, ty));
    }

    if let Some(ref enum_doc) = enum_.doc() {
        try!(write_lines(w, &enum_doc, &tabs, env));
    }
    if let Some(ref enum_doc) = enum_.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &enum_doc, &tabs, env));
    }

    let tabs : String = primitives::tabs(indent + 1);
    for member_doc in enum_.members.iter() {
        let mut sub_ty : TypeStruct = member_doc.convert();

        if member_doc.doc().is_some() || member_doc.doc_deprecated().is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));
        }
        if let Some(ref m_doc) = member_doc.doc() {
            try!(write_lines(w, &m_doc, &tabs, env));
        }
        if let Some(ref m_doc) = member_doc.doc_deprecated() {
            try!(write_header(w, &tabs, "Deprecated"));
            try!(write_lines(w, &m_doc, &tabs, env));
        }
    }
    Ok(())
}

fn create_fn_doc(w: &mut Write, fn_: &Function, parent: Option<Box<TypeStruct>>,
                 env: &Env) -> Result<()> {
    let tabs : String = primitives::tabs(compute_indent(&parent) + 1);

    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret.doc().is_none() {
        if fn_.parameters.iter().all(|x| {
            x.doc().is_none()
        }) {
            return Ok(());
        }
    }
    let mut sub_ty = fn_.convert();
    sub_ty.parent = parent;
    try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));

    if let Some(ref docs) = fn_.doc() {
        try!(write_lines(w, &docs, &tabs, env));
    };
    if let Some(ref docs) = fn_.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &docs, &tabs, env));
    };

    if fn_.parameters.iter().any(|x| {
           x.instance_parameter == false && !x.name.is_empty() && x.doc().is_some()
       }) {
        try!(write_header(w, &tabs, "Parameters"));
    }
    for parameter in fn_.parameters.iter() {
        if parameter.instance_parameter || parameter.name.is_empty() {
            continue
        }
        if let Some(ref parameter_doc) = parameter.doc() {
            try!(writeln!(w, "{}/// ## {}:", tabs, parameter.name));
            try!(write_lines(w, &parameter_doc, &tabs, env));
        }
    }

    if let Some(ref doc) = fn_.ret.doc() {
        try!(write_header(w, &tabs, "Returns"));
        try!(write_lines(w, &doc, &tabs, env));
    }
    Ok(())
}

fn write_lines(w: &mut Write, lines: &str, tabs: &str,
               env: &Env) -> Result<()> {
    for line in format::reformat_doc(&lines, env).split("\n") {
        try!(writeln!(w, "{}/// {}", tabs, line));
    }
    Ok(())
}

fn create_sub_doc<T: ToStripperType>(w: &mut Write, ty: &T,
                                     parent: Option<Box<TypeStruct>>,
                                     env: &Env) -> Result<()> {
    let tabs : String = primitives::tabs(compute_indent(&parent));
    let mut sub_ty = ty.convert();
    sub_ty.parent = parent;

    if ty.doc().is_some() || ty.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));
    }

    if let Some(doc) = ty.doc() {
        try!(write_lines(w, &doc, &tabs, env));
    }
    if let Some(doc) = ty.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &doc, &tabs, env));
    }
    Ok(())
}

fn compute_indent(e: &Option<Box<TypeStruct>>) -> usize {
    match *e {
        Some(ref e) if e.parent.is_some() => compute_indent(&e.parent) + 1,
        _ => 0,
    }
}

fn write_header(w: &mut Write, tabs: &str, header: &str) -> Result<()> {
    writeln!(w, "{0}///\n{0}/// # {1}\n{0}///", tabs, header)
}
<commit_msg>Fix class-struct/trait relationship handling<commit_after>use std::io::{Result, Write};

use analysis;
use analysis::namespaces::MAIN;
use env::Env;
use file_saver::save_to_file;
use library::*;
use library::Type as LType;
use writer::primitives;

use stripper_interface as stripper;
use stripper_interface::Type as SType;
use stripper_interface::TypeStruct;
use stripper_interface::{FILE, /*FILE_COMMENT, */MOD_COMMENT};

mod format;

trait FunctionTraitType {
    fn functions(&self) -> &Vec<Function>;
    fn name(&self) -> &str;
}

macro_rules! impl_function_trait_type {
    ($ty:ident) => {
        impl FunctionTraitType for $ty {
            fn functions(&self) -> &Vec<Function> {
                &self.functions
            }

            fn name(&self) -> &str {
                &self.name
            }
        }
    }
}

impl_function_trait_type!(Class);
impl_function_trait_type!(Interface);

trait ToStripperType {
    fn convert(&self) -> stripper::TypeStruct;
    fn doc(&self) -> Option<String>;
    fn doc_deprecated(&self) -> Option<String>;
}

macro_rules! impl_to_stripper_type {
    ($ty:ident, $enum_var:ident) => {
        impl ToStripperType for $ty {
            fn convert(&self) -> TypeStruct {
                TypeStruct::new(SType::$enum_var, &self.name)
            }

            fn doc(&self) -> Option<String> {
                self.doc.clone()
            }

            fn doc_deprecated(&self) -> Option<String> {
                self.doc_deprecated.clone()
            }
        }
    }
}

impl_to_stripper_type!(Alias, Struct);
impl_to_stripper_type!(Constant, Const);
impl_to_stripper_type!(Member, Variant);
impl_to_stripper_type!(Enumeration, Enum);
impl_to_stripper_type!(Bitfield, Type);
impl_to_stripper_type!(Record, Type);
impl_to_stripper_type!(Field, Variant);
impl_to_stripper_type!(Union, Struct);
impl_to_stripper_type!(Function, Fn);
impl_to_stripper_type!(Interface, Trait);
impl_to_stripper_type!(Class, Struct);
impl_to_stripper_type!(Namespace, Mod);
impl_to_stripper_type!(Parameter, Variant);

pub fn generate(env: &Env) {
    let path =  env.config.target_path.join("doc.cmts");
    println!("Generating documentation {:?}", path);
    save_to_file(&path, env.config.make_backup,
        |w| generate_doc(w, &env));
}

fn generate_doc(mut w: &mut Write, env: &Env) -> Result<()> {
    try!(writeln!(w, "{}*", FILE));

    let namespace = env.library.namespace(MAIN);
    for obj in env.config.objects.values() {
        if !obj.status.need_generate() {
            continue;
        }

        let info = analysis::object::class(env, obj)
            .or_else(|| analysis::object::interface(env, obj));
        let class_analysis = match info {
            Some(info) => info,
            None => continue,
        };
        let has_trait = class_analysis.has_children;

        try!(handle_type(w, &env.library.type_(class_analysis.type_id), None, has_trait,
                         true, &env));
    }

    for ty in namespace.types.iter().filter_map(|t| t.as_ref()) {
        try!(handle_type(&mut w, &ty, None, false, false, &env));
    }
    Ok(())
}

fn handle_type(w: &mut Write, ty: &LType, parent: Option<Box<TypeStruct>>,
               has_trait: bool, handle_structs: bool,
               env: &Env) -> Result<()> {
    match *ty {
        LType::Alias(ref a) => create_sub_doc(w, a, parent, env),
        LType::Enumeration(ref e) => create_enum_doc(w, &e, parent, env),
        LType::Function(ref f) => create_fn_doc(w, &f, parent, env),
        LType::Interface(ref i) if handle_structs => create_class_doc(w, i, parent, has_trait,
                                                                      env),
        LType::Class(ref c) if handle_structs => create_class_doc(w, c, parent, has_trait,
                                                                  env),
        _ => Ok(()),
    }
}

fn create_class_doc<T: FunctionTraitType + ToStripperType>(w: &mut Write, class: &T,
                                                           parent: Option<Box<TypeStruct>>,
                                                           has_trait: bool,
                                                           env: &Env)
                                                          -> Result<()> {
    let tabs : String = primitives::tabs(compute_indent(&parent));
    let ty = TypeStruct { parent: parent, ..class.convert() };
    let ty_ext = TypeStruct {
        ty: SType::Trait,
        name: format!("{}Ext", ty.name),
        ..ty.clone()
    };

    //try!(writeln!(w, "{}src/auto/{}.rs", FILE, module_name(&class.name())));
    if class.doc().is_some() || class.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, ty));
    }

    if let Some(ref class_doc) = class.doc() {
        try!(write_lines(w, &class_doc, &tabs, env));
    }
    if let Some(ref class_doc) = class.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &class_doc, &tabs, env));
    }

    let ty = TypeStruct { ty: SType::Impl, ..ty };

    for function in class.functions().iter() {
        let ty = if has_trait && function.parameters.iter().any(|p| p.instance_parameter) {
            ty_ext.clone()
        }
        else {
            ty.clone()
        };
        try!(create_fn_doc(w, &function, Some(Box::new(ty)), env));
    }
    Ok(())
}

fn create_enum_doc(w: &mut Write, enum_: &Enumeration,
                   parent: Option<Box<TypeStruct>>,
                   env: &Env) -> Result<()> {
    let indent = compute_indent(&parent);
    let mut ty = enum_.convert();
    ty.parent = parent;
    let tabs : String = primitives::tabs(indent);

    if enum_.doc().is_some() || enum_.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, ty));
    }

    if let Some(ref enum_doc) = enum_.doc() {
        try!(write_lines(w, &enum_doc, &tabs, env));
    }
    if let Some(ref enum_doc) = enum_.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &enum_doc, &tabs, env));
    }

    let tabs : String = primitives::tabs(indent + 1);
    for member_doc in enum_.members.iter() {
        let mut sub_ty : TypeStruct = member_doc.convert();

        if member_doc.doc().is_some() || member_doc.doc_deprecated().is_some() {
            sub_ty.parent = Some(Box::new(ty.clone()));
            try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));
        }
        if let Some(ref m_doc) = member_doc.doc() {
            try!(write_lines(w, &m_doc, &tabs, env));
        }
        if let Some(ref m_doc) = member_doc.doc_deprecated() {
            try!(write_header(w, &tabs, "Deprecated"));
            try!(write_lines(w, &m_doc, &tabs, env));
        }
    }
    Ok(())
}

fn create_fn_doc(w: &mut Write, fn_: &Function, parent: Option<Box<TypeStruct>>,
                 env: &Env) -> Result<()> {
    let tabs : String = primitives::tabs(compute_indent(&parent) + 1);

    if fn_.doc().is_none() && fn_.doc_deprecated().is_none() && fn_.ret.doc().is_none() {
        if fn_.parameters.iter().all(|x| {
            x.doc().is_none()
        }) {
            return Ok(());
        }
    }
    let mut sub_ty = fn_.convert();
    sub_ty.parent = parent;
    try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));

    if let Some(ref docs) = fn_.doc() {
        try!(write_lines(w, &docs, &tabs, env));
    };
    if let Some(ref docs) = fn_.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &docs, &tabs, env));
    };

    if fn_.parameters.iter().any(|x| {
           x.instance_parameter == false && !x.name.is_empty() && x.doc().is_some()
       }) {
        try!(write_header(w, &tabs, "Parameters"));
    }
    for parameter in fn_.parameters.iter() {
        if parameter.instance_parameter || parameter.name.is_empty() {
            continue
        }
        if let Some(ref parameter_doc) = parameter.doc() {
            try!(writeln!(w, "{}/// ## {}:", tabs, parameter.name));
            try!(write_lines(w, &parameter_doc, &tabs, env));
        }
    }

    if let Some(ref doc) = fn_.ret.doc() {
        try!(write_header(w, &tabs, "Returns"));
        try!(write_lines(w, &doc, &tabs, env));
    }
    Ok(())
}

fn write_lines(w: &mut Write, lines: &str, tabs: &str,
               env: &Env) -> Result<()> {
    for line in format::reformat_doc(&lines, env).split("\n") {
        try!(writeln!(w, "{}/// {}", tabs, line));
    }
    Ok(())
}

fn create_sub_doc<T: ToStripperType>(w: &mut Write, ty: &T,
                                     parent: Option<Box<TypeStruct>>,
                                     env: &Env) -> Result<()> {
    let tabs : String = primitives::tabs(compute_indent(&parent));
    let mut sub_ty = ty.convert();
    sub_ty.parent = parent;

    if ty.doc().is_some() || ty.doc_deprecated().is_some() {
        try!(writeln!(w, "{}{}", MOD_COMMENT, sub_ty));
    }

    if let Some(doc) = ty.doc() {
        try!(write_lines(w, &doc, &tabs, env));
    }
    if let Some(doc) = ty.doc_deprecated() {
        try!(write_header(w, &tabs, "Deprecated"));
        try!(write_lines(w, &doc, &tabs, env));
    }
    Ok(())
}

fn compute_indent(e: &Option<Box<TypeStruct>>) -> usize {
    match *e {
        Some(ref e) if e.parent.is_some() => compute_indent(&e.parent) + 1,
        _ => 0,
    }
}

fn write_header(w: &mut Write, tabs: &str, header: &str) -> Result<()> {
    writeln!(w, "{0}///\n{0}/// # {1}\n{0}///", tabs, header)
}
<|endoftext|>


<commit_before>extern crate mioco;

use mioco::sync::mpsc;
use std::thread;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

// NOTE: All the tests are using single MIOCO instance and
// the number of messages that reciver receives varies
// across machines. so the tests here aren't very scalable.
// on the other hand, the sleep times are generous and
// receiver should ideally receive all the messages. anything
// otherwise might help identify performance issues.

#[test]
fn tx_rx_outside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();

    thread::spawn(move || for i in 0..10 {
                      let _ = tx.send(i);
                  });

    thread::sleep_ms(1000);

    for i in 0..10 {
        assert_eq!(i, rx.recv().unwrap());
    }
}

#[test]
fn tx_outside_rx_inside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();
    // use count to check if all the messages are
    // received at receiver end
    let count = Arc::new(AtomicUsize::new(0));

    for i in 0..10 {
        let _ = tx.send(i);
    }

    let count_clone = count.clone();
    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
            count_clone.store(i, Ordering::SeqCst);
        }
    });

    thread::sleep_ms(3000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}

#[test]
fn tx_inside_rx_inside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();
    let count = Arc::new(AtomicUsize::new(0));

    mioco::spawn(move ||{
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    let count_clone = count.clone();
    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
            count_clone.store(i, Ordering::SeqCst);
        }
    });

    thread::sleep_ms(3000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}

#[test]
fn sync_tx_rx_outside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let count = Arc::new(AtomicUsize::new(0));

    thread::spawn(move || for i in 0..10 {
                      let _ = tx.send(i);
                  });

    thread::sleep_ms(1000);

    let count_clone = count.clone();
    for i in 0..10 {
        assert_eq!(i, rx.recv().unwrap());
        count_clone.store(i, Ordering::SeqCst);
    }

    thread::sleep_ms(3000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}

#[test]
fn sync_tx_outside_rx_inside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let count = Arc::new(AtomicUsize::new(0));

    thread::spawn(move || {
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    let count_clone = count.clone();
    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
            count_clone.store(i, Ordering::SeqCst);
        }
    });

    thread::sleep_ms(1000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}

#[test]
fn sync_tx_inside_rx_inside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let count = Arc::new(AtomicUsize::new(0));

    mioco::spawn(move || {
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    thread::sleep_ms(1000);

    let count_clone = count.clone();
    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
            count_clone.store(i, Ordering::SeqCst);
        }
    });

    thread::sleep_ms(3000);
    assert_eq!(9, count.load(Ordering::SeqCst));
}
<commit_msg>remove sleeps from mpsc tests & use channel for synchronization<commit_after>extern crate mioco;

use mioco::sync::mpsc;
use std::thread;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

// NOTE: All the tests are using single MIOCO instance

#[test]
fn tx_rx_outside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();

    thread::spawn(move || for i in 0..10 {
                      let _ = tx.send(i);
                  });

    thread::sleep_ms(1000);

    for i in 0..10 {
        assert_eq!(i, rx.recv().unwrap());
    }
}

#[test]
fn tx_outside_rx_inside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();
    let (sync_tx, sync_rx) = mpsc::channel();

    for i in 0..10 {
        let _ = tx.send(i);
    }

    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
        }
        let _ = sync_tx.send(true);
    });

    assert_eq!(true, sync_rx.recv().unwrap());
}

#[test]
fn tx_inside_rx_inside_mioco() {
    let (tx, rx) = mpsc::channel::<usize>();
    let (sync_tx, sync_rx) = mpsc::channel();

    mioco::spawn(move ||{
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
        }
        let _ = sync_tx.send(true);
    });

    assert_eq!(true, sync_rx.recv().unwrap());
}

#[test]
fn sync_tx_rx_outside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let (sync_tx, sync_rx) = mpsc::channel();

    thread::spawn(move || for i in 0..10 {
                      let _ = tx.send(i);
                  });

    thread::sleep_ms(1000);

    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
        }
        let _ = sync_tx.send(true);
    });

    assert_eq!(true, sync_rx.recv().unwrap());
}

#[test]
fn sync_tx_outside_rx_inside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let (sync_tx, sync_rx) = mpsc::channel();

    thread::spawn(move || {
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
        }
        let _ = sync_tx.send(true);
    });

    assert_eq!(true, sync_rx.recv().unwrap());
}

#[test]
fn sync_tx_inside_rx_inside_mioco() {
    let (tx, rx) = mpsc::sync_channel::<usize>(5);
    let (sync_tx, sync_rx) = mpsc::channel();

    mioco::spawn(move || {
        for i in 0..10 {
            let _ = tx.send(i);
        }
    });

    thread::sleep_ms(1000);

    mioco::spawn(move || {
        for i in 0..10 {
            assert_eq!(i, rx.recv().unwrap());
        }
        let _ = sync_tx.send(true);
    });

    assert_eq!(true, sync_rx.recv().unwrap());
}
<|endoftext|>


<commit_before>/// Rust TNetStrings serialization library.

/// Represents a TNetString value.
pub enum TNetString {
    Str(~[u8]),
    Int(int),
    Float(float),
    Bool(bool),
    Null,
    Map(~send_map::linear::LinearMap<~[u8], TNetString>),
    Vec(~[TNetString]),
}

/// Serializes a TNetString value into a io::Writer.
pub fn to_writer(writer: io::Writer, tnetstring: &TNetString) {
    fn write_str(wr: io::Writer, s: &[u8]) {
        wr.write_str(#fmt("%u:", s.len()));
        wr.write(s);
        wr.write_char(',');
    }

    match *tnetstring {
        Str(s) => write_str(writer, s),
        Int(i) => {
            let s = int::str(i);
            writer.write_str(#fmt("%u:%s#", s.len(), s));
        }
        Float(f) => {
            let s = float::to_str(f, 6u);
            writer.write_str(#fmt("%u:%s^", s.len(), s));
        }
        Bool(b) => {
            let s = bool::to_str(b);
            writer.write_str(#fmt("%u:%s!", s.len(), s));
        }
        Map(m) => {
            let payload = do io::with_bytes_writer |wr| {
                for m.each |key, value| {
                    write_str(wr, *key);
                    to_writer(wr, value);
                }
            };
            writer.write_str(#fmt("%u:", payload.len()));
            writer.write(payload);
            writer.write_char('}');
        }
        Vec(v) => {
            let payload = do io::with_bytes_writer |wr| {
                for v.each |e| { to_writer(wr, e) }
            };
            writer.write_str(#fmt("%u:", payload.len()));
            writer.write(payload);
            writer.write_char(']');
        }
        Null => writer.write_str("0:~"),
    }
}

/// Serializes a TNetString value into a byte string.
pub fn to_bytes(tnetstring: &TNetString) -> ~[u8] {
    do io::with_bytes_writer |wr| {
        to_writer(wr, tnetstring);
    }
}

/// Serializes a TNetString value into a string.
pub impl TNetString: to_str::ToStr {
    fn to_str() -> ~str {
        do io::with_str_writer |wr| {
            to_writer(wr, &self);
        }
    }
}

/// Deserializes a TNetString value from an io::Reader.
pub fn from_reader(reader: io::Reader) -> Option<TNetString> {
    assert !reader.eof();

    let mut c = reader.read_byte();
    let mut len = 0u;

    // Note that netstring spec explicitly forbids padding zeros.
    // If the first char is zero, it must be the only char.
    if c < '0' as int || c > '9' as int {
        fail ~"Not a TNetString: invalid or missing length prefix";
    } else if c == '0' as int {
        c = reader.read_byte();
    } else {
        loop {
            len = (10u * len) + ((c as uint) - ('0' as uint));

            if reader.eof() {
                fail ~"Not a TNetString: invalid or missing length prefix";
            }
            c = reader.read_byte();

            if c < '0' as int || c > '9' as int {
                break;
            }
        }
    }

    // Validate end-of-length-prefix marker.
    if c != ':' as int {
        fail ~"Not a TNetString: missing length prefix";
    }

    // Read the data plus terminating type tag.
    let payload = reader.read_bytes(len);

    if payload.len() != len {
        fail ~"Not a TNetString: invalid length prefix";
    }

    if reader.eof() {
        fail ~"Not a TNetString: missing type tag";
    }

    match reader.read_byte() as char {
      '#' => {
        let s = unsafe { str::raw::from_bytes(payload) };
        int::from_str(s).map(|v| Int(*v))
      }
      '}' => Some(Map(parse_map(payload))),
      ']' => Some(Vec(parse_vec(payload))),
      '!' => {
        let s = unsafe { str::raw::from_bytes(payload) };
        bool::from_str(s).map(|v| Bool(*v))
      }
      '^' => {
        let s = unsafe { str::raw::from_bytes(payload) };
        float::from_str(s).map(|v| Float(*v))
      }
      '~' => {
        assert payload.len() == 0u;
        Some(Null)
      }
      ',' => Some(Str(payload)),
      c => {
        let s = str::from_char(c);
        fail #fmt("Invalid payload type: %?", s)
      }
    }
}

fn parse_vec(data: &[u8]) -> ~[TNetString] {
    if data.len() == 0u { return ~[]; }

    do io::with_bytes_reader(data) |reader| {
        let mut result = ~[];

        match move from_reader(reader) {
            Some(move value) => result.push(value),
            None => fail ~"invalid value"
        }

        while !reader.eof() {
            match move from_reader(reader) {
                Some(move value) => result.push(value),
                None => fail ~"invalid TNetString"
            }
        }

        result
    }
}

fn parse_pair(reader: io::Reader) -> (~[u8], TNetString) {
    match move from_reader(reader) {
        Some(Str(move key)) => {
            match move from_reader(reader) {
                Some(move value) => (key, value),
                None => fail ~"invalid TNetString",
            }
        }
        Some(_) => fail ~"Keys can only be strings.",
        None => fail ~"Invalid TNetString",
    }
}

fn parse_map(data: &[u8]) -> ~send_map::linear::LinearMap<~[u8], TNetString> {
    let mut result = ~send_map::linear::LinearMap();

    if data.len() != 0u {
        do io::with_bytes_reader(data) |reader| {
            let (key, value) = parse_pair(reader);
            result.insert(key, value);

            while !reader.eof() {
                let (key, value) = parse_pair(reader);
                result.insert(key, value);
            }
        }
    }

    result
}

/// Deserializes a TNetString value from a byte string.
pub fn from_bytes(data: &[u8]) -> (Option<TNetString>, ~[u8]) {
    do io::with_bytes_reader(data) |reader| {
        let TNetString = from_reader(reader);
        (TNetString, reader.read_whole_stream())
    }
}

/// Deserializes a TNetString value from a string.
pub fn from_str(data: &str) -> (Option<TNetString>, ~str) {
    do io::with_str_reader(data) |rdr| {
        let tnetstring = from_reader(rdr);
        let bytes = rdr.read_whole_stream();
        (tnetstring, str::from_bytes(bytes))
    }

}

/// Test the equality between two TNetString values
pub impl TNetString: cmp::Eq {
    pure fn eq(other: &TNetString) -> bool {
        // FIXME: https://github.com/mozilla/rust/issues/2855
        match (&self, other) {
            (&Str(s0), &Str(s1)) => s0 == s1,
            (&Int(i0), &Int(i1)) => i0 == i1,
            (&Float(f0), &Float(f1)) => f0 == f1,
            (&Bool(b0), &Bool(b1)) => b0 == b1,
            (&Null, &Null) => true,
            (&Map(d0), &Map(d1)) => {
                if d0.len() == d1.len() {
                    for d0.each |k0, v0| {
                        let result = match d1.find_ref(k0) {
                            Some(v1) => v0 == v1,
                            None => false,
                        };
                        if !result { return false; }
                    }
                    true
                } else {
                    false
                }
            }
            (&Vec(v0), &Vec(v1)) => vec::all2(v0, v1, |x0, x1| x0 == x1),
            _ => false
        }
    }

    pure fn ne(other: &TNetString) -> bool { !self.eq(other) }
}

#[cfg(test)]
mod tests {
    // Tests inspired by https://github.com/rfk/TNetString.

    fn test(+s: ~str, expected: &TNetString) {
        let (actual, rest) = from_str(s);
        assert actual.is_some();
        assert rest == ~"";

        let actual = option::unwrap(actual);
        assert actual == *expected;
        assert expected.to_str() == s;
    }

    #[test]
    fn test_format() {
        test(~"11:hello world,", &Str(str::to_bytes("hello world")));
        test(~"0:}", &Map(~send_map::linear::LinearMap()));
        test(~"0:]", &Vec(~[]));

        let mut d = ~send_map::linear::LinearMap();
        d.insert(str::to_bytes("hello"),
                Vec(~[
                    Int(12345678901),
                    Str(str::to_bytes("this")),
                    Bool(true),
                    Null,
                    Str(str::to_bytes("\x00\x00\x00\x00"))]));

        test(~"51:5:hello,39:11:12345678901#4:this,4:true!0:~4:\x00\x00\x00\
               \x00,]}", &Map(d));

        test(~"5:12345#", &Int(12345));
        test(~"12:this is cool,", &Str(str::to_bytes("this is cool")));
        test(~"0:,", &Str(str::to_bytes("")));
        test(~"0:~", &Null);
        test(~"4:true!", &Bool(true));
        test(~"5:false!", &Bool(false));
        test(~"10:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
            &Str(str::to_bytes("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")));
        test(~"24:5:12345#5:67890#5:xxxxx,]",
            &Vec(~[
                Int(12345),
                Int(67890),
                Str(str::to_bytes("xxxxx"))]));
        test(~"18:3:0.1^3:0.2^3:0.4^]",
           &Vec(~[Float(0.1), Float(0.2), Float(0.4)]));
        test(~"243:238:233:228:223:218:213:208:203:198:193:188:183:178:173:\
               168:163:158:153:148:143:138:133:128:123:118:113:108:103:99:95:\
               91:87:83:79:75:71:67:63:59:55:51:47:43:39:35:31:27:23:19:15:\
               11:hello-there,]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\
               ]]]]",
            &Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[
                    Str(str::to_bytes("hello-there"))
                ])])])])])])])])])])])])])])])])])])])])])])])])])])])])
                ])])])])])])])])])])])])])])])])])])])])])])]));
    }

    #[test]
    fn test_random() {
        fn randint(rng: rand::Rng, a: u32, b: u32) -> u32 {
            (rng.next() % (b - a + 1u32)) + a
        }

        fn get_random_object(rng: rand::Rng, depth: u32) -> TNetString {
            if randint(rng, depth, 10u32) <= 4u32 {
                if randint(rng, 0u32, 1u32) == 0u32 {
                    let n = randint(rng, 0u32, 10u32);
                    Vec(vec::from_fn(n as uint, |_i|
                        get_random_object(rng, depth + 1u32)
                    ))
                } else {
                    let mut d = ~send_map::linear::LinearMap();

                    let mut i = randint(rng, 0u32, 10u32);
                    while i != 0u32 {
                        let s = rng.gen_bytes(randint(rng, 0u32, 100u32) as uint);
                        d.insert(s, get_random_object(rng, depth + 1u32));
                        i -= 1u32;
                    }
                    Map(d)
                }
            } else {
                match randint(rng, 0u32, 5u32) {
                  0u32 => Null,
                  1u32 => Bool(true),
                  2u32 => Bool(false),
                  3u32 => {
                    if randint(rng, 0u32, 1u32) == 0u32 {
                        Int(rng.next() as int)
                    } else {
                        Int(-rng.next() as int)
                    }
                  }
                  4u32 => {
                    let mut f = rng.gen_float();

                    // Generate a float that can be exactly converted to
                    // and from a string.
                    loop {
                        match float::from_str(float::to_str(f, 6u)) {
                          Some(f1) => {
                            if f == f1 { break; }
                            f = f1;
                          }
                          None => fail ~"invalid float"
                        }
                    }

                    if randint(rng, 0u32, 1u32) == 0u32 {
                        Float(f)
                    } else {
                        Float(-f)
                    }
                  }
                  5u32 => {
                    Str(rng.gen_bytes(randint(rng, 0u32, 100u32) as uint))
                  }
                  _ => fail
                }
            }
        }

        let rng = rand::Rng();

        let mut i = 500u;
        while i != 0u {
            let v0 = get_random_object(rng, 0u32);

            match from_bytes(to_bytes(&v0)) {
                (Some(v1), rest) if rest == ~[] => assert v0 == v1,
                _ => fail ~"invalid TNetString"
            }
            i -= 1u;
        }
    }
}
<commit_msg>Add a type alias for map<commit_after>/// Rust TNetStrings serialization library.

/// Represents a TNetString value.
pub enum TNetString {
    Str(~[u8]),
    Int(int),
    Float(float),
    Bool(bool),
    Null,
    Map(Map),
    Vec(~[TNetString]),
}

pub type Map = ~send_map::linear::LinearMap<~[u8], TNetString>;

/// Serializes a TNetString value into a io::Writer.
pub fn to_writer(writer: io::Writer, tnetstring: &TNetString) {
    fn write_str(wr: io::Writer, s: &[u8]) {
        wr.write_str(#fmt("%u:", s.len()));
        wr.write(s);
        wr.write_char(',');
    }

    match *tnetstring {
        Str(s) => write_str(writer, s),
        Int(i) => {
            let s = int::str(i);
            writer.write_str(#fmt("%u:%s#", s.len(), s));
        }
        Float(f) => {
            let s = float::to_str(f, 6u);
            writer.write_str(#fmt("%u:%s^", s.len(), s));
        }
        Bool(b) => {
            let s = bool::to_str(b);
            writer.write_str(#fmt("%u:%s!", s.len(), s));
        }
        Map(m) => {
            let payload = do io::with_bytes_writer |wr| {
                for m.each |key, value| {
                    write_str(wr, *key);
                    to_writer(wr, value);
                }
            };
            writer.write_str(#fmt("%u:", payload.len()));
            writer.write(payload);
            writer.write_char('}');
        }
        Vec(v) => {
            let payload = do io::with_bytes_writer |wr| {
                for v.each |e| { to_writer(wr, e) }
            };
            writer.write_str(#fmt("%u:", payload.len()));
            writer.write(payload);
            writer.write_char(']');
        }
        Null => writer.write_str("0:~"),
    }
}

/// Serializes a TNetString value into a byte string.
pub fn to_bytes(tnetstring: &TNetString) -> ~[u8] {
    do io::with_bytes_writer |wr| {
        to_writer(wr, tnetstring);
    }
}

/// Serializes a TNetString value into a string.
pub impl TNetString: to_str::ToStr {
    fn to_str() -> ~str {
        do io::with_str_writer |wr| {
            to_writer(wr, &self);
        }
    }
}

/// Deserializes a TNetString value from an io::Reader.
pub fn from_reader(reader: io::Reader) -> Option<TNetString> {
    assert !reader.eof();

    let mut c = reader.read_byte();
    let mut len = 0u;

    // Note that netstring spec explicitly forbids padding zeros.
    // If the first char is zero, it must be the only char.
    if c < '0' as int || c > '9' as int {
        fail ~"Not a TNetString: invalid or missing length prefix";
    } else if c == '0' as int {
        c = reader.read_byte();
    } else {
        loop {
            len = (10u * len) + ((c as uint) - ('0' as uint));

            if reader.eof() {
                fail ~"Not a TNetString: invalid or missing length prefix";
            }
            c = reader.read_byte();

            if c < '0' as int || c > '9' as int {
                break;
            }
        }
    }

    // Validate end-of-length-prefix marker.
    if c != ':' as int {
        fail ~"Not a TNetString: missing length prefix";
    }

    // Read the data plus terminating type tag.
    let payload = reader.read_bytes(len);

    if payload.len() != len {
        fail ~"Not a TNetString: invalid length prefix";
    }

    if reader.eof() {
        fail ~"Not a TNetString: missing type tag";
    }

    match reader.read_byte() as char {
      '#' => {
        let s = unsafe { str::raw::from_bytes(payload) };
        int::from_str(s).map(|v| Int(*v))
      }
      '}' => Some(Map(parse_map(payload))),
      ']' => Some(Vec(parse_vec(payload))),
      '!' => {
        let s = unsafe { str::raw::from_bytes(payload) };
        bool::from_str(s).map(|v| Bool(*v))
      }
      '^' => {
        let s = unsafe { str::raw::from_bytes(payload) };
        float::from_str(s).map(|v| Float(*v))
      }
      '~' => {
        assert payload.len() == 0u;
        Some(Null)
      }
      ',' => Some(Str(payload)),
      c => {
        let s = str::from_char(c);
        fail #fmt("Invalid payload type: %?", s)
      }
    }
}

fn parse_vec(data: &[u8]) -> ~[TNetString] {
    if data.len() == 0u { return ~[]; }

    do io::with_bytes_reader(data) |reader| {
        let mut result = ~[];

        match move from_reader(reader) {
            Some(move value) => result.push(value),
            None => fail ~"invalid value"
        }

        while !reader.eof() {
            match move from_reader(reader) {
                Some(move value) => result.push(value),
                None => fail ~"invalid TNetString"
            }
        }

        result
    }
}

fn parse_pair(reader: io::Reader) -> (~[u8], TNetString) {
    match move from_reader(reader) {
        Some(Str(move key)) => {
            match move from_reader(reader) {
                Some(move value) => (key, value),
                None => fail ~"invalid TNetString",
            }
        }
        Some(_) => fail ~"Keys can only be strings.",
        None => fail ~"Invalid TNetString",
    }
}

fn parse_map(data: &[u8]) -> ~send_map::linear::LinearMap<~[u8], TNetString> {
    let mut result = ~send_map::linear::LinearMap();

    if data.len() != 0u {
        do io::with_bytes_reader(data) |reader| {
            let (key, value) = parse_pair(reader);
            result.insert(key, value);

            while !reader.eof() {
                let (key, value) = parse_pair(reader);
                result.insert(key, value);
            }
        }
    }

    result
}

/// Deserializes a TNetString value from a byte string.
pub fn from_bytes(data: &[u8]) -> (Option<TNetString>, ~[u8]) {
    do io::with_bytes_reader(data) |reader| {
        let TNetString = from_reader(reader);
        (TNetString, reader.read_whole_stream())
    }
}

/// Deserializes a TNetString value from a string.
pub fn from_str(data: &str) -> (Option<TNetString>, ~str) {
    do io::with_str_reader(data) |rdr| {
        let tnetstring = from_reader(rdr);
        let bytes = rdr.read_whole_stream();
        (tnetstring, str::from_bytes(bytes))
    }

}

/// Test the equality between two TNetString values
pub impl TNetString: cmp::Eq {
    pure fn eq(other: &TNetString) -> bool {
        // FIXME: https://github.com/mozilla/rust/issues/2855
        match (&self, other) {
            (&Str(s0), &Str(s1)) => s0 == s1,
            (&Int(i0), &Int(i1)) => i0 == i1,
            (&Float(f0), &Float(f1)) => f0 == f1,
            (&Bool(b0), &Bool(b1)) => b0 == b1,
            (&Null, &Null) => true,
            (&Map(d0), &Map(d1)) => {
                if d0.len() == d1.len() {
                    for d0.each |k0, v0| {
                        let result = match d1.find_ref(k0) {
                            Some(v1) => v0 == v1,
                            None => false,
                        };
                        if !result { return false; }
                    }
                    true
                } else {
                    false
                }
            }
            (&Vec(v0), &Vec(v1)) => vec::all2(v0, v1, |x0, x1| x0 == x1),
            _ => false
        }
    }

    pure fn ne(other: &TNetString) -> bool { !self.eq(other) }
}

#[cfg(test)]
mod tests {
    // Tests inspired by https://github.com/rfk/TNetString.

    fn test(+s: ~str, expected: &TNetString) {
        let (actual, rest) = from_str(s);
        assert actual.is_some();
        assert rest == ~"";

        let actual = option::unwrap(actual);
        assert actual == *expected;
        assert expected.to_str() == s;
    }

    #[test]
    fn test_format() {
        test(~"11:hello world,", &Str(str::to_bytes("hello world")));
        test(~"0:}", &Map(~send_map::linear::LinearMap()));
        test(~"0:]", &Vec(~[]));

        let mut d = ~send_map::linear::LinearMap();
        d.insert(str::to_bytes("hello"),
                Vec(~[
                    Int(12345678901),
                    Str(str::to_bytes("this")),
                    Bool(true),
                    Null,
                    Str(str::to_bytes("\x00\x00\x00\x00"))]));

        test(~"51:5:hello,39:11:12345678901#4:this,4:true!0:~4:\x00\x00\x00\
               \x00,]}", &Map(d));

        test(~"5:12345#", &Int(12345));
        test(~"12:this is cool,", &Str(str::to_bytes("this is cool")));
        test(~"0:,", &Str(str::to_bytes("")));
        test(~"0:~", &Null);
        test(~"4:true!", &Bool(true));
        test(~"5:false!", &Bool(false));
        test(~"10:\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
            &Str(str::to_bytes("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")));
        test(~"24:5:12345#5:67890#5:xxxxx,]",
            &Vec(~[
                Int(12345),
                Int(67890),
                Str(str::to_bytes("xxxxx"))]));
        test(~"18:3:0.1^3:0.2^3:0.4^]",
           &Vec(~[Float(0.1), Float(0.2), Float(0.4)]));
        test(~"243:238:233:228:223:218:213:208:203:198:193:188:183:178:173:\
               168:163:158:153:148:143:138:133:128:123:118:113:108:103:99:95:\
               91:87:83:79:75:71:67:63:59:55:51:47:43:39:35:31:27:23:19:15:\
               11:hello-there,]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]\
               ]]]]",
            &Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(~[Vec(
                ~[Vec(~[Vec(~[
                    Str(str::to_bytes("hello-there"))
                ])])])])])])])])])])])])])])])])])])])])])])])])])])])])
                ])])])])])])])])])])])])])])])])])])])])])])]));
    }

    #[test]
    fn test_random() {
        fn randint(rng: rand::Rng, a: u32, b: u32) -> u32 {
            (rng.next() % (b - a + 1u32)) + a
        }

        fn get_random_object(rng: rand::Rng, depth: u32) -> TNetString {
            if randint(rng, depth, 10u32) <= 4u32 {
                if randint(rng, 0u32, 1u32) == 0u32 {
                    let n = randint(rng, 0u32, 10u32);
                    Vec(vec::from_fn(n as uint, |_i|
                        get_random_object(rng, depth + 1u32)
                    ))
                } else {
                    let mut d = ~send_map::linear::LinearMap();

                    let mut i = randint(rng, 0u32, 10u32);
                    while i != 0u32 {
                        let s = rng.gen_bytes(randint(rng, 0u32, 100u32) as uint);
                        d.insert(s, get_random_object(rng, depth + 1u32));
                        i -= 1u32;
                    }
                    Map(d)
                }
            } else {
                match randint(rng, 0u32, 5u32) {
                  0u32 => Null,
                  1u32 => Bool(true),
                  2u32 => Bool(false),
                  3u32 => {
                    if randint(rng, 0u32, 1u32) == 0u32 {
                        Int(rng.next() as int)
                    } else {
                        Int(-rng.next() as int)
                    }
                  }
                  4u32 => {
                    let mut f = rng.gen_float();

                    // Generate a float that can be exactly converted to
                    // and from a string.
                    loop {
                        match float::from_str(float::to_str(f, 6u)) {
                          Some(f1) => {
                            if f == f1 { break; }
                            f = f1;
                          }
                          None => fail ~"invalid float"
                        }
                    }

                    if randint(rng, 0u32, 1u32) == 0u32 {
                        Float(f)
                    } else {
                        Float(-f)
                    }
                  }
                  5u32 => {
                    Str(rng.gen_bytes(randint(rng, 0u32, 100u32) as uint))
                  }
                  _ => fail
                }
            }
        }

        let rng = rand::Rng();

        let mut i = 500u;
        while i != 0u {
            let v0 = get_random_object(rng, 0u32);

            match from_bytes(to_bytes(&v0)) {
                (Some(v1), rest) if rest == ~[] => assert v0 == v1,
                _ => fail ~"invalid TNetString"
            }
            i -= 1u;
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Read;
use std::collections::HashMap;

use abra::schema::{SchemaRead, FieldType};
use abra::store::{IndexStore, IndexReader};
use rustc_serialize::json::Json;

use mapping;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_put_mapping(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");
    let ref mapping_name = read_path_parameter!(req, "mapping").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Get index
    let mut index = get_index_or_404_mut!(indices, *index_name);

    // Load data from body
    let data = json_from_request_body!(req);

    let data = match data {
        Some(data) => data,
        None => {
            // TODO: Better error
            return Ok(json_response(status::BadRequest, "{\"acknowledged\": false}"));
        }
    };

    let data = data.as_object().unwrap().get(*mapping_name).unwrap();

    // Insert mapping
    let mut mapping = mapping::Mapping::from_json(&index.analyzers, &data);
    debug!("{:#?}", mapping);
    let is_updating = index.mappings.contains_key(*mapping_name);

    // Find list of new fields that need to be added to the store
    let new_fields = {
        let index_reader = index.store.reader();
        let schema = index_reader.schema();
        let mut new_fields: HashMap<String, FieldType>  = HashMap::new();
        for (field_name, field_mapping) in mapping.fields.iter() {
            let field_type = match field_mapping.data_type {
                mapping::FieldType::String => FieldType::Text,
                mapping::FieldType::Integer => FieldType::I64,
                mapping::FieldType::Boolean => FieldType::Boolean,
                mapping::FieldType::Date => FieldType::DateTime,
            };

            // Check if this field already exists
            if let Some(field_ref) = schema.get_field_by_name(&field_name) {
                let field_info = schema.get(&field_ref).expect("get_field_by_name returned an invalid FieldRef");

                // Field already exists. Check for conflicting type, otherwise ignore.
                if field_info.field_type == field_type {
                    continue;
                } else {
                    // Conflict!
                    // TODO: Better error
                    return Ok(json_response(status::BadRequest, "{\"acknowledged\": false}"));
                }
            }

            new_fields.insert(field_name.clone(), field_type);
        }

        new_fields
    };

    // Add new fields into the store
    for (field_name, field_type) in new_fields {
        system.log.info("[api] adding field", b!("index" => *index_name, "field" => field_name, "type" => format!("{:?}", field_type)));
        index.store.add_field(field_name, field_type).unwrap();
    }

    // Link the mapping
    {
        let index_reader = index.store.reader();
        let schema = index_reader.schema();

        for (field_name, field_mapping) in mapping.fields.iter_mut() {
            field_mapping.index_ref = schema.get_field_by_name(&field_name)
        }
    }

    index.mappings.insert(mapping_name.clone().to_owned(), mapping);

    if is_updating {
        // TODO: New mapping should be merged with existing one
        system.log.info("[api] updated mapping", b!("index" => *index_name, "mapping" => *mapping_name));
    } else {
        system.log.info("[api] created mapping", b!("index" => *index_name, "mapping" => *mapping_name));
    }

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}
<commit_msg>Switch to using new mapping parser<commit_after>use std::io::Read;
use std::collections::HashMap;

use abra::schema::{SchemaRead, FieldType};
use abra::store::{IndexStore, IndexReader};
use rustc_serialize::json::Json;

use mapping;
use mapping::parse::parse as parse_mapping;

use api::persistent;
use api::iron::prelude::*;
use api::iron::status;
use api::router::Router;
use api::utils::json_response;

pub fn view_put_mapping(req: &mut Request) -> IronResult<Response> {
    let ref system = get_system!(req);
    let ref index_name = read_path_parameter!(req, "index").unwrap_or("");
    let ref mapping_name = read_path_parameter!(req, "mapping").unwrap_or("");

    // Lock index array
    let mut indices = system.indices.write().unwrap();

    // Get index
    let mut index = get_index_or_404_mut!(indices, *index_name);

    // Load data from body
    let data = json_from_request_body!(req);

    let data = match data {
        Some(data) => data,
        None => {
            // TODO: Better error
            return Ok(json_response(status::BadRequest, "{\"acknowledged\": false}"));
        }
    };

    let data = data.as_object().unwrap().get(*mapping_name).unwrap();

    // Insert mapping
    let mapping_builder = match parse_mapping(&data) {
        Ok(mapping_builder) => mapping_builder,
        Err(e) => {
            // TODO: Better error
            return Ok(json_response(status::BadRequest, "{\"acknowledged\": false}"));
        }
    };
    let mut mapping = mapping_builder.build(&index.analyzers);
    debug!("{:#?}", mapping);
    let is_updating = index.mappings.contains_key(*mapping_name);

    // Find list of new fields that need to be added to the store
    let new_fields = {
        let index_reader = index.store.reader();
        let schema = index_reader.schema();
        let mut new_fields: HashMap<String, FieldType>  = HashMap::new();
        for (field_name, field_mapping) in mapping.fields.iter() {
            let field_type = match field_mapping.data_type {
                mapping::FieldType::String => FieldType::Text,
                mapping::FieldType::Integer => FieldType::I64,
                mapping::FieldType::Boolean => FieldType::Boolean,
                mapping::FieldType::Date => FieldType::DateTime,
            };

            // Check if this field already exists
            if let Some(field_ref) = schema.get_field_by_name(&field_name) {
                let field_info = schema.get(&field_ref).expect("get_field_by_name returned an invalid FieldRef");

                // Field already exists. Check for conflicting type, otherwise ignore.
                if field_info.field_type == field_type {
                    continue;
                } else {
                    // Conflict!
                    // TODO: Better error
                    return Ok(json_response(status::BadRequest, "{\"acknowledged\": false}"));
                }
            }

            new_fields.insert(field_name.clone(), field_type);
        }

        new_fields
    };

    // Add new fields into the store
    for (field_name, field_type) in new_fields {
        system.log.info("[api] adding field", b!("index" => *index_name, "field" => field_name, "type" => format!("{:?}", field_type)));
        index.store.add_field(field_name, field_type).unwrap();
    }

    // Link the mapping
    {
        let index_reader = index.store.reader();
        let schema = index_reader.schema();

        for (field_name, field_mapping) in mapping.fields.iter_mut() {
            field_mapping.index_ref = schema.get_field_by_name(&field_name)
        }
    }

    index.mappings.insert(mapping_name.clone().to_owned(), mapping);

    if is_updating {
        // TODO: New mapping should be merged with existing one
        system.log.info("[api] updated mapping", b!("index" => *index_name, "mapping" => *mapping_name));
    } else {
        system.log.info("[api] created mapping", b!("index" => *index_name, "mapping" => *mapping_name));
    }

    return Ok(json_response(status::Ok, "{\"acknowledged\": true}"));
}
<|endoftext|>


<commit_before>use ::opcodes::AddressingMode;

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum ImmediateBase {
    Base10,
    Base16,
}

#[derive(Clone, Debug, PartialEq )]
pub enum LexerToken {
    Ident(String),
    Assignment,
    Address(String),
    OpenParenthesis,
    CloseParenthesis,
    Comma,
    Period,
    Immediate(String, ImmediateBase),
    Colon,
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum Token {
    Unknown(String),
    Label(String),
    OpCode(String),
    Immediate(String, ImmediateBase),
    ZeroPage(String),
    ZeroPageX(String),
    Absolute(String),
    AbsoluteX(String),
    AbsoluteY(String),
    Indirect(String),
    IndirectX(String),
    IndirectY(String),
    Directive(String),
    Digits(String, ImmediateBase),
    Assignment,
}

impl Token {
    pub fn to_addressing_mode(&self) -> AddressingMode {
        match *self {
            Token::Immediate(_, _) => AddressingMode::Immediate,
            Token::ZeroPage(_) => AddressingMode::ZeroPage,
            Token::ZeroPageX(_) => AddressingMode::ZeroPageX,
            Token::Absolute(_) => AddressingMode::Absolute,
            Token::AbsoluteX(_) => AddressingMode::AbsoluteX,
            Token::AbsoluteY(_) => AddressingMode::AbsoluteY,
            Token::Indirect(_) => AddressingMode::Indirect,
            Token::IndirectX(_) => AddressingMode::IndirectX,
            Token::IndirectY(_) => AddressingMode::IndirectY,
            _ => AddressingMode::Implied,
        }
    }
}<commit_msg>Overnight commit<commit_after>use ::opcodes::{AddressingMode, OpCode};

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum ImmediateBase {
    Base10,
    Base16,
}

#[derive(Clone, Debug, PartialEq )]
pub enum LexerToken {
    Ident(String),
    Assignment,
    Address(String),
    OpenParenthesis,
    CloseParenthesis,
    Comma,
    Period,
    Immediate(String, ImmediateBase),
    Colon,
}

#[derive(Eq, PartialEq, Debug, Clone)]
pub enum ParserToken {
    Label(String),
    OpCode(OpCode),
    RawByte(u8),
    Directive(String),
}

impl Token {
    pub fn to_addressing_mode(&self) -> AddressingMode {
        match *self {
            Token::Immediate(_, _) => AddressingMode::Immediate,
            Token::ZeroPage(_) => AddressingMode::ZeroPage,
            Token::ZeroPageX(_) => AddressingMode::ZeroPageX,
            Token::Absolute(_) => AddressingMode::Absolute,
            Token::AbsoluteX(_) => AddressingMode::AbsoluteX,
            Token::AbsoluteY(_) => AddressingMode::AbsoluteY,
            Token::Indirect(_) => AddressingMode::Indirect,
            Token::IndirectX(_) => AddressingMode::IndirectX,
            Token::IndirectY(_) => AddressingMode::IndirectY,
            _ => AddressingMode::Implied,
        }
    }
}<|endoftext|>