<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The compiler code necessary to implement the `#[deriving(Encodable)]`
//! (and `Decodable`, in decodable.rs) extension.  The idea here is that
//! type-defining items may be tagged with `#[deriving(Encodable, Decodable)]`.
//!
//! For example, a type like:
//!
//! ```ignore
//! #[deriving(Encodable, Decodable)]
//! struct Node { id: uint }
//! ```
//!
//! would generate two implementations like:
//!
//! ```ignore
//! impl<S:serialize::Encoder> Encodable<S> for Node {
//!     fn encode(&self, s: &S) {
//!         s.emit_struct("Node", 1, || {
//!             s.emit_field("id", 0, || s.emit_uint(self.id))
//!         })
//!     }
//! }
//!
//! impl<D:Decoder> Decodable for node_id {
//!     fn decode(d: &D) -> Node {
//!         d.read_struct("Node", 1, || {
//!             Node {
//!                 id: d.read_field("x".to_string(), 0, || decode(d))
//!             }
//!         })
//!     }
//! }
//! ```
//!
//! Other interesting scenarios are when the item has type parameters or
//! references other non-built-in types.  A type definition like:
//!
//! ```ignore
//! #[deriving(Encodable, Decodable)]
//! struct spanned<T> { node: T, span: Span }
//! ```
//!
//! would yield functions like:
//!
//! ```ignore
//!     impl<
//!         S: Encoder,
//!         T: Encodable<S>
//!     > spanned<T>: Encodable<S> {
//!         fn encode<S:Encoder>(s: &S) {
//!             s.emit_rec(|| {
//!                 s.emit_field("node", 0, || self.node.encode(s));
//!                 s.emit_field("span", 1, || self.span.encode(s));
//!             })
//!         }
//!     }
//!
//!     impl<
//!         D: Decoder,
//!         T: Decodable<D>
//!     > spanned<T>: Decodable<D> {
//!         fn decode(d: &D) -> spanned<T> {
//!             d.read_rec(|| {
//!                 {
//!                     node: d.read_field("node".to_string(), 0, || decode(d)),
//!                     span: d.read_field("span".to_string(), 1, || decode(d)),
//!                 }
//!             })
//!         }
//!     }
//! ```

use ast::{MetaItem, Item, Expr, ExprRet, MutMutable, LitNil};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use parse::token;
use ptr::P;

pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
                                 span: Span,
                                 mitem: &MetaItem,
                                 item: &Item,
                                 push: |P<Item>|) {
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: Path::new_(vec!("serialize", "Encodable"), None,
                         vec!(box Literal(Path::new_local("__S")),
                              box Literal(Path::new_local("__E"))), true),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds {
            lifetimes: Vec::new(),
            bounds: vec!(("__S", None, vec!(Path::new_(
                            vec!("serialize", "Encoder"), None,
                            vec!(box Literal(Path::new_local("__E"))), true))),
                         ("__E", None, vec!()))
        },
        methods: vec!(
            MethodDef {
                name: "encode",
                generics: LifetimeBounds::empty(),
                explicit_self: borrowed_explicit_self(),
                args: vec!(Ptr(box Literal(Path::new_local("__S")),
                            Borrowed(None, MutMutable))),
                ret_ty: Literal(Path::new_(vec!("std", "result", "Result"),
                                           None,
                                           vec!(box Tuple(Vec::new()),
                                                box Literal(Path::new_local("__E"))),
                                           true)),
                attributes: Vec::new(),
                combine_substructure: combine_substructure(|a, b, c| {
                    encodable_substructure(a, b, c)
                }),
            })
    };

    trait_def.expand(cx, mitem, item, push)
}

fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
                          substr: &Substructure) -> P<Expr> {
    let encoder = substr.nonself_args[0].clone();
    // throw an underscore in front to suppress unused variable warnings
    let blkarg = cx.ident_of("_e");
    let blkencoder = cx.expr_ident(trait_span, blkarg);
    let encode = cx.ident_of("encode");

    return match *substr.fields {
        Struct(ref fields) => {
            let emit_struct_field = cx.ident_of("emit_struct_field");
            let mut stmts = Vec::new();
            let last = fields.len() - 1;
            for (i, &FieldInfo {
                    name,
                    ref self_,
                    span,
                    ..
                }) in fields.iter().enumerate() {
                let name = match name {
                    Some(id) => token::get_ident(id),
                    None => {
                        token::intern_and_get_ident(format!("_field{}",
                                                            i).as_slice())
                    }
                };
                let enc = cx.expr_method_call(span, self_.clone(),
                                              encode, vec!(blkencoder.clone()));
                let lambda = cx.lambda_expr_1(span, enc, blkarg);
                let call = cx.expr_method_call(span, blkencoder.clone(),
                                               emit_struct_field,
                                               vec!(cx.expr_str(span, name),
                                                 cx.expr_uint(span, i),
                                                 lambda));

                // last call doesn't need a try!
                let call = if i != last {
                    cx.expr_try(span, call)
                } else {
                    cx.expr(span, ExprRet(Some(call)))
                };
                stmts.push(cx.stmt_expr(call));
            }

            // unit structs have no fields and need to return Ok()
            if stmts.is_empty() {
                let ret_ok = cx.expr(trait_span,
                                     ExprRet(Some(cx.expr_ok(trait_span,
                                                             cx.expr_lit(trait_span, LitNil)))));
                stmts.push(cx.stmt_expr(ret_ok));
            }

            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
            cx.expr_method_call(trait_span,
                                encoder,
                                cx.ident_of("emit_struct"),
                                vec!(
                cx.expr_str(trait_span, token::get_ident(substr.type_ident)),
                cx.expr_uint(trait_span, fields.len()),
                blk
            ))
        }

        EnumMatching(idx, variant, ref fields) => {
            // We're not generating an AST that the borrow checker is expecting,
            // so we need to generate a unique local variable to take the
            // mutable loan out on, otherwise we get conflicts which don't
            // actually exist.
            let me = cx.stmt_let(trait_span, false, blkarg, encoder);
            let encoder = cx.expr_ident(trait_span, blkarg);
            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
            let mut stmts = Vec::new();
            let last = fields.len() - 1;
            for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() {
                let enc = cx.expr_method_call(span, self_.clone(),
                                              encode, vec!(blkencoder.clone()));
                let lambda = cx.lambda_expr_1(span, enc, blkarg);
                let call = cx.expr_method_call(span, blkencoder.clone(),
                                               emit_variant_arg,
                                               vec!(cx.expr_uint(span, i),
                                                 lambda));
                let call = if i != last {
                    cx.expr_try(span, call)
                } else {
                    cx.expr(span, ExprRet(Some(call)))
                };
                stmts.push(cx.stmt_expr(call));
            }

            // enums with no fields need to return Ok()
            if stmts.len() == 0 {
                let ret_ok = cx.expr(trait_span,
                                     ExprRet(Some(cx.expr_ok(trait_span,
                                                             cx.expr_lit(trait_span, LitNil)))));
                stmts.push(cx.stmt_expr(ret_ok));
            }

            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
            let name = cx.expr_str(trait_span, token::get_ident(variant.node.name));
            let call = cx.expr_method_call(trait_span, blkencoder,
                                           cx.ident_of("emit_enum_variant"),
                                           vec!(name,
                                             cx.expr_uint(trait_span, idx),
                                             cx.expr_uint(trait_span, fields.len()),
                                             blk));
            let blk = cx.lambda_expr_1(trait_span, call, blkarg);
            let ret = cx.expr_method_call(trait_span,
                                          encoder,
                                          cx.ident_of("emit_enum"),
                                          vec!(
                cx.expr_str(trait_span, token::get_ident(substr.type_ident)),
                blk
            ));
            cx.expr_block(cx.block(trait_span, vec!(me), Some(ret)))
        }

        _ => cx.bug("expected Struct or EnumMatching in deriving(Encodable)")
    };
}
<commit_msg>Improve examples for syntax::ext::deriving::encodable<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The compiler code necessary to implement the `#[deriving(Encodable)]`
//! (and `Decodable`, in decodable.rs) extension.  The idea here is that
//! type-defining items may be tagged with `#[deriving(Encodable, Decodable)]`.
//!
//! For example, a type like:
//!
//! ```ignore
//! #[deriving(Encodable, Decodable)]
//! struct Node { id: uint }
//! ```
//!
//! would generate two implementations like:
//!
//! ```ignore
//! impl<S: Encoder<E>, E> Encodable<S, E> for Node {
//!     fn encode(&self, s: &mut S) -> Result<(), E> {
//!         s.emit_struct("Node", 1, |this| {
//!             this.emit_struct_field("id", 0, |this| {
//!                 Encodable::encode(&self.id, this)
//!                 /* this.emit_uint(self.id) can also be used */
//!             })
//!         })
//!     }
//! }
//!
//! impl<D: Decoder<E>, E> Decodable<D, E> for Node {
//!     fn decode(d: &mut D) -> Result<Node, E> {
//!         d.read_struct("Node", 1, |this| {
//!             match this.read_struct_field("id", 0, |this| Decodable::decode(this)) {
//!                 Ok(id) => Ok(Node { id: id }),
//!                 Err(e) => Err(e),
//!             }
//!         })
//!     }
//! }
//! ```
//!
//! Other interesting scenarios are when the item has type parameters or
//! references other non-built-in types.  A type definition like:
//!
//! ```ignore
//! #[deriving(Encodable, Decodable)]
//! struct Spanned<T> { node: T, span: Span }
//! ```
//!
//! would yield functions like:
//!
//! ```ignore
//! impl<
//!     S: Encoder<E>,
//!     E,
//!     T: Encodable<S, E>
//! > Encodable<S, E> for Spanned<T> {
//!     fn encode(&self, s: &mut S) -> Result<(), E> {
//!         s.emit_struct("Spanned", 2, |this| {
//!             this.emit_struct_field("node", 0, |this| self.node.encode(this))
//!                 .ok().unwrap();
//!             this.emit_struct_field("span", 1, |this| self.span.encode(this))
//!         })
//!     }
//! }
//!
//! impl<
//!     D: Decoder<E>,
//!     E,
//!     T: Decodable<D, E>
//! > Decodable<D, E> for Spanned<T> {
//!     fn decode(d: &mut D) -> Result<Spanned<T>, E> {
//!         d.read_struct("Spanned", 2, |this| {
//!             Ok(Spanned {
//!                 node: this.read_struct_field("node", 0, |this| Decodable::decode(this))
//!                     .ok().unwrap(),
//!                 span: this.read_struct_field("span", 1, |this| Decodable::decode(this))
//!                     .ok().unwrap(),
//!             })
//!         })
//!     }
//! }
//! ```

use ast::{MetaItem, Item, Expr, ExprRet, MutMutable, LitNil};
use codemap::Span;
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use ext::deriving::generic::*;
use ext::deriving::generic::ty::*;
use parse::token;
use ptr::P;

pub fn expand_deriving_encodable(cx: &mut ExtCtxt,
                                 span: Span,
                                 mitem: &MetaItem,
                                 item: &Item,
                                 push: |P<Item>|) {
    let trait_def = TraitDef {
        span: span,
        attributes: Vec::new(),
        path: Path::new_(vec!("serialize", "Encodable"), None,
                         vec!(box Literal(Path::new_local("__S")),
                              box Literal(Path::new_local("__E"))), true),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds {
            lifetimes: Vec::new(),
            bounds: vec!(("__S", None, vec!(Path::new_(
                            vec!("serialize", "Encoder"), None,
                            vec!(box Literal(Path::new_local("__E"))), true))),
                         ("__E", None, vec!()))
        },
        methods: vec!(
            MethodDef {
                name: "encode",
                generics: LifetimeBounds::empty(),
                explicit_self: borrowed_explicit_self(),
                args: vec!(Ptr(box Literal(Path::new_local("__S")),
                            Borrowed(None, MutMutable))),
                ret_ty: Literal(Path::new_(vec!("std", "result", "Result"),
                                           None,
                                           vec!(box Tuple(Vec::new()),
                                                box Literal(Path::new_local("__E"))),
                                           true)),
                attributes: Vec::new(),
                combine_substructure: combine_substructure(|a, b, c| {
                    encodable_substructure(a, b, c)
                }),
            })
    };

    trait_def.expand(cx, mitem, item, push)
}

fn encodable_substructure(cx: &mut ExtCtxt, trait_span: Span,
                          substr: &Substructure) -> P<Expr> {
    let encoder = substr.nonself_args[0].clone();
    // throw an underscore in front to suppress unused variable warnings
    let blkarg = cx.ident_of("_e");
    let blkencoder = cx.expr_ident(trait_span, blkarg);
    let encode = cx.ident_of("encode");

    return match *substr.fields {
        Struct(ref fields) => {
            let emit_struct_field = cx.ident_of("emit_struct_field");
            let mut stmts = Vec::new();
            let last = fields.len() - 1;
            for (i, &FieldInfo {
                    name,
                    ref self_,
                    span,
                    ..
                }) in fields.iter().enumerate() {
                let name = match name {
                    Some(id) => token::get_ident(id),
                    None => {
                        token::intern_and_get_ident(format!("_field{}",
                                                            i).as_slice())
                    }
                };
                let enc = cx.expr_method_call(span, self_.clone(),
                                              encode, vec!(blkencoder.clone()));
                let lambda = cx.lambda_expr_1(span, enc, blkarg);
                let call = cx.expr_method_call(span, blkencoder.clone(),
                                               emit_struct_field,
                                               vec!(cx.expr_str(span, name),
                                                 cx.expr_uint(span, i),
                                                 lambda));

                // last call doesn't need a try!
                let call = if i != last {
                    cx.expr_try(span, call)
                } else {
                    cx.expr(span, ExprRet(Some(call)))
                };
                stmts.push(cx.stmt_expr(call));
            }

            // unit structs have no fields and need to return Ok()
            if stmts.is_empty() {
                let ret_ok = cx.expr(trait_span,
                                     ExprRet(Some(cx.expr_ok(trait_span,
                                                             cx.expr_lit(trait_span, LitNil)))));
                stmts.push(cx.stmt_expr(ret_ok));
            }

            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
            cx.expr_method_call(trait_span,
                                encoder,
                                cx.ident_of("emit_struct"),
                                vec!(
                cx.expr_str(trait_span, token::get_ident(substr.type_ident)),
                cx.expr_uint(trait_span, fields.len()),
                blk
            ))
        }

        EnumMatching(idx, variant, ref fields) => {
            // We're not generating an AST that the borrow checker is expecting,
            // so we need to generate a unique local variable to take the
            // mutable loan out on, otherwise we get conflicts which don't
            // actually exist.
            let me = cx.stmt_let(trait_span, false, blkarg, encoder);
            let encoder = cx.expr_ident(trait_span, blkarg);
            let emit_variant_arg = cx.ident_of("emit_enum_variant_arg");
            let mut stmts = Vec::new();
            let last = fields.len() - 1;
            for (i, &FieldInfo { ref self_, span, .. }) in fields.iter().enumerate() {
                let enc = cx.expr_method_call(span, self_.clone(),
                                              encode, vec!(blkencoder.clone()));
                let lambda = cx.lambda_expr_1(span, enc, blkarg);
                let call = cx.expr_method_call(span, blkencoder.clone(),
                                               emit_variant_arg,
                                               vec!(cx.expr_uint(span, i),
                                                 lambda));
                let call = if i != last {
                    cx.expr_try(span, call)
                } else {
                    cx.expr(span, ExprRet(Some(call)))
                };
                stmts.push(cx.stmt_expr(call));
            }

            // enums with no fields need to return Ok()
            if stmts.len() == 0 {
                let ret_ok = cx.expr(trait_span,
                                     ExprRet(Some(cx.expr_ok(trait_span,
                                                             cx.expr_lit(trait_span, LitNil)))));
                stmts.push(cx.stmt_expr(ret_ok));
            }

            let blk = cx.lambda_stmts_1(trait_span, stmts, blkarg);
            let name = cx.expr_str(trait_span, token::get_ident(variant.node.name));
            let call = cx.expr_method_call(trait_span, blkencoder,
                                           cx.ident_of("emit_enum_variant"),
                                           vec!(name,
                                             cx.expr_uint(trait_span, idx),
                                             cx.expr_uint(trait_span, fields.len()),
                                             blk));
            let blk = cx.lambda_expr_1(trait_span, call, blkarg);
            let ret = cx.expr_method_call(trait_span,
                                          encoder,
                                          cx.ident_of("emit_enum"),
                                          vec!(
                cx.expr_str(trait_span, token::get_ident(substr.type_ident)),
                blk
            ));
            cx.expr_block(cx.block(trait_span, vec!(me), Some(ret)))
        }

        _ => cx.bug("expected Struct or EnumMatching in deriving(Encodable)")
    };
}
<|endoftext|>


<commit_before>use super::*;
use peephole;

use common::{Count, Instruction};

/// Program forms that can be compiled to bytecode bytecode.
pub trait BytecodeCompilable {
    /// Compile the given program into the peephole AST to prepare for bytecode bytecode compilation.
    fn with_peephole<F, R>(&self, k: F) -> R
        where F: FnOnce(&peephole::Program) -> R;

    /// Compile the given program to bytecode bytecode.
    fn bytecode_compile(&self) -> Box<Program> {
        self.with_peephole(compile)
    }
}

/// Compiles peephole-optimized AST to a bytecode bytecode program.
pub fn compile(src: &[peephole::Statement]) -> Box<Program> {
    let mut compiler = Compiler::new();
    compiler.compile(src);
    compiler.into_program()
}

pub struct Compiler {
    instructions: Vec<Instruction>,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler {
            instructions: Vec::new(),
        }
    }

    pub fn compile(&mut self, src: &[peephole::Statement]) {
        use peephole::Statement as Src;
        use common::Instruction as Obj;

        for instruction in src {
            match *instruction {
                Src::Instr(instruction) => self.issue(instruction),
                Src::Loop(ref body) => {
                    let begin_pc = self.instructions.len();
                    self.issue(Obj::JumpZero(0));
                    self.compile(body);
                    let end_pc = self.instructions.len();
                    self.issue(Obj::JumpNotZero(usize_to_count(begin_pc)));
                    self.instructions[begin_pc] = Obj::JumpZero(usize_to_count(end_pc));
                }
            }
        }
    }

    pub fn into_program(self) -> Box<Program> {
        self.instructions.into_boxed_slice()
    }

    fn issue(&mut self, instruction: Instruction) {
        self.instructions.push(instruction);
    }
}

/// Converts a `usize` to a `Count`, panicking if the `usize` is out of range.
pub fn usize_to_count(count: usize) -> Count {
    let result: Count = count as Count;
    assert_eq!(result as usize, count);
    result
}

impl BytecodeCompilable for peephole::Program {
    fn with_peephole<F, R>(&self, k: F) -> R
        where F: FnOnce(&peephole::Program) -> R
    {
        k(self)
    }
}

impl<T: peephole::PeepholeCompilable + ?Sized> BytecodeCompilable for T {
    fn with_peephole<F, R>(&self, k: F) -> R
        where F: FnOnce(&peephole::Program) -> R
    {
        k(&self.peephole_compile())
    }
}
<commit_msg>removed repeated word "bytecode"<commit_after>use super::*;
use peephole;

use common::{Count, Instruction};

/// Program forms that can be compiled to bytecode.
pub trait BytecodeCompilable {
    /// Compile the given program into the peephole AST to prepare for bytecode compilation.
    fn with_peephole<F, R>(&self, k: F) -> R
        where F: FnOnce(&peephole::Program) -> R;

    /// Compile the given program to bytecode.
    fn bytecode_compile(&self) -> Box<Program> {
        self.with_peephole(compile)
    }
}

/// Compiles peephole-optimized AST to a bytecode program.
pub fn compile(src: &[peephole::Statement]) -> Box<Program> {
    let mut compiler = Compiler::new();
    compiler.compile(src);
    compiler.into_program()
}

pub struct Compiler {
    instructions: Vec<Instruction>,
}

impl Compiler {
    pub fn new() -> Self {
        Compiler {
            instructions: Vec::new(),
        }
    }

    pub fn compile(&mut self, src: &[peephole::Statement]) {
        use peephole::Statement as Src;
        use common::Instruction as Obj;

        for instruction in src {
            match *instruction {
                Src::Instr(instruction) => self.issue(instruction),
                Src::Loop(ref body) => {
                    let begin_pc = self.instructions.len();
                    self.issue(Obj::JumpZero(0));
                    self.compile(body);
                    let end_pc = self.instructions.len();
                    self.issue(Obj::JumpNotZero(usize_to_count(begin_pc)));
                    self.instructions[begin_pc] = Obj::JumpZero(usize_to_count(end_pc));
                }
            }
        }
    }

    pub fn into_program(self) -> Box<Program> {
        self.instructions.into_boxed_slice()
    }

    fn issue(&mut self, instruction: Instruction) {
        self.instructions.push(instruction);
    }
}

/// Converts a `usize` to a `Count`, panicking if the `usize` is out of range.
pub fn usize_to_count(count: usize) -> Count {
    let result: Count = count as Count;
    assert_eq!(result as usize, count);
    result
}

impl BytecodeCompilable for peephole::Program {
    fn with_peephole<F, R>(&self, k: F) -> R
        where F: FnOnce(&peephole::Program) -> R
    {
        k(self)
    }
}

impl<T: peephole::PeepholeCompilable + ?Sized> BytecodeCompilable for T {
    fn with_peephole<F, R>(&self, k: F) -> R
        where F: FnOnce(&peephole::Program) -> R
    {
        k(&self.peephole_compile())
    }
}
<|endoftext|>


<commit_before>use libc::{c_void, size_t};
use libc::funcs::posix88::mman;
use std::ptr;

// Using String to get ownership of the input string
pub struct SecureString {
    pub string: String,
}

impl SecureString {
    pub fn new(string: String) -> SecureString {
        // Lock the string against swapping
        unsafe { mman::mlock(string.as_ptr() as *const c_void, string.len() as size_t); }
        SecureString { string: string }
    }

    pub fn new_from_str(string: &str) -> SecureString {
	let s: String = string.to_string();
    	SecureString::new(s)
    }

    pub fn delete(&self) {
        unsafe { ptr::zero_memory(self.string.as_ptr() as *mut c_void, self.string.len()) };
    }
}

impl Drop for SecureString {
    fn drop(&mut self) {
        self.delete();
    }
}

#[cfg(test)]
mod tests {
    use super::SecureString;

    #[test]
    fn test_new() {
        let str = "Hello, box!".to_string();
        // Ownership of str moves to SecureString <- secure input interface
        let sec_str = SecureString::new(str);
        assert_eq!(sec_str.string.as_slice(), "Hello, box!");
    }

    #[test]
    fn test_new_from_str() {
        let str = "Hello, box!";
        // Ownership of str moves to SecureString <- secure input interface
        let sec_str = SecureString::new_from_str(str);
        assert_eq!(sec_str.string.as_slice(), "Hello, box!");
    }

    #[test]
    fn test_delete() {
        let str = "delete".to_string();
        let sec_str = SecureString::new(str);
        sec_str.delete();
        assert_eq!(sec_str.string.as_slice(), "\0\0\0\0\0\0");

        // Test with umlauts
        let str = "ä".to_string();
        let sec_str = SecureString::new(str);
        sec_str.delete();
        assert_eq!(sec_str.string.as_slice(), "\0\0");

	// Test with new_from_str
	let str = "deletä";
	let sec_str = SecureString::new_from_str(str);
	sec_str.delete();
	assert_eq!(sec_str.string.as_slice(), "\0\0\0\0\0\0\0");
    }
}
<commit_msg>removed new_from_str because it is unsecure as a copy of the string remains in stack<commit_after>use libc::{c_void, size_t};
use libc::funcs::posix88::mman;
use std::ptr;

// Using String to get ownership of the input string
pub struct SecureString {
    pub string: String,
}

impl SecureString {
    pub fn new(string: String) -> SecureString {
        // Lock the string against swapping
        unsafe { mman::mlock(string.as_ptr() as *const c_void, string.len() as size_t); }
        SecureString { string: string }
    }

    pub fn delete(&self) {
        unsafe { ptr::zero_memory(self.string.as_ptr() as *mut c_void, self.string.len()) };
    }
}

impl Drop for SecureString {
    fn drop(&mut self) {
        self.delete();
    }
}

#[cfg(test)]
mod tests {
    use super::SecureString;

    #[test]
    fn test_new() {
        let str = "Hello, box!".to_string();
        // Ownership of str moves to SecureString <- secure input interface
        let sec_str = SecureString::new(str);
        assert_eq!(sec_str.string.as_slice(), "Hello, box!");
    }

    #[test]
    fn test_delete() {
        let str = "delete".to_string();
        let sec_str = SecureString::new(str);
        sec_str.delete();
        assert_eq!(sec_str.string.as_slice(), "\0\0\0\0\0\0");

        // Test with umlauts
        let str = "ä".to_string();
        let sec_str = SecureString::new(str);
        sec_str.delete();
        assert_eq!(sec_str.string.as_slice(), "\0\0");
    }
}
<|endoftext|>


<commit_before>//! Read a las file.
//!
//! Though right now we always read all point data into memory, in the future we may support
//! streaming reads. This class abstracts out the reading process to make future streaming reads
//! less impactful.
//!
//! Prefer to use the `Reader` class to get las data from the filesystem.

use std::fs::File;
use std::io::{BufReader, Read, Seek, SeekFrom};
use std::iter::IntoIterator;
use std::path::Path;

use byteorder::{LittleEndian, ReadBytesExt};

use Result;
use header::Header;
use io::read_full;
use point::{Classification, NumberOfReturns, Point, ReturnNumber, ScanDirection};
use scale::scale;
use vlr::Vlr;

/// A reader of las points.
#[derive(Debug)]
pub struct Reader<R: Read> {
    header: Header,
    vlrs: Vec<Vlr>,
    reader: R,
    nread: u32,
}

impl Reader<BufReader<File>> {
    /// Opens a new reader for the given path.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>> {
        let reader = BufReader::new(try!(File::open(path)));
        Reader::new(reader)
    }
}

impl<R: Read + Seek> Reader<R> {
    /// Creates a new reader for a given `Read` object, consuming the read.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use las::reader::Reader;
    /// let file = File::open("data/1.0_0.las").unwrap();
    /// let reader = Reader::new(file);
    /// ```
    pub fn new(mut reader: R) -> Result<Reader<R>> {
        let header = try!(Header::read_from(&mut reader));
        let mut vlrs = Vec::with_capacity(header.number_of_variable_length_records as usize);
        let _ = try!(reader.seek(SeekFrom::Start(header.header_size as u64)));
        for _ in 0..header.number_of_variable_length_records {
            vlrs.push(try!(Vlr::read_from(&mut reader)));
        }

        let _ = try!(reader.seek(SeekFrom::Start(header.offset_to_point_data as u64)));

        Ok(Reader {
            header: header,
            vlrs: vlrs,
            reader: reader,
            nread: 0,
        })
    }

    /// Returns the next point in this reader.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let mut reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// let point = reader.next_point().unwrap();
    /// assert!(point.is_some());
    /// let point = reader.next_point().unwrap();
    /// assert!(point.is_none());
    /// ```
    pub fn next_point(&mut self) -> Result<Option<Point>> {
        if self.eof() {
            return Ok(None);
        }
        let mut point = Point::new();
        let start = try!(self.reader.seek(SeekFrom::Current(0)));
        point.x = scale(try!(self.reader.read_i32::<LittleEndian>()),
                        self.header.x_scale_factor,
                        self.header.x_offset);
        point.y = scale(try!(self.reader.read_i32::<LittleEndian>()),
                        self.header.y_scale_factor,
                        self.header.y_offset);
        point.z = scale(try!(self.reader.read_i32::<LittleEndian>()),
                        self.header.z_scale_factor,
                        self.header.x_offset);
        point.intensity = try!(self.reader.read_u16::<LittleEndian>());
        let byte = try!(self.reader.read_u8());
        point.return_number = try!(ReturnNumber::from_u8(byte & 0b00000111));
        point.number_of_returns = try!(NumberOfReturns::from_u8((byte >> 3) & 0b00000111));
        point.scan_direction = ScanDirection::from((byte >> 6) & 0b00000001 == 1);
        point.edge_of_flight_line = byte >> 7 == 1;
        let byte = try!(self.reader.read_u8());
        point.classification = try!(Classification::from_u8(byte & 0b00011111));
        point.synthetic = (byte >> 5) & 0b00000001 == 1;
        point.key_point = (byte >> 6) & 0b00000001 == 1;
        point.withheld = byte >> 7 == 1;
        point.scan_angle_rank = try!(self.reader.read_i8());
        point.user_data = try!(self.reader.read_u8());
        point.point_source_id = try!(self.reader.read_u16::<LittleEndian>());
        if self.header.point_data_format.has_time() {
            point.gps_time = Some(try!(self.reader.read_f64::<LittleEndian>()));
        }
        if self.header.point_data_format.has_color() {
            point.red = Some(try!(self.reader.read_u16::<LittleEndian>()));
            point.green = Some(try!(self.reader.read_u16::<LittleEndian>()));
            point.blue = Some(try!(self.reader.read_u16::<LittleEndian>()));
        }
        let bytes_read = try!(self.reader.seek(SeekFrom::Current(0))) - start;

        if bytes_read < self.header.point_data_record_length as u64 {
            let mut buf =
                vec![0; (self.header.point_data_record_length as u64 - bytes_read) as usize];
            try!(read_full(&mut self.reader, &mut buf[..]));
            point.extra_bytes = Some(buf);
        }

        self.nread += 1;

        Ok(Some(point))
    }
}

impl<R: Read> Reader<R> {
    /// Returns this reader's las header.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// let header = reader.header();
    pub fn header(&self) -> Header {
        self.header
    }

    /// Returns a reference to this reader's vlrs.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// let vlrs = reader.vlrs();
    pub fn vlrs(&self) -> &Vec<Vlr> {
        &self.vlrs
    }

    /// Returns the number of points in this lasfile, as specified by the header.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// assert_eq!(1, reader.npoints());
    /// ```
    pub fn npoints(&self) -> u32 {
        self.header.number_of_point_records
    }

    /// Returns true if this reader is at the end of the file.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let mut reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// assert!(!reader.eof());
    /// let _ = reader.next_point().unwrap();
    /// assert!(reader.eof());
    /// ```
    pub fn eof(&self) -> bool {
        self.nread == self.npoints()
    }
}

impl<R: Read + Seek> IntoIterator for Reader<R> {
    type Item = Point;
    type IntoIter = ReaderIterator<R>;
    fn into_iter(self) -> Self::IntoIter {
        ReaderIterator { reader: self }
    }
}

/// An iterator over the reader's points.
///
/// # Panics
///
/// This iterator will panic if something goes wrong while reading the points. If you need to catch
/// those errors, use `Reader::next_point`.
#[derive(Debug)]
pub struct ReaderIterator<R: Read + Seek> {
    reader: Reader<R>,
}

impl<R: Read + Seek> Iterator for ReaderIterator<R> {
    type Item = Point;
    fn next(&mut self) -> Option<Self::Item> {
        self.reader.next_point().unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reader_as_iter() {
        let reader = Reader::from_path("data/1.0_0.las").unwrap();
        let points: Vec<_> = reader.into_iter().collect();
        assert_eq!(1, points.len());
    }
}
<commit_msg>Add closing code fences to some docs<commit_after>//! Read a las file.
//!
//! Though right now we always read all point data into memory, in the future we may support
//! streaming reads. This class abstracts out the reading process to make future streaming reads
//! less impactful.
//!
//! Prefer to use the `Reader` class to get las data from the filesystem.

use std::fs::File;
use std::io::{BufReader, Read, Seek, SeekFrom};
use std::iter::IntoIterator;
use std::path::Path;

use byteorder::{LittleEndian, ReadBytesExt};

use Result;
use header::Header;
use io::read_full;
use point::{Classification, NumberOfReturns, Point, ReturnNumber, ScanDirection};
use scale::scale;
use vlr::Vlr;

/// A reader of las points.
#[derive(Debug)]
pub struct Reader<R: Read> {
    header: Header,
    vlrs: Vec<Vlr>,
    reader: R,
    nread: u32,
}

impl Reader<BufReader<File>> {
    /// Opens a new reader for the given path.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// ```
    pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Reader<BufReader<File>>> {
        let reader = BufReader::new(try!(File::open(path)));
        Reader::new(reader)
    }
}

impl<R: Read + Seek> Reader<R> {
    /// Creates a new reader for a given `Read` object, consuming the read.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::fs::File;
    /// use las::reader::Reader;
    /// let file = File::open("data/1.0_0.las").unwrap();
    /// let reader = Reader::new(file);
    /// ```
    pub fn new(mut reader: R) -> Result<Reader<R>> {
        let header = try!(Header::read_from(&mut reader));
        let mut vlrs = Vec::with_capacity(header.number_of_variable_length_records as usize);
        let _ = try!(reader.seek(SeekFrom::Start(header.header_size as u64)));
        for _ in 0..header.number_of_variable_length_records {
            vlrs.push(try!(Vlr::read_from(&mut reader)));
        }

        let _ = try!(reader.seek(SeekFrom::Start(header.offset_to_point_data as u64)));

        Ok(Reader {
            header: header,
            vlrs: vlrs,
            reader: reader,
            nread: 0,
        })
    }

    /// Returns the next point in this reader.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let mut reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// let point = reader.next_point().unwrap();
    /// assert!(point.is_some());
    /// let point = reader.next_point().unwrap();
    /// assert!(point.is_none());
    /// ```
    pub fn next_point(&mut self) -> Result<Option<Point>> {
        if self.eof() {
            return Ok(None);
        }
        let mut point = Point::new();
        let start = try!(self.reader.seek(SeekFrom::Current(0)));
        point.x = scale(try!(self.reader.read_i32::<LittleEndian>()),
                        self.header.x_scale_factor,
                        self.header.x_offset);
        point.y = scale(try!(self.reader.read_i32::<LittleEndian>()),
                        self.header.y_scale_factor,
                        self.header.y_offset);
        point.z = scale(try!(self.reader.read_i32::<LittleEndian>()),
                        self.header.z_scale_factor,
                        self.header.x_offset);
        point.intensity = try!(self.reader.read_u16::<LittleEndian>());
        let byte = try!(self.reader.read_u8());
        point.return_number = try!(ReturnNumber::from_u8(byte & 0b00000111));
        point.number_of_returns = try!(NumberOfReturns::from_u8((byte >> 3) & 0b00000111));
        point.scan_direction = ScanDirection::from((byte >> 6) & 0b00000001 == 1);
        point.edge_of_flight_line = byte >> 7 == 1;
        let byte = try!(self.reader.read_u8());
        point.classification = try!(Classification::from_u8(byte & 0b00011111));
        point.synthetic = (byte >> 5) & 0b00000001 == 1;
        point.key_point = (byte >> 6) & 0b00000001 == 1;
        point.withheld = byte >> 7 == 1;
        point.scan_angle_rank = try!(self.reader.read_i8());
        point.user_data = try!(self.reader.read_u8());
        point.point_source_id = try!(self.reader.read_u16::<LittleEndian>());
        if self.header.point_data_format.has_time() {
            point.gps_time = Some(try!(self.reader.read_f64::<LittleEndian>()));
        }
        if self.header.point_data_format.has_color() {
            point.red = Some(try!(self.reader.read_u16::<LittleEndian>()));
            point.green = Some(try!(self.reader.read_u16::<LittleEndian>()));
            point.blue = Some(try!(self.reader.read_u16::<LittleEndian>()));
        }
        let bytes_read = try!(self.reader.seek(SeekFrom::Current(0))) - start;

        if bytes_read < self.header.point_data_record_length as u64 {
            let mut buf =
                vec![0; (self.header.point_data_record_length as u64 - bytes_read) as usize];
            try!(read_full(&mut self.reader, &mut buf[..]));
            point.extra_bytes = Some(buf);
        }

        self.nread += 1;

        Ok(Some(point))
    }
}

impl<R: Read> Reader<R> {
    /// Returns this reader's las header.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// let header = reader.header();
    /// ```
    pub fn header(&self) -> Header {
        self.header
    }

    /// Returns a reference to this reader's vlrs.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// let vlrs = reader.vlrs();
    /// ```
    pub fn vlrs(&self) -> &Vec<Vlr> {
        &self.vlrs
    }

    /// Returns the number of points in this lasfile, as specified by the header.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// assert_eq!(1, reader.npoints());
    /// ```
    pub fn npoints(&self) -> u32 {
        self.header.number_of_point_records
    }

    /// Returns true if this reader is at the end of the file.
    ///
    /// # Examples
    ///
    /// ```
    /// use las::reader::Reader;
    /// let mut reader = Reader::from_path("data/1.0_0.las").unwrap();
    /// assert!(!reader.eof());
    /// let _ = reader.next_point().unwrap();
    /// assert!(reader.eof());
    /// ```
    pub fn eof(&self) -> bool {
        self.nread == self.npoints()
    }
}

impl<R: Read + Seek> IntoIterator for Reader<R> {
    type Item = Point;
    type IntoIter = ReaderIterator<R>;
    fn into_iter(self) -> Self::IntoIter {
        ReaderIterator { reader: self }
    }
}

/// An iterator over the reader's points.
///
/// # Panics
///
/// This iterator will panic if something goes wrong while reading the points. If you need to catch
/// those errors, use `Reader::next_point`.
#[derive(Debug)]
pub struct ReaderIterator<R: Read + Seek> {
    reader: Reader<R>,
}

impl<R: Read + Seek> Iterator for ReaderIterator<R> {
    type Item = Point;
    fn next(&mut self) -> Option<Self::Item> {
        self.reader.next_point().unwrap()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reader_as_iter() {
        let reader = Reader::from_path("data/1.0_0.las").unwrap();
        let points: Vec<_> = reader.into_iter().collect();
        assert_eq!(1, points.len());
    }
}
<|endoftext|>


<commit_before>
use std::num::Float;

use sdl2::surface::Surface;

use world::{RayCastResult};
use math::{LineSeg, Vec2, Mat3};
use game::{Game};

const MAP_SCALE: f32 = 2.0;
const FOV_DIV: f32 = 300.0;
const VISPLANE_DIST: f32 = 300.0;
const PERSON_HEIGHT: f32 = 5.0;

struct RenderContext<'a> {
    pub pixels: &'a mut [u8],
    pub width: isize,
    pub height: isize,
}

impl<'a> Game<'a> {
    pub fn render(&self, sky: &mut Surface, pixels: &mut [u8], w :usize, h: usize) {
        let mut ctx = RenderContext {
            pixels: pixels,
            width: w as isize,
            height: h as isize,
        };

        if self.show_map {
            self.render_map(&mut ctx);
        } else {
            self.render_game(sky, &mut ctx);
        }
    }

    fn render_map(&self, ctx: &mut RenderContext) {
        let trans = Mat3::rotation(-self.face_angle)
                  * Mat3::translation(-self.pos * MAP_SCALE)
                  * Mat3::scale(Vec2::new(MAP_SCALE, MAP_SCALE));

        ctx.clear();
        let (player_x, player_y) = (ctx.width / 2, ctx.height / 2);
        ctx.put_px(player_x as usize, player_y as usize, 0xFF, 0x00, 0x00);

        for wall in self.world.get_walls().iter() {
            ctx.draw_seg(wall.seg.transform(trans), 0xFF, 0x00, 0x00);
        }
    }

    fn render_game(&self, sky: &mut Surface, ctx: &mut RenderContext) {
        let person_height = PERSON_HEIGHT + self.world.get_elevation(self.sector); //+ Float::abs(Float::sin(self.t * 3.0)) * 10.0;
        let looking_offset = -self.look_angle as isize;
        let w = ctx.width as usize;
        let h = ctx.height as usize;

        for x in 0..w {
            let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;

            let mut render_bottom = h as isize;
            let mut render_top = 0;

            for RayCastResult {along, hit_pos, in_info, out_info}
            in self.world.cast_ray(self.sector, self.pos, self.face_angle + offset) {
                let dist = (hit_pos - self.pos).get_length();
                let cast_dist = dist * Float::cos(offset);

                let floor_wall_seg_height = match out_info {
                    Some(i) => i.floor_elev - in_info.floor_elev,
                    None    => in_info.ceiling_elev - in_info.floor_elev,
                };
                let floor_wall_seg_height_px = if floor_wall_seg_height > 0.0 {
                    (VISPLANE_DIST * floor_wall_seg_height / cast_dist) as isize
                } else {
                    0
                };

                let ceiling_wall_seg_height = match out_info {
                    Some(i) => in_info.ceiling_elev - i.ceiling_elev,
                    None    => 0.0
                };
                let ceiling_wall_seg_height_px = if ceiling_wall_seg_height > 0.0 {
                    (VISPLANE_DIST * ceiling_wall_seg_height / cast_dist) as isize
                } else {
                    0
                };

                let middle = (h as isize / 2 + looking_offset);

                let floor_wall_bottom = middle + (VISPLANE_DIST * (person_height - in_info.floor_elev) / cast_dist) as isize;
                let floor_wall_top = floor_wall_bottom - floor_wall_seg_height_px;
                let floor_wall_offset_bottom = if floor_wall_bottom > render_bottom { floor_wall_bottom - render_bottom } else { 0 };

                let draw_floor_wall_top = if floor_wall_top < render_top { render_top } else { floor_wall_top };
                let draw_floor_wall_bottom = if floor_wall_bottom > render_bottom { render_bottom } else { floor_wall_bottom };

                ctx.draw_wall(x, draw_floor_wall_top, draw_floor_wall_bottom, floor_wall_offset_bottom, along, cast_dist);

                let ceiling_wall_top = middle + (VISPLANE_DIST * (person_height - in_info.ceiling_elev) / cast_dist) as isize;
                let ceiling_wall_bottom = ceiling_wall_top + ceiling_wall_seg_height_px;

                let draw_ceiling_wall_top = if ceiling_wall_top < render_top { render_top } else { ceiling_wall_top };
                let draw_ceiling_wall_bottom = if ceiling_wall_bottom > render_bottom { render_bottom } else { ceiling_wall_bottom };

                ctx.draw_wall(x, draw_ceiling_wall_top, draw_ceiling_wall_bottom, 0, along, cast_dist);

                ctx.draw_flat(x, draw_floor_wall_bottom, render_bottom, person_height - in_info.floor_elev, self.pos, hit_pos, offset, -looking_offset);
                ctx.draw_flat(x, render_top, draw_ceiling_wall_top, person_height - in_info.ceiling_elev, self.pos, hit_pos, offset, -looking_offset);

                render_top = ceiling_wall_bottom;
                render_bottom = floor_wall_top;
            }

            // SKY
             // if render_bottom > 0 {
             //     for y in 0..render_bottom as usize {
             //         sky.with_lock(|buffer| {
             //             let (r,g,b) = get_px(buffer, x, y, w);
             //             ctx.put_px(x, y, r, g, b);
             //         });
             //     }
             // }
        }

        ctx.draw_seg(LineSeg::new(0.0, -3.0, 0.0, 4.0), 0xff, 0xff, 0xff);
        ctx.draw_seg(LineSeg::new(-3.0, 0.0, 4.0, 0.0), 0xff, 0xff, 0xff);
        ctx.put_px(160, 120, 0x00, 0x00, 0x00);
    }
}

pub fn get_px(tex: &mut [u8], x: usize, y: usize, w: usize) -> (u8,u8,u8) {
    (tex[3*(w*y+x)+0], tex[3*(w*y+x)+1], tex[3*(w*y+x)+2])
}

impl<'a> RenderContext<'a> {
    pub fn put_px(&mut self, x: usize, y: usize, r: u8, g: u8, b: u8) {
        self.pixels[3*(self.width as usize*y+x) + 0] = r;
        self.pixels[3*(self.width as usize*y+x) + 1] = g;
        self.pixels[3*(self.width as usize*y+x) + 2] = b;
    }

    pub fn clear(&mut self) {
        for x in 0..self.width as usize {
            for y in 0..self.height as usize {
                self.put_px(x, y, 0x00, 0x00, 0x00);
            }
        }
    }

    pub fn draw_seg(&mut self, seg: LineSeg, r: u8, g: u8, b: u8) {
        let len = seg.get_length();

        for t in 0..(len as usize) {
            let pt = seg.at(t as f32 / len);
            let ux = (pt.x + (self.width /2) as f32) as usize;
            let uy = (pt.y + (self.height/2) as f32) as usize;

            if ux < self.width as usize && uy < self.height as usize {
                self.put_px(ux, uy, r, g, b);
            }
        }
    }

    pub fn draw_wall(&mut self, x: usize, top: isize, bottom: isize, y_offset: isize, along:f32, cast_dist: f32) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < 0 { 0 } else { top } as usize;
        let cut_bottom = if bottom > self.height { self.height } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let yy = ((bottom + y_offset) as usize - y) as f32 * cast_dist / 5000.0;
            let tex_lookup = (along * 25.0) as u8 ^ (512.0*yy) as u8;
            let color = ((tex_lookup as f32) * brightness_from_dist(cast_dist)) as u8;
            self.put_px(x, y, color / 2, color / 2, color);
        }
    }

    pub fn draw_flat(&mut self, x: usize, top: isize, bottom: isize, elevation: f32, pos: Vec2, hit_pos: Vec2, angle: f32, look: isize) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < 0 { 0 } else { top } as usize;
        let cut_bottom = if bottom > self.height { self.height } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let dist_floor = VISPLANE_DIST * elevation / ((y as isize + look) as f32 - self.height as f32 / 2.0);
            let floor_pos = pos + (hit_pos - pos).normalize() * dist_floor / Float::cos(angle);
            let tex_lookup = (floor_pos.x * 10.0) as u8 ^ (floor_pos.y * 10.0) as u8;
            let color = (tex_lookup as f32 * brightness_from_dist(dist_floor)) as u8;
            self.put_px(x, y, 0x00, color, 0x00);
        }
    }
}

fn brightness_from_dist(dist: f32) -> f32 {
    (20.0 / dist).min(1.0).max(0.0)
}

<commit_msg>No longer computing cosine zillions of excess times<commit_after>
use std::num::Float;

use sdl2::surface::Surface;

use world::{RayCastResult};
use math::{LineSeg, Vec2, Mat3};
use game::{Game};

const MAP_SCALE: f32 = 2.0;
const FOV_DIV: f32 = 300.0;
const VISPLANE_DIST: f32 = 300.0;
const PERSON_HEIGHT: f32 = 5.0;

struct RenderContext<'a> {
    pub pixels: &'a mut [u8],
    pub width: isize,
    pub height: isize,
}

impl<'a> Game<'a> {
    pub fn render(&self, sky: &mut Surface, pixels: &mut [u8], w :usize, h: usize) {
        let mut ctx = RenderContext {
            pixels: pixels,
            width: w as isize,
            height: h as isize,
        };

        if self.show_map {
            self.render_map(&mut ctx);
        } else {
            self.render_game(sky, &mut ctx);
        }
    }

    fn render_map(&self, ctx: &mut RenderContext) {
        let trans = Mat3::rotation(-self.face_angle)
                  * Mat3::translation(-self.pos * MAP_SCALE)
                  * Mat3::scale(Vec2::new(MAP_SCALE, MAP_SCALE));

        ctx.clear();
        let (player_x, player_y) = (ctx.width / 2, ctx.height / 2);
        ctx.put_px(player_x as usize, player_y as usize, 0xFF, 0x00, 0x00);

        for wall in self.world.get_walls().iter() {
            ctx.draw_seg(wall.seg.transform(trans), 0xFF, 0x00, 0x00);
        }
    }

    fn render_game(&self, sky: &mut Surface, ctx: &mut RenderContext) {
        let person_height = PERSON_HEIGHT + self.world.get_elevation(self.sector); //+ Float::abs(Float::sin(self.t * 3.0)) * 10.0;
        let looking_offset = -self.look_angle as isize;
        let w = ctx.width as usize;
        let h = ctx.height as usize;

        for x in 0..w {
            let offset = ((x as f32) - (w as f32) / 2.0) / FOV_DIV;
            let cos_offset = Float::cos(offset);

            let mut render_bottom = h as isize;
            let mut render_top = 0;

            for RayCastResult {along, hit_pos, in_info, out_info}
            in self.world.cast_ray(self.sector, self.pos, self.face_angle + offset) {
                let dist = (hit_pos - self.pos).get_length();
                let cast_dist = dist * cos_offset;

                let floor_wall_seg_height = match out_info {
                    Some(i) => i.floor_elev - in_info.floor_elev,
                    None    => in_info.ceiling_elev - in_info.floor_elev,
                };
                let floor_wall_seg_height_px = if floor_wall_seg_height > 0.0 {
                    (VISPLANE_DIST * floor_wall_seg_height / cast_dist) as isize
                } else {
                    0
                };

                let ceiling_wall_seg_height = match out_info {
                    Some(i) => in_info.ceiling_elev - i.ceiling_elev,
                    None    => 0.0
                };
                let ceiling_wall_seg_height_px = if ceiling_wall_seg_height > 0.0 {
                    (VISPLANE_DIST * ceiling_wall_seg_height / cast_dist) as isize
                } else {
                    0
                };

                let middle = (h as isize / 2 + looking_offset);

                let floor_wall_bottom = middle + (VISPLANE_DIST * (person_height - in_info.floor_elev) / cast_dist) as isize;
                let floor_wall_top = floor_wall_bottom - floor_wall_seg_height_px;
                let floor_wall_offset_bottom = if floor_wall_bottom > render_bottom { floor_wall_bottom - render_bottom } else { 0 };

                let draw_floor_wall_top = if floor_wall_top < render_top { render_top } else { floor_wall_top };
                let draw_floor_wall_bottom = if floor_wall_bottom > render_bottom { render_bottom } else { floor_wall_bottom };

                ctx.draw_wall(x, draw_floor_wall_top, draw_floor_wall_bottom, floor_wall_offset_bottom, along, cast_dist);

                let ceiling_wall_top = middle + (VISPLANE_DIST * (person_height - in_info.ceiling_elev) / cast_dist) as isize;
                let ceiling_wall_bottom = ceiling_wall_top + ceiling_wall_seg_height_px;

                let draw_ceiling_wall_top = if ceiling_wall_top < render_top { render_top } else { ceiling_wall_top };
                let draw_ceiling_wall_bottom = if ceiling_wall_bottom > render_bottom { render_bottom } else { ceiling_wall_bottom };

                ctx.draw_wall(x, draw_ceiling_wall_top, draw_ceiling_wall_bottom, 0, along, cast_dist);

                ctx.draw_flat(x, draw_floor_wall_bottom, render_bottom, person_height - in_info.floor_elev, self.pos, hit_pos, cos_offset, -looking_offset);
                ctx.draw_flat(x, render_top, draw_ceiling_wall_top, person_height - in_info.ceiling_elev, self.pos, hit_pos, cos_offset, -looking_offset);

                render_top = ceiling_wall_bottom;
                render_bottom = floor_wall_top;
            }

            // SKY
             // if render_bottom > 0 {
             //     for y in 0..render_bottom as usize {
             //         sky.with_lock(|buffer| {
             //             let (r,g,b) = get_px(buffer, x, y, w);
             //             ctx.put_px(x, y, r, g, b);
             //         });
             //     }
             // }
        }

        ctx.draw_seg(LineSeg::new(0.0, -3.0, 0.0, 4.0), 0xff, 0xff, 0xff);
        ctx.draw_seg(LineSeg::new(-3.0, 0.0, 4.0, 0.0), 0xff, 0xff, 0xff);
        ctx.put_px(160, 120, 0x00, 0x00, 0x00);
    }
}

pub fn get_px(tex: &mut [u8], x: usize, y: usize, w: usize) -> (u8,u8,u8) {
    (tex[3*(w*y+x)+0], tex[3*(w*y+x)+1], tex[3*(w*y+x)+2])
}

impl<'a> RenderContext<'a> {
    pub fn put_px(&mut self, x: usize, y: usize, r: u8, g: u8, b: u8) {
        self.pixels[3*(self.width as usize*y+x) + 0] = r;
        self.pixels[3*(self.width as usize*y+x) + 1] = g;
        self.pixels[3*(self.width as usize*y+x) + 2] = b;
    }

    pub fn clear(&mut self) {
        for x in 0..self.width as usize {
            for y in 0..self.height as usize {
                self.put_px(x, y, 0x00, 0x00, 0x00);
            }
        }
    }

    pub fn draw_seg(&mut self, seg: LineSeg, r: u8, g: u8, b: u8) {
        let len = seg.get_length();

        for t in 0..(len as usize) {
            let pt = seg.at(t as f32 / len);
            let ux = (pt.x + (self.width /2) as f32) as usize;
            let uy = (pt.y + (self.height/2) as f32) as usize;

            if ux < self.width as usize && uy < self.height as usize {
                self.put_px(ux, uy, r, g, b);
            }
        }
    }

    pub fn draw_wall(&mut self, x: usize, top: isize, bottom: isize, y_offset: isize, along:f32, cast_dist: f32) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < 0 { 0 } else { top } as usize;
        let cut_bottom = if bottom > self.height { self.height } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let yy = ((bottom + y_offset) as usize - y) as f32 * cast_dist / 5000.0;
            let tex_lookup = (along * 25.0) as u8 ^ (512.0*yy) as u8;
            let color = ((tex_lookup as f32) * brightness_from_dist(cast_dist)) as u8;
            self.put_px(x, y, color / 2, color / 2, color);
        }
    }

    pub fn draw_flat(&mut self, x: usize, top: isize, bottom: isize, elevation: f32, pos: Vec2, hit_pos: Vec2, cos_angle: f32, look: isize) {
        if bottom < 0 || top >= self.height { return; }

        let cut_top = if top < 0 { 0 } else { top } as usize;
        let cut_bottom = if bottom > self.height { self.height } else { bottom } as usize;

        for y in cut_top..cut_bottom {
            let dist_floor = VISPLANE_DIST * elevation / ((y as isize + look) as f32 - self.height as f32 / 2.0);
            let floor_pos = pos + (hit_pos - pos).normalize() * dist_floor / cos_angle;
            let tex_lookup = (floor_pos.x * 10.0) as u8 ^ (floor_pos.y * 10.0) as u8;
            let color = (tex_lookup as f32 * brightness_from_dist(dist_floor)) as u8;
            self.put_px(x, y, 0x00, color, 0x00);
        }
    }
}

fn brightness_from_dist(dist: f32) -> f32 {
    (20.0 / dist).min(1.0).max(0.0)
}

<|endoftext|>


<commit_before>use std;

fn unknown() -> str {
    ret "<unknown ast node>";
}

fn print_expr(@ast.expr expr) -> str {
    alt (expr.node) {
        case (ast.expr_lit(?lit, _)) {
            ret print_expr_lit(lit);
        }
        case (ast.expr_binary(?op, ?lhs, ?rhs, _)) {
            ret print_expr_binary(op, lhs, rhs);
        }
        case (_) {
            ret unknown();
        }
    }
}

fn print_expr_lit(@ast.lit lit) -> str {
    alt (lit.node) {
        case (ast.lit_str(?s)) {
            ret "\"" + s + "\"";
        }
        case (_) {
            ret unknown();
        }
    }
}

fn print_expr_binary(ast.binop op, @ast.expr lhs, @ast.expr rhs) -> str {
    alt (op) {
        case (ast.add) {
            auto l = print_expr(lhs);
            auto r = print_expr(rhs);
            ret l + " + " + r;
        }
    }
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Add pretty printing for expr_call, expr_path, and more literals<commit_after>import std._int;
import std._str;
import std._uint;
import std._vec;

export print_expr;

fn unknown() -> str {
    ret "<unknown ast node>";
}

fn print_expr(@ast.expr expr) -> str {
    alt (expr.node) {
        case (ast.expr_lit(?lit, _)) {
            ret print_lit(lit);
        }
        case (ast.expr_binary(?op, ?lhs, ?rhs, _)) {
            ret print_expr_binary(op, lhs, rhs);
        }
        case (ast.expr_call(?path, ?args, _)) {
            ret print_expr_call(path, args);
        }
        case (ast.expr_path(?path, _, _)) {
            ret print_path(path);
        }
        case (_) {
            ret unknown();
        }
    }
}

fn print_lit(@ast.lit lit) -> str {
    alt (lit.node) {
        case (ast.lit_str(?s)) {
            ret "\"" + s + "\"";
        }
        case (ast.lit_int(?i)) {
            ret _int.to_str(i, 10u);
        }
        case (ast.lit_uint(?u)) {
            ret _uint.to_str(u, 10u);
        }
        case (_) {
            ret unknown();
        }
    }
}

fn print_expr_binary(ast.binop op, @ast.expr lhs, @ast.expr rhs) -> str {
    alt (op) {
        case (ast.add) {
            auto l = print_expr(lhs);
            auto r = print_expr(rhs);
            ret l + " + " + r;
        }
    }
}

fn print_expr_call(@ast.expr path_expr, vec[@ast.expr] args) -> str {
    auto s = print_expr(path_expr);

    s += "(";
    fn print_expr_ref(&@ast.expr e) -> str { ret print_expr(e); }
    auto mapfn = print_expr_ref;
    auto argstrs = _vec.map[@ast.expr, str](mapfn, args);
    s += _str.connect(argstrs, ", ");
    s += ")";

    ret s;
}

fn print_path(ast.path path) -> str {
    ret _str.connect(path.node.idents, ".");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::RangeBinding;
use dom::bindings::codegen::Bindings::RangeBinding::RangeMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};

#[deriving(Encodable)]
pub struct Range {
    pub reflector_: Reflector
}

impl Range {
    pub fn new_inherited() -> Range {
        Range {
            reflector_: Reflector::new()
        }
    }

    pub fn new(global: &GlobalRef) -> Temporary<Range> {
        reflect_dom_object(box Range::new_inherited(), global, RangeBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef) -> Fallible<Temporary<Range>> {
        Ok(Range::new(global))
    }
}

impl<'a> RangeMethods for JSRef<'a, Range> {
}

impl Reflectable for Range {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }
}
<commit_msg>Make Range::reflector private.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::RangeBinding;
use dom::bindings::codegen::Bindings::RangeBinding::RangeMethods;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};

#[deriving(Encodable)]
pub struct Range {
    reflector_: Reflector
}

impl Range {
    pub fn new_inherited() -> Range {
        Range {
            reflector_: Reflector::new()
        }
    }

    pub fn new(global: &GlobalRef) -> Temporary<Range> {
        reflect_dom_object(box Range::new_inherited(), global, RangeBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef) -> Fallible<Temporary<Range>> {
        Ok(Range::new(global))
    }
}

impl<'a> RangeMethods for JSRef<'a, Range> {
}

impl Reflectable for Range {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate encoding;

use std::borrow::Cow;
use std::default::Default;
use std::error;
use std::fmt;
use std::io;

use self::byteorder::{ByteOrder, BigEndian, LittleEndian};
use self::encoding::label::encoding_from_whatwg_label;
use self::encoding::types::EncodingRef;
use self::encoding::types::DecoderTrap::Strict;

use super::{Catalog, Message};
use super::plurals::Resolver;
use metadata::parse_metadata;

#[allow(non_upper_case_globals)]
static utf8_encoding: EncodingRef = &encoding::codec::utf_8::UTF8Encoding;

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
    /// Incorrect syntax encountered while parsing the meta information
    MalformedMetadata,
    /// Meta information string was not the first string in the catalog
    MisplacedMetadata,
    /// An unknown encoding was specified in the metadata
    UnknownEncoding,
}
// Can not use use `Error::*` as per this issue:
// (https://github.com/rust-lang/rust/issues/4865)
use Error::{BadMagic, DecodingError, Eof, Io, MalformedMetadata, MisplacedMetadata,
            UnknownEncoding};

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
            MalformedMetadata => "metadata syntax error",
            MisplacedMetadata => "misplaced metadata",
            UnknownEncoding => "unknown encoding specified",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(_: Cow<'static, str>) -> Error {
        DecodingError
    }
}

/// ParseOptions allows setting options for parsing MO catalogs.
///
/// # Examples
/// ```ignore
/// use std::fs::File;
///
/// extern crate encoding;
/// use encoding::all::ISO_8859_1;
///
/// let file = File::open("french.mo").unwrap();
/// let catalog = ParseOptions::new().force_encoding(ISO_8859_1).parse(file).unwrap();
/// ```
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
    force_plural: Option<Box<Fn(u64) -> usize + 'static>>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        Default::default()
    }

    /// Tries to parse the catalog from the given reader using the specified options.
    pub fn parse<R: io::Read>(self, reader: R) -> Result<Catalog, Error> {
        parse_catalog(reader, self)
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(mut self, encoding: EncodingRef) -> Self {
        self.force_encoding = Some(encoding);
        self
    }

    /// Forces a use of the given plural formula
    /// for deciding the proper plural form for a message.
    /// If this option is not enabled,
    /// the parser tries to use the plural formula
    /// specified in the catalog,
    /// falling back on `n != 1`
    /// in case it fails to find or parse one.
    pub fn force_plural<T: Fn(u64) -> usize + 'static>(mut self, plural: T) -> Self {
        self.force_plural = Some(Box::new(plural));
        self
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

pub fn parse_catalog<R: io::Read>(mut file: R, opts: ParseOptions) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    let resolver = match opts.force_plural {
        Some(func) => Some(Resolver::Function(func)),
        None => None,
    };
    let mut encoding = opts.force_encoding.unwrap_or(utf8_encoding);

    for i in 0..num_strings {
        let id;
        let context;
        let translated: Vec<String>;
        // Parse the original string
        {
            if n < off_otable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
            let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            let mut original = &contents[off..off + len + 1];
            // check for context
            context = match original.iter().position(|x| *x == 4) {
                Some(idx) => {
                    let ctx = &original[..idx];
                    original = &original[idx + 1..];
                    Some(try!(encoding.decode(ctx, Strict)))
                }
                None => None,
            };
            // extract msg_id singular, ignoring the plural
            id = match original.iter().position(|x| *x == 0).map(|i| &original[..i]) {
                Some(b) => try!(encoding.decode(b, Strict)),
                None => return Err(Eof),
            };
            if id == "" && i != 0 {
                return Err(MisplacedMetadata);
            }
        }

        // Parse the translation strings
        {
            if n < off_ttable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
            let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            translated = try!((&contents[off..off + len])
                                  .split(|x| *x == 0)
                                  .map(|b| encoding.decode(b, Strict))
                                  .collect::<Result<Vec<_>, _>>());
            if id == "" {
                let map = parse_metadata(&*translated[0]).unwrap();
                if let (Some(c), None) = (map.charset(), opts.force_encoding) {
                    encoding = match encoding_from_whatwg_label(c) {
                        Some(enc_ref) => enc_ref,
                        None => return Err(UnknownEncoding),
                    }
                }
            }
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    if let Some(r) = resolver {
        catalog.resolver = r;
    }

    Ok(catalog)
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(catalog.strings["this is context\x04Text"],
                   Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(catalog.strings["Image"],
                   Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader, ParseOptions::new()).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<commit_msg>Plural formula parsing not implemented yet<commit_after>extern crate byteorder;
extern crate encoding;

use std::borrow::Cow;
use std::default::Default;
use std::error;
use std::fmt;
use std::io;

use self::byteorder::{ByteOrder, BigEndian, LittleEndian};
use self::encoding::label::encoding_from_whatwg_label;
use self::encoding::types::EncodingRef;
use self::encoding::types::DecoderTrap::Strict;

use super::{Catalog, Message};
use super::plurals::Resolver;
use metadata::parse_metadata;

#[allow(non_upper_case_globals)]
static utf8_encoding: EncodingRef = &encoding::codec::utf_8::UTF8Encoding;

/// Represents an error encountered while parsing an MO file.
#[derive(Debug)]
pub enum Error {
    /// An incorrect magic number has been encountered
    BadMagic,
    /// An invalid byte sequence for the given encoding has been encountered
    DecodingError,
    /// An unexpected EOF occured
    Eof,
    /// An I/O error occured
    Io(io::Error),
    /// Incorrect syntax encountered while parsing the meta information
    MalformedMetadata,
    /// Meta information string was not the first string in the catalog
    MisplacedMetadata,
    /// An unknown encoding was specified in the metadata
    UnknownEncoding,
}
// Can not use use `Error::*` as per this issue:
// (https://github.com/rust-lang/rust/issues/4865)
use Error::{BadMagic, DecodingError, Eof, Io, MalformedMetadata, MisplacedMetadata,
            UnknownEncoding};

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            BadMagic => "bad magic number",
            DecodingError => "invalid byte sequence in a string",
            Eof => "unxpected end of file",
            Io(ref err) => err.description(),
            MalformedMetadata => "metadata syntax error",
            MisplacedMetadata => "misplaced metadata",
            UnknownEncoding => "unknown encoding specified",
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        let self_err: &error::Error = self;
        write!(fmt, "{}", self_err.description())
    }
}

impl From<io::Error> for Error {
    fn from(inner: io::Error) -> Error {
        Io(inner)
    }
}

impl From<Cow<'static, str>> for Error {
    fn from(_: Cow<'static, str>) -> Error {
        DecodingError
    }
}

/// ParseOptions allows setting options for parsing MO catalogs.
///
/// # Examples
/// ```ignore
/// use std::fs::File;
///
/// extern crate encoding;
/// use encoding::all::ISO_8859_1;
///
/// let file = File::open("french.mo").unwrap();
/// let catalog = ParseOptions::new().force_encoding(ISO_8859_1).parse(file).unwrap();
/// ```
#[allow(missing_debug_implementations)]
#[derive(Default)]
pub struct ParseOptions {
    force_encoding: Option<EncodingRef>,
    force_plural: Option<Box<Fn(u64) -> usize + 'static>>,
}

impl ParseOptions {
    /// Returns a new instance of ParseOptions with default options.
    pub fn new() -> Self {
        Default::default()
    }

    /// Tries to parse the catalog from the given reader using the specified options.
    pub fn parse<R: io::Read>(self, reader: R) -> Result<Catalog, Error> {
        parse_catalog(reader, self)
    }

    /// Forces a use of a specific encoding
    /// when parsing strings from a catalog.
    /// If this option is not enabled,
    /// the parser tries to use the encoding specified in the metadata
    /// or UTF-8 if metadata is non-existent.
    pub fn force_encoding(mut self, encoding: EncodingRef) -> Self {
        self.force_encoding = Some(encoding);
        self
    }

    /// Forces a use of the given plural formula
    /// for deciding the proper plural form for a message.
    /// If this option is not enabled,
    /// the parser uses the default formula
    /// (`n != 1`).
    pub fn force_plural<T: Fn(u64) -> usize + 'static>(mut self, plural: T) -> Self {
        self.force_plural = Some(Box::new(plural));
        self
    }
}

/// According to the given magic number of a MO file,
/// returns the function which reads a `u32` in the relevant endianness.
fn get_read_u32_fn(magic: &[u8]) -> Option<fn(&[u8]) -> u32> {
    if magic == [0xde, 0x12, 0x04, 0x95] {
        Some(LittleEndian::read_u32)
    } else if magic == [0x95, 0x04, 0x12, 0xde] {
        Some(BigEndian::read_u32)
    } else {
        None
    }
}

pub fn parse_catalog<R: io::Read>(mut file: R, opts: ParseOptions) -> Result<Catalog, Error> {
    let mut contents = vec![];
    let n = try!(file.read_to_end(&mut contents));
    if n < 28 {
        return Err(Eof);
    }

    let read_u32 = match get_read_u32_fn(&contents[0..4]) {
        Some(f) => f,
        None => return Err(BadMagic),
    };

    // ignore hashing tables (bytes at 20..28)
    let num_strings = read_u32(&contents[8..12]) as usize;
    let mut off_otable = read_u32(&contents[12..16]) as usize;
    let mut off_ttable = read_u32(&contents[16..20]) as usize;
    if n < off_otable || n < off_ttable {
        return Err(Eof);
    }

    let mut catalog = Catalog::new();
    let resolver = match opts.force_plural {
        Some(func) => Some(Resolver::Function(func)),
        None => None,
    };
    let mut encoding = opts.force_encoding.unwrap_or(utf8_encoding);

    for i in 0..num_strings {
        let id;
        let context;
        let translated: Vec<String>;
        // Parse the original string
        {
            if n < off_otable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_otable..off_otable + 4]) as usize;
            let off = read_u32(&contents[off_otable + 4..off_otable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            let mut original = &contents[off..off + len + 1];
            // check for context
            context = match original.iter().position(|x| *x == 4) {
                Some(idx) => {
                    let ctx = &original[..idx];
                    original = &original[idx + 1..];
                    Some(try!(encoding.decode(ctx, Strict)))
                }
                None => None,
            };
            // extract msg_id singular, ignoring the plural
            id = match original.iter().position(|x| *x == 0).map(|i| &original[..i]) {
                Some(b) => try!(encoding.decode(b, Strict)),
                None => return Err(Eof),
            };
            if id == "" && i != 0 {
                return Err(MisplacedMetadata);
            }
        }

        // Parse the translation strings
        {
            if n < off_ttable + 8 {
                return Err(Eof);
            }
            let len = read_u32(&contents[off_ttable..off_ttable + 4]) as usize;
            let off = read_u32(&contents[off_ttable + 4..off_ttable + 8]) as usize;
            // +1 compensates for the ending NUL byte which is not included in length
            if n < off + len + 1 {
                return Err(Eof);
            }
            translated = try!((&contents[off..off + len])
                                  .split(|x| *x == 0)
                                  .map(|b| encoding.decode(b, Strict))
                                  .collect::<Result<Vec<_>, _>>());
            if id == "" {
                let map = parse_metadata(&*translated[0]).unwrap();
                if let (Some(c), None) = (map.charset(), opts.force_encoding) {
                    encoding = match encoding_from_whatwg_label(c) {
                        Some(enc_ref) => enc_ref,
                        None => return Err(UnknownEncoding),
                    }
                }
            }
        }

        catalog.insert(Message::new(id, context, translated));

        off_otable += 8;
        off_ttable += 8;
    }

    if let Some(r) = resolver {
        catalog.resolver = r;
    }

    Ok(catalog)
}

#[test]
fn test_get_read_u32_fn() {
    use std::mem;

    assert!(get_read_u32_fn(&[]).is_none());
    assert!(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95, 0x00]).is_none());

    {
        let le_ptr: *const ();
        let ret_ptr;
        unsafe {
            le_ptr = mem::transmute(LittleEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0xde, 0x12, 0x04, 0x95]).unwrap());
        }
        assert_eq!(le_ptr, ret_ptr);
    }

    {
        let be_ptr: *const ();
        let ret_ptr;
        unsafe {
            be_ptr = mem::transmute(BigEndian::read_u32 as usize);
            ret_ptr = mem::transmute(get_read_u32_fn(&[0x95, 0x04, 0x12, 0xde]).unwrap());
        }
        assert_eq!(be_ptr, ret_ptr);
    }
}

#[test]
fn test_parse_catalog() {
    macro_rules! assert_variant {
        ($value:expr, $variant:path) => {
            match $value {
                $variant => (),
                _ => panic!("Expected {:?}, got {:?}", $variant, $value),
            }
        };
    }

    let fluff = [0; 24]; // zeros to pad our magic test cases to satisfy the length requirements

    {
        let mut reader = vec![1u8, 2, 3];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, Eof);
    }

    {
        let mut reader = vec![1u8, 2, 3, 4];
        reader.extend(fluff.iter().cloned());
        let err = parse_catalog(&reader[..], ParseOptions::new()).unwrap_err();
        assert_variant!(err, BadMagic);
    }

    {
        let mut reader = vec![0x95, 0x04, 0x12, 0xde];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let mut reader = vec![0xde, 0x12, 0x04, 0x95];
        reader.extend(fluff.iter().cloned());
        assert!(parse_catalog(&reader[..], ParseOptions::new()).is_ok());
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/1.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 1);
        assert_eq!(catalog.strings["this is context\x04Text"],
                   Message::new("Text", Some("this is context"), vec!["Tekstas", "Tekstai"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/2.mo");
        let catalog = parse_catalog(reader, ParseOptions::new()).unwrap();
        assert_eq!(catalog.strings.len(), 2);
        assert_eq!(catalog.strings["Image"],
                   Message::new("Image", None, vec!["Nuotrauka", "Nuotraukos"]));
    }

    {
        let reader: &[u8] = include_bytes!("../test_cases/invalid_utf8.mo");
        let err = parse_catalog(reader, ParseOptions::new()).unwrap_err();
        assert_variant!(err, DecodingError);
    }
}
<|endoftext|>