<commit_before>extern crate llvm_sys as llvm;
use std::collections::hash_map::Entry;
use std::ffi::CString;
use std::ptr;
use self::llvm::prelude::*;

use node::*;
use env::Env;

pub struct VM {
    context: LLVMContextRef,
    builder: LLVMBuilderRef,
    module: LLVMModuleRef,
    int_value_type: LLVMTypeRef,
    prims: Env<String>,
}

macro_rules! cptr {
    ($x: expr) => (CString::new($x).unwrap().as_ptr())
}

impl VM {
    pub fn new() -> VM {
        let context = VM::create_context();
        let e = &mut Env::new();
        // alias
        e.register("+", "prim_add".to_string());
        e.register("-", "prim_sub".to_string());
        e.register("*", "prim_mul".to_string());
        e.register("/", "prim_div".to_string());

        VM {
            context: context,
            builder: VM::create_builder_in_context(context),
            module: VM::create_module_with_name("rlisp"),
            int_value_type: VM::int_type(context),
            prims: e.clone(),
        }
    }

    pub fn run(&self, node: &Node) {
        let env = &mut Env::new();
        self.init(env);
        self.pre_gen(node, env);
        self.llvm_ret(self.codegen(node, env));
        self.finalize();
    }

    fn init(&self, env: &mut Env<LLVMValueRef>) {
        self.register_symbols(env);

        // create main
        self.create_fun_and_set_bb("main", self.int_value_type, &mut []);
    }

    fn pre_gen(&self, ast: &Node, env: &mut Env<LLVMValueRef>) {
        if let &Node::Cell(ref car, ref cdr) = ast {
            match sym_to_str(car).unwrap().as_ref() {
                "define" => {
                    if let Node::Cell(ref ncar, ref ncdr) = **cdr {
                        // vm should know a type of the return value
                        // TODO: create LLVMValueRef wrapper struct
                        let sym_name = sym_to_str(ncar).unwrap();
                        let val = self.codegen(&rcar(ncdr).unwrap().clone(), env);
                        let ptr = match env.entry(sym_name.as_ref()) {
                            Entry::Occupied(o) => *o.get(),
                            Entry::Vacant(v) => {
                                let p = self.allocate_mem(sym_name.as_ref(), self.int_value_type);
                                v.insert(p);
                                p
                            }
                        };
                        self.llmv_store(val, ptr);
                    }
                }
                _ => panic!("not suport in pre gen"),
            }
        } else {
            panic!("not suport in pre gen");
        }
    }

    fn register_symbols(&self, env: &mut Env<LLVMValueRef>) {
        env.register("+", self.codegen_prim_arith("prim_add"));
        env.register("-", self.codegen_prim_arith("prim_sub"));
        env.register("*", self.codegen_prim_arith("prim_mul"));
        env.register("/", self.codegen_prim_arith("prim_div"));
    }

    fn finalize(&self) {
        unsafe {
            llvm::core::LLVMDumpModule(self.module);
            llvm::core::LLVMPrintModuleToFile(self.module, cptr!("out.ll"), ptr::null_mut());

            llvm::core::LLVMDisposeBuilder(self.builder);
            llvm::core::LLVMDisposeModule(self.module);
            llvm::core::LLVMContextDispose(self.context);
        }
    }

    fn codegen_prim_arith(&self, name: &str) -> LLVMValueRef {
        let ty = self.int_value_type;
        let arg_types = &mut [ty, ty];
        let fun = self.create_fun_and_set_bb(name, ty, arg_types);
        let lh = self.get_param_fun(&fun, 0);
        let rh = self.get_param_fun(&fun, 1);
        let v = match name {
            "prim_add" => self.llvm_add(lh, rh),
            "prim_sub" => self.llvm_sub(lh, rh),
            "prim_mul" => self.llvm_mul(lh, rh),
            "prim_div" => self.llvm_div(lh, rh),
            _ => {
                println!("{:?}", name);
                panic!("not support arith")
            }
        };
        self.llvm_ret(v);
        fun
    }

    fn llvm_ret(&self, ret: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildRet(self.builder, ret) }
    }

    fn llvm_add(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildAdd(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_sub(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildSub(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_mul(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildMul(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_div(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildUDiv(self.builder, lh, rh, cptr!("v")) }
    }

    fn get_param_fun(&self, func: &LLVMValueRef, i: u32) -> LLVMValueRef {
        unsafe { llvm::core::LLVMGetParam(*func, i) }
    }

    fn count_params_fun(&self, func: &LLVMValueRef) -> u32 {
        unsafe { llvm::core::LLVMCountParams(*func) }
    }

    fn get_params_fun(&self, fun: &LLVMValueRef) -> Vec<LLVMValueRef> {
        let count = self.count_params_fun(fun) as usize;
        let p = {
            let buf = &mut Vec::with_capacity(count);
            buf.as_mut_ptr()
        };
        unsafe {
            // std::mem::forget(buf);
            llvm::core::LLVMGetParams(*fun, p);
            Vec::from_raw_parts(p, count, count)
        }
    }

    fn create_fun_and_set_bb(&self,
                             name: &str,
                             ret_ty: LLVMTypeRef,
                             arg_types: &mut [LLVMTypeRef])
                             -> LLVMValueRef {
        let fun_type = self.get_function_type(ret_ty, arg_types);
        let fun = self.add_function(name, fun_type);
        let bb = self.append_basic_block("entry", fun);
        self.set_builder_position_at_end(bb);
        fun
    }

    fn codegen(&self, ast: &Node, env: &mut Env<LLVMValueRef>) -> LLVMValueRef {
        match *ast {
            Node::Int(val) => self.int_value(val as u64),
            Node::Cell(ref car, ref cdr) => {
                match **car {
                    Node::Sym(ref n) => self.apply_fun(env, n, cdr),
                    _ => panic!("not suport"),
                }
            }
            Node::Sym(ref v) => *env.find(v).unwrap(),  // TODO fix
            ref a => {
                println!("{:?}", a);
                panic!("not support in codegen")
            }
        }
    }

    fn apply_fun(&self, env: &mut Env<LLVMValueRef>, name: &str, rest: &Node) -> LLVMValueRef {
        match name {
            "+" | "-" | "*" | "/" => self.codegen_arith(name, rest, env),
            "define" => {
                let c = rcar(rest).and_then(|v| sym_to_str(&v.clone())).unwrap();
                *env.find(c.as_ref()).unwrap()
            }
            _ => {
                println!("at apply fun {:?}", name);
                panic!("unknow");
            }
        }
    }

    fn codegen_arith(&self, fname: &str, rest: &Node, env: &mut Env<LLVMValueRef>) -> LLVMValueRef {
        match rest {
            &Node::Cell(ref car, ref cdr) => {
                let lh = self.codegen(car, env); // to fix
                if **cdr == rnil() {
                    return lh;
                }
                let rh = self.codegen_arith(fname, cdr, env);
                let v = &fname.into();
                let name = self.prims.find(fname).unwrap_or(v);
                let fun = self.find_function(name).unwrap();
                let args = &mut Vec::new();
                args.push(lh);
                args.push(rh);
                unsafe {
                    llvm::core::LLVMBuildCall(self.builder, fun, args.as_mut_ptr(), 2, cptr!("v"))
                }

            }
            _ => panic!("siran"),
        }
    }

    fn codegen_list(&self, env: &mut Env<LLVMValueRef>, n: &Node) -> Vec<LLVMValueRef> {
        let args = &mut Vec::new();
        let mut node = n;
        while *node != rnil() {
            match node {
                &Node::Cell(ref car, ref cdr) => {
                    args.push(self.codegen(car, env));
                    node = cdr
                }
                _ => panic!("hgoe"),
            }
        }
        args.clone()
    }

    fn apply_codegen(&self,
                     env: &mut Env<LLVMValueRef>,
                     fun: LLVMValueRef,
                     rest: &Node)
                     -> LLVMValueRef {
        let args = self.codegen_list(env, rest);
        let mut_args = args.clone().as_mut_ptr();
        unsafe {
            llvm::core::LLVMBuildCall(self.builder, fun, mut_args, args.len() as u32, cptr!("v"))
        }
    }

    fn find_function(&self, name: &str) -> Option<LLVMValueRef> {
        let v = unsafe { llvm::core::LLVMGetNamedFunction(self.module, cptr!(name)) };
        let is_null = unsafe { llvm::core::LLVMIsNull(v) > 0 };
        if is_null { None } else { Some(v) }
    }

    fn int_value(&self, val: u64) -> LLVMValueRef {
        unsafe { llvm::core::LLVMConstInt(self.int_value_type, val, 0) }
    }

    fn allocate_mem(&self, name: &str, typ: LLVMTypeRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildAlloca(self.builder, typ, cptr!(name)) }
    }

    fn llmv_store(&self, val: LLVMValueRef, target: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildStore(self.builder, val, target) }
    }

    fn set_builder_position_at_end(&self, bb: LLVMBasicBlockRef) {
        unsafe {
            llvm::core::LLVMPositionBuilderAtEnd(self.builder, bb);
        }
    }

    fn append_basic_block(&self, name: &str, fun: LLVMValueRef) -> LLVMBasicBlockRef {
        unsafe { llvm::core::LLVMAppendBasicBlockInContext(self.context, fun, cptr!(name)) }
    }

    fn get_function_type(&self,
                         ret_type: LLVMTypeRef,
                         args_type: &mut [LLVMTypeRef])
                         -> LLVMTypeRef {
        let l = args_type.len() as u32;
        if l == 0 {
            unsafe { llvm::core::LLVMFunctionType(ret_type, ptr::null_mut(), 0, 0) }
        } else {
            unsafe { llvm::core::LLVMFunctionType(ret_type, args_type.as_mut_ptr(), l, 0) }
        }
    }

    fn add_function(&self, name: &str, fun_type: LLVMTypeRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMAddFunction(self.module, cptr!(name), fun_type) }
    }

    fn create_module_with_name(name: &str) -> LLVMModuleRef {
        unsafe { llvm::core::LLVMModuleCreateWithName(cptr!(name)) }
    }

    fn create_builder_in_context(context: LLVMContextRef) -> LLVMBuilderRef {
        unsafe { llvm::core::LLVMCreateBuilderInContext(context) }
    }

    fn create_context() -> LLVMContextRef {
        unsafe { llvm::core::LLVMContextCreate() }
    }

    fn int_type(context: LLVMContextRef) -> LLVMTypeRef {
        unsafe { llvm::core::LLVMInt32TypeInContext(context) }
    }
}
<commit_msg>Change function name<commit_after>extern crate llvm_sys as llvm;
use std::collections::hash_map::Entry;
use std::ffi::CString;
use std::ptr;
use self::llvm::prelude::*;

use node::*;
use env::Env;

pub struct VM {
    context: LLVMContextRef,
    builder: LLVMBuilderRef,
    module: LLVMModuleRef,
    int_value_type: LLVMTypeRef,
    prims: Env<String>,
}

macro_rules! cptr {
    ($x: expr) => (CString::new($x).unwrap().as_ptr())
}

impl VM {
    pub fn new() -> VM {
        let context = VM::create_context();
        let e = &mut Env::new();
        // alias
        e.register("+", "prim_add".to_string());
        e.register("-", "prim_sub".to_string());
        e.register("*", "prim_mul".to_string());
        e.register("/", "prim_div".to_string());

        VM {
            context: context,
            builder: VM::create_builder_in_context(context),
            module: VM::create_module_with_name("rlisp"),
            int_value_type: VM::int_type(context),
            prims: e.clone(),
        }
    }

    pub fn run(&self, node: &Node) {
        let env = &mut Env::new();
        self.init(env);
        self.pre_gen(node, env);
        self.llvm_ret(self.codegen(node, env));
        self.finalize();
    }

    fn init(&self, env: &mut Env<LLVMValueRef>) {
        self.register_symbols(env);

        // create main
        self.create_fun_and_set_bb("main", self.int_value_type, &mut []);
    }

    fn pre_gen(&self, ast: &Node, env: &mut Env<LLVMValueRef>) {
        if let &Node::Cell(ref car, ref cdr) = ast {
            match sym_to_str(car).unwrap().as_ref() {
                "define" => {
                    if let Node::Cell(ref ncar, ref ncdr) = **cdr {
                        // vm should know a type of the return value
                        // TODO: create LLVMValueRef wrapper struct
                        let sym_name = sym_to_str(ncar).unwrap();
                        let val = self.codegen(&rcar(ncdr).unwrap().clone(), env);
                        let ptr = match env.entry(sym_name.as_ref()) {
                            Entry::Occupied(o) => *o.get(),
                            Entry::Vacant(v) => {
                                let p = self.allocate_mem(sym_name.as_ref(), self.int_value_type);
                                v.insert(p);
                                p
                            }
                        };
                        self.llmv_store(val, ptr);
                    }
                }
                _ => panic!("not suport in pre gen"),
            }
        } else {
            panic!("not suport in pre gen");
        }
    }

    fn register_symbols(&self, env: &mut Env<LLVMValueRef>) {
        env.register("+", self.prim_arith("prim_add"));
        env.register("-", self.prim_arith("prim_sub"));
        env.register("*", self.prim_arith("prim_mul"));
        env.register("/", self.prim_arith("prim_div"));
    }

    fn finalize(&self) {
        unsafe {
            llvm::core::LLVMDumpModule(self.module);
            llvm::core::LLVMPrintModuleToFile(self.module, cptr!("out.ll"), ptr::null_mut());

            llvm::core::LLVMDisposeBuilder(self.builder);
            llvm::core::LLVMDisposeModule(self.module);
            llvm::core::LLVMContextDispose(self.context);
        }
    }

    fn prim_arith(&self, name: &str) -> LLVMValueRef {
        let ty = self.int_value_type;
        let arg_types = &mut [ty, ty];
        let fun = self.create_fun_and_set_bb(name, ty, arg_types);
        let lh = self.get_param_fun(&fun, 0);
        let rh = self.get_param_fun(&fun, 1);
        let v = match name {
            "prim_add" => self.llvm_add(lh, rh),
            "prim_sub" => self.llvm_sub(lh, rh),
            "prim_mul" => self.llvm_mul(lh, rh),
            "prim_div" => self.llvm_div(lh, rh),
            _ => {
                println!("{:?}", name);
                panic!("not support arith")
            }
        };
        self.llvm_ret(v);
        fun
    }

    fn llvm_ret(&self, ret: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildRet(self.builder, ret) }
    }

    fn llvm_add(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildAdd(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_sub(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildSub(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_mul(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildMul(self.builder, lh, rh, cptr!("v")) }
    }

    fn llvm_div(&self, lh: LLVMValueRef, rh: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildUDiv(self.builder, lh, rh, cptr!("v")) }
    }

    fn get_param_fun(&self, func: &LLVMValueRef, i: u32) -> LLVMValueRef {
        unsafe { llvm::core::LLVMGetParam(*func, i) }
    }

    fn count_params_fun(&self, func: &LLVMValueRef) -> u32 {
        unsafe { llvm::core::LLVMCountParams(*func) }
    }

    fn get_params_fun(&self, fun: &LLVMValueRef) -> Vec<LLVMValueRef> {
        let count = self.count_params_fun(fun) as usize;
        let p = {
            let buf = &mut Vec::with_capacity(count);
            buf.as_mut_ptr()
        };
        unsafe {
            // std::mem::forget(buf);
            llvm::core::LLVMGetParams(*fun, p);
            Vec::from_raw_parts(p, count, count)
        }
    }

    fn create_fun_and_set_bb(&self,
                             name: &str,
                             ret_ty: LLVMTypeRef,
                             arg_types: &mut [LLVMTypeRef])
                             -> LLVMValueRef {
        let fun_type = self.get_function_type(ret_ty, arg_types);
        let fun = self.add_function(name, fun_type);
        let bb = self.append_basic_block("entry", fun);
        self.set_builder_position_at_end(bb);
        fun
    }

    fn codegen(&self, ast: &Node, env: &mut Env<LLVMValueRef>) -> LLVMValueRef {
        match *ast {
            Node::Int(val) => self.int_value(val as u64),
            Node::Cell(ref car, ref cdr) => {
                match **car {
                    Node::Sym(ref n) => self.apply_fun(env, n, cdr),
                    _ => panic!("not suport"),
                }
            }
            Node::Sym(ref v) => *env.find(v).unwrap(),  // TODO fix
            ref a => {
                println!("{:?}", a);
                panic!("not support in codegen")
            }
        }
    }

    fn apply_fun(&self, env: &mut Env<LLVMValueRef>, name: &str, rest: &Node) -> LLVMValueRef {
        match name {
            "+" | "-" | "*" | "/" => self.codegen_arith(name, rest, env),
            "define" => {
                let c = rcar(rest).and_then(|v| sym_to_str(&v.clone())).unwrap();
                *env.find(c.as_ref()).unwrap()
            }
            _ => {
                // env.find(name)
                println!("at apply fun {:?}", name);
                panic!("unknow");
            }
        }
    }

    fn codegen_arith(&self, fname: &str, rest: &Node, env: &mut Env<LLVMValueRef>) -> LLVMValueRef {
        match rest {
            &Node::Cell(ref car, ref cdr) => {
                let lh = self.codegen(car, env); // to fix
                if **cdr == rnil() {
                    return lh;
                }
                let rh = self.codegen_arith(fname, cdr, env);
                let v = &fname.into();
                let name = self.prims.find(fname).unwrap_or(v);
                let fun = self.find_function(name).unwrap();
                let args = &mut Vec::new();
                args.push(lh);
                args.push(rh);
                unsafe {
                    llvm::core::LLVMBuildCall(self.builder, fun, args.as_mut_ptr(), 2, cptr!("v"))
                }

            }
            _ => panic!("siran"),
        }
    }

    fn codegen_list(&self, env: &mut Env<LLVMValueRef>, n: &Node) -> Vec<LLVMValueRef> {
        let args = &mut Vec::new();
        let mut node = n;
        while *node != rnil() {
            match node {
                &Node::Cell(ref car, ref cdr) => {
                    args.push(self.codegen(car, env));
                    node = cdr
                }
                _ => panic!("hgoe"),
            }
        }
        args.clone()
    }

    fn apply_codegen(&self,
                     env: &mut Env<LLVMValueRef>,
                     fun: LLVMValueRef,
                     rest: &Node)
                     -> LLVMValueRef {
        let args = self.codegen_list(env, rest);
        let mut_args = args.clone().as_mut_ptr();
        unsafe {
            llvm::core::LLVMBuildCall(self.builder, fun, mut_args, args.len() as u32, cptr!("v"))
        }
    }

    fn find_function(&self, name: &str) -> Option<LLVMValueRef> {
        let v = unsafe { llvm::core::LLVMGetNamedFunction(self.module, cptr!(name)) };
        let is_null = unsafe { llvm::core::LLVMIsNull(v) > 0 };
        if is_null { None } else { Some(v) }
    }

    fn int_value(&self, val: u64) -> LLVMValueRef {
        unsafe { llvm::core::LLVMConstInt(self.int_value_type, val, 0) }
    }

    fn allocate_mem(&self, name: &str, typ: LLVMTypeRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildAlloca(self.builder, typ, cptr!(name)) }
    }

    fn llmv_store(&self, val: LLVMValueRef, target: LLVMValueRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMBuildStore(self.builder, val, target) }
    }

    fn set_builder_position_at_end(&self, bb: LLVMBasicBlockRef) {
        unsafe {
            llvm::core::LLVMPositionBuilderAtEnd(self.builder, bb);
        }
    }

    fn append_basic_block(&self, name: &str, fun: LLVMValueRef) -> LLVMBasicBlockRef {
        unsafe { llvm::core::LLVMAppendBasicBlockInContext(self.context, fun, cptr!(name)) }
    }

    fn get_function_type(&self,
                         ret_type: LLVMTypeRef,
                         args_type: &mut [LLVMTypeRef])
                         -> LLVMTypeRef {
        let l = args_type.len() as u32;
        if l == 0 {
            unsafe { llvm::core::LLVMFunctionType(ret_type, ptr::null_mut(), 0, 0) }
        } else {
            unsafe { llvm::core::LLVMFunctionType(ret_type, args_type.as_mut_ptr(), l, 0) }
        }
    }

    fn add_function(&self, name: &str, fun_type: LLVMTypeRef) -> LLVMValueRef {
        unsafe { llvm::core::LLVMAddFunction(self.module, cptr!(name), fun_type) }
    }

    fn create_module_with_name(name: &str) -> LLVMModuleRef {
        unsafe { llvm::core::LLVMModuleCreateWithName(cptr!(name)) }
    }

    fn create_builder_in_context(context: LLVMContextRef) -> LLVMBuilderRef {
        unsafe { llvm::core::LLVMCreateBuilderInContext(context) }
    }

    fn create_context() -> LLVMContextRef {
        unsafe { llvm::core::LLVMContextCreate() }
    }

    fn int_type(context: LLVMContextRef) -> LLVMTypeRef {
        unsafe { llvm::core::LLVMInt32TypeInContext(context) }
    }
}
<|endoftext|>


<commit_before>#![allow(visible_private_types)]

use std::cmp;
use std::iter;
use std::slice::Vector;
use std::str::{MaybeOwned, Owned};
use super::parse;
use super::parse::{
    Flags, FLAG_EMPTY,
    Nothing, Literal, Dot, Class, Begin, End, WordBoundary, Capture, Cat, Alt,
    Rep,
    ZeroOne, ZeroMore, OneMore,
};

type InstIdx = uint;

#[deriving(Show, Clone)]
pub enum MaybeStatic<T> {
    Dynamic(Vec<T>),
    Static(&'static [T]),
}

impl<T> Vector<T> for MaybeStatic<T> {
    fn as_slice<'a>(&'a self) -> &'a [T] {
        match *self {
            Dynamic(ref xs) => xs.as_slice(),
            Static(xs) => xs,
        }
    }
}

impl<T> Container for MaybeStatic<T> {
    fn len(&self) -> uint { self.as_slice().len() }
}

#[deriving(Show, Clone)]
pub enum Inst {
    // When a Match instruction is executed, the current thread is successful.
    Match,

    // The OneChar instruction matches a literal character.
    // If the bool is true, then the match is done case insensitively.
    OneChar(char, Flags),

    // The CharClass instruction tries to match one input character against
    // the range of characters given.
    // If the first bool is true, then the character class is negated.
    // If the second bool is true, then the character class is matched
    // case insensitively.
    CharClass(MaybeStatic<(char, char)>, Flags),

    // Matches any character except new lines.
    // If the bool is true, then new lines are matched.
    Any(Flags),

    // Matches the beginning of the string, consumes no characters.
    // If the bool is true, then it also matches when the preceding character
    // is a new line.
    EmptyBegin(Flags),

    // Matches the end of the string, consumes no characters.
    // If the bool is true, then it also matches when the proceeding character
    // is a new line.
    EmptyEnd(Flags),

    // Matches a word boundary (\w on one side and \W \A or \z on the other),
    // and consumes no character.
    // If the bool is false, then it matches anything that is NOT a word
    // boundary.
    EmptyWordBoundary(Flags),

    // Saves the current position in the input string to the Nth save slot.
    Save(uint),

    // Jumps to the instruction at the index given.
    Jump(InstIdx),

    // Jumps to the instruction at the first index given. If that leads to
    // a failing state, then the instruction at the second index given is
    // tried.
    Split(InstIdx, InstIdx),
}

pub struct Program {
    pub regex: MaybeOwned<'static>,
    pub insts: MaybeStatic<Inst>,
    pub names: MaybeStatic<Option<MaybeOwned<'static>>>,
    pub prefix: MaybeStatic<char>,
}

impl Program {
    pub fn new(regex: &str, ast: ~parse::Ast) -> Program {
        let mut c = Compiler {
            insts: Vec::with_capacity(100),
            names: Vec::with_capacity(10),
        };

        c.insts.push(Save(0));
        c.compile(ast);
        c.insts.push(Save(1));
        c.insts.push(Match);

        // Try to discover a literal string prefix.
        // This is a bit hacky since we have to skip over the initial
        // 'Save' instruction.
        let mut pre = Vec::with_capacity(5);
        for i in iter::range(1, c.insts.len()) {
            match *c.insts.get(i) {
                OneChar(c, FLAG_EMPTY) => pre.push(c),
                _ => break
            }
        }

        let names = c.names.clone();
        Program {
            regex: Owned(regex.to_owned()),
            insts: Dynamic(c.insts),
            names: Dynamic(names),
            prefix: Dynamic(pre),
        }
    }

    /// Returns the total number of capture groups in the regular expression.
    /// This includes the zeroth capture.
    pub fn num_captures(&self) -> uint {
        let mut n = 0;
        for inst in self.insts.as_slice().iter() {
            match *inst {
                Save(c) => n = cmp::max(n, c+1),
                _ => {}
            }
        }
        // There's exactly 2 Save slots for every capture.
        n / 2
    }
}

struct Compiler<'r> {
    insts: Vec<Inst>,
    names: Vec<Option<MaybeOwned<'r>>>,
}

impl<'r> Compiler<'r> {
    fn compile(&mut self, ast: ~parse::Ast) {
        match ast {
            ~Nothing => {},
            ~Literal(c, flags) => self.push(OneChar(c, flags)),
            ~Dot(nl) => self.push(Any(nl)),
            ~Class(ranges, flags) =>
                self.push(CharClass(Dynamic(ranges), flags)),
            ~Begin(flags) => self.push(EmptyBegin(flags)),
            ~End(flags) => self.push(EmptyEnd(flags)),
            ~WordBoundary(flags) => self.push(EmptyWordBoundary(flags)),
            ~Capture(cap, name, x) => {
                let len = self.names.len();
                if cap >= len {
                    self.names.grow(10 + cap - len, &None)
                }
                *self.names.get_mut(cap) = name.map(Owned);

                self.push(Save(2 * cap));
                self.compile(x);
                self.push(Save(2 * cap + 1));
            }
            ~Cat(xs) => {
                for x in xs.move_iter() {
                    self.compile(x)
                }
            }
            ~Alt(x, y) => {
                let split = self.empty_split(); // push: split 0, 0
                let j1 = self.insts.len();
                self.compile(x);                // push: insts for x
                let jmp = self.empty_jump();    // push: jmp 0
                let j2 = self.insts.len();
                self.compile(y);                // push: insts for y
                let j3 = self.insts.len();

                self.set_split(split, j1, j2);  // split 0, 0 -> split j1, j2
                self.set_jump(jmp, j3);         // jmp 0      -> jmp j3
            }
            ~Rep(x, ZeroOne, g) => {
                let split = self.empty_split();
                let j1 = self.insts.len();
                self.compile(x);
                let j2 = self.insts.len();

                if g.is_greedy() {
                    self.set_split(split, j1, j2);
                } else {
                    self.set_split(split, j2, j1);
                }
            }
            ~Rep(x, ZeroMore, g) => {
                let j1 = self.insts.len();
                let split = self.empty_split();
                let j2 = self.insts.len();
                self.compile(x);
                let jmp = self.empty_jump();
                let j3 = self.insts.len();

                self.set_jump(jmp, j1);
                if g.is_greedy() {
                    self.set_split(split, j2, j3);
                } else {
                    self.set_split(split, j3, j2);
                }
            }
            ~Rep(x, OneMore, g) => {
                let j1 = self.insts.len();
                self.compile(x);
                let split = self.empty_split();
                let j2 = self.insts.len();

                if g.is_greedy() {
                    self.set_split(split, j1, j2);
                } else {
                    self.set_split(split, j2, j1);
                }
            }
        }
    }

    /// Appends the given instruction to the program.
    #[inline(always)]
    fn push(&mut self, x: Inst) {
        self.insts.push(x)
    }

    /// Appends an *empty* `Split` instruction to the program and returns
    /// the index of that instruction. (The index can then be used to "patch"
    /// the actual locations of the split in later.)
    #[inline(always)]
    fn empty_split(&mut self) -> InstIdx {
        self.insts.push(Split(0, 0));
        self.insts.len() - 1
    }

    /// Sets the left and right locations of a `Split` instruction at index
    /// `i` to `pc1` and `pc2`, respectively.
    /// If the instruction at index `i` isn't a `Split` instruction, then
    /// `fail!` is called.
    #[inline(always)]
    fn set_split(&mut self, i: InstIdx, pc1: InstIdx, pc2: InstIdx) {
        let split = self.insts.get_mut(i);
        match *split {
            Split(_, _) => *split = Split(pc1, pc2),
            _ => fail!("BUG: Invalid split index."),
        }
    }

    /// Appends an *empty* `Jump` instruction to the program and returns the
    /// index of that instruction.
    #[inline(always)]
    fn empty_jump(&mut self) -> InstIdx {
        self.insts.push(Jump(0));
        self.insts.len() - 1
    }

    /// Sets the location of a `Jump` instruction at index `i` to `pc`.
    /// If the instruction at index `i` isn't a `Jump` instruction, then
    /// `fail!` is called.
    #[inline(always)]
    fn set_jump(&mut self, i: InstIdx, pc: InstIdx) {
        let jmp = self.insts.get_mut(i);
        match *jmp {
            Jump(_) => *jmp = Jump(pc),
            _ => fail!("BUG: Invalid jump index."),
        }
    }
}
<commit_msg>Doco updates to the compiler.<commit_after>#![allow(visible_private_types)]

use std::cmp;
use std::iter;
use std::slice::Vector;
use std::str::{MaybeOwned, Owned};
use super::parse;
use super::parse::{
    Flags, FLAG_EMPTY,
    Nothing, Literal, Dot, Class, Begin, End, WordBoundary, Capture, Cat, Alt,
    Rep,
    ZeroOne, ZeroMore, OneMore,
};

type InstIdx = uint;

#[deriving(Show, Clone)]
pub enum MaybeStatic<T> {
    Dynamic(Vec<T>),
    Static(&'static [T]),
}

impl<T> Vector<T> for MaybeStatic<T> {
    fn as_slice<'a>(&'a self) -> &'a [T] {
        match *self {
            Dynamic(ref xs) => xs.as_slice(),
            Static(xs) => xs,
        }
    }
}

impl<T> Container for MaybeStatic<T> {
    fn len(&self) -> uint { self.as_slice().len() }
}

#[deriving(Show, Clone)]
pub enum Inst {
    // When a Match instruction is executed, the current thread is successful.
    Match,

    // The OneChar instruction matches a literal character.
    // The flags indicate whether to do a case insensitive match.
    OneChar(char, Flags),

    // The CharClass instruction tries to match one input character against
    // the range of characters given.
    // The flags indicate whether to do a case insentivie match and whether
    // the character class is negated or not.
    CharClass(MaybeStatic<(char, char)>, Flags),

    // Matches any character except new lines.
    // The flags indicate whether to include the '\n' character.
    Any(Flags),

    // Matches the beginning of the string, consumes no characters.
    // The flags indicate whether it matches if the preceding character
    // is a new line.
    EmptyBegin(Flags),

    // Matches the end of the string, consumes no characters.
    // The flags indicate whether it matches if the proceding character
    // is a new line.
    EmptyEnd(Flags),

    // Matches a word boundary (\w on one side and \W \A or \z on the other),
    // and consumes no character.
    // The flags indicate whether this matches a word boundary or something
    // that isn't a word boundary.
    EmptyWordBoundary(Flags),

    // Saves the current position in the input string to the Nth save slot.
    Save(uint),

    // Jumps to the instruction at the index given.
    Jump(InstIdx),

    // Jumps to the instruction at the first index given. If that leads to
    // a failing state, then the instruction at the second index given is
    // tried.
    Split(InstIdx, InstIdx),
}

/// Program represents a compiled regular expression. Once an expression is
/// compiled, its representation is immutable and will never change.
///
/// All of the data in a compiled expression is wrapped in "MaybeStatic" or
/// "MaybeOwned" types so that a `Program` can be represented as static data.
/// (This makes it convenient and efficient for use with the `re!` macro.)
pub struct Program {
    pub regex: MaybeOwned<'static>,
    pub insts: MaybeStatic<Inst>,
    pub names: MaybeStatic<Option<MaybeOwned<'static>>>,
    pub prefix: MaybeStatic<char>,
}

impl Program {
    pub fn new(regex: &str, ast: ~parse::Ast) -> Program {
        let mut c = Compiler {
            insts: Vec::with_capacity(100),
            names: Vec::with_capacity(10),
        };

        c.insts.push(Save(0));
        c.compile(ast);
        c.insts.push(Save(1));
        c.insts.push(Match);

        // Try to discover a literal string prefix.
        // This is a bit hacky since we have to skip over the initial
        // 'Save' instruction.
        let mut pre = Vec::with_capacity(5);
        for i in iter::range(1, c.insts.len()) {
            match *c.insts.get(i) {
                OneChar(c, FLAG_EMPTY) => pre.push(c),
                _ => break
            }
        }

        let names = c.names.clone();
        Program {
            regex: Owned(regex.to_owned()),
            insts: Dynamic(c.insts),
            names: Dynamic(names),
            prefix: Dynamic(pre),
        }
    }

    /// Returns the total number of capture groups in the regular expression.
    /// This includes the zeroth capture.
    pub fn num_captures(&self) -> uint {
        let mut n = 0;
        for inst in self.insts.as_slice().iter() {
            match *inst {
                Save(c) => n = cmp::max(n, c+1),
                _ => {}
            }
        }
        // There's exactly 2 Save slots for every capture.
        n / 2
    }
}

struct Compiler<'r> {
    insts: Vec<Inst>,
    names: Vec<Option<MaybeOwned<'r>>>,
}

// The compiler implemented here is extremely simple. Most of the complexity
// in this crate is in the parser or the VM.
// The only tricky thing here is patching jump/split instructions to point to
// the right instruction.
impl<'r> Compiler<'r> {
    fn compile(&mut self, ast: ~parse::Ast) {
        match ast {
            ~Nothing => {},
            ~Literal(c, flags) => self.push(OneChar(c, flags)),
            ~Dot(nl) => self.push(Any(nl)),
            ~Class(ranges, flags) =>
                self.push(CharClass(Dynamic(ranges), flags)),
            ~Begin(flags) => self.push(EmptyBegin(flags)),
            ~End(flags) => self.push(EmptyEnd(flags)),
            ~WordBoundary(flags) => self.push(EmptyWordBoundary(flags)),
            ~Capture(cap, name, x) => {
                let len = self.names.len();
                if cap >= len {
                    self.names.grow(10 + cap - len, &None)
                }
                *self.names.get_mut(cap) = name.map(Owned);

                self.push(Save(2 * cap));
                self.compile(x);
                self.push(Save(2 * cap + 1));
            }
            ~Cat(xs) => {
                for x in xs.move_iter() {
                    self.compile(x)
                }
            }
            ~Alt(x, y) => {
                let split = self.empty_split(); // push: split 0, 0
                let j1 = self.insts.len();
                self.compile(x);                // push: insts for x
                let jmp = self.empty_jump();    // push: jmp 0
                let j2 = self.insts.len();
                self.compile(y);                // push: insts for y
                let j3 = self.insts.len();

                self.set_split(split, j1, j2);  // split 0, 0 -> split j1, j2
                self.set_jump(jmp, j3);         // jmp 0      -> jmp j3
            }
            ~Rep(x, ZeroOne, g) => {
                let split = self.empty_split();
                let j1 = self.insts.len();
                self.compile(x);
                let j2 = self.insts.len();

                if g.is_greedy() {
                    self.set_split(split, j1, j2);
                } else {
                    self.set_split(split, j2, j1);
                }
            }
            ~Rep(x, ZeroMore, g) => {
                let j1 = self.insts.len();
                let split = self.empty_split();
                let j2 = self.insts.len();
                self.compile(x);
                let jmp = self.empty_jump();
                let j3 = self.insts.len();

                self.set_jump(jmp, j1);
                if g.is_greedy() {
                    self.set_split(split, j2, j3);
                } else {
                    self.set_split(split, j3, j2);
                }
            }
            ~Rep(x, OneMore, g) => {
                let j1 = self.insts.len();
                self.compile(x);
                let split = self.empty_split();
                let j2 = self.insts.len();

                if g.is_greedy() {
                    self.set_split(split, j1, j2);
                } else {
                    self.set_split(split, j2, j1);
                }
            }
        }
    }

    /// Appends the given instruction to the program.
    #[inline(always)]
    fn push(&mut self, x: Inst) {
        self.insts.push(x)
    }

    /// Appends an *empty* `Split` instruction to the program and returns
    /// the index of that instruction. (The index can then be used to "patch"
    /// the actual locations of the split in later.)
    #[inline(always)]
    fn empty_split(&mut self) -> InstIdx {
        self.insts.push(Split(0, 0));
        self.insts.len() - 1
    }

    /// Sets the left and right locations of a `Split` instruction at index
    /// `i` to `pc1` and `pc2`, respectively.
    /// If the instruction at index `i` isn't a `Split` instruction, then
    /// `fail!` is called.
    #[inline(always)]
    fn set_split(&mut self, i: InstIdx, pc1: InstIdx, pc2: InstIdx) {
        let split = self.insts.get_mut(i);
        match *split {
            Split(_, _) => *split = Split(pc1, pc2),
            _ => fail!("BUG: Invalid split index."),
        }
    }

    /// Appends an *empty* `Jump` instruction to the program and returns the
    /// index of that instruction.
    #[inline(always)]
    fn empty_jump(&mut self) -> InstIdx {
        self.insts.push(Jump(0));
        self.insts.len() - 1
    }

    /// Sets the location of a `Jump` instruction at index `i` to `pc`.
    /// If the instruction at index `i` isn't a `Jump` instruction, then
    /// `fail!` is called.
    #[inline(always)]
    fn set_jump(&mut self, i: InstIdx, pc: InstIdx) {
        let jmp = self.insts.get_mut(i);
        match *jmp {
            Jump(_) => *jmp = Jump(pc),
            _ => fail!("BUG: Invalid jump index."),
        }
    }
}
<|endoftext|>


<commit_before>// The implementation is based on:
// http://www.librow.com/articles/article-10

use num_complex::Complex;
use num_traits::Float;

use {Operation, Plan, Transform};

impl<T> Transform<T> for [Complex<T>] where T: Float {
    fn transform(&mut self, plan: &Plan<T>) {
        let n = self.len();
        assert!(n <= plan.n);
        rearrange(self, n);
        calculate(self, n, &plan.factors);
        if let Operation::Inverse = plan.operation {
            scale(self, n);
        }
    }
}

impl<T> Transform<T> for Vec<Complex<T>> where T: Float {
    #[inline(always)]
    fn transform(&mut self, plan: &Plan<T>) {
        Transform::transform(&mut self[..], plan)
    }
}

#[inline(always)]
fn calculate<T>(data: &mut [Complex<T>], n: usize, factors: &[Complex<T>]) where T: Float {
    let mut k = 0;
    let mut step = 1;
    while step < n {
        let jump = step << 1;
        for mut i in 0..step {
            while i < n {
                let j = i + step;
                let product = factors[k] * data[j];
                data[j] = data[i] - product;
                data[i] = data[i] + product;
                i += jump;
            }
            k += 1;
        }
        step <<= 1;
    }
}

#[inline(always)]
fn rearrange<T>(data: &mut [Complex<T>], n: usize) {
    let mut j = 0;
    for i in 0..n {
        if j > i {
            data.swap(i, j);
        }
        let mut mask = n >> 1;
        while j & mask != 0 {
            j &= !mask;
            mask >>= 1;
        }
        j |= mask;
    }
}

#[inline(always)]
fn scale<T>(data: &mut [Complex<T>], n: usize) where T: Float {
    let factor = T::from(n).unwrap().recip();
    for value in data {
        *value = value.scale(factor);
    }
}
<commit_msg>Use unchecked indexing in calculate()<commit_after>// The implementation is based on:
// http://www.librow.com/articles/article-10

use num_complex::Complex;
use num_traits::Float;

use {Operation, Plan, Transform};

impl<T> Transform<T> for [Complex<T>] where T: Float {
    fn transform(&mut self, plan: &Plan<T>) {
        let n = self.len();
        assert!(n <= plan.n);
        rearrange(self, n);
        calculate(self, n, &plan.factors);
        if let Operation::Inverse = plan.operation {
            scale(self, n);
        }
    }
}

impl<T> Transform<T> for Vec<Complex<T>> where T: Float {
    #[inline(always)]
    fn transform(&mut self, plan: &Plan<T>) {
        Transform::transform(&mut self[..], plan)
    }
}

#[inline(always)]
fn calculate<T>(data: &mut [Complex<T>], n: usize, factors: &[Complex<T>]) where T: Float {
    let mut k = 0;
    let mut step = 1;
    while step < n {
        let jump = step << 1;
        for mut i in 0..step {
            while i < n {
                let j = i + step;
                unsafe {
                    let product = *factors.get_unchecked(k) * *data.get_unchecked(j);
                    *data.get_unchecked_mut(j) = *data.get_unchecked(i) - product;
                    *data.get_unchecked_mut(i) = *data.get_unchecked(i) + product;
                }
                i += jump;
            }
            k += 1;
        }
        step <<= 1;
    }
}

#[inline(always)]
fn rearrange<T>(data: &mut [Complex<T>], n: usize) {
    let mut j = 0;
    for i in 0..n {
        if j > i {
            data.swap(i, j);
        }
        let mut mask = n >> 1;
        while j & mask != 0 {
            j &= !mask;
            mask >>= 1;
        }
        j |= mask;
    }
}

#[inline(always)]
fn scale<T>(data: &mut [Complex<T>], n: usize) where T: Float {
    let factor = T::from(n).unwrap().recip();
    for value in data {
        *value = value.scale(factor);
    }
}
<|endoftext|>


<commit_before>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method<'a>(&'a self) -> &'a str;

    /// The scheme part of the request URL
    fn scheme<'a>(&'a self) -> &'a str;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> &'a str;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// A Reader for the body of the request
    fn body<'a>(&mut self) -> Box<Reader + Send>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, String>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

pub type Handler = fn(&mut Request) -> Response;
<commit_msg>Add a few more types<commit_after>extern crate semver;

use std::collections::HashMap;
use std::io::net::ip::IpAddr;

pub enum Scheme {
    Http,
    Https
}

pub enum Host<'a> {
    HostName(&'a str),
    HostIp(IpAddr)
}

pub enum Method<'a> {
    Get,
    Post,
    Put,
    Patch,
    Delete,
    Other(&'a str)
}

pub trait Request {
    /// The version of HTTP being used
    fn http_version(&self) -> semver::Version;

    /// The version of the conduit spec being used
    fn conduit_version(&self) -> semver::Version;

    /// The request method, such as GET, POST, PUT, DELETE or PATCH
    fn method<'a>(&'a self) -> Method<'a>;

    /// The scheme part of the request URL
    fn scheme(&self) -> Scheme;

    /// The host part of the requested URL
    fn host<'a>(&'a self) -> Host<'a>;

    /// The initial part of the request URL's path that corresponds
    /// to a virtual root. This allows an application to have a
    /// virtual location that consumes part of the path.
    fn virtual_root<'a>(&'a self) -> Option<&'a str>;

    /// The remainder of the path.
    fn path<'a>(&'a self) -> &'a str;

    /// The portion of the request URL that follows the "?"
    fn query_string<'a>(&'a self) -> Option<&'a str>;

    /// The remote IP address of the client or the last proxy that
    /// sent the request.
    fn remote_ip(&self) -> IpAddr;

    /// The byte-size of the body, if any
    fn content_length(&self) -> Option<uint>;

    /// A Reader for the body of the request
    fn body(&mut self) -> Box<Reader + Send>;
}

pub struct Response {
    /// The status code as a tuple of the return code and status string
    pub status: (uint, &'static str),

    /// A Map of the headers
    pub headers: HashMap<String, String>,

    /// A Writer for body of the response
    pub body: Box<Reader + Send>
}

pub type Handler = fn(&mut Request) -> Response;
<|endoftext|>


<commit_before>use std::fmt;
use irc::client::prelude::*;
use irc::error::Error as IrcError;

pub trait Plugin: Send + Sync + fmt::Debug {
    fn is_allowed(&self, server: &IrcServer, message: &Message) -> bool;
    fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError>;
}

#[macro_export]
macro_rules! register_plugin {
    ($t:ident) => {
        #[derive(Debug)]
        pub struct $t;

        impl $t {
            pub fn new() -> $t {
                $t { }
            }
        }
    };

    ($t:ident, $element: ident: $ty: ty) => {
        #[derive(Debug)]
        pub struct $t {
            $element: $ty
        }

        impl $t {
            pub fn new() -> $t {
                $t { $element: <$ty>::new() }
            }
        }
    };
}
<commit_msg>Add the Display trait to Plugins<commit_after>use std::fmt;
use irc::client::prelude::*;
use irc::error::Error as IrcError;

pub trait Plugin: Send + Sync + fmt::Display + fmt::Debug {
    fn is_allowed(&self, server: &IrcServer, message: &Message) -> bool;
    fn execute(&mut self, server: &IrcServer, message: &Message) -> Result<(), IrcError>;
}

#[macro_export]
macro_rules! register_plugin {
    ($t:ident) => {
        use std::fmt;

        #[derive(Debug)]
        pub struct $t {
            _name: &'static str,
        }

        impl fmt::Display for $t {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{}", self._name)
            }
        }

        impl $t {
            pub fn new() -> $t {
                $t { _name: stringify!($t) }
            }
        }
    };
}
<|endoftext|>


<commit_before>use crc32::Crc32Reader;
use types::ZipFile;
use compression::CompressionMethod;
use spec;
use reader_spec;
use result::{ZipResult, ZipError};
use std::io;
use std::io::prelude::*;
use std::cell::{RefCell, BorrowState};
use std::collections::HashMap;
use flate2::FlateReadExt;
use bzip2::reader::BzDecompressor;

/// Wrapper for reading the contents of a ZIP file.
///
/// ```
/// fn doit() -> zip::result::ZipResult<()>
/// {
///     use std::io::prelude::*;
///
///     // For demonstration purposes we read from an empty buffer.
///     // Normally a File object would be used.
///     let buf: &[u8] = &[0u8; 128];
///     let mut reader = std::io::Cursor::new(buf);
///
///     let zip = try!(zip::ZipReader::new(reader));
///
///     for file in zip.files()
///     {
///         println!("Filename: {}", file.file_name);
///         let mut file_reader = try!(zip.read_file(file));
///         let first_byte = try!(file_reader.bytes().next().unwrap());
///         println!("{}", first_byte);
///     }
///     Ok(())
/// }
///
/// println!("Result: {:?}", doit());
/// ```
pub struct ZipReader<T>
{
    inner: RefCell<T>,
    files: Vec<ZipFile>,
    names_map: HashMap<String, usize>,
}

fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
{
    Err(ZipError::UnsupportedZipFile(detail))
}

impl<T: Read+io::Seek> ZipReader<T>
{
    /// Opens a ZIP file and parses the content headers.
    pub fn new(mut reader: T) -> ZipResult<ZipReader<T>>
    {
        let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader));

        if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") }

        let directory_start = footer.central_directory_offset as u64;
        let number_of_files = footer.number_of_files_on_this_disk as usize;

        let mut files = Vec::with_capacity(number_of_files);
        let mut names_map = HashMap::new();

        try!(reader.seek(io::SeekFrom::Start(directory_start)));
        for _ in (0 .. number_of_files)
        {
            let file = try!(reader_spec::central_header_to_zip_file(&mut reader));
            names_map.insert(file.file_name.clone(), files.len());
            files.push(file);
        }

        Ok(ZipReader { inner: RefCell::new(reader), files: files, names_map: names_map })
    }

    /// An iterator over the information of all contained files.
    pub fn files(&self) -> ::std::slice::Iter<ZipFile>
    {
        (&*self.files).iter()
    }

    /// Search for a file entry by name
    pub fn get(&self, name: &str) -> Option<&ZipFile>
    {
        self.names_map.get(name).map(|index| &self.files[*index])
    }

    /// Gets a reader for a contained zipfile.
    ///
    /// May return `ReaderUnavailable` if there is another reader borrowed.
    pub fn read_file<'a>(&'a self, file: &ZipFile) -> ZipResult<Box<Read+'a>>
    {
        let mut inner_reader = match self.inner.borrow_state()
        {
            BorrowState::Unused => self.inner.borrow_mut(),
            _ => return Err(ZipError::ReaderUnavailable),
        };
        let pos = file.data_start as u64;

        if file.encrypted
        {
            return unsupported_zip_error("Encrypted files are not supported")
        }

        try!(inner_reader.seek(io::SeekFrom::Start(pos)));
        let refmut_reader = ::util::RefMutReader::new(inner_reader);
        let limit_reader = refmut_reader.take(file.compressed_size as u64);

        let reader = match file.compression_method
        {
            CompressionMethod::Stored =>
            {
                Box::new(
                    Crc32Reader::new(
                        limit_reader,
                        file.crc32))
                    as Box<Read>
            },
            CompressionMethod::Deflated =>
            {
                let deflate_reader = limit_reader.deflate_decode();
                Box::new(
                    Crc32Reader::new(
                        deflate_reader,
                        file.crc32))
                    as Box<Read>
            },
            CompressionMethod::Bzip2 =>
            {
                let bzip2_reader = BzDecompressor::new(limit_reader);
                Box::new(
                    Crc32Reader::new(
                        bzip2_reader,
                        file.crc32))
                    as Box<Read>
            },
            _ => return unsupported_zip_error("Compression method not supported"),
        };
        Ok(reader)
    }

    /// Unwrap and return the inner reader object
    ///
    /// The position of the reader is undefined.
    pub fn into_inner(self) -> T
    {
        self.inner.into_inner()
    }

    /// Deprecated method equal to `into_inner()`
    #[deprecated="renamed to into_inner()"]
    pub fn unwrap(self) -> T
    {
        self.into_inner()
    }
}
<commit_msg>Wrap the files() iterator<commit_after>use crc32::Crc32Reader;
use types::ZipFile;
use compression::CompressionMethod;
use spec;
use reader_spec;
use result::{ZipResult, ZipError};
use std::io;
use std::io::prelude::*;
use std::cell::{RefCell, BorrowState};
use std::collections::HashMap;
use flate2::FlateReadExt;
use bzip2::reader::BzDecompressor;

/// Wrapper for reading the contents of a ZIP file.
///
/// ```
/// fn doit() -> zip::result::ZipResult<()>
/// {
///     use std::io::prelude::*;
///
///     // For demonstration purposes we read from an empty buffer.
///     // Normally a File object would be used.
///     let buf: &[u8] = &[0u8; 128];
///     let mut reader = std::io::Cursor::new(buf);
///
///     let zip = try!(zip::ZipReader::new(reader));
///
///     for file in zip.files()
///     {
///         println!("Filename: {}", file.file_name);
///         let mut file_reader = try!(zip.read_file(file));
///         let first_byte = try!(file_reader.bytes().next().unwrap());
///         println!("{}", first_byte);
///     }
///     Ok(())
/// }
///
/// println!("Result: {:?}", doit());
/// ```
pub struct ZipReader<T>
{
    inner: RefCell<T>,
    files: Vec<ZipFile>,
    names_map: HashMap<String, usize>,
}

pub struct ZipFileIterator<'a>
{
    inner: ::std::slice::Iter<'a, ZipFile>,
}

impl<'a> Iterator for ZipFileIterator<'a> {
    type Item = &'a ZipFile;
    fn next(&mut self) -> Option<&'a ZipFile> {
        self.inner.next()
    }
}

fn unsupported_zip_error<T>(detail: &'static str) -> ZipResult<T>
{
    Err(ZipError::UnsupportedZipFile(detail))
}

impl<T: Read+io::Seek> ZipReader<T>
{
    /// Opens a ZIP file and parses the content headers.
    pub fn new(mut reader: T) -> ZipResult<ZipReader<T>>
    {
        let footer = try!(spec::CentralDirectoryEnd::find_and_parse(&mut reader));

        if footer.disk_number != footer.disk_with_central_directory { return unsupported_zip_error("Support for multi-disk files is not implemented") }

        let directory_start = footer.central_directory_offset as u64;
        let number_of_files = footer.number_of_files_on_this_disk as usize;

        let mut files = Vec::with_capacity(number_of_files);
        let mut names_map = HashMap::new();

        try!(reader.seek(io::SeekFrom::Start(directory_start)));
        for _ in (0 .. number_of_files)
        {
            let file = try!(reader_spec::central_header_to_zip_file(&mut reader));
            names_map.insert(file.file_name.clone(), files.len());
            files.push(file);
        }

        Ok(ZipReader { inner: RefCell::new(reader), files: files, names_map: names_map })
    }

    /// An iterator over the information of all contained files.
    pub fn files(&self) -> ZipFileIterator
    {
        ZipFileIterator { inner: (&*self.files).iter(), }
    }

    /// Search for a file entry by name
    pub fn get(&self, name: &str) -> Option<&ZipFile>
    {
        self.names_map.get(name).map(|index| &self.files[*index])
    }

    /// Gets a reader for a contained zipfile.
    ///
    /// May return `ReaderUnavailable` if there is another reader borrowed.
    pub fn read_file<'a>(&'a self, file: &ZipFile) -> ZipResult<Box<Read+'a>>
    {
        let mut inner_reader = match self.inner.borrow_state()
        {
            BorrowState::Unused => self.inner.borrow_mut(),
            _ => return Err(ZipError::ReaderUnavailable),
        };
        let pos = file.data_start as u64;

        if file.encrypted
        {
            return unsupported_zip_error("Encrypted files are not supported")
        }

        try!(inner_reader.seek(io::SeekFrom::Start(pos)));
        let refmut_reader = ::util::RefMutReader::new(inner_reader);
        let limit_reader = refmut_reader.take(file.compressed_size as u64);

        let reader = match file.compression_method
        {
            CompressionMethod::Stored =>
            {
                Box::new(
                    Crc32Reader::new(
                        limit_reader,
                        file.crc32))
                    as Box<Read>
            },
            CompressionMethod::Deflated =>
            {
                let deflate_reader = limit_reader.deflate_decode();
                Box::new(
                    Crc32Reader::new(
                        deflate_reader,
                        file.crc32))
                    as Box<Read>
            },
            CompressionMethod::Bzip2 =>
            {
                let bzip2_reader = BzDecompressor::new(limit_reader);
                Box::new(
                    Crc32Reader::new(
                        bzip2_reader,
                        file.crc32))
                    as Box<Read>
            },
            _ => return unsupported_zip_error("Compression method not supported"),
        };
        Ok(reader)
    }

    /// Unwrap and return the inner reader object
    ///
    /// The position of the reader is undefined.
    pub fn into_inner(self) -> T
    {
        self.inner.into_inner()
    }

    /// Deprecated method equal to `into_inner()`
    #[deprecated="renamed to into_inner()"]
    pub fn unwrap(self) -> T
    {
        self.into_inner()
    }
}
<|endoftext|>


<commit_before>use na::{self, DVectorSlice, DVectorSliceMut, Real};

use math::{Force, Inertia, Isometry, Point, Rotation, Translation, Vector, Velocity, SPATIAL_DIM};
use object::{ActivationStatus, BodyHandle, BodyStatus};
use solver::IntegrationParameters;

#[cfg(feature = "dim3")]
use math::AngularVector;
#[cfg(feature = "dim3")]
use utils::GeneralizedCross;

/// A rigid body.
pub struct RigidBody<N: Real> {
    handle: BodyHandle,
    local_to_world: Isometry<N>,
    velocity: Velocity<N>,
    local_inertia: Inertia<N>,
    inertia: Inertia<N>,
    local_com: Point<N>,
    com: Point<N>,
    augmented_mass: Inertia<N>,
    inv_augmented_mass: Inertia<N>,
    external_forces: Force<N>,
    acceleration: Velocity<N>,
    status: BodyStatus,
    activation: ActivationStatus<N>,
    companion_id: usize,
}

impl<N: Real> RigidBody<N> {
    /// Create a new rigid body with the specified handle and dynamic properties.
    pub fn new(
        handle: BodyHandle,
        position: Isometry<N>,
        local_inertia: Inertia<N>,
        local_com: Point<N>,
    ) -> Self {
        let inertia = local_inertia.transformed(&position);
        let com = position * local_com;

        RigidBody {
            handle,
            local_to_world: position,
            velocity: Velocity::zero(),
            local_inertia,
            inertia,
            local_com,
            com,
            augmented_mass: inertia,
            inv_augmented_mass: inertia.inverse(),
            external_forces: Force::zero(),
            acceleration: Velocity::zero(),
            status: BodyStatus::Dynamic,
            activation: ActivationStatus::new_active(),
            companion_id: 0,
        }
    }

    /// Informations regarding activation and deactivation (sleeping) of this rigid body.
    #[inline]
    pub fn activation_status(&self) -> &ActivationStatus<N> {
        &self.activation
    }

    /// Mutable informations regarding activation and deactivation (sleeping) of this rigid body.
    #[inline]
    pub fn activation_status_mut(&mut self) -> &mut ActivationStatus<N> {
        &mut self.activation
    }

    /// Force the activation of this rigid body.
    #[inline]
    pub fn activate(&mut self) {
        if let Some(threshold) = self.activation.deactivation_threshold() {
            self.activate_with_energy(threshold * na::convert(2.0));
        }
    }

    /// Force the activation of this rigid body with the given level of energy.
    #[inline]
    pub fn activate_with_energy(&mut self, energy: N) {
        self.activation.set_energy(energy)
    }

    /// Put this rigid body to sleep.
    #[inline]
    pub fn deactivate(&mut self) {
        self.activation.set_energy(N::zero());
        self.velocity = Velocity::zero();
    }

    /// Return `true` if this rigid body is kinematic or dynamic and awake.
    #[inline]
    pub fn is_active(&self) -> bool {
        match self.status {
            BodyStatus::Dynamic => self.activation.is_active(),
            BodyStatus::Kinematic => true,
            BodyStatus::Static => false,
            BodyStatus::Disabled => false,
        }
    }

    /// The status of this rigid body.
    #[inline]
    pub fn status(&self) -> BodyStatus {
        self.status
    }

    /// Set the status of this body.
    #[inline]
    pub fn set_status(&mut self, status: BodyStatus) {
        self.status = status
    }

    /// The companion ID of this rigid body.
    #[inline]
    pub fn companion_id(&self) -> usize {
        self.companion_id
    }

    /// Set the companion ID of this rigid body.
    ///
    /// This value may be overriden by nphysics during a timestep.
    #[inline]
    pub fn set_companion_id(&mut self, id: usize) {
        self.companion_id = id
    }

    /// Whether or not the status of this rigid body is dynamic.
    #[inline]
    pub fn is_dynamic(&self) -> bool {
        self.status == BodyStatus::Dynamic
    }

    /// Whether or not the status of this rigid body is static.
    #[inline]
    pub fn is_static(&self) -> bool {
        self.status == BodyStatus::Static
    }

    /// Whether or not the status of this rigid body is kinematic.
    #[inline]
    pub fn is_kinematic(&self) -> bool {
        self.status == BodyStatus::Kinematic
    }

    /// The center of mass of this rigid body.
    #[inline]
    pub fn center_of_mass(&self) -> Point<N> {
        self.com
    }

    /// The velocity of this rigid body.
    #[inline]
    pub fn velocity(&self) -> &Velocity<N> {
        &self.velocity
    }

    /// Sets the position of this rigid body.
    #[inline]
    pub fn set_position(&mut self, pos: Isometry<N>) {
        self.local_to_world = pos;
        self.com = pos * self.local_com;
    }

    /// Set the velocity of this rigid body.
    #[inline]
    pub fn set_velocity(&mut self, vel: Velocity<N>) {
        self.velocity = vel;
        self.activate();
    }

    /// Set the linear velocity of this rigid body.
    #[inline]
    pub fn set_linear_velocity(&mut self, vel: Vector<N>) {
        self.velocity.linear = vel;
        self.activate();

    }

    #[cfg(feature = "dim2")]
    /// Set the angular velocity of this rigid body.
    #[inline]
    pub fn set_angular_velocity(&mut self, vel: N) {
        self.velocity.angular = vel;
        self.activate();
    }

    #[cfg(feature = "dim3")]
    /// Set the angular velocity of this rigid body.
    #[inline]
    pub fn set_angular_velocity(&mut self, vel: AngularVector<N>) {
        self.velocity.angular = vel;
        self.activate();
    }

    /// Reset the timestep-specific dynamic information of this rigid body.
    pub fn clear_dynamics(&mut self) {
        self.augmented_mass = Inertia::zero();
        self.acceleration = Velocity::zero();
    }

    /// Clears the external forces applied to this rigid-body.
    pub fn clear_forces(&mut self) {
        self.external_forces = Force::zero();
    }

    /// Update the timestep-specific dynamic information of this rigid body.
    #[allow(unused_variables)] // for params used only in 3D.
    pub fn update_dynamics(&mut self, gravity: &Vector<N>, params: &IntegrationParameters<N>) {
        if let BodyStatus::Dynamic = self.status {
            // The inverse inertia matrix is constant in 2D.
            #[cfg(feature = "dim3")]
            {
                self.inertia = self.local_inertia.transformed(&self.local_to_world);
                self.augmented_mass += self.inertia;

                let i = &self.inertia.angular;
                let w = &self.velocity.angular;
                let iw = i * w;
                let w_dt = w * params.dt;
                let w_dt_cross = w_dt.gcross_matrix();
                let iw_dt_cross = (iw * params.dt).gcross_matrix();
                self.augmented_mass.angular += w_dt_cross * i - iw_dt_cross;

                // NOTE: if we did not have the gyroscopic forces, we would not have to invert the inertia
                // matrix at each time-step => add a flag to disable gyroscopic forces?
                self.inv_augmented_mass = self.augmented_mass.inverse();

                /*
                 * Compute acceleration due to gyroscopic forces.
                 */
                let gyroscopic = -w.cross(&iw);
                self.acceleration.angular += self.inv_augmented_mass.angular * gyroscopic;
            }

            self.acceleration.linear += *gravity;
            self.acceleration += self.inv_augmented_mass * self.external_forces
        }
    }

    /// The rigid body inertia in local-space.
    #[inline]
    pub fn local_inertia(&self) -> &Inertia<N> {
        &self.local_inertia
    }

    /// The rigid body inertia in world-space.
    #[inline]
    pub fn inertia(&self) -> &Inertia<N> {
        &self.inertia
    }

    /// The augmented mass (inluding gyroscropic terms) in world-space of this rigid body.
    #[inline]
    pub fn augmented_mass(&self) -> &Inertia<N> {
        &self.augmented_mass
    }

    /// The inverse augmented mass (inluding gyroscropic terms) in world-space of this rigid body.
    #[inline]
    pub fn inv_augmented_mass(&self) -> &Inertia<N> {
        &self.inv_augmented_mass
    }

    /// The handle of this rigid body.
    #[inline]
    pub fn handle(&self) -> BodyHandle {
        self.handle
    }

    /// The number of degrees of freedom of this rigid body.
    #[inline]
    pub fn ndofs(&self) -> usize {
        SPATIAL_DIM
    }

    /// The generalized velocities of this rigid body.
    #[inline]
    pub fn generalized_velocity(&self) -> DVectorSlice<N> {
        DVectorSlice::from_slice(self.velocity.as_slice(), SPATIAL_DIM)
    }

    /// The mutable generalized velocities of this rigid body.
    #[inline]
    pub fn generalized_velocity_mut(&mut self) -> DVectorSliceMut<N> {
        DVectorSliceMut::from_slice(self.velocity.as_mut_slice(), SPATIAL_DIM)
    }

    /// The generalized accelerations at each degree of freedom of this rigid body.
    #[inline]
    pub fn generalized_acceleration(&self) -> DVectorSlice<N> {
        DVectorSlice::from_slice(self.acceleration.as_slice(), SPATIAL_DIM)
    }

    /// Integrate the position of this rigid body.
    #[inline]
    pub fn integrate(&mut self, params: &IntegrationParameters<N>) {
        let disp = self.velocity * params.dt;
        self.apply_displacement(&disp);
    }

    /// Apply a displacement to this rigid body.
    ///
    /// Note that the applied displacement is given by `displacement` multiplied by a time equal to `1.0`.
    #[inline]
    pub fn apply_displacement(&mut self, displacement: &Velocity<N>) {
        let rotation = Rotation::new(displacement.angular);
        let translation = Translation::from_vector(displacement.linear);
        let shift = Translation::from_vector(self.com.coords);
        let disp = translation * shift * rotation * shift.inverse();
        let new_pos = disp * self.local_to_world;
        self.set_position(new_pos);
    }

    /// Apply a force to this rigid body for the next timestep.
    #[inline]
    pub fn apply_force(&mut self, force: &Force<N>) {
        self.external_forces.linear += force.linear;
        self.external_forces.angular += force.angular;
    }

    /// The position of this rigid body wrt. the ground.
    #[inline]
    pub fn position(&self) -> Isometry<N> {
        self.local_to_world
    }

    /// Convert a force applied to this rigid body center of mass into generalized force.
    #[inline]
    pub fn body_jacobian_mul_force(&self, force: &Force<N>, out: &mut [N]) {
        out[..SPATIAL_DIM].copy_from_slice(force.as_slice());
    }

    /// Convert generalized forces applied to this rigid body into generalized accelerations.
    #[inline]
    pub fn inv_mass_mul_generalized_forces(&self, out: &mut [N]) {
        let force = Force::from_slice(out);
        self.inv_mass_mul_force(&force, out)
    }

    /// Convert a force applied to this rigid body's center of mass into generalized accelerations.
    #[inline]
    pub fn inv_mass_mul_force(&self, force: &Force<N>, out: &mut [N]) {
        let acc = self.inv_augmented_mass * *force;
        out[..SPATIAL_DIM].copy_from_slice(acc.as_slice());
    }
}
<commit_msg>Fix typo<commit_after>use na::{self, DVectorSlice, DVectorSliceMut, Real};

use math::{Force, Inertia, Isometry, Point, Rotation, Translation, Vector, Velocity, SPATIAL_DIM};
use object::{ActivationStatus, BodyHandle, BodyStatus};
use solver::IntegrationParameters;

#[cfg(feature = "dim3")]
use math::AngularVector;
#[cfg(feature = "dim3")]
use utils::GeneralizedCross;

/// A rigid body.
pub struct RigidBody<N: Real> {
    handle: BodyHandle,
    local_to_world: Isometry<N>,
    velocity: Velocity<N>,
    local_inertia: Inertia<N>,
    inertia: Inertia<N>,
    local_com: Point<N>,
    com: Point<N>,
    augmented_mass: Inertia<N>,
    inv_augmented_mass: Inertia<N>,
    external_forces: Force<N>,
    acceleration: Velocity<N>,
    status: BodyStatus,
    activation: ActivationStatus<N>,
    companion_id: usize,
}

impl<N: Real> RigidBody<N> {
    /// Create a new rigid body with the specified handle and dynamic properties.
    pub fn new(
        handle: BodyHandle,
        position: Isometry<N>,
        local_inertia: Inertia<N>,
        local_com: Point<N>,
    ) -> Self {
        let inertia = local_inertia.transformed(&position);
        let com = position * local_com;

        RigidBody {
            handle,
            local_to_world: position,
            velocity: Velocity::zero(),
            local_inertia,
            inertia,
            local_com,
            com,
            augmented_mass: inertia,
            inv_augmented_mass: inertia.inverse(),
            external_forces: Force::zero(),
            acceleration: Velocity::zero(),
            status: BodyStatus::Dynamic,
            activation: ActivationStatus::new_active(),
            companion_id: 0,
        }
    }

    /// Informations regarding activation and deactivation (sleeping) of this rigid body.
    #[inline]
    pub fn activation_status(&self) -> &ActivationStatus<N> {
        &self.activation
    }

    /// Mutable informations regarding activation and deactivation (sleeping) of this rigid body.
    #[inline]
    pub fn activation_status_mut(&mut self) -> &mut ActivationStatus<N> {
        &mut self.activation
    }

    /// Force the activation of this rigid body.
    #[inline]
    pub fn activate(&mut self) {
        if let Some(threshold) = self.activation.deactivation_threshold() {
            self.activate_with_energy(threshold * na::convert(2.0));
        }
    }

    /// Force the activation of this rigid body with the given level of energy.
    #[inline]
    pub fn activate_with_energy(&mut self, energy: N) {
        self.activation.set_energy(energy)
    }

    /// Put this rigid body to sleep.
    #[inline]
    pub fn deactivate(&mut self) {
        self.activation.set_energy(N::zero());
        self.velocity = Velocity::zero();
    }

    /// Return `true` if this rigid body is kinematic or dynamic and awake.
    #[inline]
    pub fn is_active(&self) -> bool {
        match self.status {
            BodyStatus::Dynamic => self.activation.is_active(),
            BodyStatus::Kinematic => true,
            BodyStatus::Static => false,
            BodyStatus::Disabled => false,
        }
    }

    /// The status of this rigid body.
    #[inline]
    pub fn status(&self) -> BodyStatus {
        self.status
    }

    /// Set the status of this body.
    #[inline]
    pub fn set_status(&mut self, status: BodyStatus) {
        self.status = status
    }

    /// The companion ID of this rigid body.
    #[inline]
    pub fn companion_id(&self) -> usize {
        self.companion_id
    }

    /// Set the companion ID of this rigid body.
    ///
    /// This value may be overriden by nphysics during a timestep.
    #[inline]
    pub fn set_companion_id(&mut self, id: usize) {
        self.companion_id = id
    }

    /// Whether or not the status of this rigid body is dynamic.
    #[inline]
    pub fn is_dynamic(&self) -> bool {
        self.status == BodyStatus::Dynamic
    }

    /// Whether or not the status of this rigid body is static.
    #[inline]
    pub fn is_static(&self) -> bool {
        self.status == BodyStatus::Static
    }

    /// Whether or not the status of this rigid body is kinematic.
    #[inline]
    pub fn is_kinematic(&self) -> bool {
        self.status == BodyStatus::Kinematic
    }

    /// The center of mass of this rigid body.
    #[inline]
    pub fn center_of_mass(&self) -> Point<N> {
        self.com
    }

    /// The velocity of this rigid body.
    #[inline]
    pub fn velocity(&self) -> &Velocity<N> {
        &self.velocity
    }

    /// Sets the position of this rigid body.
    #[inline]
    pub fn set_position(&mut self, pos: Isometry<N>) {
        self.local_to_world = pos;
        self.com = pos * self.local_com;
    }

    /// Set the velocity of this rigid body.
    #[inline]
    pub fn set_velocity(&mut self, vel: Velocity<N>) {
        self.velocity = vel;
        self.activate();
    }

    /// Set the linear velocity of this rigid body.
    #[inline]
    pub fn set_linear_velocity(&mut self, vel: Vector<N>) {
        self.velocity.linear = vel;
        self.activate();
    }

    #[cfg(feature = "dim2")]
    /// Set the angular velocity of this rigid body.
    #[inline]
    pub fn set_angular_velocity(&mut self, vel: N) {
        self.velocity.angular = vel;
        self.activate();
    }

    #[cfg(feature = "dim3")]
    /// Set the angular velocity of this rigid body.
    #[inline]
    pub fn set_angular_velocity(&mut self, vel: AngularVector<N>) {
        self.velocity.angular = vel;
        self.activate();
    }

    /// Reset the timestep-specific dynamic information of this rigid body.
    pub fn clear_dynamics(&mut self) {
        self.augmented_mass = Inertia::zero();
        self.acceleration = Velocity::zero();
    }

    /// Clears the external forces applied to this rigid-body.
    pub fn clear_forces(&mut self) {
        self.external_forces = Force::zero();
    }

    /// Update the timestep-specific dynamic information of this rigid body.
    #[allow(unused_variables)] // for params used only in 3D.
    pub fn update_dynamics(&mut self, gravity: &Vector<N>, params: &IntegrationParameters<N>) {
        if let BodyStatus::Dynamic = self.status {
            // The inverse inertia matrix is constant in 2D.
            #[cfg(feature = "dim3")]
            {
                self.inertia = self.local_inertia.transformed(&self.local_to_world);
                self.augmented_mass += self.inertia;

                let i = &self.inertia.angular;
                let w = &self.velocity.angular;
                let iw = i * w;
                let w_dt = w * params.dt;
                let w_dt_cross = w_dt.gcross_matrix();
                let iw_dt_cross = (iw * params.dt).gcross_matrix();
                self.augmented_mass.angular += w_dt_cross * i - iw_dt_cross;

                // NOTE: if we did not have the gyroscopic forces, we would not have to invert the inertia
                // matrix at each time-step => add a flag to disable gyroscopic forces?
                self.inv_augmented_mass = self.augmented_mass.inverse();

                /*
                 * Compute acceleration due to gyroscopic forces.
                 */
                let gyroscopic = -w.cross(&iw);
                self.acceleration.angular += self.inv_augmented_mass.angular * gyroscopic;
            }

            self.acceleration.linear += *gravity;
            self.acceleration += self.inv_augmented_mass * self.external_forces
        }
    }

    /// The rigid body inertia in local-space.
    #[inline]
    pub fn local_inertia(&self) -> &Inertia<N> {
        &self.local_inertia
    }

    /// The rigid body inertia in world-space.
    #[inline]
    pub fn inertia(&self) -> &Inertia<N> {
        &self.inertia
    }

    /// The augmented mass (inluding gyroscropic terms) in world-space of this rigid body.
    #[inline]
    pub fn augmented_mass(&self) -> &Inertia<N> {
        &self.augmented_mass
    }

    /// The inverse augmented mass (inluding gyroscropic terms) in world-space of this rigid body.
    #[inline]
    pub fn inv_augmented_mass(&self) -> &Inertia<N> {
        &self.inv_augmented_mass
    }

    /// The handle of this rigid body.
    #[inline]
    pub fn handle(&self) -> BodyHandle {
        self.handle
    }

    /// The number of degrees of freedom of this rigid body.
    #[inline]
    pub fn ndofs(&self) -> usize {
        SPATIAL_DIM
    }

    /// The generalized velocities of this rigid body.
    #[inline]
    pub fn generalized_velocity(&self) -> DVectorSlice<N> {
        DVectorSlice::from_slice(self.velocity.as_slice(), SPATIAL_DIM)
    }

    /// The mutable generalized velocities of this rigid body.
    #[inline]
    pub fn generalized_velocity_mut(&mut self) -> DVectorSliceMut<N> {
        DVectorSliceMut::from_slice(self.velocity.as_mut_slice(), SPATIAL_DIM)
    }

    /// The generalized accelerations at each degree of freedom of this rigid body.
    #[inline]
    pub fn generalized_acceleration(&self) -> DVectorSlice<N> {
        DVectorSlice::from_slice(self.acceleration.as_slice(), SPATIAL_DIM)
    }

    /// Integrate the position of this rigid body.
    #[inline]
    pub fn integrate(&mut self, params: &IntegrationParameters<N>) {
        let disp = self.velocity * params.dt;
        self.apply_displacement(&disp);
    }

    /// Apply a displacement to this rigid body.
    ///
    /// Note that the applied displacement is given by `displacement` multiplied by a time equal to `1.0`.
    #[inline]
    pub fn apply_displacement(&mut self, displacement: &Velocity<N>) {
        let rotation = Rotation::new(displacement.angular);
        let translation = Translation::from_vector(displacement.linear);
        let shift = Translation::from_vector(self.com.coords);
        let disp = translation * shift * rotation * shift.inverse();
        let new_pos = disp * self.local_to_world;
        self.set_position(new_pos);
    }

    /// Apply a force to this rigid body for the next timestep.
    #[inline]
    pub fn apply_force(&mut self, force: &Force<N>) {
        self.external_forces.linear += force.linear;
        self.external_forces.angular += force.angular;
    }

    /// The position of this rigid body wrt. the ground.
    #[inline]
    pub fn position(&self) -> Isometry<N> {
        self.local_to_world
    }

    /// Convert a force applied to this rigid body center of mass into generalized force.
    #[inline]
    pub fn body_jacobian_mul_force(&self, force: &Force<N>, out: &mut [N]) {
        out[..SPATIAL_DIM].copy_from_slice(force.as_slice());
    }

    /// Convert generalized forces applied to this rigid body into generalized accelerations.
    #[inline]
    pub fn inv_mass_mul_generalized_forces(&self, out: &mut [N]) {
        let force = Force::from_slice(out);
        self.inv_mass_mul_force(&force, out)
    }

    /// Convert a force applied to this rigid body's center of mass into generalized accelerations.
    #[inline]
    pub fn inv_mass_mul_force(&self, force: &Force<N>, out: &mut [N]) {
        let acc = self.inv_augmented_mass * *force;
        out[..SPATIAL_DIM].copy_from_slice(acc.as_slice());
    }
}
<|endoftext|>


<commit_before>use glium::VertexBuffer;
use glium::IndexBuffer;
use glium::Program;
use glium::DrawParameters;
use glium::Surface;
use glium::Frame;
use glium::Rect;
use glium::index::PrimitiveType;

use nalgebra::Mat4;
use nalgebra::OrthoMat3;

pub const LCD_WIDTH: u32    = 160;
pub const LCD_HEIGHT: u32   = 144;
pub const LCD_ASPECT: f32   = (LCD_WIDTH as f32) / (LCD_HEIGHT as f32);

pub const BG_SIZE: u32      = 256;

static SIMPLE_VERT: &'static str = r#"
#version 140

in vec2 coord;

out vec2 tex_coord;

uniform mat4 projection;

void main() {
    tex_coord = coord;
    gl_Position = projection * vec4(coord, 0.0, 1.0);
}
"#;

static COLOR_FRAG: &'static str = r#"
#version 140

in vec2 tex_coord;

out vec4 frag_color;

uniform vec4 color;

void main() {
    frag_color = color;
}
"#;

static TEXTURE_FRAG: &'static str = r#"
#version 140

in vec2 tex_coord;

out vec4 frag_color;

uniform sampler2D tex;

void main() {
    frag_color = texture(tex, tex_coord);
}
"#;

#[derive(Copy, Clone)]
struct Vertex {
    coord: [f32; 2],
}

implement_vertex!(Vertex, coord);

pub struct GbDisplay {
    simple_surface: VertexBuffer<Vertex>,
    simple_surface_idx: IndexBuffer<u32>,
    color_prog: Program,
    tex_prog: Program,
    projection: Mat4<f32>,
}

impl GbDisplay {

    pub fn new<F>(display: &F) -> GbDisplay where F: ::glium::backend::Facade {
        let (vertbuf, idxbuf) = {
            let topleft = Vertex {
                coord: [0.0, 0.0],
            };
            let topright = Vertex {
                coord: [BG_SIZE as f32, 0.0],
            };
            let bottomright = Vertex {
                coord: [BG_SIZE as f32, BG_SIZE as f32],
            };
            let bottomleft = Vertex {
                coord: [0.0, BG_SIZE as f32],
            };
            let vertices = vec![topleft, topright, bottomright, bottomleft];
            let indices = vec![0, 1, 3, 1, 2, 3];
            (
                VertexBuffer::new(display, &vertices).unwrap(),
                IndexBuffer::immutable(display, PrimitiveType::TrianglesList, &indices).unwrap()
            )
        };
        let colorprog = Program::from_source(display, SIMPLE_VERT, COLOR_FRAG, None).unwrap();
        let texprog = Program::from_source(display, SIMPLE_VERT, TEXTURE_FRAG, None).unwrap();
        let projection = {
            let orthomat = OrthoMat3::new(LCD_WIDTH as f32, LCD_HEIGHT as f32, 0.0, 1.0);
            // Reverse y coord, and translate origin to top left
            let adjust = Mat4::new(
                1.0f32, 0.0, 0.0, (LCD_WIDTH as f32) / -2.0,
                0.0, -1.0, 0.0, (LCD_HEIGHT as f32) / 2.0,
                0.0, 0.0, 1.0, 0.0,
                0.0, 0.0, 0.0, 1.0
                );
            orthomat.to_mat() * adjust
        };
        GbDisplay {
            simple_surface: vertbuf,
            simple_surface_idx: idxbuf,
            color_prog: colorprog,
            tex_prog: texprog,
            projection: projection,
        }
    }

    pub fn clear_viewport(&mut self, frame: &mut Frame, view: Rect, color: (f32, f32, f32, f32)) {
        let params = DrawParameters {
            viewport: Some(view),
            .. Default::default()
        };
        let uniforms = uniform! {
            projection: self.projection,
            color: color,
        };
        frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.color_prog, &uniforms, &params);
    }
}

pub fn calculate_viewport(width: u32, height: u32) -> Rect {
    let aspect = (width as f32) / (height as f32);
    if aspect > LCD_ASPECT {
        let fixwidth = ((height as f32) * LCD_ASPECT) as u32;
        Rect {
            left: (width - fixwidth) / 2,
            bottom: 0,
            width: fixwidth,
            height: height,
        }
    } else {
        let fixheight = ((width as f32) / LCD_ASPECT) as u32;
        Rect {
            left: 0,
            bottom: (height - fixheight) / 2,
            width: width,
            height: fixheight,
        }
    }
}
<commit_msg>Implement intial parts of video emulation<commit_after>use glium::VertexBuffer;
use glium::IndexBuffer;
use glium::Program;
use glium::DrawParameters;
use glium::Surface;
use glium::Frame;
use glium::Rect;
use glium::Texture2d;
use glium::Blend;
use glium::index::PrimitiveType;
use glium::backend::Facade;

use nalgebra::Mat4;
use nalgebra::OrthoMat3;

use MemSection;
use AddressSpace;

pub const LCD_WIDTH: u32    = 160;
pub const LCD_HEIGHT: u32   = 144;
pub const LCD_ASPECT: f32   = (LCD_WIDTH as f32) / (LCD_HEIGHT as f32);

pub const BG_SIZE: u32      = 256;

static SIMPLE_VERT: &'static str = r#"
#version 140

in vec2 coord;

out vec2 tex_coord;

uniform mat4 projection;
uniform vec2 translate;

void main() {
    tex_coord = coord;
    gl_Position = projection * vec4(coord.x + translate.x, coord.y + translate.y, 0.0, 1.0);
}
"#;

static COLOR_FRAG: &'static str = r#"
#version 140

in vec2 tex_coord;

out vec4 frag_color;

uniform vec4 color;
uniform vec2 translate;

void main() {
    frag_color = color;
}
"#;

static TEXTURE_FRAG: &'static str = r#"
#version 140

in vec2 tex_coord;

out vec4 frag_color;

uniform sampler2D tex;

void main() {
    frag_color = texture(tex, tex_coord);
}
"#;

#[derive(Copy, Clone)]
struct Vertex {
    coord: [f32; 2],
}

implement_vertex!(Vertex, coord);

pub struct GbDisplay {
    simple_surface: VertexBuffer<Vertex>,
    simple_surface_idx: IndexBuffer<u32>,
    color_prog: Program,
    tex_prog: Program,
    projection: Mat4<f32>,
}

impl GbDisplay {

    pub fn new<F>(display: &F) -> GbDisplay where F: Facade {
        let (vertbuf, idxbuf) = {
            let topleft = Vertex {
                coord: [0.0, 0.0],
            };
            let topright = Vertex {
                coord: [BG_SIZE as f32, 0.0],
            };
            let bottomright = Vertex {
                coord: [BG_SIZE as f32, BG_SIZE as f32],
            };
            let bottomleft = Vertex {
                coord: [0.0, BG_SIZE as f32],
            };
            let vertices = vec![topleft, topright, bottomright, bottomleft];
            let indices = vec![0, 1, 3, 1, 2, 3];
            (
                VertexBuffer::new(display, &vertices).unwrap(),
                IndexBuffer::immutable(display, PrimitiveType::TrianglesList, &indices).unwrap()
            )
        };
        let colorprog = Program::from_source(display, SIMPLE_VERT, COLOR_FRAG, None).unwrap();
        let texprog = Program::from_source(display, SIMPLE_VERT, TEXTURE_FRAG, None).unwrap();
        let projection = {
            let orthomat = OrthoMat3::new(LCD_WIDTH as f32, LCD_HEIGHT as f32, 0.0, 1.0);
            // Reverse y coord, and translate origin to top left
            let adjust = Mat4::new(
                1.0f32, 0.0, 0.0, (LCD_WIDTH as f32) / -2.0,
                0.0, -1.0, 0.0, (LCD_HEIGHT as f32) / 2.0,
                0.0, 0.0, 1.0, 0.0,
                0.0, 0.0, 0.0, 1.0
                );
            orthomat.to_mat() * adjust
        };
        GbDisplay {
            simple_surface: vertbuf,
            simple_surface_idx: idxbuf,
            color_prog: colorprog,
            tex_prog: texprog,
            projection: projection,
        }
    }

    pub fn clear_viewport(&mut self, frame: &mut Frame, view: Rect, color: (f32, f32, f32, f32)) {
        let params = DrawParameters {
            viewport: Some(view),
            .. Default::default()
        };
        let uniforms = uniform! {
            projection: self.projection,
            translate: (0.0f32, 0.0),
            color: color,
        };
        frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.color_prog, &uniforms, &params);
    }

    pub fn draw<F>(&mut self, display: &F, frame: &mut Frame, view: Rect, mem: &AddressSpace) where F: Facade {
        let lcdc_reg = mem[0xFF40];
        let lcd_on                  = (lcdc_reg & 0x80) != 0;
        let win_map_addr            = if (lcdc_reg & 0x40) == 0 { 0x9800 } else { 0x9C00 };
        let win_on                  = (lcdc_reg & 0x20) != 0;
        let (tile_data, signed_idx) = if (lcdc_reg & 0x10) == 0 { (0x8800, false) }
                                        else { (0x8000, true) };
        let bg_map_addr             = if (lcdc_reg & 0x08) == 0 { 0x9800 } else { 0x9C00 };
        let sprite_height           = if (lcdc_reg & 0x04) == 0 { 8 } else { 16 };
        let sprite_on               = (lcdc_reg & 0x02) != 0;
        let bg_on                   = (lcdc_reg & 0x01) != 0;
        let scroll_y = mem[0xFF42];
        let scroll_x = mem[0xFF43];
        let bg_palette = build_palette(mem[0xFF47]);
        let sprite_palette0 = build_palette(mem[0xFF48]);
        let sprite_palette1 = build_palette(mem[0xFF49]);
        let win_y = mem[0xFF4A];
        let win_x = mem[0xFF4B];

        let params = DrawParameters {
            blend: Blend::alpha_blending(),
            viewport: Some(view),
            .. Default::default()
        };

        // Draw BG
        if bg_on {
            let opts = TileOpts {
                map_addr: bg_map_addr,
                tile_addr: tile_data,
                signed_idx: signed_idx,
                palette: bg_palette,
            };
            let bg_tex = build_tile_tex(display, mem, &opts);
            let uniforms = uniform! {
                projection: self.projection,
                translate: (scroll_x as f32, scroll_y as f32),
                tex: &bg_tex,
            };
            frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.tex_prog, &uniforms, &params);
        }

        // Draw window
        if win_on {
            let opts = TileOpts {
                map_addr: win_map_addr,
                tile_addr: tile_data,
                signed_idx: signed_idx,
                palette: bg_palette,
            };
            let win_tex = build_tile_tex(display, mem, &opts);
            let uniforms = uniform! {
                projection: self.projection,
                translate: (win_x as f32, win_y as f32),
                tex: &win_tex,
            };
            frame.draw(&self.simple_surface, &self.simple_surface_idx, &self.tex_prog, &uniforms, &params);
        }
    }
}

const PALETTE_COLOR0: (f32, f32, f32, f32) = (1.0, 1.0, 1.0, 1.0);
const PALETTE_COLOR1: (f32, f32, f32, f32) = (0.25, 0.25, 0.25, 0.25);
const PALETTE_COLOR2: (f32, f32, f32, f32) = (0.75, 0.75, 0.75, 0.75);
const PALETTE_COLOR3: (f32, f32, f32, f32) = (0.0, 0.0, 0.0, 0.0);

fn build_palette(bits: u8) -> [(f32, f32, f32, f32); 4] {
    let c0 = bits & 0x03;
    let c1 = bits & 0x0C >> 2;
    let c2 = bits & 0x30 >> 4;
    let c3 = bits & 0xC0 >> 6;
    let mut colors = [PALETTE_COLOR0; 4];
    colors[c0 as usize] = PALETTE_COLOR0;
    colors[c1 as usize] = PALETTE_COLOR1;
    colors[c2 as usize] = PALETTE_COLOR2;
    colors[c3 as usize] = PALETTE_COLOR3;
    colors
}

struct TileOpts {
    map_addr: u16,
    tile_addr: u16,
    signed_idx: bool,
    palette: [(f32, f32, f32, f32); 4],
}

fn build_tile_tex<F>(display: &F, mem: &AddressSpace, opts: &TileOpts) -> Texture2d where F: Facade {
    // Data layout: data[y][x], origin top left
    let mut data: Vec<Vec<(f32, f32, f32, f32)>> = Vec::with_capacity(256);
    for i in 0..256 {
        data.push(Vec::with_capacity(256));
    }
    for i in 0..1024 {
        let offset: i32 = if opts.signed_idx {
            // Abuse conversion operations
            let tmp = mem[opts.map_addr + i] as i8;
            tmp as i32
        } else {
            mem[opts.map_addr + i] as i32
        };
        let addr = (opts.tile_addr as i32 + offset) as u16;
        let y_coord = i / 32;
        // Pixel format: big endian pixel pos
        for j in 0..8 {
            let lo = mem[addr + j*2];
            let hi = mem[addr + j*2 + 1];
            for k in (0..8).rev() {
                let mask = 1 << k;
                let color = ((lo & mask) >> k) | (((hi & mask) >> k) << 1);
                data[(y_coord + j) as usize].push(opts.palette[color as usize]);
            }
        }
    }
    Texture2d::new(display, data).unwrap()
}

pub fn calculate_viewport(width: u32, height: u32) -> Rect {
    let aspect = (width as f32) / (height as f32);
    if aspect > LCD_ASPECT {
        let fixwidth = ((height as f32) * LCD_ASPECT) as u32;
        Rect {
            left: (width - fixwidth) / 2,
            bottom: 0,
            width: fixwidth,
            height: height,
        }
    } else {
        let fixheight = ((width as f32) / LCD_ASPECT) as u32;
        Rect {
            left: 0,
            bottom: (height - fixheight) / 2,
            width: width,
            height: fixheight,
        }
    }
}
<|endoftext|>