<commit_before>// Copyright 2012-2014 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 Rust Standard Library
//!
//! The Rust Standard Library provides the essential runtime
//! functionality for building portable Rust software.
//! It is linked to all Rust crates by default.
//!
//! ## Intrinsic types and operations
//!
//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html)
//! modules deal with unsafe pointers and memory manipulation.
//! [`kinds`](kinds/index.html) defines the special built-in traits,
//! and [`raw`](raw/index.html) the runtime representation of Rust types.
//! These are some of the lowest-level building blocks in Rust.
//!
//! ## Math on primitive types and math traits
//!
//! Although basic operations on primitive types are implemented
//! directly by the compiler, the standard library additionally
//! defines many common operations through traits defined in
//! mod [`num`](num/index.html).
//!
//! ## Pervasive types
//!
//! The [`option`](option/index.html) and [`result`](result/index.html)
//! modules define optional and error-handling types, `Option` and `Result`.
//! [`iter`](iter/index.html) defines Rust's iterator protocol
//! along with a wide variety of iterators.
//! [`Cell` and `RefCell`](cell/index.html) are for creating types that
//! manage their own mutability.
//!
//! ## Vectors, slices and strings
//!
//! The common container type, `Vec`, a growable vector backed by an
//! array, lives in the [`vec`](vec/index.html) module. References to
//! arrays, `&[T]`, more commonly called "slices", are built-in types
//! for which the [`slice`](slice/index.html) module defines many
//! methods.
//!
//! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! defines methods for it on a variety of traits in the
//! [`str`](str/index.html) module. Rust strings are immutable;
//! use the `String` type defined in [`string`](string/index.html)
//! for a mutable string builder.
//!
//! For converting to strings use the [`format!`](fmt/index.html)
//! macro, and for converting from strings use the
//! [`FromStr`](from_str/index.html) trait.
//!
//! ## Platform abstractions
//!
//! Besides basic data types, the standard library is largely concerned
//! with abstracting over differences in common platforms, most notably
//! Windows and Unix derivatives. The [`os`](os/index.html) module
//! provides a number of basic functions for interacting with the
//! operating environment, including program arguments, environment
//! variables, and directory navigation. The [`path`](path/index.html)
//! module encapsulates the platform-specific rules for dealing
//! with file paths.
//!
//! `std` also includes modules for interoperating with the
//! C language: [`c_str`](c_str/index.html) and
//! [`c_vec`](c_vec/index.html).
//!
//! ## Concurrency, I/O, and the runtime
//!
//! The [`task`](task/index.html) module contains Rust's threading abstractions,
//! while [`comm`](comm/index.html) contains the channel types for message
//! passing. [`sync`](sync/index.html) contains further, primitive, shared
//! memory types, including [`atomics`](sync/atomics/index.html).
//!
//! Common types of I/O, including files, TCP, UPD, pipes, Unix domain sockets,
//! timers, and process spawning, are defined in the [`io`](io/index.html) module.
//!
//! Rust's I/O and concurrency depends on a small runtime interface
//! that lives, along with its support code, in mod [`rt`](rt/index.html).
//! While a notable part of the standard library's architecture, this
//! module is not intended for public use.
//!
//! ## The Rust prelude and macros
//!
//! Finally, the [`prelude`](prelude/index.html) defines a
//! common set of traits, types, and functions that are made available
//! to all code by default. [`macros`](macros/index.html) contains
//! all the standard macros, such as `assert!`, `fail!`, `println!`,
//! and `format!`, also available to all Rust code.

#![crate_name = "std"]
#![unstable]
#![comment = "The Rust standard library"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/0.11.0/",
       html_playground_url = "http://play.rust-lang.org/")]

#![feature(macro_rules, globs, managed_boxes, linkage)]
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]

// Don't link to std. We are std.
#![no_std]

#![allow(deprecated)]
#![deny(missing_doc)]

// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::io tests have an I/O interface to run on top
// of
#[cfg(test)] extern crate rustuv;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate green;
#[cfg(test)] extern crate debug;
#[cfg(test)] #[phase(plugin, link)] extern crate log;

extern crate alloc;
extern crate unicode;
extern crate core;
extern crate core_collections = "collections";
extern crate core_rand = "rand";
extern crate core_sync = "sync";
extern crate libc;
extern crate rustrt;

// Make std testable by not duplicating lang items. See #2912
#[cfg(test)] extern crate realstd = "std";
#[cfg(test)] pub use realstd::kinds;
#[cfg(test)] pub use realstd::ops;
#[cfg(test)] pub use realstd::cmp;
#[cfg(test)] pub use realstd::ty;
#[cfg(test)] pub use realstd::owned;
#[cfg(test)] pub use realstd::gc;

// NB: These reexports are in the order they should be listed in rustdoc

pub use core::any;
pub use core::bool;
pub use core::cell;
pub use core::clone;
#[cfg(not(test))] pub use core::cmp;
pub use core::default;
pub use core::finally;
pub use core::intrinsics;
pub use core::iter;
#[cfg(not(test))] pub use core::kinds;
pub use core::mem;
#[cfg(not(test))] pub use core::ops;
pub use core::ptr;
pub use core::raw;
pub use core::simd;
pub use core::tuple;
// FIXME #15320: primitive documentation needs top-level modules, this
// should be `std::tuple::unit`.
pub use core::unit;
#[cfg(not(test))] pub use core::ty;
pub use core::result;
pub use core::option;

pub use alloc::owned;
pub use alloc::rc;

pub use core_collections::slice;
pub use core_collections::str;
pub use core_collections::string;
pub use core_collections::vec;

pub use rustrt::c_str;
pub use rustrt::local_data;

pub use unicode::char;

pub use core_sync::comm;

// Run tests with libgreen instead of libnative.
//
// FIXME: This egregiously hacks around starting the test runner in a different
//        threading mode than the default by reaching into the auto-generated
//        '__test' module.
#[cfg(test)] #[start]
fn start(argc: int, argv: *const *const u8) -> int {
    green::start(argc, argv, rustuv::event_loop, __test::main)
}

/* Exported macros */

pub mod macros;
pub mod bitflags;

mod rtdeps;

/* The Prelude. */

pub mod prelude;

/* Primitive types */

#[path = "num/float_macros.rs"] mod float_macros;
#[path = "num/int_macros.rs"]   mod int_macros;
#[path = "num/uint_macros.rs"]  mod uint_macros;

#[path = "num/int.rs"]  pub mod int;
#[path = "num/i8.rs"]   pub mod i8;
#[path = "num/i16.rs"]  pub mod i16;
#[path = "num/i32.rs"]  pub mod i32;
#[path = "num/i64.rs"]  pub mod i64;

#[path = "num/uint.rs"] pub mod uint;
#[path = "num/u8.rs"]   pub mod u8;
#[path = "num/u16.rs"]  pub mod u16;
#[path = "num/u32.rs"]  pub mod u32;
#[path = "num/u64.rs"]  pub mod u64;

#[path = "num/f32.rs"]   pub mod f32;
#[path = "num/f64.rs"]   pub mod f64;

pub mod rand;

pub mod ascii;

#[cfg(not(test))]
pub mod gc;

/* Common traits */

pub mod from_str;
pub mod num;
pub mod to_str;

/* Common data structures */

pub mod collections;
pub mod hash;

/* Tasks and communication */

pub mod task;
pub mod sync;

/* Runtime and platform support */

pub mod c_vec;
pub mod dynamic_lib;
pub mod os;
pub mod io;
pub mod path;
pub mod fmt;

// FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
// but name resolution doesn't work without it being pub.
#[unstable]
pub mod rt;
mod failure;

// A curious inner-module that's not exported that contains the binding
// 'std' so that macro-expanded references to std::error and such
// can be resolved within libstd.
#[doc(hidden)]
mod std {
    // mods used for deriving
    pub use clone;
    pub use cmp;
    pub use hash;

    pub use comm; // used for select!()
    pub use fmt; // used for any formatting strings
    pub use io; // used for println!()
    pub use local_data; // used for local_data_key!()
    pub use option; // used for bitflags!()
    pub use rt; // used for fail!()
    pub use vec; // used for vec![]

    // The test runner calls ::std::os::args() but really wants realstd
    #[cfg(test)] pub use os = realstd::os;
    // The test runner requires std::slice::Vector, so re-export std::slice just for it.
    #[cfg(test)] pub use slice;
}

#[deprecated]
#[allow(missing_doc)]
#[doc(hiden)]
pub mod unstable {
    #[deprecated = "use std::dynamic_lib"]
    pub use dynamic_lib;
}
<commit_msg>Remove deprecated std::unstable module.<commit_after>// Copyright 2012-2014 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 Rust Standard Library
//!
//! The Rust Standard Library provides the essential runtime
//! functionality for building portable Rust software.
//! It is linked to all Rust crates by default.
//!
//! ## Intrinsic types and operations
//!
//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html)
//! modules deal with unsafe pointers and memory manipulation.
//! [`kinds`](kinds/index.html) defines the special built-in traits,
//! and [`raw`](raw/index.html) the runtime representation of Rust types.
//! These are some of the lowest-level building blocks in Rust.
//!
//! ## Math on primitive types and math traits
//!
//! Although basic operations on primitive types are implemented
//! directly by the compiler, the standard library additionally
//! defines many common operations through traits defined in
//! mod [`num`](num/index.html).
//!
//! ## Pervasive types
//!
//! The [`option`](option/index.html) and [`result`](result/index.html)
//! modules define optional and error-handling types, `Option` and `Result`.
//! [`iter`](iter/index.html) defines Rust's iterator protocol
//! along with a wide variety of iterators.
//! [`Cell` and `RefCell`](cell/index.html) are for creating types that
//! manage their own mutability.
//!
//! ## Vectors, slices and strings
//!
//! The common container type, `Vec`, a growable vector backed by an
//! array, lives in the [`vec`](vec/index.html) module. References to
//! arrays, `&[T]`, more commonly called "slices", are built-in types
//! for which the [`slice`](slice/index.html) module defines many
//! methods.
//!
//! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! defines methods for it on a variety of traits in the
//! [`str`](str/index.html) module. Rust strings are immutable;
//! use the `String` type defined in [`string`](string/index.html)
//! for a mutable string builder.
//!
//! For converting to strings use the [`format!`](fmt/index.html)
//! macro, and for converting from strings use the
//! [`FromStr`](from_str/index.html) trait.
//!
//! ## Platform abstractions
//!
//! Besides basic data types, the standard library is largely concerned
//! with abstracting over differences in common platforms, most notably
//! Windows and Unix derivatives. The [`os`](os/index.html) module
//! provides a number of basic functions for interacting with the
//! operating environment, including program arguments, environment
//! variables, and directory navigation. The [`path`](path/index.html)
//! module encapsulates the platform-specific rules for dealing
//! with file paths.
//!
//! `std` also includes modules for interoperating with the
//! C language: [`c_str`](c_str/index.html) and
//! [`c_vec`](c_vec/index.html).
//!
//! ## Concurrency, I/O, and the runtime
//!
//! The [`task`](task/index.html) module contains Rust's threading abstractions,
//! while [`comm`](comm/index.html) contains the channel types for message
//! passing. [`sync`](sync/index.html) contains further, primitive, shared
//! memory types, including [`atomics`](sync/atomics/index.html).
//!
//! Common types of I/O, including files, TCP, UPD, pipes, Unix domain sockets,
//! timers, and process spawning, are defined in the [`io`](io/index.html) module.
//!
//! Rust's I/O and concurrency depends on a small runtime interface
//! that lives, along with its support code, in mod [`rt`](rt/index.html).
//! While a notable part of the standard library's architecture, this
//! module is not intended for public use.
//!
//! ## The Rust prelude and macros
//!
//! Finally, the [`prelude`](prelude/index.html) defines a
//! common set of traits, types, and functions that are made available
//! to all code by default. [`macros`](macros/index.html) contains
//! all the standard macros, such as `assert!`, `fail!`, `println!`,
//! and `format!`, also available to all Rust code.

#![crate_name = "std"]
#![unstable]
#![comment = "The Rust standard library"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/0.11.0/",
       html_playground_url = "http://play.rust-lang.org/")]

#![feature(macro_rules, globs, managed_boxes, linkage)]
#![feature(default_type_params, phase, lang_items, unsafe_destructor)]

// Don't link to std. We are std.
#![no_std]

#![allow(deprecated)]
#![deny(missing_doc)]

// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::io tests have an I/O interface to run on top
// of
#[cfg(test)] extern crate rustuv;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate green;
#[cfg(test)] extern crate debug;
#[cfg(test)] #[phase(plugin, link)] extern crate log;

extern crate alloc;
extern crate unicode;
extern crate core;
extern crate core_collections = "collections";
extern crate core_rand = "rand";
extern crate core_sync = "sync";
extern crate libc;
extern crate rustrt;

// Make std testable by not duplicating lang items. See #2912
#[cfg(test)] extern crate realstd = "std";
#[cfg(test)] pub use realstd::kinds;
#[cfg(test)] pub use realstd::ops;
#[cfg(test)] pub use realstd::cmp;
#[cfg(test)] pub use realstd::ty;
#[cfg(test)] pub use realstd::owned;
#[cfg(test)] pub use realstd::gc;

// NB: These reexports are in the order they should be listed in rustdoc

pub use core::any;
pub use core::bool;
pub use core::cell;
pub use core::clone;
#[cfg(not(test))] pub use core::cmp;
pub use core::default;
pub use core::finally;
pub use core::intrinsics;
pub use core::iter;
#[cfg(not(test))] pub use core::kinds;
pub use core::mem;
#[cfg(not(test))] pub use core::ops;
pub use core::ptr;
pub use core::raw;
pub use core::simd;
pub use core::tuple;
// FIXME #15320: primitive documentation needs top-level modules, this
// should be `std::tuple::unit`.
pub use core::unit;
#[cfg(not(test))] pub use core::ty;
pub use core::result;
pub use core::option;

pub use alloc::owned;
pub use alloc::rc;

pub use core_collections::slice;
pub use core_collections::str;
pub use core_collections::string;
pub use core_collections::vec;

pub use rustrt::c_str;
pub use rustrt::local_data;

pub use unicode::char;

pub use core_sync::comm;

// Run tests with libgreen instead of libnative.
//
// FIXME: This egregiously hacks around starting the test runner in a different
//        threading mode than the default by reaching into the auto-generated
//        '__test' module.
#[cfg(test)] #[start]
fn start(argc: int, argv: *const *const u8) -> int {
    green::start(argc, argv, rustuv::event_loop, __test::main)
}

/* Exported macros */

pub mod macros;
pub mod bitflags;

mod rtdeps;

/* The Prelude. */

pub mod prelude;

/* Primitive types */

#[path = "num/float_macros.rs"] mod float_macros;
#[path = "num/int_macros.rs"]   mod int_macros;
#[path = "num/uint_macros.rs"]  mod uint_macros;

#[path = "num/int.rs"]  pub mod int;
#[path = "num/i8.rs"]   pub mod i8;
#[path = "num/i16.rs"]  pub mod i16;
#[path = "num/i32.rs"]  pub mod i32;
#[path = "num/i64.rs"]  pub mod i64;

#[path = "num/uint.rs"] pub mod uint;
#[path = "num/u8.rs"]   pub mod u8;
#[path = "num/u16.rs"]  pub mod u16;
#[path = "num/u32.rs"]  pub mod u32;
#[path = "num/u64.rs"]  pub mod u64;

#[path = "num/f32.rs"]   pub mod f32;
#[path = "num/f64.rs"]   pub mod f64;

pub mod rand;

pub mod ascii;

#[cfg(not(test))]
pub mod gc;

/* Common traits */

pub mod from_str;
pub mod num;
pub mod to_str;

/* Common data structures */

pub mod collections;
pub mod hash;

/* Tasks and communication */

pub mod task;
pub mod sync;

/* Runtime and platform support */

pub mod c_vec;
pub mod dynamic_lib;
pub mod os;
pub mod io;
pub mod path;
pub mod fmt;

// FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
// but name resolution doesn't work without it being pub.
#[unstable]
pub mod rt;
mod failure;

// A curious inner-module that's not exported that contains the binding
// 'std' so that macro-expanded references to std::error and such
// can be resolved within libstd.
#[doc(hidden)]
mod std {
    // mods used for deriving
    pub use clone;
    pub use cmp;
    pub use hash;

    pub use comm; // used for select!()
    pub use fmt; // used for any formatting strings
    pub use io; // used for println!()
    pub use local_data; // used for local_data_key!()
    pub use option; // used for bitflags!()
    pub use rt; // used for fail!()
    pub use vec; // used for vec![]

    // The test runner calls ::std::os::args() but really wants realstd
    #[cfg(test)] pub use os = realstd::os;
    // The test runner requires std::slice::Vector, so re-export std::slice just for it.
    #[cfg(test)] pub use slice;
}
<|endoftext|>


<commit_before>
pub enum Op {
    Increment,
    Decrement,
    Output,
    Right,
    Left,
    Jump,
    JumpBack,
    Unknown,
}

pub trait ToOp {
    fn to_op(&self) -> Op;
}

impl ToOp for String {
    fn to_op(&self) -> Op {
        match self.as_slice() {
            "iamgroot" => Op::Increment,
            "IamGroot" => Op::Decrement,
            "IAMGROOOT" => Op::Output,
            "IAMGROOT" => Op::Right,
            "Iamgroot" => Op::Left,
            "I'mGroot" => Op::Jump,
            "WeareGroot" => Op::JumpBack,
            _ => Op::Unknown,
        }
    }
}

<commit_msg>derive PartialEq for Op<commit_after>
#[derive(Debug, PartialEq)]
pub enum Op {
    Increment,
    Decrement,
    Output,
    Right,
    Left,
    Jump,
    JumpBack,
    Unknown,
}

pub trait ToOp {
    fn to_op(&self) -> Op;
}

impl ToOp for String {
    fn to_op(&self) -> Op {
        match self.as_slice() {
            "iamgroot" => Op::Increment,
            "IamGroot" => Op::Decrement,
            "IAMGROOOT" => Op::Output,
            "IAMGROOT" => Op::Right,
            "Iamgroot" => Op::Left,
            "I'mGroot" => Op::Jump,
            "WeareGroot" => Op::JumpBack,
            _ => Op::Unknown,
        }
    }
}

<|endoftext|>


<commit_before>//! Parsing functionality - get cookie data

use std::collections::hashmap::HashMap;
use url;
use serialize::json;
use serialize::json::{Object, Null};
use iron::{Request, Response, Middleware, Alloy};
use iron::middleware::{Status, Continue};
use super::Cookie;

/// The cookie parsing `Middleware`.
///
/// It will parse the body of a cookie into the alloy, under type `Cookie`.
///
/// This middleware should be linked (added to the `Chain`)
/// before any other middleware using cookies, or the parsed cookie
/// will not be available to that middleware.
#[deriving(Clone)]
pub struct CookieParser {
    secret: Option<String>
}

impl CookieParser {
    /// Create a new instance of the cookie parsing `Middleware`.
    ///
    /// This instance will parse both RFC 6265-styled cookies:
    /// `key=value; key=value;`
    /// and json-styled cookies, as set with `res.set_json_cookie(...)`.
    pub fn new() -> CookieParser { CookieParser{ secret: None} }

    /// Create a cookie parser with secret, for signed cookies.
    ///
    /// This instance will parse any cookies that have been signed by
    /// you, or that are unsigned. It will not parse those cookies signed by others.
    ///
    /// Otherwise, it will behave exactly like that produced by `new`.
    pub fn signed(secret: String) -> CookieParser { CookieParser{ secret: Some(secret) } }
}

impl Middleware for CookieParser {
    /// Parse the cookie received in the HTTP header.
    ///
    /// This will parse the body of a cookie into the alloy, under type `Cookie`.
    fn enter(&mut self, req: &mut Request, _res: &mut Response, alloy: &mut Alloy) -> Status {
        let mut parsed_cookie = Cookie::new(self.secret.clone());
        // kudos to @Blei for rustic JSON tips
        let mut parsed_json = json::from_str("{}").unwrap();
        match req.headers.extensions.find_mut(&"Cookie".to_string()) {
            Some(cookie) => {
                let mut map: HashMap<String, String> =
                    cookie.as_slice().split(';').map(|substr| {
                        let vec: Vec<&str> = substr.splitn('=', 1).collect();
                        (url::decode_component((*vec.get(0)).chars().skip_while(|c| {
                            match *c {
                                ' '|'\r'|'\t'|'\n' => true,
                                _                  => false
                            }
                         }).collect::<String>().as_slice()),
                         if vec.len() == 1 { "".to_string() } else {
                            url::decode_component((*vec.get(1)).chars().skip_while(|c| {
                                match *c {
                                    ' '|'\r'|'\t'|'\n' => true,
                                    _                  => false
                                }
                            }).collect::<String>().as_slice())
                         })
                    }).collect();

                match self.secret {
                    Some(ref _secret) => {
                        let mut tokens = vec![];
                        for (token, value) in map.mut_iter() {
                            if value.len() > 2 && value.as_slice().slice(0, 2) == "s:" {
                                match regex!(r"\.[^\.]*$").find(value.as_slice()) {
                                    Some((beg, end)) => {
                                        // If it was signed by us, clear the signature
                                        match parsed_cookie.sign(&value.as_slice().slice(2, beg).to_string()) {
                                            Some(signature) => {
                                                if value.as_slice().slice(beg + 1, end) == signature.as_slice() {
                                                    *value = value.as_slice().slice(2, beg).to_string();
                                                // Else, set them for removal
                                                } else {
                                                    tokens.push(token.clone());
                                                }
                                            },
                                            None            => {
                                                tokens.push(token.clone())
                                            }
                                        }
                                    },
                                    None           => {
                                    }
                                }
                            }
                        }
                        for token in tokens.iter() {
                            map.remove(token);
                        }
                    },
                    None         => ()
                }

                for (token, value) in map.mut_iter() {
                    if value.len() > 2 && value.as_slice().slice(0, 2) == "j:" {
                        match parsed_json {
                            Object(ref mut root) => {
                                root.insert(token.clone(),
                                    match json::from_str(value.as_slice().slice_from(2)) {
                                        Ok(obj) => obj,
                                        Err(_)  => Null
                                    });
                            },
                            _                    => {}
                        }
                    }
                }

                parsed_cookie.map = map;
                parsed_cookie.json = parsed_json;
                alloy.insert(parsed_cookie);
            },
            None => { alloy.insert(parsed_cookie); }
        }
        Continue
    }
}
<commit_msg>(refactor) Modularized parsing logic.<commit_after>//! Parsing functionality - get cookie data

use std::collections::treemap::TreeMap;
use url;
use serialize::json;
use serialize::json::{Json, Null};
use iron::{Request, Response, Middleware, Alloy};
use iron::middleware::{Status, Continue};
use super::Cookie;

/// The cookie parsing `Middleware`.
///
/// It will parse the body of a cookie into the alloy, under type `Cookie`.
///
/// This middleware should be linked (added to the `Chain`)
/// before any other middleware using cookies, or the parsed cookie
/// will not be available to that middleware.
#[deriving(Clone)]
pub struct CookieParser {
    secret: Option<String>
}

impl CookieParser {
    /// Create a new instance of the cookie parsing `Middleware`.
    ///
    /// This instance will parse both RFC 6265-styled cookies:
    /// `key=value; key=value;`
    /// and json-styled cookies, as set with `res.set_json_cookie(...)`.
    pub fn new() -> CookieParser { CookieParser{ secret: None} }

    /// Create a cookie parser with secret, for signed cookies.
    ///
    /// This instance will parse any cookies that have been signed by
    /// you, or that are unsigned. It will not parse those cookies signed by others.
    ///
    /// Otherwise, it will behave exactly like that produced by `new`.
    pub fn signed(secret: String) -> CookieParser { CookieParser{ secret: Some(secret) } }
}

impl Middleware for CookieParser {
    /// Parse the cookie received in the HTTP header.
    ///
    /// This will parse the body of a cookie into the alloy, under type `Cookie`.
    fn enter(&mut self, req: &mut Request, _res: &mut Response, alloy: &mut Alloy) -> Status {
        // Initialize a cookie. This will store parsed cookies and generate signatures.
        let mut new_cookie = Cookie::new(self.secret.clone());

        match req.headers.extensions.find_mut(&"Cookie".to_string()) {
            Some(cookies) => {
                // Initialize an empty json object.
                let mut new_json = json::Object(box TreeMap::new());
                new_cookie.map =
                    cookies
                        .as_slice()
                        .split(';')
                        // Decode from uri component encoding
                        .map(|substr| {
                            let vec: Vec<&str> = substr.splitn('=', 1).collect();
                            let key = from_rfc_compliant(*vec.get(0));
                            let val = from_rfc_compliant(*vec.get(1));
                            (key, val) })
                        // Check for signed cookies, and filter those not signed by us
                        .filter_map(|cookie| strip_signature(cookie, &new_cookie))
                        // Move json cookies into a separate container
                        .filter(|cookie| parse_json(cookie, &mut new_json))
                        .collect();

                // This cannot be inserted via iterators because strip_signature
                // is already borrowing new_cookie.
                new_cookie.json = new_json;
            },
            None => ()
        }
        alloy.insert(new_cookie);
        Continue
    }
}

fn from_rfc_compliant(string: &str) -> String {
    url::decode_component(
        string
            .chars()
            .skip_while(is_whitespace)
            .collect::<String>().as_slice())
}

fn is_whitespace(c: &char) -> bool {
    match *c {
        ' '|'\r'|'\t'|'\n' => true,
        _                  => false
    }
}

fn strip_signature((key, val): (String, String), signer: &Cookie) -> Option<(String, String)> {
    if val.len() > 2 && val.as_slice().slice(0, 2) == "s:" {
        // Extract the signature (in hex), appended onto the cookie after `.`
        return regex!(r"\.[^\.]*$").find(val.as_slice())
            // If it was signed by us, clear the signature
            .and_then(|(beg, end)| {
                signer.sign(&val.as_slice().slice(2, beg).to_string())
                    // We need to maintain access to (beg, end), so we chain the signature
                    .and_then(|signature| {
                        // If the signature is valid, strip it
                        if val.as_slice().slice(beg + 1, end) == signature.as_slice() {
                            // key must be cloned to move out of the closure capture
                            Some((key.clone(), val.as_slice().slice(2, beg).to_string()))
                        // Else, remove the cookie
                        } else {
                            None
                        }
                    })
            })
    }
    Some((key, val))
}

fn parse_json(&(ref key, ref val): &(String, String), json: &mut Json) -> bool {
    if val.len() > 2 && val.as_slice().slice(0, 2) == "j:" {
        match *json {
            json::Object(ref mut root) => {
                root.insert(key.clone(),
                    match json::from_str(val.as_slice().slice_from(2)) {
                        Ok(obj) => obj,
                        Err(_)  => Null
                    });
            },
            _                    => ()
        }
        return true
    }
    false
}
<|endoftext|>


<commit_before>#[cfg(test)]
mod tests;

use crate::tokens::*;
use nom::error::ErrorKind;
use nom::IResult;
use nom::{
    branch::alt,
    bytes::complete::{tag, tag_no_case},
    character::complete::{line_ending, space1},
    combinator::{eof, map, opt, value},
    multi::separated_list0,
    sequence::{delimited, preceded, separated_pair, terminated, tuple},
};

pub fn parse_lines(input: &[u8]) -> IResult<&[u8], Vec<OpCode>> {
    separated_list0(line_ending, opcode)(input)
}

fn opcode(input: &[u8]) -> IResult<&[u8], OpCode> {
    let (input, (mnemonic, am)) =
        separated_pair(mnemonic, alt((space1, line_ending, eof)), addressing_mode)(input)?;
    Ok((input, OpCode(mnemonic, am)))
}

fn mnemonic(input: &[u8]) -> IResult<&[u8], Mnemonic> {
    alt((
        alt((
            value(Mnemonic::Adc, tag_no_case("ADC")),
            value(Mnemonic::And, tag_no_case("AND")),
            value(Mnemonic::Asl, tag_no_case("ASL")),
            value(Mnemonic::Bcc, tag_no_case("BCC")),
            value(Mnemonic::Bcs, tag_no_case("BCS")),
            value(Mnemonic::Beq, tag_no_case("BEQ")),
            value(Mnemonic::Bit, tag_no_case("BIT")),
            value(Mnemonic::Bmi, tag_no_case("BMI")),
            value(Mnemonic::Bne, tag_no_case("BNE")),
            value(Mnemonic::Bpl, tag_no_case("BPL")),
            value(Mnemonic::Brk, tag_no_case("BRK")),
            value(Mnemonic::Bvc, tag_no_case("BVC")),
            value(Mnemonic::Bvs, tag_no_case("BVS")),
            value(Mnemonic::Clc, tag_no_case("CLC")),
            value(Mnemonic::Cld, tag_no_case("CLD")),
            value(Mnemonic::Cli, tag_no_case("CLI")),
            value(Mnemonic::Clv, tag_no_case("CLV")),
            value(Mnemonic::Cmp, tag_no_case("CMP")),
            value(Mnemonic::Cpx, tag_no_case("CPX")),
            value(Mnemonic::Cpy, tag_no_case("CPY")),
            value(Mnemonic::Dec, tag_no_case("DEC")),
        )),
        alt((
            value(Mnemonic::Dex, tag_no_case("DEX")),
            value(Mnemonic::Dey, tag_no_case("DEY")),
            value(Mnemonic::Eor, tag_no_case("EOR")),
            value(Mnemonic::Inc, tag_no_case("INC")),
            value(Mnemonic::Inx, tag_no_case("INX")),
            value(Mnemonic::Iny, tag_no_case("INY")),
            value(Mnemonic::Jmp, tag_no_case("JMP")),
            value(Mnemonic::Jsr, tag_no_case("JSR")),
            value(Mnemonic::Lda, tag_no_case("LDA")),
            value(Mnemonic::Ldx, tag_no_case("LDX")),
            value(Mnemonic::Ldy, tag_no_case("LDY")),
            value(Mnemonic::Lsr, tag_no_case("LSR")),
            value(Mnemonic::Nop, tag_no_case("NOP")),
            value(Mnemonic::Ora, tag_no_case("ORA")),
            value(Mnemonic::Pha, tag_no_case("PHA")),
            value(Mnemonic::Php, tag_no_case("PHP")),
            value(Mnemonic::Pla, tag_no_case("PLA")),
            value(Mnemonic::Plp, tag_no_case("PLP")),
            value(Mnemonic::Rol, tag_no_case("ROL")),
            value(Mnemonic::Ror, tag_no_case("ROR")),
            value(Mnemonic::Rti, tag_no_case("RTI")),
        )),
        alt((
            value(Mnemonic::Rts, tag_no_case("RTS")),
            value(Mnemonic::Sbc, tag_no_case("SBC")),
            value(Mnemonic::Sec, tag_no_case("SEC")),
            value(Mnemonic::Sed, tag_no_case("SED")),
            value(Mnemonic::Sei, tag_no_case("SEI")),
            value(Mnemonic::Sta, tag_no_case("STA")),
            value(Mnemonic::Stx, tag_no_case("STX")),
            value(Mnemonic::Sty, tag_no_case("STY")),
            value(Mnemonic::Tax, tag_no_case("TAX")),
            value(Mnemonic::Tay, tag_no_case("TAY")),
            value(Mnemonic::Tsx, tag_no_case("TSX")),
            value(Mnemonic::Txa, tag_no_case("TXA")),
            value(Mnemonic::Txs, tag_no_case("TXS")),
            value(Mnemonic::Tya, tag_no_case("TYA")),
        )),
    ))(input)
}

fn addressing_mode(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    alt((
        am_accumulator,
        am_immediate,
        am_indirect,
        am_indexed_indirect,
        am_indirect_indexed,
        am_zp_x,
        am_zp_y,
        am_zp_or_relative,
        am_abs_x,
        am_abs_y,
        am_abs,
        am_implied,
    ))(input)
}

fn am_implied(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    value(AddressingMode::Implied, alt((line_ending, eof)))(input)
}

fn am_indirect(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = tuple((
        tag("("),
        alt((parse_word_hex, dec_u16)),
        tag(")"),
        nom::combinator::not(tag(",")),
    ));
    map(parser, |(_, val, _, _)| AddressingMode::Indirect(val))(input)
}

fn am_indexed_indirect(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = delimited(
        tag("("),
        alt((parse_byte_hex, parse_byte_dec)),
        tag_no_case(",X"),
    );
    map(parser, |(addr, _)| AddressingMode::IndexedIndirect(addr))(input)
}

fn am_indirect_indexed(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = delimited(
        tag("("),
        alt((parse_byte_hex, parse_byte_dec)),
        tag_no_case("),Y"),
    );
    map(parser, |(addr, _)| AddressingMode::IndirectIndexed(addr))(input)
}

fn am_accumulator(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    map(tag_no_case("A"), |_| AddressingMode::Accumulator)(input)
}

fn am_immediate(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = preceded(tag("#"), alt((parse_byte_hex, parse_byte_dec)));
    map(parser, |(byte, sign)| AddressingMode::Immediate(byte, sign))(input)
}

fn am_abs(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = alt((parse_word_hex, dec_u16));
    map(parser, |val| AddressingMode::Absolute(val))(input)
}

fn am_zp_or_relative(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = alt((parse_byte_hex, parse_byte_dec));
    map(parser, |(byte, sign)| {
        AddressingMode::ZeroPageOrRelative(byte, sign)
    })(input)
}

fn am_zp_x(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = terminated(alt((parse_byte_hex, parse_byte_dec)), tag_no_case(",X"));
    map(parser, |(byte, _)| AddressingMode::ZeroPageX(byte))(input)
}

fn am_zp_y(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = terminated(alt((parse_byte_hex, parse_byte_dec)), tag_no_case(",Y"));
    map(parser, |(byte, _)| AddressingMode::ZeroPageY(byte))(input)
}

fn am_abs_x(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = terminated(alt((parse_word_hex, dec_u16)), tag_no_case(",X"));
    map(parser, |val| AddressingMode::AbsoluteX(val))(input)
}

fn am_abs_y(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = terminated(alt((parse_word_hex, dec_u16)), tag_no_case(",Y"));
    map(parser, |val| AddressingMode::AbsoluteY(val))(input)
}

fn parse_word_hex(input: &[u8]) -> IResult<&[u8], u16> {
    preceded(tag("$"), hex_u16)(input)
}

fn parse_byte_hex(input: &[u8]) -> IResult<&[u8], (u8, Sign)> {
    map(preceded(tag("$"), hex_u8), |val| (val, Sign::Implied))(input)
}

fn parse_byte_dec(input: &[u8]) -> IResult<&[u8], (u8, Sign)> {
    map(tuple((parse_sign, dec_u8)), |(sign, val)| (val, sign))(input)
}

fn parse_sign(input: &[u8]) -> IResult<&[u8], Sign> {
    map(opt(tag("-")), |sign| {
        if sign.is_some() {
            Sign::Negative
        } else {
            Sign::Implied
        }
    })(input)
}

fn hex_u16(input: &[u8]) -> IResult<&[u8], u16> {
    let (i, o) = nom::bytes::complete::is_a(&b"0123456789abcdefABCDEF"[..])(input)?;
    let mut res = 0u16;

    // Do not parse more than 4 characters for a u16
    let mut remaining = i;
    let mut parsed = o;
    if o.len() > 4 {
        remaining = &input[4..];
        parsed = &input[..4];
    }

    for &e in parsed {
        let digit = e as char;
        let value = digit.to_digit(16).unwrap_or(0) as u16;
        res = value + (res << 4);
    }
    IResult::Ok((remaining, res))
}

fn dec_u16(input: &[u8]) -> IResult<&[u8], u16> {
    let (remaining, parsed) = nom::bytes::complete::is_a(&b"0123456789"[..])(input)?;
    // Do not parse more than 5 characters for a u16
    if parsed.len() > 5 {
        IResult::Err(nom::Err::Error(nom::error::make_error(
            input,
            ErrorKind::TooLarge,
        )))
    } else {
        let mut res = 0u32;
        for &e in parsed {
            let digit = e as char;
            let value = digit.to_digit(10).unwrap_or(0) as u32;
            res = value + (res * 10);
        }
        if res > u16::max_value() as u32 {
            // TODO: propper error handling. ErrorKind::TooLarge probably is not
            // the best choice here. Some custome error?
            IResult::Err(nom::Err::Error(nom::error::make_error(
                input,
                ErrorKind::TooLarge,
            )))
        } else {
            IResult::Ok((remaining, res as u16))
        }
    }
}

fn dec_u8(input: &[u8]) -> IResult<&[u8], u8> {
    let (remaining, parsed) = nom::bytes::complete::is_a(&b"0123456789"[..])(input)?;
    // Do not parse more than 3 characters for a u16
    if parsed.len() > 3 {
        IResult::Err(nom::Err::Error(nom::error::make_error(
            input,
            ErrorKind::TooLarge,
        )))
    } else {
        let mut res = 0u16;
        for &e in parsed {
            let digit = e as char;
            let value = digit.to_digit(10).unwrap_or(0) as u16;
            res = value + (res * 10);
        }
        if res > u8::max_value() as u16 {
            IResult::Err(nom::Err::Error(nom::error::make_error(
                input,
                ErrorKind::TooLarge,
            )))
        } else {
            IResult::Ok((remaining, res as u8))
        }
    }
}

fn hex_u8(input: &[u8]) -> IResult<&[u8], u8> {
    let (remaining, parsed) = nom::bytes::complete::is_a(&b"0123456789abcdefABCDEF"[..])(input)?;
    // Not valid if exceeds 2 characters
    if parsed.len() > 2 {
        IResult::Err(nom::Err::Error(nom::error::make_error(
            input,
            ErrorKind::TooLarge,
        )))
    } else {
        let mut res = 0u8;
        for &e in parsed {
            let digit = e as char;
            let value = digit.to_digit(16).unwrap_or(0) as u8;
            res = value + (res << 4);
        }
        IResult::Ok((remaining, res))
    }
}
<commit_msg>Remove redundant closure<commit_after>#[cfg(test)]
mod tests;

use crate::tokens::*;
use nom::error::ErrorKind;
use nom::IResult;
use nom::{
    branch::alt,
    bytes::complete::{tag, tag_no_case},
    character::complete::{line_ending, space1},
    combinator::{eof, map, opt, value},
    multi::separated_list0,
    sequence::{delimited, preceded, separated_pair, terminated, tuple},
};

pub fn parse_lines(input: &[u8]) -> IResult<&[u8], Vec<OpCode>> {
    separated_list0(line_ending, opcode)(input)
}

fn opcode(input: &[u8]) -> IResult<&[u8], OpCode> {
    let (input, (mnemonic, am)) =
        separated_pair(mnemonic, alt((space1, line_ending, eof)), addressing_mode)(input)?;
    Ok((input, OpCode(mnemonic, am)))
}

fn mnemonic(input: &[u8]) -> IResult<&[u8], Mnemonic> {
    alt((
        alt((
            value(Mnemonic::Adc, tag_no_case("ADC")),
            value(Mnemonic::And, tag_no_case("AND")),
            value(Mnemonic::Asl, tag_no_case("ASL")),
            value(Mnemonic::Bcc, tag_no_case("BCC")),
            value(Mnemonic::Bcs, tag_no_case("BCS")),
            value(Mnemonic::Beq, tag_no_case("BEQ")),
            value(Mnemonic::Bit, tag_no_case("BIT")),
            value(Mnemonic::Bmi, tag_no_case("BMI")),
            value(Mnemonic::Bne, tag_no_case("BNE")),
            value(Mnemonic::Bpl, tag_no_case("BPL")),
            value(Mnemonic::Brk, tag_no_case("BRK")),
            value(Mnemonic::Bvc, tag_no_case("BVC")),
            value(Mnemonic::Bvs, tag_no_case("BVS")),
            value(Mnemonic::Clc, tag_no_case("CLC")),
            value(Mnemonic::Cld, tag_no_case("CLD")),
            value(Mnemonic::Cli, tag_no_case("CLI")),
            value(Mnemonic::Clv, tag_no_case("CLV")),
            value(Mnemonic::Cmp, tag_no_case("CMP")),
            value(Mnemonic::Cpx, tag_no_case("CPX")),
            value(Mnemonic::Cpy, tag_no_case("CPY")),
            value(Mnemonic::Dec, tag_no_case("DEC")),
        )),
        alt((
            value(Mnemonic::Dex, tag_no_case("DEX")),
            value(Mnemonic::Dey, tag_no_case("DEY")),
            value(Mnemonic::Eor, tag_no_case("EOR")),
            value(Mnemonic::Inc, tag_no_case("INC")),
            value(Mnemonic::Inx, tag_no_case("INX")),
            value(Mnemonic::Iny, tag_no_case("INY")),
            value(Mnemonic::Jmp, tag_no_case("JMP")),
            value(Mnemonic::Jsr, tag_no_case("JSR")),
            value(Mnemonic::Lda, tag_no_case("LDA")),
            value(Mnemonic::Ldx, tag_no_case("LDX")),
            value(Mnemonic::Ldy, tag_no_case("LDY")),
            value(Mnemonic::Lsr, tag_no_case("LSR")),
            value(Mnemonic::Nop, tag_no_case("NOP")),
            value(Mnemonic::Ora, tag_no_case("ORA")),
            value(Mnemonic::Pha, tag_no_case("PHA")),
            value(Mnemonic::Php, tag_no_case("PHP")),
            value(Mnemonic::Pla, tag_no_case("PLA")),
            value(Mnemonic::Plp, tag_no_case("PLP")),
            value(Mnemonic::Rol, tag_no_case("ROL")),
            value(Mnemonic::Ror, tag_no_case("ROR")),
            value(Mnemonic::Rti, tag_no_case("RTI")),
        )),
        alt((
            value(Mnemonic::Rts, tag_no_case("RTS")),
            value(Mnemonic::Sbc, tag_no_case("SBC")),
            value(Mnemonic::Sec, tag_no_case("SEC")),
            value(Mnemonic::Sed, tag_no_case("SED")),
            value(Mnemonic::Sei, tag_no_case("SEI")),
            value(Mnemonic::Sta, tag_no_case("STA")),
            value(Mnemonic::Stx, tag_no_case("STX")),
            value(Mnemonic::Sty, tag_no_case("STY")),
            value(Mnemonic::Tax, tag_no_case("TAX")),
            value(Mnemonic::Tay, tag_no_case("TAY")),
            value(Mnemonic::Tsx, tag_no_case("TSX")),
            value(Mnemonic::Txa, tag_no_case("TXA")),
            value(Mnemonic::Txs, tag_no_case("TXS")),
            value(Mnemonic::Tya, tag_no_case("TYA")),
        )),
    ))(input)
}

fn addressing_mode(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    alt((
        am_accumulator,
        am_immediate,
        am_indirect,
        am_indexed_indirect,
        am_indirect_indexed,
        am_zp_x,
        am_zp_y,
        am_zp_or_relative,
        am_abs_x,
        am_abs_y,
        am_abs,
        am_implied,
    ))(input)
}

fn am_implied(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    value(AddressingMode::Implied, alt((line_ending, eof)))(input)
}

fn am_indirect(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = tuple((
        tag("("),
        alt((parse_word_hex, dec_u16)),
        tag(")"),
        nom::combinator::not(tag(",")),
    ));
    map(parser, |(_, val, _, _)| AddressingMode::Indirect(val))(input)
}

fn am_indexed_indirect(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = delimited(
        tag("("),
        alt((parse_byte_hex, parse_byte_dec)),
        tag_no_case(",X"),
    );
    map(parser, |(addr, _)| AddressingMode::IndexedIndirect(addr))(input)
}

fn am_indirect_indexed(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = delimited(
        tag("("),
        alt((parse_byte_hex, parse_byte_dec)),
        tag_no_case("),Y"),
    );
    map(parser, |(addr, _)| AddressingMode::IndirectIndexed(addr))(input)
}

fn am_accumulator(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    map(tag_no_case("A"), |_| AddressingMode::Accumulator)(input)
}

fn am_immediate(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = preceded(tag("#"), alt((parse_byte_hex, parse_byte_dec)));
    map(parser, |(byte, sign)| AddressingMode::Immediate(byte, sign))(input)
}

fn am_abs(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = alt((parse_word_hex, dec_u16));
    map(parser, AddressingMode::Absolute)(input)
}

fn am_zp_or_relative(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = alt((parse_byte_hex, parse_byte_dec));
    map(parser, |(byte, sign)| {
        AddressingMode::ZeroPageOrRelative(byte, sign)
    })(input)
}

fn am_zp_x(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = terminated(alt((parse_byte_hex, parse_byte_dec)), tag_no_case(",X"));
    map(parser, |(byte, _)| AddressingMode::ZeroPageX(byte))(input)
}

fn am_zp_y(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = terminated(alt((parse_byte_hex, parse_byte_dec)), tag_no_case(",Y"));
    map(parser, |(byte, _)| AddressingMode::ZeroPageY(byte))(input)
}

fn am_abs_x(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = terminated(alt((parse_word_hex, dec_u16)), tag_no_case(",X"));
    map(parser, AddressingMode::AbsoluteX)(input)
}

fn am_abs_y(input: &[u8]) -> IResult<&[u8], AddressingMode> {
    let parser = terminated(alt((parse_word_hex, dec_u16)), tag_no_case(",Y"));
    map(parser, AddressingMode::AbsoluteY)(input)
}

fn parse_word_hex(input: &[u8]) -> IResult<&[u8], u16> {
    preceded(tag("$"), hex_u16)(input)
}

fn parse_byte_hex(input: &[u8]) -> IResult<&[u8], (u8, Sign)> {
    map(preceded(tag("$"), hex_u8), |val| (val, Sign::Implied))(input)
}

fn parse_byte_dec(input: &[u8]) -> IResult<&[u8], (u8, Sign)> {
    map(tuple((parse_sign, dec_u8)), |(sign, val)| (val, sign))(input)
}

fn parse_sign(input: &[u8]) -> IResult<&[u8], Sign> {
    map(opt(tag("-")), |sign| {
        if sign.is_some() {
            Sign::Negative
        } else {
            Sign::Implied
        }
    })(input)
}

fn hex_u16(input: &[u8]) -> IResult<&[u8], u16> {
    let (i, o) = nom::bytes::complete::is_a(&b"0123456789abcdefABCDEF"[..])(input)?;
    let mut res = 0u16;

    // Do not parse more than 4 characters for a u16
    let mut remaining = i;
    let mut parsed = o;
    if o.len() > 4 {
        remaining = &input[4..];
        parsed = &input[..4];
    }

    for &e in parsed {
        let digit = e as char;
        let value = digit.to_digit(16).unwrap_or(0) as u16;
        res = value + (res << 4);
    }
    IResult::Ok((remaining, res))
}

fn dec_u16(input: &[u8]) -> IResult<&[u8], u16> {
    let (remaining, parsed) = nom::bytes::complete::is_a(&b"0123456789"[..])(input)?;
    // Do not parse more than 5 characters for a u16
    if parsed.len() > 5 {
        IResult::Err(nom::Err::Error(nom::error::make_error(
            input,
            ErrorKind::TooLarge,
        )))
    } else {
        let mut res = 0u32;
        for &e in parsed {
            let digit = e as char;
            let value = digit.to_digit(10).unwrap_or(0) as u32;
            res = value + (res * 10);
        }
        if res > u16::max_value() as u32 {
            // TODO: propper error handling. ErrorKind::TooLarge probably is not
            // the best choice here. Some custome error?
            IResult::Err(nom::Err::Error(nom::error::make_error(
                input,
                ErrorKind::TooLarge,
            )))
        } else {
            IResult::Ok((remaining, res as u16))
        }
    }
}

fn dec_u8(input: &[u8]) -> IResult<&[u8], u8> {
    let (remaining, parsed) = nom::bytes::complete::is_a(&b"0123456789"[..])(input)?;
    // Do not parse more than 3 characters for a u16
    if parsed.len() > 3 {
        IResult::Err(nom::Err::Error(nom::error::make_error(
            input,
            ErrorKind::TooLarge,
        )))
    } else {
        let mut res = 0u16;
        for &e in parsed {
            let digit = e as char;
            let value = digit.to_digit(10).unwrap_or(0) as u16;
            res = value + (res * 10);
        }
        if res > u8::max_value() as u16 {
            IResult::Err(nom::Err::Error(nom::error::make_error(
                input,
                ErrorKind::TooLarge,
            )))
        } else {
            IResult::Ok((remaining, res as u8))
        }
    }
}

fn hex_u8(input: &[u8]) -> IResult<&[u8], u8> {
    let (remaining, parsed) = nom::bytes::complete::is_a(&b"0123456789abcdefABCDEF"[..])(input)?;
    // Not valid if exceeds 2 characters
    if parsed.len() > 2 {
        IResult::Err(nom::Err::Error(nom::error::make_error(
            input,
            ErrorKind::TooLarge,
        )))
    } else {
        let mut res = 0u8;
        for &e in parsed {
            let digit = e as char;
            let value = digit.to_digit(16).unwrap_or(0) as u8;
            res = value + (res << 4);
        }
        IResult::Ok((remaining, res))
    }
}
<|endoftext|>


<commit_before>use super::mode;
use super::util;
use std::collections::DList;
use std::collections::Deque;

#[deriving(Clone)]
#[deriving(Show)]
enum DOC {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Group(Box<Doc>),
    Nest(uint, Box<Doc>),
    Newline,
    Text(String),
}

pub type Doc = DOC;
type Cmd<'a> = (uint,mode::Mode,&'a Doc);

fn fitting(mut cmds:DList<Cmd>, mut rem:int) -> bool {
    let mut fits = true;

    loop {
        if rem < 0 {
            fits = false;
            break;
        }
        match cmds.pop_front() {
            None => {
                break;
            },
            Some((ind, mode, doc)) => match doc {
                &Nil => {
                },
                &Append(box ref ldoc, box ref rdoc) => {
                    cmds.push_front((ind, mode, rdoc));
                    cmds.push_front((ind, mode, ldoc));
                },
                &Group(box ref doc) => {
                    cmds.push_front((ind, mode, doc));
                },
                &Nest(off, box ref doc) => {
                    cmds.push_front((ind + off, mode, doc));
                },
                &Newline => {
                    fits = true;
                },
                &Text(ref str) => {
                    rem -= str.len() as int;
                },
            }
        }
    }

    fits
}

impl Doc {

    fn best(&self, width:uint) -> DList<String> {
        let mut pos: uint = 0;
        let mut cmds: DList<Cmd> = DList::new();
        let mut result:DList<String> = DList::new();

        cmds.push((0, mode::Break, self));

        loop {
            match cmds.pop_front() {
                None => {
                    break;
                },
                Some((ind, mode, doc)) => match doc {
                    &Nil => {
                    },
                    &Append(box ref ldoc, box ref rdoc) => {
                        cmds.push_front((ind, mode, rdoc));
                        cmds.push_front((ind, mode, ldoc));
                    },
                    &Group(box ref doc) => match mode {
                        mode::Flat => {
                            cmds.push_front((ind, mode::Flat, doc));
                        },
                        mode::Break => {
                            // FIXME: fitting() modifies cmds so we must either
                            // take a clone and pass it or rewrite fitting()
                            // to modify a separate cmd stack and only observe
                            // this one.
                            let mut cmds_dup = cmds.clone();
                            let next = (ind, mode::Flat, doc);
                            cmds_dup.push_front(next);
                            if fitting(cmds_dup, width as int - pos as int) {
                                cmds.push_front(next);
                            } else {
                                cmds.push_front((ind, mode::Break, doc));
                            }
                        }
                    },
                    &Nest(off, box ref doc) => {
                        cmds.push_front((ind + off, mode, doc));
                    },
                    &Newline => {
                        result.push(util::string::nl_spaces(ind));
                        pos = ind;
                    },
                    &Text(ref str) => {
                        // FIXME: we have to clone here otherwise result would
                        // have to contain String and &String. We cannot make
                        // Newline case return &String because the region is
                        // limited to the scope of its arm; it does not live
                        // long enough (the strings in Text will outlast).
                        result.push(str.clone());
                        pos += str.len();
                    },
                }
            }
        }

        result
    }

    #[inline]
    pub fn nil() -> Doc {
        Nil
    }

    #[inline]
    pub fn append(self, that:Doc) -> Doc {
        match self {
            Nil => {
                that
            },
            ldoc => match that {
                Nil => {
                    ldoc
                },
                rdoc => {
                    Append(box ldoc, box rdoc)
                },
            }
        }
    }

    #[inline]
    pub fn as_string<T:ToString>(t:T) -> Doc {
        Doc::text(t.to_string())
    }

    #[inline]
    pub fn concat(ds:&[Doc]) -> Doc {
        ds.iter().fold(Nil, |a, b| a.append(b.clone()))
    }

    #[inline]
    pub fn group(self) -> Doc {
        Group(box self)
    }

    #[inline]
    pub fn nest(self, off:uint) -> Doc {
        Nest(off, box self)
    }

    #[inline]
    pub fn newline() -> Doc {
        Newline
    }

    // FIXME: could possibly parallelize this part since string append should
    // be associative. Might be a good example for rust-monoid…
    #[inline]
    pub fn render(&self, width:uint) -> String {
        let mut result = String::new();
        for str in self.best(width).iter() {
            result.push_str(str.as_slice());
        }
        result
    }

    #[inline]
    pub fn text<T:Str>(str:T) -> Doc {
        Text(String::from_str(str.as_slice()))
    }

}
<commit_msg>More optimizations; another 30-40%<commit_after>use super::mode;
use super::util;
use std::collections::Deque;
use std::collections::RingBuf;

#[deriving(Clone)]
#[deriving(Show)]
enum DOC {
    Nil,
    Append(Box<Doc>, Box<Doc>),
    Group(Box<Doc>),
    Nest(uint, Box<Doc>),
    Newline,
    Text(String),
}

pub type Doc = DOC;
type Cmd<'a> = (uint,mode::Mode,&'a Doc);

fn fitting(mut cmds:RingBuf<Cmd>, mut rem:int) -> bool {
    let mut fits = true;

    loop {
        if rem < 0 {
            fits = false;
            break;
        }
        match cmds.pop_front() {
            None => {
                break;
            },
            Some((ind, mode, doc)) => match doc {
                &Nil => {
                },
                &Append(box ref ldoc, box ref rdoc) => {
                    cmds.push_front((ind, mode, rdoc));
                    cmds.push_front((ind, mode, ldoc));
                },
                &Group(box ref doc) => {
                    cmds.push_front((ind, mode, doc));
                },
                &Nest(off, box ref doc) => {
                    cmds.push_front((ind + off, mode, doc));
                },
                &Newline => {
                    fits = true;
                },
                &Text(ref str) => {
                    rem -= str.len() as int;
                },
            }
        }
    }

    fits
}

impl Doc {

    fn best(&self, width:uint) -> Vec<String> {
        let mut pos: uint = 0;
        let mut cmds: RingBuf<Cmd> = RingBuf::new();
        let mut result:Vec<String> = Vec::new();

        cmds.push((0, mode::Break, self));

        loop {
            match cmds.pop_front() {
                None => {
                    break;
                },
                Some((ind, mode, doc)) => match doc {
                    &Nil => {
                    },
                    &Append(box ref ldoc, box ref rdoc) => {
                        cmds.push_front((ind, mode, rdoc));
                        cmds.push_front((ind, mode, ldoc));
                    },
                    &Group(box ref doc) => match mode {
                        mode::Flat => {
                            cmds.push_front((ind, mode::Flat, doc));
                        },
                        mode::Break => {
                            // FIXME: fitting() modifies cmds so we must either
                            // take a clone and pass it or rewrite fitting()
                            // to modify a separate cmd stack and only observe
                            // this one.
                            let mut cmds_dup = cmds.clone();
                            let next = (ind, mode::Flat, doc);
                            cmds_dup.push_front(next);
                            if fitting(cmds_dup, width as int - pos as int) {
                                cmds.push_front(next);
                            } else {
                                cmds.push_front((ind, mode::Break, doc));
                            }
                        }
                    },
                    &Nest(off, box ref doc) => {
                        cmds.push_front((ind + off, mode, doc));
                    },
                    &Newline => {
                        result.push(util::string::nl_spaces(ind));
                        pos = ind;
                    },
                    &Text(ref str) => {
                        // FIXME: we have to clone here otherwise result would
                        // have to contain String and &String. We cannot make
                        // Newline case return &String because the region is
                        // limited to the scope of its arm; it does not live
                        // long enough (the strings in Text will outlast).
                        result.push(str.clone());
                        pos += str.len();
                    },
                }
            }
        }

        result
    }

    #[inline]
    pub fn nil() -> Doc {
        Nil
    }

    #[inline]
    pub fn append(self, that:Doc) -> Doc {
        match self {
            Nil => {
                that
            },
            ldoc => match that {
                Nil => {
                    ldoc
                },
                rdoc => {
                    Append(box ldoc, box rdoc)
                },
            }
        }
    }

    #[inline]
    pub fn as_string<T:ToString>(t:T) -> Doc {
        Doc::text(t.to_string())
    }

    #[inline]
    pub fn concat(ds:&[Doc]) -> Doc {
        ds.iter().fold(Nil, |a, b| a.append(b.clone()))
    }

    #[inline]
    pub fn group(self) -> Doc {
        Group(box self)
    }

    #[inline]
    pub fn nest(self, off:uint) -> Doc {
        Nest(off, box self)
    }

    #[inline]
    pub fn newline() -> Doc {
        Newline
    }

    // FIXME: could possibly parallelize this part since string append should
    // be associative. Might be a good example for rust-monoid…
    #[inline]
    pub fn render(&self, width:uint) -> String {
        let mut result = String::new();
        for str in self.best(width).iter() {
            result.push_str(str.as_slice());
        }
        result
    }

    #[inline]
    pub fn text<T:Str>(str:T) -> Doc {
        Text(String::from_str(str.as_slice()))
    }

}
<|endoftext|>


<commit_before>

pub struct StreamOfPrimes {
    seed_primes: Vec<u64>,
    current_index: usize,
    segment_size: usize,
    next_segment_floor: u64,
}

fn primes_from_next_seive_segment(floor: u64, size: usize, seed_primes: &Vec<u64>) -> Vec<u64> {
    let mut result = Vec::with_capacity(size / 2);

    let mut new_segment = vec![true; size+1];
    for i in seed_primes.iter() {
        let p = i.clone() as f64;

        let start_at = (floor as f64 / p).ceil() as u64;
        let end_at = ((floor as usize + size) as f64 / p).floor() as u64;

        for j in start_at..end_at + 1 {
            let target = (i * j) - floor;
            new_segment[target as usize] = false;
        }
    }

    for (pos, &is_prime) in new_segment.iter().enumerate() {
        if is_prime {
            result.push(pos as u64 + floor)
        }
    }

    result
}

impl Iterator for StreamOfPrimes {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current_index < self.seed_primes.len() {
            let current_index = self.current_index;
            self.current_index += 1;
            Some(self.seed_primes[current_index])
        } else {

            let mut next_segment = primes_from_next_seive_segment(self.next_segment_floor,
                                                                  self.segment_size,
                                                                  &self.seed_primes);

            self.seed_primes.append(&mut next_segment);

            self.next_segment_floor = self.next_segment_floor + self.segment_size as u64;

            self.next()
        }
    }
}

pub fn stream_of_primes(upper_bound: u64) -> StreamOfPrimes {
    let segment_size = (upper_bound as f64).sqrt().ceil() as usize;

    let mut initial_seive = vec![true; segment_size + 1];
    initial_seive[0] = false;
    initial_seive[1] = false;

    let mut seed_primes = Vec::with_capacity(segment_size / 2);

    for i in 2..segment_size {
        if initial_seive[i] {
            for j in i..(segment_size / i) {
                initial_seive[i * j] = false
            }
            seed_primes.push(i as u64);
        }
    }

    StreamOfPrimes {
        seed_primes: seed_primes,
        current_index: 0,
        segment_size: segment_size,
        next_segment_floor: segment_size as u64,
    }
}

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

    #[test]
    fn stream_of_primes_yields_some_primes() {
        let mut s = stream_of_primes(100);
        assert_eq!(s.next(), Some(2));
        assert_eq!(s.next(), Some(3));
        assert_eq!(s.next(), Some(5));
        assert_eq!(s.next(), Some(7));
    }

    #[test]
    fn stream_of_primes_yields_primes_including_max() {
        let mut s = stream_of_primes(7);
        assert_eq!(s.next(), Some(2));
        assert_eq!(s.next(), Some(3));
        assert_eq!(s.next(), Some(5));
        assert_eq!(s.next(), Some(7));
    }
}
<commit_msg>Improve the performance of stream of primes by:<commit_after>

pub struct StreamOfPrimes {
    seed_primes: Vec<u64>,
    upper_bound: u64,
    current_index: usize,
    segment_size: usize,
    next_segment_floor: u64,
}

fn primes_from_next_seive_segment(floor: u64, size: usize, seed_primes: &Vec<u64>) -> Vec<u64> {
    let mut result = Vec::with_capacity(size / 2);

    let mut new_segment = vec![true; size+1];
    for i in seed_primes.iter().take_while(|&x| x.pow(2) < (floor + size as u64)) {
        let p = i.clone() as f64;

        let start_at = (floor as f64 / p).ceil() as u64;
        let end_at = ((floor as usize + size) as f64 / p).floor() as u64;

        for j in start_at..end_at + 1 {
            let target = (i * j) - floor;
            new_segment[target as usize] = false;
        }
    }

    for (pos, &is_prime) in new_segment.iter().enumerate() {
        if is_prime {
            result.push(pos as u64 + floor)
        }
    }

    result
}

impl Iterator for StreamOfPrimes {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current_index < self.seed_primes.len() {
            let current_index = self.current_index;
            self.current_index += 1;
            Some(self.seed_primes[current_index])
        } else if self.next_segment_floor >= self.upper_bound {
            None
        } else {
            let mut next_segment = primes_from_next_seive_segment(self.next_segment_floor,
                                                                  self.segment_size,
                                                                  &self.seed_primes);

            self.seed_primes.append(&mut next_segment);

            self.next_segment_floor = self.next_segment_floor + self.segment_size as u64;

            self.next()
        }
    }
}

pub fn stream_of_primes(upper_bound: u64) -> StreamOfPrimes {

    let segment_size = if upper_bound > 1000 {
        (upper_bound as f64).sqrt().ceil() as usize
    } else {
        (upper_bound + 1) as usize
    };

    let mut initial_seive = vec![true; segment_size + 1];
    initial_seive[0] = false;
    initial_seive[1] = false;

    let mut seed_primes = Vec::with_capacity(segment_size / 2);

    for i in 2..segment_size {
        if initial_seive[i] {
            for j in i..(segment_size / i) + 1 {
                initial_seive[i * j] = false
            }
            seed_primes.push(i as u64);
        }
    }

    StreamOfPrimes {
        seed_primes: seed_primes,
        upper_bound: upper_bound,
        current_index: 0,
        segment_size: segment_size,
        next_segment_floor: segment_size as u64,
    }
}

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

    #[test]
    fn stream_of_primes_yields_some_primes() {
        let mut s = stream_of_primes(100);
        assert_eq!(s.next(), Some(2));
        assert_eq!(s.next(), Some(3));
        assert_eq!(s.next(), Some(5));
        assert_eq!(s.next(), Some(7));
    }

    #[test]
    fn stream_of_primes_yields_primes_including_max() {
        let mut s = stream_of_primes(7);
        assert_eq!(s.next(), Some(2));
        assert_eq!(s.next(), Some(3));
        assert_eq!(s.next(), Some(5));
        assert_eq!(s.next(), Some(7));
    }

    #[test]
    fn stream_of_primes_finished_at_its_upper_bound() {
        let r = stream_of_primes(100).collect::<Vec<_>>();
        assert_eq!(r,
                   vec![2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
                        71, 73, 79, 83, 89, 97]);
    }
}
<|endoftext|>


<commit_before>use rocket;

mod application;
mod authors;
mod errors;
mod posts;

pub fn mount(server: rocket::Rocket) -> rocket::Rocket {
    server.mount("/", routes![application::health])
        .mount("/posts", routes![
            posts::show,
            posts::index,
            posts::create,
            posts::update,
            posts::destroy,
        ])
        .mount("/authors", routes![
            authors::show,
            authors::index,
            authors::create,
            authors::update,
            authors::destroy,
        ])
        .catch(errors![
            errors::not_found,
            errors::bad_request,
            errors::internal_server_error,
        ])
}
<commit_msg>refactor: alias rocket in routes module<commit_after>use rocket::Rocket;

mod application;
mod authors;
mod errors;
mod posts;

pub fn mount(server: Rocket) -> Rocket {
    use rocket;

    server.mount("/", routes![application::health])
        .mount("/posts", routes![
            posts::show,
            posts::index,
            posts::create,
            posts::update,
            posts::destroy,
        ])
        .mount("/authors", routes![
            authors::show,
            authors::index,
            authors::create,
            authors::update,
            authors::destroy,
        ])
        .catch(errors![
            errors::not_found,
            errors::bad_request,
            errors::internal_server_error,
        ])
}
<|endoftext|>


<commit_before>use super::*;
use super::LittleEndian as LE;
use byteorder::BigEndian as BE;
use std::io::Seek;

const TYPE_ID: &'static [u8; 4] = b"TXTR";

pub fn read(reader: &mut FileBufRead) -> Result<Txtr, Box<Error>> {
    let size = expect_chunk(reader, TYPE_ID)?;
    println!("Read size: {}", size);
    let begin = reader.tell()?;
    let num_textures = reader.read_u32::<LE>()?;
    // TODO: Here we assume these offsets are useless, because texture entries
    // are laid out sequentially right after these offsets.
    // This might be a wrong assumption.
    for _ in 0..num_textures {
        let _offset = reader.read_u32::<LE>()?;
    }
    let mut textures = Vec::with_capacity(num_textures as usize);
    for _ in 0..num_textures {
        println!("Read texture entry @ {}", reader.tell()?);
        let unknown = reader.read_u32::<LE>()?;
        let offset = reader.read_u32::<LE>()?;
        println!("Read texture offset: {}", offset);
        textures.push(Texture {
            unknown,
            source: TextureSource::Original {
                offset: offset.into(),
            },
        });
    }
    let end = reader.tell()?;
    let total_read = end - begin;
    let true_end = reader.seek(SeekFrom::Current((size as u64 - total_read) as i64))?;
    Ok(Txtr {
        textures,
        end_offset: true_end,
    })
}

pub fn write(
    txtr: &Txtr,
    writer: &mut FileBufWrite,
    reader_orig: &mut FileBufRead,
) -> io::Result<()> {
    writer.write_all(TYPE_ID)?;
    // Write size of chunk later
    let after_size_pos = writer.seek(SeekFrom::Current(4))?;
    let len = txtr.textures.len();
    // Write number of textures
    writer.write_u32::<LE>(len as u32)?;
    // Skip writing the offsets
    let after_offset_pos = writer.seek(SeekFrom::Current((len * 4) as i64))?;
    let mut offsets = Vec::with_capacity(len);
    for tex in &txtr.textures {
        println!("Write texture entry @ {}", writer.tell()?);
        offsets.push(writer.tell()?);
        writer.write_u32::<LE>(tex.unknown)?;
        let data_offset_pos = writer.tell()?;
        // Skip over data offset, write it later.
        writer.seek(SeekFrom::Current(4))?;
        let before_write_src = writer.tell()?;
        let data_offset = write_texture_source(&tex.source, writer, reader_orig)?;
        writer.seek(SeekFrom::Start(before_write_src))?;
        writer.seek(SeekFrom::Start(data_offset_pos))?;
        writer.write_u32::<LE>(data_offset as u32)?;
        writer.seek(SeekFrom::Start(before_write_src))?;
    }
    let end_pos = writer.seek(SeekFrom::Start(txtr.end_offset))?;
    let size = end_pos - after_size_pos;
    println!("Write size: {}", size);
    writer.seek(SeekFrom::Start(after_size_pos - 4))?;
    writer.write_u32::<LE>(size as u32)?;
    writer.seek(SeekFrom::Start(after_offset_pos - (len * 4) as u64))?;
    for &offset in &offsets {
        writer.write_u32::<LE>(offset as u32)?;
    }
    writer.seek(SeekFrom::Start(txtr.end_offset))?;
    Ok(())
}

pub fn write_texture_source(
    source: &TextureSource,
    writer: &mut FileBufWrite,
    reader_orig: &mut FileBufRead,
) -> io::Result<u64> {
    match *source {
        TextureSource::Original { offset } => {
            let offset = reader_orig.seek(SeekFrom::Start(offset))?;
            println!("Writing texture data at offset {}", offset);
            let len = png_length(reader_orig)?;
            writer.seek(SeekFrom::Start(offset))?;
            io::copy(&mut reader_orig.take(len.into()), writer)?;
            Ok(offset)
        }
    }
}

fn png_length(reader: &mut FileBufRead) -> Result<u32, io::Error> {
    const MAGIC: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
    let reader_start = reader.tell()?;
    let mut buf = [0u8; 8];
    reader.read_exact(&mut buf)?;
    assert_eq!(buf, MAGIC);
    loop {
        let length = reader.read_u32::<BE>()?;
        let mut chunk_type = [0u8; 4];
        reader.read_exact(&mut chunk_type)?;
        let crc_len = 4;
        reader.seek(io::SeekFrom::Current(length as i64 + crc_len))?;
        if chunk_type == *b"IEND" {
            break;
        }
    }
    let reader_end = reader.tell()?;
    let length = reader_end - reader_start;
    reader.seek(io::SeekFrom::Start(reader_start))?;
    Ok(length as u32)
}
<commit_msg>Make non-lossy casts explicit<commit_after>use super::*;
use super::LittleEndian as LE;
use byteorder::BigEndian as BE;
use std::io::Seek;

const TYPE_ID: &'static [u8; 4] = b"TXTR";

pub fn read(reader: &mut FileBufRead) -> Result<Txtr, Box<Error>> {
    let size = expect_chunk(reader, TYPE_ID)?;
    println!("Read size: {}", size);
    let begin = reader.tell()?;
    let num_textures = reader.read_u32::<LE>()?;
    // TODO: Here we assume these offsets are useless, because texture entries
    // are laid out sequentially right after these offsets.
    // This might be a wrong assumption.
    for _ in 0..num_textures {
        let _offset = reader.read_u32::<LE>()?;
    }
    let mut textures = Vec::with_capacity(num_textures as usize);
    for _ in 0..num_textures {
        println!("Read texture entry @ {}", reader.tell()?);
        let unknown = reader.read_u32::<LE>()?;
        let offset = reader.read_u32::<LE>()?;
        println!("Read texture offset: {}", offset);
        textures.push(Texture {
            unknown,
            source: TextureSource::Original {
                offset: offset.into(),
            },
        });
    }
    let end = reader.tell()?;
    let total_read = end - begin;
    let true_end = reader.seek(SeekFrom::Current((u64::from(size) - total_read) as i64))?;
    Ok(Txtr {
        textures,
        end_offset: true_end,
    })
}

pub fn write(
    txtr: &Txtr,
    writer: &mut FileBufWrite,
    reader_orig: &mut FileBufRead,
) -> io::Result<()> {
    writer.write_all(TYPE_ID)?;
    // Write size of chunk later
    let after_size_pos = writer.seek(SeekFrom::Current(4))?;
    let len = txtr.textures.len();
    // Write number of textures
    writer.write_u32::<LE>(len as u32)?;
    // Skip writing the offsets
    let after_offset_pos = writer.seek(SeekFrom::Current((len * 4) as i64))?;
    let mut offsets = Vec::with_capacity(len);
    for tex in &txtr.textures {
        println!("Write texture entry @ {}", writer.tell()?);
        offsets.push(writer.tell()?);
        writer.write_u32::<LE>(tex.unknown)?;
        let data_offset_pos = writer.tell()?;
        // Skip over data offset, write it later.
        writer.seek(SeekFrom::Current(4))?;
        let before_write_src = writer.tell()?;
        let data_offset = write_texture_source(&tex.source, writer, reader_orig)?;
        writer.seek(SeekFrom::Start(before_write_src))?;
        writer.seek(SeekFrom::Start(data_offset_pos))?;
        writer.write_u32::<LE>(data_offset as u32)?;
        writer.seek(SeekFrom::Start(before_write_src))?;
    }
    let end_pos = writer.seek(SeekFrom::Start(txtr.end_offset))?;
    let size = end_pos - after_size_pos;
    println!("Write size: {}", size);
    writer.seek(SeekFrom::Start(after_size_pos - 4))?;
    writer.write_u32::<LE>(size as u32)?;
    writer.seek(SeekFrom::Start(after_offset_pos - (len * 4) as u64))?;
    for &offset in &offsets {
        writer.write_u32::<LE>(offset as u32)?;
    }
    writer.seek(SeekFrom::Start(txtr.end_offset))?;
    Ok(())
}

pub fn write_texture_source(
    source: &TextureSource,
    writer: &mut FileBufWrite,
    reader_orig: &mut FileBufRead,
) -> io::Result<u64> {
    match *source {
        TextureSource::Original { offset } => {
            let offset = reader_orig.seek(SeekFrom::Start(offset))?;
            println!("Writing texture data at offset {}", offset);
            let len = png_length(reader_orig)?;
            writer.seek(SeekFrom::Start(offset))?;
            io::copy(&mut reader_orig.take(len.into()), writer)?;
            Ok(offset)
        }
    }
}

fn png_length(reader: &mut FileBufRead) -> Result<u32, io::Error> {
    const MAGIC: [u8; 8] = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
    let reader_start = reader.tell()?;
    let mut buf = [0u8; 8];
    reader.read_exact(&mut buf)?;
    assert_eq!(buf, MAGIC);
    loop {
        let length = reader.read_u32::<BE>()?;
        let mut chunk_type = [0u8; 4];
        reader.read_exact(&mut chunk_type)?;
        let crc_len = 4;
        reader.seek(io::SeekFrom::Current(i64::from(length) + crc_len))?;
        if chunk_type == *b"IEND" {
            break;
        }
    }
    let reader_end = reader.tell()?;
    let length = reader_end - reader_start;
    reader.seek(io::SeekFrom::Start(reader_start))?;
    Ok(length as u32)
}
<|endoftext|>


<commit_before>// Code for creating styled buffers

use crate::snippet::{Style, StyledString};
use std::iter;

#[derive(Debug)]
pub struct StyledBuffer {
    text: Vec<Vec<char>>,
    styles: Vec<Vec<Style>>,
}

impl StyledBuffer {
    pub fn new() -> StyledBuffer {
        StyledBuffer { text: vec![], styles: vec![] }
    }

    pub fn render(&self) -> Vec<Vec<StyledString>> {
        // Tabs are assumed to have been replaced by spaces in calling code.
        debug_assert!(self.text.iter().all(|r| !r.contains(&'\t')));

        let mut output: Vec<Vec<StyledString>> = vec![];
        let mut styled_vec: Vec<StyledString> = vec![];

        for (row, row_style) in iter::zip(&self.text, &self.styles) {
            let mut current_style = Style::NoStyle;
            let mut current_text = String::new();

            for (&c, &s) in iter::zip(row, row_style) {
                if s != current_style {
                    if !current_text.is_empty() {
                        styled_vec.push(StyledString { text: current_text, style: current_style });
                    }
                    current_style = s;
                    current_text = String::new();
                }
                current_text.push(c);
            }
            if !current_text.is_empty() {
                styled_vec.push(StyledString { text: current_text, style: current_style });
            }

            // We're done with the row, push and keep going
            output.push(styled_vec);

            styled_vec = vec![];
        }

        output
    }

    fn ensure_lines(&mut self, line: usize) {
        while line >= self.text.len() {
            self.text.push(vec![]);
            self.styles.push(vec![]);
        }
    }

    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
        self.ensure_lines(line);
        if col < self.text[line].len() {
            self.text[line][col] = chr;
            self.styles[line][col] = style;
        } else {
            let mut i = self.text[line].len();
            while i < col {
                self.text[line].push(' ');
                self.styles[line].push(Style::NoStyle);
                i += 1;
            }
            self.text[line].push(chr);
            self.styles[line].push(style);
        }
    }

    pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
        let mut n = col;
        for c in string.chars() {
            self.putc(line, n, c, style);
            n += 1;
        }
    }

    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
        self.ensure_lines(line);
        let string_len = string.chars().count();

        // Push the old content over to make room for new content
        for _ in 0..string_len {
            self.styles[line].insert(0, Style::NoStyle);
            self.text[line].insert(0, ' ');
        }

        self.puts(line, 0, string, style);
    }

    pub fn append(&mut self, line: usize, string: &str, style: Style) {
        if line >= self.text.len() {
            self.puts(line, 0, string, style);
        } else {
            let col = self.text[line].len();
            self.puts(line, col, string, style);
        }
    }

    pub fn num_lines(&self) -> usize {
        self.text.len()
    }

    pub fn set_style_range(
        &mut self,
        line: usize,
        col_start: usize,
        col_end: usize,
        style: Style,
        overwrite: bool,
    ) {
        for col in col_start..col_end {
            self.set_style(line, col, style, overwrite);
        }
    }

    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
        if let Some(ref mut line) = self.styles.get_mut(line) {
            if let Some(s) = line.get_mut(col) {
                if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
                    *s = style;
                }
            }
        }
    }
}
<commit_msg>refactored StyledBuffer parts into StyledChar<commit_after>// Code for creating styled buffers

use crate::snippet::{Style, StyledString};

#[derive(Debug)]
pub struct StyledBuffer {
    text: Vec<Vec<StyledChar>>,
}

#[derive(Debug)]
struct StyledChar {
    chr: char,
    style: Style,
}

impl StyledChar {
    fn new(chr: char, style: Style) -> Self {
        StyledChar { chr, style }
    }
}

impl StyledBuffer {
    pub fn new() -> StyledBuffer {
        StyledBuffer { text: vec![] }
    }

    pub fn render(&self) -> Vec<Vec<StyledString>> {
        // Tabs are assumed to have been replaced by spaces in calling code.
        debug_assert!(self.text.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));

        let mut output: Vec<Vec<StyledString>> = vec![];
        let mut styled_vec: Vec<StyledString> = vec![];

        for styled_row in &self.text {
            let mut current_style = Style::NoStyle;
            let mut current_text = String::new();

            for sc in styled_row {
                if sc.style != current_style {
                    if !current_text.is_empty() {
                        styled_vec.push(StyledString { text: current_text, style: current_style });
                    }
                    current_style = sc.style;
                    current_text = String::new();
                }
                current_text.push(sc.chr);
            }
            if !current_text.is_empty() {
                styled_vec.push(StyledString { text: current_text, style: current_style });
            }

            // We're done with the row, push and keep going
            output.push(styled_vec);

            styled_vec = vec![];
        }

        output
    }

    fn ensure_lines(&mut self, line: usize) {
        while line >= self.text.len() {
            self.text.push(vec![]);
        }
    }

    pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
        self.ensure_lines(line);
        if col < self.text[line].len() {
            self.text[line][col] = StyledChar::new(chr, style);
        } else {
            let mut i = self.text[line].len();
            while i < col {
                self.text[line].push(StyledChar::new(' ', Style::NoStyle));
                i += 1;
            }
            self.text[line].push(StyledChar::new(chr, style));
        }
    }

    pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
        let mut n = col;
        for c in string.chars() {
            self.putc(line, n, c, style);
            n += 1;
        }
    }

    pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
        self.ensure_lines(line);
        let string_len = string.chars().count();

        // Push the old content over to make room for new content
        for _ in 0..string_len {
            self.text[line].insert(0, StyledChar::new(' ', Style::NoStyle));
        }

        self.puts(line, 0, string, style);
    }

    pub fn append(&mut self, line: usize, string: &str, style: Style) {
        if line >= self.text.len() {
            self.puts(line, 0, string, style);
        } else {
            let col = self.text[line].len();
            self.puts(line, col, string, style);
        }
    }

    pub fn num_lines(&self) -> usize {
        self.text.len()
    }

    pub fn set_style_range(
        &mut self,
        line: usize,
        col_start: usize,
        col_end: usize,
        style: Style,
        overwrite: bool,
    ) {
        for col in col_start..col_end {
            self.set_style(line, col, style, overwrite);
        }
    }

    pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
        if let Some(ref mut line) = self.text.get_mut(line) {
            if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
                if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
                    *s = style;
                }
            }
        }
    }
}
<|endoftext|>