<commit_before>//! Error handlers for Pathfinder application
//!
//! This module is intended for simplifying error handling and propagating
//! them in an existing application, easy to use and quite extendable in
//! the future.
//!

use std::error;
use std::fmt;
use std::io;
use std::result;

use config::ConfigError;
use json::JsonValue;
use strum_macros::AsStaticStr;

/// Type alias for `Result` objects that return a Pathfinder error.
pub type Result<T> = result::Result<T, PathfinderError>;

/// An enum of all possible errors which could occur during the work of reverse proxy.
#[derive(Debug, AsStaticStr)]
pub enum PathfinderError {
    /// The error that occurred during work with I/O.
    Io(io::Error),
    /// Represents all possible errors that can occur when working with
    /// configuration (reading, watching for a changes, etc.).
    SettingsError(ConfigError),
    /// Occurs when an inner structure of an endpoint is invalid.
    /// For example: missed fields or invalid format.
    InvalidEndpoint(String),
    /// Occurs when router is trying to get an access to an endpoint, that
    /// doesn't not exist.
    EndpointNotFound(String),
    /// Occurs during processing an incoming message (e.g. parsing,
    /// converting into JSON).
    DecodingError(String),
    /// The error that occurred when token isn't specified or invalid.
    AuthenticationError(String),
    /// The error that occurred with a message broker.
    MessageBrokerError(String),
    /// The error that occurred when returned an error from a microservice.
    MicroserviceError(JsonValue)
}

impl fmt::Display for PathfinderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            PathfinderError::Io(ref err) => write!(f, "IO error: {}", err),
            PathfinderError::SettingsError(ref err) => write!(f, "Settings error: {}", err),
            PathfinderError::InvalidEndpoint(ref msg) => write!(f, "Parse error: {}", msg),
            PathfinderError::EndpointNotFound(ref msg) => write!(f, "Endpoint \"{}\" was not found", msg),
            PathfinderError::DecodingError(ref msg) => write!(f, "Decoding error: {}", msg),
            PathfinderError::AuthenticationError(ref msg) => write!(f, "Authentication error: {}", msg),
            PathfinderError::MessageBrokerError(ref msg) => write!(f, "{}", msg),
            PathfinderError::MicroserviceError(ref json) => write!(f, "{:?}", json),
        }
    }
}

impl error::Error for PathfinderError {
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            PathfinderError::Io(ref err) => Some(err),
            PathfinderError::SettingsError(ref err) => Some(err),
            _ => None,
        }
    }
}

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

impl From<config::ConfigError> for PathfinderError {
    fn from(err: config::ConfigError) -> PathfinderError {
        PathfinderError::SettingsError(err)
    }
}
<commit_msg>Added a new type of errors for Lapin futures<commit_after>//! Error handlers for Pathfinder application
//!
//! This module is intended for simplifying error handling and propagating
//! them in an existing application, easy to use and quite extendable in
//! the future.
//!

use std::error;
use std::fmt;
use std::io;
use std::result;

use config::ConfigError;
use json::JsonValue;
use lapin_futures::error::{Error as LapinFuturesError};
use strum_macros::AsStaticStr;

/// Type alias for `Result` objects that return a Pathfinder error.
pub type Result<T> = result::Result<T, PathfinderError>;

/// An enum of all possible errors which could occur during the work of reverse proxy.
#[derive(Debug, AsStaticStr)]
pub enum PathfinderError {
    /// The error that occurred during work with I/O.
    Io(io::Error),
    /// Represents a Lapin client error.
    LapinError(LapinFuturesError),
    /// Represents all possible errors that can occur when working with
    /// configuration (reading, watching for a changes, etc.).
    SettingsError(ConfigError),
    /// Occurs when an inner structure of an endpoint is invalid.
    /// For example: missed fields or invalid format.
    InvalidEndpoint(String),
    /// Occurs when router is trying to get an access to an endpoint, that
    /// doesn't not exist.
    EndpointNotFound(String),
    /// Occurs during processing an incoming message (e.g. parsing,
    /// converting into JSON).
    DecodingError(String),
    /// The error that occurred when token isn't specified or invalid.
    AuthenticationError(String),
    /// The error that occurred with a message broker.
    MessageBrokerError(String),
    /// The error that occurred when returned an error from a microservice.
    MicroserviceError(JsonValue)
}

impl fmt::Display for PathfinderError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            PathfinderError::Io(ref err) => write!(f, "IO error: {}", err),
            PathfinderError::LapinError(ref err) => write!(f, "Lapin error: {}", err),
            PathfinderError::SettingsError(ref err) => write!(f, "Settings error: {}", err),
            PathfinderError::InvalidEndpoint(ref msg) => write!(f, "Parse error: {}", msg),
            PathfinderError::EndpointNotFound(ref msg) => write!(f, "Endpoint \"{}\" was not found", msg),
            PathfinderError::DecodingError(ref msg) => write!(f, "Decoding error: {}", msg),
            PathfinderError::AuthenticationError(ref msg) => write!(f, "Authentication error: {}", msg),
            PathfinderError::MessageBrokerError(ref msg) => write!(f, "{}", msg),
            PathfinderError::MicroserviceError(ref json) => write!(f, "{:?}", json),
        }
    }
}

impl error::Error for PathfinderError {
    fn cause(&self) -> Option<&error::Error> {
        match *self {
            PathfinderError::Io(ref err) => Some(err),
            PathfinderError::SettingsError(ref err) => Some(err),
            _ => None,
        }
    }
}

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

impl From<config::ConfigError> for PathfinderError {
    fn from(err: config::ConfigError) -> PathfinderError {
        PathfinderError::SettingsError(err)
    }
}
<|endoftext|>


<commit_before>
use serialize::json;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::f32::consts::{PI, SQRT2};
use std::f32::INFINITY;
use std::io::fs::File;
use std::num::Float;
use std::num::FloatMath;

use array::*;
use self::OrthoRotation::*;
use cube;
use texture::AtlasBuilder;

pub struct Vertex {
    pub xyz: [f32, ..3],
    pub uv: [f32, ..2]
}

#[deriving(Clone)]
pub enum Tint {
    None,
    Grass,
    Foliage,
    Redstone
}

pub enum OrthoRotation {
    Rotate0,
    Rotate90,
    Rotate180,
    Rotate270
}

impl OrthoRotation {
    pub fn from_json(json: &json::Json) -> Option<OrthoRotation> {
        json.as_i64().and_then(|r| Some(match r {
            0 => Rotate0,
            90 => Rotate90,
            180 => Rotate180,
            270 => Rotate270,
            _ => return None
        }))
    }
}

pub struct Face {
    pub vertices: [Vertex, ..4],
    pub tint: bool,
    pub cull_face: Option<cube::Face>,
    pub ao_face: Option<cube::Face>
}

impl Clone for Face {
    fn clone(&self) -> Face { *self }
}

#[deriving(Clone)]
enum PartialTexture {
    Variable(String),
    Coords(f32, f32)
}

#[deriving(Clone)]
pub struct PartialModel {
    textures: HashMap<String, PartialTexture>,
    faces: Vec<(Face, String)>,
    full_faces: Vec<uint>,
    no_ambient_occlusion: bool
}

#[deriving(PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Opacity {
    Transparent,
    TranslucentSolid,
    TransparentSolid,
    Opaque
}

impl Opacity {
    pub fn is_opaque(self) -> bool {
        self == Opacity::Opaque
    }

    pub fn is_solid(self) -> bool {
        self != Opacity::Transparent
    }
}

#[deriving(Clone)]
pub struct Model {
    pub faces: Vec<Face>,
    pub opacity: Opacity,
    pub tint_source: Tint
}

impl PartialModel {
    fn load<T>(name: &str, assets: &Path, atlas: &mut AtlasBuilder,
               cache: &mut HashMap<String, PartialModel>,
               f: |&PartialModel, &mut AtlasBuilder| -> T) -> T {
        match cache.get(name) {
            Some(model) => return f(model, atlas),
            None => {}
        }
        let path = assets.join(Path::new(format!("minecraft/models/{}.json", name).as_slice()));
        let json = json::from_reader(&mut File::open(&path).unwrap()).unwrap();
        let json = json.as_object().unwrap();

        let mut model = match json.find_with(|k| "parent".cmp(k.as_slice())).and_then(|x| x.as_string()) {
            Some(parent) => PartialModel::load(parent, assets, atlas, cache, |m, _| m.clone()),
            None => PartialModel {
                textures: HashMap::new(),
                faces: vec![],
                full_faces: vec![],
                no_ambient_occlusion: false
            }
        };

        match json.find_with(|k| "ambientocclusion".cmp(k.as_slice())).and_then(|x| x.as_boolean()) {
            Some(ambient_occlusion) => model.no_ambient_occlusion = !ambient_occlusion,
            None => {}
        }

        match json.find_with(|k| "textures".cmp(k.as_slice())).and_then(|x| x.as_object()) {
            Some(textures) => for (name, tex) in textures.iter() {
                let tex = tex.as_string().unwrap();
                let tex = if tex.starts_with("#") {
                    PartialTexture::Variable(tex.slice_from(1).to_string())
                } else {
                    let (u, v) = atlas.load(tex);
                    PartialTexture::Coords(u as f32, v as f32)
                };
                model.textures.insert(name.clone(), tex);
            },
            None => {}
        }
        match json.find_with(|k| "elements".cmp(k.as_slice())).and_then(|x| x.as_array()) {
            Some(elements) => for element in elements.iter().map(|x| x.as_object().unwrap()) {
                fn array3_num<T>(json: &json::Json, f: |f64| -> T) -> [T, ..3] {
                    Array::from_iter(json.as_array().unwrap().iter().map(|x| f(x.as_f64().unwrap())))
                }
                let from = array3_num(element.find_with(|k| "from".cmp(k.as_slice())).unwrap(), |x| x as f32 / 16.0);
                let to = array3_num(element.find_with(|k| "to".cmp(k.as_slice())).unwrap(), |x| x as f32 / 16.0);
                let scale = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];

                let is_full_cube = from == [0.0, 0.0, 0.0] && to == [1.0, 1.0, 1.0];
                let element_start = model.faces.len();

                for (k, v) in element.find_with(|k| "faces".cmp(k.as_slice())).unwrap().as_object().unwrap().iter() {
                    let face: cube::Face = from_str(k.as_slice()).unwrap();
                    let o = v.as_object().unwrap();
                    let [u0, v0, u1, v1] = match o.find_with(|k| "uv".cmp(k.as_slice())) {
                        Some(uv) => {
                            Array::from_iter(uv.as_array().unwrap().iter().map(|x| x.as_f64().unwrap() as f32))
                        }
                        None => match face {
                            cube::West | cube::East => [from[2], from[1], to[2], to[1]],
                            cube::Down | cube::Up => [from[0], from[2], to[0], to[2]],
                            cube::North | cube::South => [from[0], from[1], to[0], to[1]]
                        }.map(|x| x * 16.0)
                    };

                    let tex = o.find_with(|k| "texture".cmp(k.as_slice())).unwrap().as_string().unwrap();
                    assert!(tex.starts_with("#"));
                    let tex = tex.slice_from(1).to_string();

                    let cull_face = o.find_with(|k| "cullface".cmp(k.as_slice())).map(|s| {
                        from_str(s.as_string().unwrap()).unwrap()
                    });

                    if cull_face.is_some() && cull_face != Some(face) {
                        println!("odd case: cull_face = {} for face = {}", cull_face.unwrap(), face);
                    }

                    let tint = o.find_with(|k| "tintindex".cmp(k.as_slice())).map(|x| {
                        let x = x.as_i64().unwrap();
                        if x != 0 {
                            println!("odd case: tint_index = {}", x);
                        }
                    }).is_some();

                    if cull_face == Some(face) && is_full_cube {
                        model.full_faces.push(model.faces.len());
                    }

                    let rotation = o.find_with(|k| "rotation".cmp(k.as_slice())).map_or(Rotate0, |r| {
                        match OrthoRotation::from_json(r) {
                            Some(r) => r,
                            None => panic!("invalid rotation for face {}", r)
                        }
                    });

                    let xyz = face.vertices(from, scale);
                    // Swap vertical texture coordinates.
                    let [v0, v1] = [v1, v0];
                    // Bring texture coordinates closer to avoid seams.
                    let u_center = (u0 + u1) / 2.0;
                    let [u0, u1] = [u0, u1].map(|u| u - (u - u_center).signum() / 128.0);
                    let v_center = (v0 + v1) / 2.0;
                    let [v0, v1] = [v0, v1].map(|v| v - (v - v_center).signum() / 128.0);
                    // Clockwise quad (from bottom-right to top-right).
                    let uvs = [
                        [u1, v0],
                        [u0, v0],
                        [u0, v1],
                        [u1, v1]
                    ].map(|[u, v]| match rotation {
                        Rotate0 => [u, v],
                        Rotate90 => [v, 16.0 - u],
                        Rotate180 => [16.0 - u, 16.0 - v],
                        Rotate270 => [16.0 - v, u]
                    });

                    model.faces.push((Face {
                        vertices: Array::from_fn(|i| Vertex { xyz: xyz[i], uv: uvs[i] }),
                        tint: tint,
                        cull_face: cull_face,
                        ao_face: Some(face)
                    }, tex));
                }

                match element.find_with(|k| "rotation".cmp(k.as_slice())) {
                    Some(r) => {
                        let r = r.as_object().unwrap();
                        let angle = r.find_with(|k| "angle".cmp(k.as_slice())).unwrap().as_f64().unwrap();
                        let angle = angle as f32 / 180.0 * PI;
                        let rescale = r.find_with(|k| "rescale".cmp(k.as_slice())).map_or(false, |x| x.as_boolean().unwrap());
                        let origin = array3_num(r.find_with(|k| "origin".cmp(k.as_slice())).unwrap(), |x| x as f32 / 16.0);

                        let (s, c) = (angle.sin(), angle.cos());
                        let rot = |ix, iy| {
                            for &(ref mut face, _) in model.faces.slice_from_mut(element_start).iter_mut() {
                                face.ao_face = None;

                                let [ox, oy] = [origin[ix], origin[iy]];
                                for v in face.vertices.iter_mut() {
                                    let [x, y] = [v.xyz[ix] - ox, v.xyz[iy] - oy];
                                    v.xyz[ix] = x * c + y * s;
                                    v.xyz[iy] =-x * s + y * c;
                                }

                                if rescale {
                                    for v in face.vertices.iter_mut() {
                                        v.xyz[ix] *= SQRT2;
                                        v.xyz[iy] *= SQRT2;
                                    }
                                }

                                for v in face.vertices.iter_mut() {
                                    v.xyz[ix] += ox;
                                    v.xyz[iy] += oy;
                                }
                            }
                        };
                        match r.find_with(|k| "axis".cmp(k.as_slice())).unwrap().as_string().unwrap() {
                            "x" => rot(2, 1),
                            "y" => rot(0, 2),
                            "z" => rot(1, 0),
                            axis => panic!("invalid rotation axis {}", axis)
                        }
                    }
                    None => {}
                }
            },
            None => {}
        }

        match cache.entry(name.to_string()) {
            Occupied(entry) => f(entry.get(), atlas),
            Vacant(entry) => f(entry.set(model), atlas)
        }
    }
}

impl Model {
    pub fn load(name: &str, assets: &Path, atlas: &mut AtlasBuilder,
                cache: &mut HashMap<String, PartialModel>) -> Model {
        PartialModel::load(format!("block/{}", name).as_slice(), assets, atlas, cache, |partial, atlas| {
            let mut faces: Vec<Face> = partial.faces.iter().map(|&(mut face, ref tex)| {
                fn texture_coords(textures: &HashMap<String, PartialTexture>,
                                  tex: &String) -> Option<(f32, f32)> {
                    match textures.get(tex) {
                        Some(&PartialTexture::Variable(ref tex)) => texture_coords(textures, tex),
                        Some(&PartialTexture::Coords(u, v)) => Some((u, v)),
                        None => None
                    }
                }
                let (u, v) = texture_coords(&partial.textures, tex).unwrap();
                for vertex in face.vertices.iter_mut() {
                    vertex.uv[0] += u;
                    vertex.uv[1] += v;
                }
                face
            }).collect();

            let mut full_faces = [Opacity::Transparent, ..6];
            if partial.full_faces.len() >= 6 {
                for &i in partial.full_faces.iter() {
                    let face = faces[i].cull_face.unwrap() as uint;
                    if full_faces[face] == Opacity::Opaque {
                        continue;
                    }
                    let (mut min_u, mut min_v) = (INFINITY, INFINITY);
                    let (mut max_u, mut max_v) = (0.0, 0.0);
                    for vertex in faces[i].vertices.iter() {
                        let [u, v] = vertex.uv;
                        min_u = u.min(min_u);
                        min_v = v.min(min_v);
                        max_u = u.max(max_u);
                        max_v = v.max(max_v);
                    }
                    let (u0, v0) = (min_u.floor() as u32, min_v.floor() as u32);
                    let (u1, v1) = (max_u.ceil() as u32, max_v.ceil() as u32);
                    let rect = [u0, v0, u1 - u0, v1 - v0];
                    let opacity = match atlas.min_alpha(rect) {
                        0 => Opacity::TransparentSolid,
                        255 => Opacity::Opaque,
                        _ => Opacity::TranslucentSolid
                    };
                    if full_faces[face] < opacity {
                        full_faces[face] = opacity;
                    }
                }
            }

            if !partial.no_ambient_occlusion {
                if faces.iter().any(|f| f.ao_face.is_none()) {
                    println!("Warning: model {} uses AO but has faces which are unsuitable", name);
                }
            } else {
                for face in faces.iter_mut() {
                    face.ao_face = None;
                }
            }

            let tint_source = if faces.iter().any(|f| f.tint) {
                match name {
                    name if name.starts_with("grass_") ||
                            name.starts_with("double_grass_") ||
                            name.starts_with("double_fern_") => Tint::Grass,
                    "reeds" | "fern" | "tall_grass" => Tint::Grass,
                    name if name.ends_with("_leaves") || name.ends_with("_stem_fruit") ||
                            name.starts_with("vine_") || name.starts_with("stem_") => Tint::Foliage,
                    "waterlily" => Tint::Foliage,
                    name if name.starts_with("redstone_") => Tint::Redstone,
                    _ => {
                        println!("tint source not known for '{}'", name);
                        Tint::None
                    }
                }
            } else {
                Tint::None
            };

            Model {
                faces: faces,
                opacity: *full_faces.iter().min().unwrap(),
                tint_source: tint_source
            }
        })
    }

    pub fn empty() -> Model {
        Model {
            faces: Vec::new(),
            opacity: Opacity::Transparent,
            tint_source: Tint::None
        }
    }

    pub fn is_empty(&self) -> bool {
        self.faces.is_empty()
    }
}
<commit_msg>Added some missing Copy implementations<commit_after>
use serialize::json;
use std::collections::HashMap;
use std::collections::hash_map::Entry::{ Occupied, Vacant };
use std::f32::consts::{PI, SQRT2};
use std::f32::INFINITY;
use std::io::fs::File;
use std::num::Float;
use std::num::FloatMath;

use array::*;
use self::OrthoRotation::*;
use cube;
use texture::AtlasBuilder;

#[deriving(Copy)]
pub struct Vertex {
    pub xyz: [f32, ..3],
    pub uv: [f32, ..2]
}

#[deriving(Copy, Clone)]
pub enum Tint {
    None,
    Grass,
    Foliage,
    Redstone
}

#[deriving(Copy)]
pub enum OrthoRotation {
    Rotate0,
    Rotate90,
    Rotate180,
    Rotate270
}

impl OrthoRotation {
    pub fn from_json(json: &json::Json) -> Option<OrthoRotation> {
        json.as_i64().and_then(|r| Some(match r {
            0 => Rotate0,
            90 => Rotate90,
            180 => Rotate180,
            270 => Rotate270,
            _ => return None
        }))
    }
}

#[deriving(Copy)]
pub struct Face {
    pub vertices: [Vertex, ..4],
    pub tint: bool,
    pub cull_face: Option<cube::Face>,
    pub ao_face: Option<cube::Face>
}

impl Clone for Face {
    fn clone(&self) -> Face { *self }
}

#[deriving(Clone)]
enum PartialTexture {
    Variable(String),
    Coords(f32, f32)
}

#[deriving(Clone)]
pub struct PartialModel {
    textures: HashMap<String, PartialTexture>,
    faces: Vec<(Face, String)>,
    full_faces: Vec<uint>,
    no_ambient_occlusion: bool
}

#[deriving(Copy, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub enum Opacity {
    Transparent,
    TranslucentSolid,
    TransparentSolid,
    Opaque
}

impl Opacity {
    pub fn is_opaque(self) -> bool {
        self == Opacity::Opaque
    }

    pub fn is_solid(self) -> bool {
        self != Opacity::Transparent
    }
}

#[deriving(Clone)]
pub struct Model {
    pub faces: Vec<Face>,
    pub opacity: Opacity,
    pub tint_source: Tint
}

impl PartialModel {
    fn load<T>(name: &str, assets: &Path, atlas: &mut AtlasBuilder,
               cache: &mut HashMap<String, PartialModel>,
               f: |&PartialModel, &mut AtlasBuilder| -> T) -> T {
        match cache.get(name) {
            Some(model) => return f(model, atlas),
            None => {}
        }
        let path = assets.join(Path::new(format!("minecraft/models/{}.json", name).as_slice()));
        let json = json::from_reader(&mut File::open(&path).unwrap()).unwrap();
        let json = json.as_object().unwrap();

        let mut model = match json.find_with(|k| "parent".cmp(k.as_slice())).and_then(|x| x.as_string()) {
            Some(parent) => PartialModel::load(parent, assets, atlas, cache, |m, _| m.clone()),
            None => PartialModel {
                textures: HashMap::new(),
                faces: vec![],
                full_faces: vec![],
                no_ambient_occlusion: false
            }
        };

        match json.find_with(|k| "ambientocclusion".cmp(k.as_slice())).and_then(|x| x.as_boolean()) {
            Some(ambient_occlusion) => model.no_ambient_occlusion = !ambient_occlusion,
            None => {}
        }

        match json.find_with(|k| "textures".cmp(k.as_slice())).and_then(|x| x.as_object()) {
            Some(textures) => for (name, tex) in textures.iter() {
                let tex = tex.as_string().unwrap();
                let tex = if tex.starts_with("#") {
                    PartialTexture::Variable(tex.slice_from(1).to_string())
                } else {
                    let (u, v) = atlas.load(tex);
                    PartialTexture::Coords(u as f32, v as f32)
                };
                model.textures.insert(name.clone(), tex);
            },
            None => {}
        }
        match json.find_with(|k| "elements".cmp(k.as_slice())).and_then(|x| x.as_array()) {
            Some(elements) => for element in elements.iter().map(|x| x.as_object().unwrap()) {
                fn array3_num<T>(json: &json::Json, f: |f64| -> T) -> [T, ..3] {
                    Array::from_iter(json.as_array().unwrap().iter().map(|x| f(x.as_f64().unwrap())))
                }
                let from = array3_num(element.find_with(|k| "from".cmp(k.as_slice())).unwrap(), |x| x as f32 / 16.0);
                let to = array3_num(element.find_with(|k| "to".cmp(k.as_slice())).unwrap(), |x| x as f32 / 16.0);
                let scale = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];

                let is_full_cube = from == [0.0, 0.0, 0.0] && to == [1.0, 1.0, 1.0];
                let element_start = model.faces.len();

                for (k, v) in element.find_with(|k| "faces".cmp(k.as_slice())).unwrap().as_object().unwrap().iter() {
                    let face: cube::Face = from_str(k.as_slice()).unwrap();
                    let o = v.as_object().unwrap();
                    let [u0, v0, u1, v1] = match o.find_with(|k| "uv".cmp(k.as_slice())) {
                        Some(uv) => {
                            Array::from_iter(uv.as_array().unwrap().iter().map(|x| x.as_f64().unwrap() as f32))
                        }
                        None => match face {
                            cube::West | cube::East => [from[2], from[1], to[2], to[1]],
                            cube::Down | cube::Up => [from[0], from[2], to[0], to[2]],
                            cube::North | cube::South => [from[0], from[1], to[0], to[1]]
                        }.map(|x| x * 16.0)
                    };

                    let tex = o.find_with(|k| "texture".cmp(k.as_slice())).unwrap().as_string().unwrap();
                    assert!(tex.starts_with("#"));
                    let tex = tex.slice_from(1).to_string();

                    let cull_face = o.find_with(|k| "cullface".cmp(k.as_slice())).map(|s| {
                        from_str(s.as_string().unwrap()).unwrap()
                    });

                    if cull_face.is_some() && cull_face != Some(face) {
                        println!("odd case: cull_face = {} for face = {}", cull_face.unwrap(), face);
                    }

                    let tint = o.find_with(|k| "tintindex".cmp(k.as_slice())).map(|x| {
                        let x = x.as_i64().unwrap();
                        if x != 0 {
                            println!("odd case: tint_index = {}", x);
                        }
                    }).is_some();

                    if cull_face == Some(face) && is_full_cube {
                        model.full_faces.push(model.faces.len());
                    }

                    let rotation = o.find_with(|k| "rotation".cmp(k.as_slice())).map_or(Rotate0, |r| {
                        match OrthoRotation::from_json(r) {
                            Some(r) => r,
                            None => panic!("invalid rotation for face {}", r)
                        }
                    });

                    let xyz = face.vertices(from, scale);
                    // Swap vertical texture coordinates.
                    let [v0, v1] = [v1, v0];
                    // Bring texture coordinates closer to avoid seams.
                    let u_center = (u0 + u1) / 2.0;
                    let [u0, u1] = [u0, u1].map(|u| u - (u - u_center).signum() / 128.0);
                    let v_center = (v0 + v1) / 2.0;
                    let [v0, v1] = [v0, v1].map(|v| v - (v - v_center).signum() / 128.0);
                    // Clockwise quad (from bottom-right to top-right).
                    let uvs = [
                        [u1, v0],
                        [u0, v0],
                        [u0, v1],
                        [u1, v1]
                    ].map(|[u, v]| match rotation {
                        Rotate0 => [u, v],
                        Rotate90 => [v, 16.0 - u],
                        Rotate180 => [16.0 - u, 16.0 - v],
                        Rotate270 => [16.0 - v, u]
                    });

                    model.faces.push((Face {
                        vertices: Array::from_fn(|i| Vertex { xyz: xyz[i], uv: uvs[i] }),
                        tint: tint,
                        cull_face: cull_face,
                        ao_face: Some(face)
                    }, tex));
                }

                match element.find_with(|k| "rotation".cmp(k.as_slice())) {
                    Some(r) => {
                        let r = r.as_object().unwrap();
                        let angle = r.find_with(|k| "angle".cmp(k.as_slice())).unwrap().as_f64().unwrap();
                        let angle = angle as f32 / 180.0 * PI;
                        let rescale = r.find_with(|k| "rescale".cmp(k.as_slice())).map_or(false, |x| x.as_boolean().unwrap());
                        let origin = array3_num(r.find_with(|k| "origin".cmp(k.as_slice())).unwrap(), |x| x as f32 / 16.0);

                        let (s, c) = (angle.sin(), angle.cos());
                        let rot = |ix, iy| {
                            for &(ref mut face, _) in model.faces.slice_from_mut(element_start).iter_mut() {
                                face.ao_face = None;

                                let [ox, oy] = [origin[ix], origin[iy]];
                                for v in face.vertices.iter_mut() {
                                    let [x, y] = [v.xyz[ix] - ox, v.xyz[iy] - oy];
                                    v.xyz[ix] = x * c + y * s;
                                    v.xyz[iy] =-x * s + y * c;
                                }

                                if rescale {
                                    for v in face.vertices.iter_mut() {
                                        v.xyz[ix] *= SQRT2;
                                        v.xyz[iy] *= SQRT2;
                                    }
                                }

                                for v in face.vertices.iter_mut() {
                                    v.xyz[ix] += ox;
                                    v.xyz[iy] += oy;
                                }
                            }
                        };
                        match r.find_with(|k| "axis".cmp(k.as_slice())).unwrap().as_string().unwrap() {
                            "x" => rot(2, 1),
                            "y" => rot(0, 2),
                            "z" => rot(1, 0),
                            axis => panic!("invalid rotation axis {}", axis)
                        }
                    }
                    None => {}
                }
            },
            None => {}
        }

        match cache.entry(name.to_string()) {
            Occupied(entry) => f(entry.get(), atlas),
            Vacant(entry) => f(entry.set(model), atlas)
        }
    }
}

impl Model {
    pub fn load(name: &str, assets: &Path, atlas: &mut AtlasBuilder,
                cache: &mut HashMap<String, PartialModel>) -> Model {
        PartialModel::load(format!("block/{}", name).as_slice(), assets, atlas, cache, |partial, atlas| {
            let mut faces: Vec<Face> = partial.faces.iter().map(|&(mut face, ref tex)| {
                fn texture_coords(textures: &HashMap<String, PartialTexture>,
                                  tex: &String) -> Option<(f32, f32)> {
                    match textures.get(tex) {
                        Some(&PartialTexture::Variable(ref tex)) => texture_coords(textures, tex),
                        Some(&PartialTexture::Coords(u, v)) => Some((u, v)),
                        None => None
                    }
                }
                let (u, v) = texture_coords(&partial.textures, tex).unwrap();
                for vertex in face.vertices.iter_mut() {
                    vertex.uv[0] += u;
                    vertex.uv[1] += v;
                }
                face
            }).collect();

            let mut full_faces = [Opacity::Transparent, ..6];
            if partial.full_faces.len() >= 6 {
                for &i in partial.full_faces.iter() {
                    let face = faces[i].cull_face.unwrap() as uint;
                    if full_faces[face] == Opacity::Opaque {
                        continue;
                    }
                    let (mut min_u, mut min_v) = (INFINITY, INFINITY);
                    let (mut max_u, mut max_v) = (0.0, 0.0);
                    for vertex in faces[i].vertices.iter() {
                        let [u, v] = vertex.uv;
                        min_u = u.min(min_u);
                        min_v = v.min(min_v);
                        max_u = u.max(max_u);
                        max_v = v.max(max_v);
                    }
                    let (u0, v0) = (min_u.floor() as u32, min_v.floor() as u32);
                    let (u1, v1) = (max_u.ceil() as u32, max_v.ceil() as u32);
                    let rect = [u0, v0, u1 - u0, v1 - v0];
                    let opacity = match atlas.min_alpha(rect) {
                        0 => Opacity::TransparentSolid,
                        255 => Opacity::Opaque,
                        _ => Opacity::TranslucentSolid
                    };
                    if full_faces[face] < opacity {
                        full_faces[face] = opacity;
                    }
                }
            }

            if !partial.no_ambient_occlusion {
                if faces.iter().any(|f| f.ao_face.is_none()) {
                    println!("Warning: model {} uses AO but has faces which are unsuitable", name);
                }
            } else {
                for face in faces.iter_mut() {
                    face.ao_face = None;
                }
            }

            let tint_source = if faces.iter().any(|f| f.tint) {
                match name {
                    name if name.starts_with("grass_") ||
                            name.starts_with("double_grass_") ||
                            name.starts_with("double_fern_") => Tint::Grass,
                    "reeds" | "fern" | "tall_grass" => Tint::Grass,
                    name if name.ends_with("_leaves") || name.ends_with("_stem_fruit") ||
                            name.starts_with("vine_") || name.starts_with("stem_") => Tint::Foliage,
                    "waterlily" => Tint::Foliage,
                    name if name.starts_with("redstone_") => Tint::Redstone,
                    _ => {
                        println!("tint source not known for '{}'", name);
                        Tint::None
                    }
                }
            } else {
                Tint::None
            };

            Model {
                faces: faces,
                opacity: *full_faces.iter().min().unwrap(),
                tint_source: tint_source
            }
        })
    }

    pub fn empty() -> Model {
        Model {
            faces: Vec::new(),
            opacity: Opacity::Transparent,
            tint_source: Tint::None
        }
    }

    pub fn is_empty(&self) -> bool {
        self.faces.is_empty()
    }
}
<|endoftext|>


<commit_before>use output::Colours;

use options::{flags, Misfire};
use options::parser::MatchedFlags;

/// Under what circumstances we should display coloured, rather than plain,
/// output to the terminal.
///
/// By default, we want to display the colours when stdout can display them.
/// Turning them on when output is going to, say, a pipe, would make programs
/// such as `grep` or `more` not work properly. So the `Automatic` mode does
/// this check and only displays colours when they can be truly appreciated.
#[derive(PartialEq, Debug)]
enum TerminalColours {

    /// Display them even when output isn’t going to a terminal.
    Always,

    /// Display them when output is going to a terminal, but not otherwise.
    Automatic,

    /// Never display them, even when output is going to a terminal.
    Never,
}

impl Default for TerminalColours {
    fn default() -> TerminalColours {
        TerminalColours::Automatic
    }
}

const COLOURS: &[&str] = &["always", "auto", "never"];

impl TerminalColours {

    /// Determine which terminal colour conditions to use.
    fn deduce(matches: &MatchedFlags) -> Result<TerminalColours, Misfire> {

        let word = match matches.get_where(|f| f.matches(&flags::COLOR) || f.matches(&flags::COLOUR))? {
            Some(w) => w,
            None    => return Ok(TerminalColours::default()),
        };

        if word == "always" {
            Ok(TerminalColours::Always)
        }
        else if word == "auto" || word == "automatic" {
            Ok(TerminalColours::Automatic)
        }
        else if word == "never" {
            Ok(TerminalColours::Never)
        }
        else {
            Err(Misfire::bad_argument(&flags::COLOR, word, COLOURS))
        }
    }
}

impl Colours {
    pub fn deduce<TW>(matches: &MatchedFlags, widther: TW) -> Result<Colours, Misfire>
    where TW: Fn() -> Option<usize> {
        use self::TerminalColours::*;

        let tc = TerminalColours::deduce(matches)?;
        if tc == Always || (tc == Automatic && widther().is_some()) {
            let scale = matches.has_where(|f| f.matches(&flags::COLOR_SCALE) || f.matches(&flags::COLOUR_SCALE))?;
            Ok(Colours::colourful(scale.is_some()))
        }
        else {
            Ok(Colours::plain())
        }
    }
}

#[cfg(test)]
mod terminal_test {
    use super::*;
    use std::ffi::OsString;
    use options::flags;
    use options::parser::{Flag, Arg};

    use options::test::parse_for_test;
    use options::test::Strictnesses::*;

    pub fn os(input: &'static str) -> OsString {
        let mut os = OsString::new();
        os.push(input);
        os
    }

    static TEST_ARGS: &[&Arg] = &[ &flags::COLOR, &flags::COLOUR ];

    macro_rules! test {
        ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
            /// Macro that writes a test.
            /// If testing both strictnesses, they’ll both be done in the same function.
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
                    assert_eq!(result, $result);
                }
            }
        };

        ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => err $result:expr) => {
            /// Special macro for testing Err results.
            /// This is needed because sometimes the Ok type doesn’t implement PartialEq.
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
                    assert_eq!(result.unwrap_err(), $result);
                }
            }
        };
    }

    // Default
    test!(empty:        TerminalColours <- [];                     Both => Ok(TerminalColours::default()));

    // --colour
    test!(u_always:     TerminalColours <- ["--colour=always"];    Both => Ok(TerminalColours::Always));
    test!(u_auto:       TerminalColours <- ["--colour", "auto"];   Both => Ok(TerminalColours::Automatic));
    test!(u_never:      TerminalColours <- ["--colour=never"];     Both => Ok(TerminalColours::Never));

    // --color
    test!(no_u_always:  TerminalColours <- ["--color", "always"];  Both => Ok(TerminalColours::Always));
    test!(no_u_auto:    TerminalColours <- ["--color=auto"];       Both => Ok(TerminalColours::Automatic));
    test!(no_u_never:   TerminalColours <- ["--color", "never"];   Both => Ok(TerminalColours::Never));

    // Errors
    test!(no_u_error:   TerminalColours <- ["--color=upstream"];   Both => err Misfire::bad_argument(&flags::COLOR, &os("upstream"), super::COLOURS));  // the error is for --color
    test!(u_error:      TerminalColours <- ["--colour=lovers"];    Both => err Misfire::bad_argument(&flags::COLOR, &os("lovers"),   super::COLOURS));  // and so is this one!

    // Overriding
    test!(overridden_1: TerminalColours <- ["--colour=auto", "--colour=never"];  Last => Ok(TerminalColours::Never));
    test!(overridden_2: TerminalColours <- ["--color=auto",  "--colour=never"];  Last => Ok(TerminalColours::Never));
    test!(overridden_3: TerminalColours <- ["--colour=auto", "--color=never"];   Last => Ok(TerminalColours::Never));
    test!(overridden_4: TerminalColours <- ["--color=auto",  "--color=never"];   Last => Ok(TerminalColours::Never));

    test!(overridden_5: TerminalColours <- ["--colour=auto", "--colour=never"];  Complain => err Misfire::Duplicate(Flag::Long("colour"), Flag::Long("colour")));
    test!(overridden_6: TerminalColours <- ["--color=auto",  "--colour=never"];  Complain => err Misfire::Duplicate(Flag::Long("color"),  Flag::Long("colour")));
    test!(overridden_7: TerminalColours <- ["--colour=auto", "--color=never"];   Complain => err Misfire::Duplicate(Flag::Long("colour"), Flag::Long("color")));
    test!(overridden_8: TerminalColours <- ["--color=auto",  "--color=never"];   Complain => err Misfire::Duplicate(Flag::Long("color"),  Flag::Long("color")));
}

#[cfg(test)]
mod colour_test {
    use super::*;
    use options::flags;
    use options::parser::{Flag, Arg};

    use options::test::parse_for_test;
    use options::test::Strictnesses::*;

    static TEST_ARGS: &[&Arg] = &[ &flags::COLOR,       &flags::COLOUR,
                                   &flags::COLOR_SCALE, &flags::COLOUR_SCALE ];

    macro_rules! test {
        ($name:ident: $type:ident <- $inputs:expr, $widther:expr; $stricts:expr => err $result:expr) => {
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$widther)) {
                    assert_eq!(result.unwrap_err(), $result);
                }
            }
        };

        ($name:ident: $type:ident <- $inputs:expr, $widther:expr; $stricts:expr => like $pat:pat) => {
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$widther)) {
                    println!("Testing {:?}", result);
                    match result {
                        $pat => assert!(true),
                        _    => assert!(false),
                    }
                }
            }
        };
    }

    test!(scale_1: Colours <- ["--color=always", "--color-scale", "--colour-scale"], || None;   Last => like Ok(Colours { scale: true,  .. }));
    test!(scale_2: Colours <- ["--color=always", "--color-scale",                 ], || None;   Last => like Ok(Colours { scale: true,  .. }));
    test!(scale_3: Colours <- ["--color=always",                  "--colour-scale"], || None;   Last => like Ok(Colours { scale: true,  .. }));
    test!(scale_4: Colours <- ["--color=always",                                  ], || None;   Last => like Ok(Colours { scale: false, .. }));

    test!(scale_5: Colours <- ["--color=always", "--color-scale", "--colour-scale"], || None;   Complain => err Misfire::Duplicate(Flag::Long("color-scale"),  Flag::Long("colour-scale")));
    test!(scale_6: Colours <- ["--color=always", "--color-scale",                 ], || None;   Complain => like Ok(Colours { scale: true,  .. }));
    test!(scale_7: Colours <- ["--color=always",                  "--colour-scale"], || None;   Complain => like Ok(Colours { scale: true,  .. }));
    test!(scale_8: Colours <- ["--color=always",                                  ], || None;   Complain => like Ok(Colours { scale: false, .. }));
}
<commit_msg>Tests for turning colours on/off<commit_after>use output::Colours;

use options::{flags, Misfire};
use options::parser::MatchedFlags;

/// Under what circumstances we should display coloured, rather than plain,
/// output to the terminal.
///
/// By default, we want to display the colours when stdout can display them.
/// Turning them on when output is going to, say, a pipe, would make programs
/// such as `grep` or `more` not work properly. So the `Automatic` mode does
/// this check and only displays colours when they can be truly appreciated.
#[derive(PartialEq, Debug)]
enum TerminalColours {

    /// Display them even when output isn’t going to a terminal.
    Always,

    /// Display them when output is going to a terminal, but not otherwise.
    Automatic,

    /// Never display them, even when output is going to a terminal.
    Never,
}

impl Default for TerminalColours {
    fn default() -> TerminalColours {
        TerminalColours::Automatic
    }
}

const COLOURS: &[&str] = &["always", "auto", "never"];

impl TerminalColours {

    /// Determine which terminal colour conditions to use.
    fn deduce(matches: &MatchedFlags) -> Result<TerminalColours, Misfire> {

        let word = match matches.get_where(|f| f.matches(&flags::COLOR) || f.matches(&flags::COLOUR))? {
            Some(w) => w,
            None    => return Ok(TerminalColours::default()),
        };

        if word == "always" {
            Ok(TerminalColours::Always)
        }
        else if word == "auto" || word == "automatic" {
            Ok(TerminalColours::Automatic)
        }
        else if word == "never" {
            Ok(TerminalColours::Never)
        }
        else {
            Err(Misfire::bad_argument(&flags::COLOR, word, COLOURS))
        }
    }
}

impl Colours {
    pub fn deduce<TW>(matches: &MatchedFlags, widther: TW) -> Result<Colours, Misfire>
    where TW: Fn() -> Option<usize> {
        use self::TerminalColours::*;

        let tc = TerminalColours::deduce(matches)?;
        if tc == Always || (tc == Automatic && widther().is_some()) {
            let scale = matches.has_where(|f| f.matches(&flags::COLOR_SCALE) || f.matches(&flags::COLOUR_SCALE))?;
            Ok(Colours::colourful(scale.is_some()))
        }
        else {
            Ok(Colours::plain())
        }
    }
}

#[cfg(test)]
mod terminal_test {
    use super::*;
    use std::ffi::OsString;
    use options::flags;
    use options::parser::{Flag, Arg};

    use options::test::parse_for_test;
    use options::test::Strictnesses::*;

    pub fn os(input: &'static str) -> OsString {
        let mut os = OsString::new();
        os.push(input);
        os
    }

    static TEST_ARGS: &[&Arg] = &[ &flags::COLOR, &flags::COLOUR ];

    macro_rules! test {
        ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => $result:expr) => {
            /// Macro that writes a test.
            /// If testing both strictnesses, they’ll both be done in the same function.
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
                    assert_eq!(result, $result);
                }
            }
        };

        ($name:ident: $type:ident <- $inputs:expr; $stricts:expr => err $result:expr) => {
            /// Special macro for testing Err results.
            /// This is needed because sometimes the Ok type doesn’t implement PartialEq.
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf)) {
                    assert_eq!(result.unwrap_err(), $result);
                }
            }
        };
    }

    // Default
    test!(empty:        TerminalColours <- [];                     Both => Ok(TerminalColours::default()));

    // --colour
    test!(u_always:     TerminalColours <- ["--colour=always"];    Both => Ok(TerminalColours::Always));
    test!(u_auto:       TerminalColours <- ["--colour", "auto"];   Both => Ok(TerminalColours::Automatic));
    test!(u_never:      TerminalColours <- ["--colour=never"];     Both => Ok(TerminalColours::Never));

    // --color
    test!(no_u_always:  TerminalColours <- ["--color", "always"];  Both => Ok(TerminalColours::Always));
    test!(no_u_auto:    TerminalColours <- ["--color=auto"];       Both => Ok(TerminalColours::Automatic));
    test!(no_u_never:   TerminalColours <- ["--color", "never"];   Both => Ok(TerminalColours::Never));

    // Errors
    test!(no_u_error:   TerminalColours <- ["--color=upstream"];   Both => err Misfire::bad_argument(&flags::COLOR, &os("upstream"), super::COLOURS));  // the error is for --color
    test!(u_error:      TerminalColours <- ["--colour=lovers"];    Both => err Misfire::bad_argument(&flags::COLOR, &os("lovers"),   super::COLOURS));  // and so is this one!

    // Overriding
    test!(overridden_1: TerminalColours <- ["--colour=auto", "--colour=never"];  Last => Ok(TerminalColours::Never));
    test!(overridden_2: TerminalColours <- ["--color=auto",  "--colour=never"];  Last => Ok(TerminalColours::Never));
    test!(overridden_3: TerminalColours <- ["--colour=auto", "--color=never"];   Last => Ok(TerminalColours::Never));
    test!(overridden_4: TerminalColours <- ["--color=auto",  "--color=never"];   Last => Ok(TerminalColours::Never));

    test!(overridden_5: TerminalColours <- ["--colour=auto", "--colour=never"];  Complain => err Misfire::Duplicate(Flag::Long("colour"), Flag::Long("colour")));
    test!(overridden_6: TerminalColours <- ["--color=auto",  "--colour=never"];  Complain => err Misfire::Duplicate(Flag::Long("color"),  Flag::Long("colour")));
    test!(overridden_7: TerminalColours <- ["--colour=auto", "--color=never"];   Complain => err Misfire::Duplicate(Flag::Long("colour"), Flag::Long("color")));
    test!(overridden_8: TerminalColours <- ["--color=auto",  "--color=never"];   Complain => err Misfire::Duplicate(Flag::Long("color"),  Flag::Long("color")));
}

#[cfg(test)]
mod colour_test {
    use super::*;
    use options::flags;
    use options::parser::{Flag, Arg};

    use options::test::parse_for_test;
    use options::test::Strictnesses::*;

    static TEST_ARGS: &[&Arg] = &[ &flags::COLOR,       &flags::COLOUR,
                                   &flags::COLOR_SCALE, &flags::COLOUR_SCALE ];

    macro_rules! test {
        ($name:ident: $type:ident <- $inputs:expr, $widther:expr; $stricts:expr => $result:expr) => {
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$widther)) {
                    assert_eq!(result, $result);
                }
            }
        };

        ($name:ident: $type:ident <- $inputs:expr, $widther:expr; $stricts:expr => err $result:expr) => {
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$widther)) {
                    assert_eq!(result.unwrap_err(), $result);
                }
            }
        };

        ($name:ident: $type:ident <- $inputs:expr, $widther:expr; $stricts:expr => like $pat:pat) => {
            #[test]
            fn $name() {
                for result in parse_for_test($inputs.as_ref(), TEST_ARGS, $stricts, |mf| $type::deduce(mf, &$widther)) {
                    println!("Testing {:?}", result);
                    match result {
                        $pat => assert!(true),
                        _    => assert!(false),
                    }
                }
            }
        };
    }

    test!(width_1: Colours <- ["--colour", "always"],    || Some(80);  Both => Ok(Colours::colourful(false)));
    test!(width_2: Colours <- ["--colour", "always"],    || None;      Both => Ok(Colours::colourful(false)));
    test!(width_3: Colours <- ["--colour", "never"],     || Some(80);  Both => Ok(Colours::plain()));
    test!(width_4: Colours <- ["--colour", "never"],     || None;      Both => Ok(Colours::plain()));
    test!(width_5: Colours <- ["--colour", "automatic"], || Some(80);  Both => Ok(Colours::colourful(false)));
    test!(width_6: Colours <- ["--colour", "automatic"], || None;      Both => Ok(Colours::plain()));
    test!(width_7: Colours <- [],                        || Some(80);  Both => Ok(Colours::colourful(false)));
    test!(width_8: Colours <- [],                        || None;      Both => Ok(Colours::plain()));

    test!(scale_1: Colours <- ["--color=always", "--color-scale", "--colour-scale"], || None;   Last => like Ok(Colours { scale: true,  .. }));
    test!(scale_2: Colours <- ["--color=always", "--color-scale",                 ], || None;   Last => like Ok(Colours { scale: true,  .. }));
    test!(scale_3: Colours <- ["--color=always",                  "--colour-scale"], || None;   Last => like Ok(Colours { scale: true,  .. }));
    test!(scale_4: Colours <- ["--color=always",                                  ], || None;   Last => like Ok(Colours { scale: false, .. }));

    test!(scale_5: Colours <- ["--color=always", "--color-scale", "--colour-scale"], || None;   Complain => err Misfire::Duplicate(Flag::Long("color-scale"),  Flag::Long("colour-scale")));
    test!(scale_6: Colours <- ["--color=always", "--color-scale",                 ], || None;   Complain => like Ok(Colours { scale: true,  .. }));
    test!(scale_7: Colours <- ["--color=always",                  "--colour-scale"], || None;   Complain => like Ok(Colours { scale: true,  .. }));
    test!(scale_8: Colours <- ["--color=always",                                  ], || None;   Complain => like Ok(Colours { scale: false, .. }));
}
<|endoftext|>


<commit_before>use std::borrow::Borrow;
use std::collections::hash_map::{self, Entry};
use std::collections::HashMap;
use std::hash::Hash;
use std::iter::IntoIterator;

#[derive(Debug)]
pub struct OrderedHashMap<K, V> {
    #[doc(hidden)]
    base: HashMap<K, V>,
    order: Vec<K>,
}

pub struct Iter<'a, K, V> {
    #[doc(hidden)]
    base: &'a HashMap<K, V>,
    order_iterator: std::slice::Iter<'a, K>,
}

pub struct IntoIter<K, V> {
    #[doc(hidden)]
    base: HashMap<K, V>,
    order_iterator: std::vec::IntoIter<K>,
}

pub type IterMut<'a, K, V> = hash_map::IterMut<'a, K, V>;

impl<'a, K, V> IntoIterator for &'a OrderedHashMap<K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a V);
    type IntoIter = Iter<'a, K, V>;

    fn into_iter(self) -> Self::IntoIter {
        Iter { base: &self.base, order_iterator: self.order.iter() }
    }
}

impl<K, V> IntoIterator for OrderedHashMap<K, V>
where
    K: Eq + Hash,
{
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter { base: self.base, order_iterator: self.order.into_iter() }
    }
}

impl<'a, K, V> Iterator for Iter<'a, K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        match self.order_iterator.next() {
            Some(k) => self.base.get_key_value(&k),
            None => None,
        }
    }
}

impl<K, V> Iterator for IntoIter<K, V>
where
    K: Eq + Hash,
{
    type Item = (K, V);
    fn next(&mut self) -> Option<Self::Item> {
        match self.order_iterator.next() {
            Some(k) => self.base.remove_entry(&k),
            None => None,
        }
    }
}

impl<K, V> Default for OrderedHashMap<K, V>
where
    K: Eq + Hash + Clone,
{
    fn default() -> Self {
        Self::new()
    }
}

impl<K, V> OrderedHashMap<K, V>
where
    K: Eq + Hash + Clone,
{
    pub fn new() -> OrderedHashMap<K, V> {
        OrderedHashMap { base: HashMap::<K, V>::new(), order: Vec::<K>::new() }
    }

    pub fn get<Q>(&self, k: &Q) -> Option<&V>
    where
        K: Borrow<Q>,
        Q: ?Sized + Hash + Eq,
    {
        self.base.get(k)
    }

    pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
    where
        K: Borrow<Q>,
        Q: ?Sized + Hash + Eq,
    {
        self.base.get_mut(k)
    }

    pub fn remove(&mut self, k: &K) -> Option<V> {
        match self.order.iter().position(|x| x == k) {
            Some(index) => {
                self.order.swap_remove(index);
                self.base.remove(k)
            }
            None => None,
        }
    }

    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if !self.base.contains_key(&k) {
            self.order.push(k.clone());
        }
        self.base.insert(k, v)
    }

    pub fn iter(&self) -> Iter<'_, K, V> {
        Iter { base: &self.base, order_iterator: self.order.iter() }
    }

    pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
        self.base.iter_mut()
    }

    pub fn keys(&self) -> std::slice::Iter<K> {
        self.order.iter()
    }

    pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
        if !self.base.contains_key(&key) {
            self.order.push(key.clone());
        }
        self.base.entry(key)
    }
}
<commit_msg>ignore doctest in private ordered_hashmap module<commit_after>use std::borrow::Borrow;
use std::collections::hash_map::{self, Entry};
use std::collections::HashMap;
use std::hash::Hash;
use std::iter::IntoIterator;

/// Ordered hashmap built on top of std::collections::HashMap
#[derive(Debug)]
pub struct OrderedHashMap<K, V> {
    #[doc(hidden)]
    base: HashMap<K, V>,
    keys: Vec<K>,
}

impl<K, V> OrderedHashMap<K, V>
where
    K: Eq + Hash + Clone,
{
    /// Creates an empty `OrderedHashMap`.
    ///
    /// The hash map is initially created with a capacity of 0, so it will not allocate until it
    /// is first inserted into.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use ordered_hashmap::OrderedHashMap;
    /// let mut map: OrderedHashMap<&str, i32> = HashMap::new();
    /// ```
    pub fn new() -> OrderedHashMap<K, V> {
        OrderedHashMap { base: HashMap::<K, V>::new(), keys: Vec::<K>::new() }
    }

    pub fn get<Q>(&self, k: &Q) -> Option<&V>
    where
        K: Borrow<Q>,
        Q: ?Sized + Hash + Eq,
    {
        self.base.get(k)
    }

    pub fn get_mut<Q>(&mut self, k: &Q) -> Option<&mut V>
    where
        K: Borrow<Q>,
        Q: ?Sized + Hash + Eq,
    {
        self.base.get_mut(k)
    }

    pub fn remove(&mut self, k: &K) -> Option<V> {
        match self.keys.iter().position(|x| x == k) {
            Some(index) => {
                self.keys.swap_remove(index);
                self.base.remove(k)
            }
            None => None,
        }
    }

    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        if !self.base.contains_key(&k) {
            self.keys.push(k.clone());
        }
        self.base.insert(k, v)
    }

    pub fn iter(&self) -> Iter<'_, K, V> {
        Iter { base: &self.base, keys_iterator: self.keys.iter() }
    }

    pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
        self.base.iter_mut()
    }

    pub fn keys(&self) -> std::slice::Iter<K> {
        self.keys.iter()
    }

    pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
        if !self.base.contains_key(&key) {
            self.keys.push(key.clone());
        }
        self.base.entry(key)
    }
}

impl<K, V> Default for OrderedHashMap<K, V>
where
    K: Eq + Hash + Clone,
{
    fn default() -> Self {
        Self::new()
    }
}

impl<'a, K, V> IntoIterator for &'a OrderedHashMap<K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a V);
    type IntoIter = Iter<'a, K, V>;

    fn into_iter(self) -> Self::IntoIter {
        Iter { base: &self.base, keys_iterator: self.keys.iter() }
    }
}

impl<K, V> IntoIterator for OrderedHashMap<K, V>
where
    K: Eq + Hash,
{
    type Item = (K, V);
    type IntoIter = IntoIter<K, V>;

    fn into_iter(self) -> Self::IntoIter {
        IntoIter { base: self.base, keys_iterator: self.keys.into_iter() }
    }
}

pub struct Iter<'a, K, V> {
    #[doc(hidden)]
    base: &'a HashMap<K, V>,
    keys_iterator: std::slice::Iter<'a, K>,
}

impl<'a, K, V> Iterator for Iter<'a, K, V>
where
    K: Eq + Hash,
{
    type Item = (&'a K, &'a V);
    fn next(&mut self) -> Option<Self::Item> {
        match self.keys_iterator.next() {
            Some(k) => self.base.get_key_value(&k),
            None => None,
        }
    }
}

pub struct IntoIter<K, V> {
    #[doc(hidden)]
    base: HashMap<K, V>,
    keys_iterator: std::vec::IntoIter<K>,
}

impl<K, V> Iterator for IntoIter<K, V>
where
    K: Eq + Hash,
{
    type Item = (K, V);
    fn next(&mut self) -> Option<Self::Item> {
        match self.keys_iterator.next() {
            Some(k) => self.base.remove_entry(&k),
            None => None,
        }
    }
}

pub type IterMut<'a, K, V> = hash_map::IterMut<'a, K, V>;

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

    #[test]
    fn get() {
        let mut map = OrderedHashMap::new();
        map.insert("a", 1);
        assert_eq!(map.get("a"), Some(&1));
        assert_eq!(map.get("b"), None);
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use io;
use message::*;
use serialize::*;

#[inline]
unsafe fn ptr_inc(p : &mut *mut u8, count : int) {
    *p = std::ptr::mut_offset(*p, count);
}

#[inline]
unsafe fn ptr_sub<T>(p1 : * T, p2 : * T) -> uint {
    let p1Addr : uint = std::cast::transmute(p1);
    let p2Addr : uint = std::cast::transmute(p2);
    return (p1Addr - p2Addr) / std::mem::size_of::<T>();
}

#[inline]
unsafe fn mut_ptr_sub <T>(p1 : *mut T, p2 : *mut T) -> uint {
    let p1Addr : uint = std::cast::transmute(p1);
    let p2Addr : uint = std::cast::transmute(p2);
    return (p1Addr - p2Addr) / std::mem::size_of::<T>();
}

pub struct PackedInputStream<'a, 'b,  R> {
    inner : &'a mut io::BufferedInputStream<'b, R>
}

macro_rules! refresh_buffer(
    ($inner:expr, $size:ident, $inPtr:ident, $inEnd:ident, $out:ident,
     $outBuf:ident, $bufferBegin:ident) => (
        {
            $inner.skip($size);
            let (b, e) = $inner.getReadBuffer();
            $inPtr = b;
            $inEnd = e;
            $size = ptr_sub($inEnd, $inPtr);
            $bufferBegin = b;
            assert!($size > 0);
        }
        );
    )

impl <'a, 'b, R : std::io::Reader> std::io::Reader for PackedInputStream<'a, 'b, R> {
    fn eof(&mut self) -> bool {
        self.inner.eof()
    }

    fn read(&mut self, outBuf: &mut [u8]) -> Option<uint> {
        let len = outBuf.len();

        if (len == 0) { return Some(0); }

        assert!(len % 8 == 0, "PackInputStream reads must be word-aligned");

        unsafe {
            let mut out = outBuf.unsafe_mut_ref(0);
            let outEnd = outBuf.unsafe_mut_ref(len);

            let (mut inPtr, mut inEnd) = self.inner.getReadBuffer();
            let mut bufferBegin = inPtr;
            let mut size = ptr_sub(inEnd, inPtr);
            if size == 0 {
                return Some(0);
            }

            loop {

                let mut tag : u8;

                assert!(mut_ptr_sub(out, outBuf.unsafe_mut_ref(0)) % 8 == 0,
                        "Output pointer should always be aligned here.");

                if ptr_sub(inEnd, inPtr) < 10 {
                    if out >= outEnd {
                        self.inner.skip(ptr_sub(inPtr, bufferBegin));
                        return Some(mut_ptr_sub(out, outBuf.unsafe_mut_ref(0)));
                    }

                    if ptr_sub(inEnd, inPtr) == 0 {
                        refresh_buffer!(self.inner, size, inPtr, inEnd, out, outBuf, bufferBegin);
                        continue;
                    }

                    //# We have at least 1, but not 10, bytes availabe. We need to read
                    //# slowly, doing a bounds check on each byte.

                    tag = *inPtr;
                    inPtr = std::ptr::offset(inPtr, 1);

                    for i in range(0, 8) {
                        if (tag & (1u8 << i)) != 0 {
                            if ptr_sub(inEnd, inPtr) == 0 {
                                refresh_buffer!(self.inner, size, inPtr, inEnd,
                                                out, outBuf, bufferBegin);
                            }
                            *out = *inPtr;
                            out = std::ptr::mut_offset(out, 1);
                            inPtr = std::ptr::offset(inPtr, 1);
                        } else {
                            *out = 0;
                            out = std::ptr::mut_offset(out, 1);
                        }
                    }

                    if ptr_sub(inEnd, inPtr) == 0 && (tag == 0 || tag == 0xff) {
                        refresh_buffer!(self.inner, size, inPtr, inEnd,
                                        out, outBuf, bufferBegin);
                    }
                } else {
                    tag = *inPtr;
                    inPtr = std::ptr::offset(inPtr, 1);

                    for n in range(0, 8) {
                        let isNonzero = (tag & (1 as u8 << n)) != 0;
                        *out = (*inPtr) & ((-(isNonzero as i8)) as u8);
                        out = std::ptr::mut_offset(out, 1);
                        inPtr = std::ptr::offset(inPtr, isNonzero as int);
                    }
                }
                if (tag == 0) {
                    assert!(ptr_sub(inEnd, inPtr) > 0,
                            "Should always have non-empty buffer here");

                    let runLength : uint = (*inPtr) as uint * 8;
                    inPtr = std::ptr::offset(inPtr, 1);

                    assert!(runLength <= mut_ptr_sub(outEnd, out),
                            "Packed input did not end cleanly on a segment boundary");

                    std::ptr::set_memory(out, 0, runLength);
                    out = std::ptr::mut_offset(out, runLength as int);

                } else if (tag == 0xff) {
                    assert!(ptr_sub(inEnd, inPtr) > 0,
                            "Should always have non-empty buffer here");

                    let mut runLength : uint = (*inPtr) as uint * 8;
                    inPtr = std::ptr::offset(inPtr, 1);

                    assert!(runLength <= mut_ptr_sub(outEnd, out),
                            "Packed input did not end cleanly on a segment boundary");

                    let inRemaining = ptr_sub(inEnd, inPtr);
                    if (inRemaining >= runLength) {
                        //# Fast path.
                        std::ptr::copy_nonoverlapping_memory(out, inPtr, runLength);
                        out = std::ptr::mut_offset(out, runLength as int);
                        inPtr = std::ptr::offset(inPtr, runLength as int);
                    } else {
                        //# Copy over the first buffer, then do one big read for the rest.
                        std::ptr::copy_nonoverlapping_memory(out, inPtr, inRemaining);
                        out = std::ptr::mut_offset(out, inRemaining as int);
                        runLength -= inRemaining;

                        self.inner.skip(size);
                        do std::vec::raw::mut_buf_as_slice::<u8,()>(out, runLength) |buf| {
                            self.inner.read(buf);
                        }
                        out = std::ptr::mut_offset(out, runLength as int);

                        if (out == outEnd) {
                            return Some(len);
                        } else {
                            let (b, e) = self.inner.getReadBuffer();
                            inPtr = b;
                            inEnd = e;
                            size = ptr_sub(e, b);
                            continue;
                        }
                    }
                }
            }
        }
    }
}

pub struct PackedOutputStream<'a, 'b, W> {
    inner : &'a mut io::BufferedOutputStream<'b, W>
}

impl <'a, 'b, W : std::io::Writer> std::io::Writer for PackedOutputStream<'a, 'b, W> {
    fn write(&mut self, inBuf : &[u8]) {
        unsafe {
            let (mut out, mut bufferEnd) = self.inner.getWriteBuffer();
            let mut bufferBegin = out;
            let mut slowBuffer : [u8,..20] = [0, ..20];

            let mut inPtr : *u8 = inBuf.unsafe_ref(0);
            let inEnd : *u8 = inBuf.unsafe_ref(inBuf.len());

            while (inPtr < inEnd) {

                if (mut_ptr_sub(bufferEnd, out) < 10) {
                    //# Oops, we're out of space. We need at least 10
                    //# bytes for the fast path, since we don't
                    //# bounds-check on every byte.
                    self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));

                    out = slowBuffer.unsafe_mut_ref(0);
                    bufferEnd = slowBuffer.unsafe_mut_ref(20);
                    bufferBegin = out;
                }

                let tagPos : *mut u8 = out;
                ptr_inc(&mut out, 1);

                let bit0 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit0 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit1 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit1 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit2 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit2 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit3 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit3 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit4 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit4 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit5 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit5 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit6 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit6 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit7 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit7 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let tag : u8 = (bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
                    | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7);

                *tagPos = tag;

                if (tag == 0) {
                    //# An all-zero word is followed by a count of
                    //# consecutive zero words (not including the first
                    //# one).

                    let mut inWord : *u64 = std::cast::transmute(inPtr);
                    let mut limit : *u64 = std::cast::transmute(inEnd);
                    if (ptr_sub(limit, inWord) > 255) {
                        limit = std::ptr::offset(inWord, 255);
                    }
                    while (inWord < limit && *inWord == 0) {
                        inWord = std::ptr::offset(inWord, 1)
                    }
                    *out = ptr_sub(inWord, std::cast::transmute::<*u8, *u64>(inPtr)) as u8;

                    ptr_inc(&mut out, 1);
                    inPtr = std::cast::transmute::<*u64, *u8>(inWord);

                } else if (tag == 0xff) {
                    //# An all-nonzero word is followed by a count of
                    //# consecutive uncompressed words, followed by the
                    //# uncompressed words themselves.

                    //# Count the number of consecutive words in the input
                    //# which have no more than a single zero-byte. We look
                    //# for at least two zeros because that's the point
                    //# where our compression scheme becomes a net win.
                    let runStart = inPtr;
                    let mut limit = inEnd;
                    if (ptr_sub(limit, inPtr) > 255 * 8) {
                        limit = std::ptr::offset(inPtr, 255 * 8);
                    }

                    while (inPtr < limit) {
                        let mut c = 0;

                        for _ in range(0,8) {
                            c += (*inPtr == 0) as u8;
                            inPtr = std::ptr::offset(inPtr, 1);
                        }

                        if (c >= 2) {
                            //# Un-read the word with multiple zeros, since
                            //# we'll want to compress that one.
                            inPtr = std::ptr::offset(inPtr, -8);
                            break;
                        }
                    }
                    let count : uint = ptr_sub(inPtr, runStart);
                    *out = (count / 8) as u8;
                    ptr_inc(&mut out, 1);

                    if (count <= mut_ptr_sub(bufferEnd, out)) {
                        //# There's enough space to memcpy.

                        let src : *u8 = runStart;
                        std::ptr::copy_nonoverlapping_memory(out, src, count);

                        ptr_inc(&mut out, count as int);
                    } else {
                        //# Input overruns the output buffer. We'll give it
                        //# to the output stream in one chunk and let it
                        //# decide what to do.
                        self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));

                        do std::vec::raw::buf_as_slice::<u8,()>(runStart, count) |buf| {
                            self.inner.write(buf);
                        }

                        let (out1, bufferEnd1) = self.inner.getWriteBuffer();
                        out = out1; bufferEnd = bufferEnd1;
                        bufferBegin = out;
                    }
                }
            }

            self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));
            self.inner.flush();
        }
    }

   fn flush(&mut self) { self.inner.flush(); }
}

pub trait WritePacked {
    fn writePackedMessage(&mut self, message : &MessageBuilder);
}

impl <'self, T : std::io::Writer> WritePacked for io::BufferedOutputStream<'self, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut packedOutputStream = PackedOutputStream {inner : self};
        writeMessage(&mut packedOutputStream, message);
    }
}

pub struct WritePackedWrapper<'a, T> {writer : &'a mut T }

impl <'a, T: std::io::Writer> WritePacked for WritePackedWrapper<'a, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut buffered = io::BufferedOutputStream::new(self.writer);
        buffered.writePackedMessage(message);
    }
}
<commit_msg>fix one bug<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use io;
use message::*;
use serialize::*;

#[inline]
unsafe fn ptr_inc(p : &mut *mut u8, count : int) {
    *p = std::ptr::mut_offset(*p, count);
}

#[inline]
unsafe fn ptr_sub<T>(p1 : * T, p2 : * T) -> uint {
    let p1Addr : uint = std::cast::transmute(p1);
    let p2Addr : uint = std::cast::transmute(p2);
    return (p1Addr - p2Addr) / std::mem::size_of::<T>();
}

#[inline]
unsafe fn mut_ptr_sub <T>(p1 : *mut T, p2 : *mut T) -> uint {
    let p1Addr : uint = std::cast::transmute(p1);
    let p2Addr : uint = std::cast::transmute(p2);
    return (p1Addr - p2Addr) / std::mem::size_of::<T>();
}

pub struct PackedInputStream<'a, 'b,  R> {
    inner : &'a mut io::BufferedInputStream<'b, R>
}

macro_rules! refresh_buffer(
    ($inner:expr, $size:ident, $inPtr:ident, $inEnd:ident, $out:ident,
     $outBuf:ident, $bufferBegin:ident) => (
        {
            $inner.skip($size);
            let (b, e) = $inner.getReadBuffer();
            $inPtr = b;
            $inEnd = e;
            $size = ptr_sub($inEnd, $inPtr);
            $bufferBegin = b;
            assert!($size > 0);
        }
        );
    )

impl <'a, 'b, R : std::io::Reader> std::io::Reader for PackedInputStream<'a, 'b, R> {
    fn eof(&mut self) -> bool {
        self.inner.eof()
    }

    fn read(&mut self, outBuf: &mut [u8]) -> Option<uint> {
        let len = outBuf.len();

        if (len == 0) { return Some(0); }

        assert!(len % 8 == 0, "PackInputStream reads must be word-aligned");

        unsafe {
            let mut out = outBuf.unsafe_mut_ref(0);
            let outEnd = outBuf.unsafe_mut_ref(len);

            let (mut inPtr, mut inEnd) = self.inner.getReadBuffer();
            let mut bufferBegin = inPtr;
            let mut size = ptr_sub(inEnd, inPtr);
            if size == 0 {
                return Some(0);
            }

            loop {

                let mut tag : u8;

                assert!(mut_ptr_sub(out, outBuf.unsafe_mut_ref(0)) % 8 == 0,
                        "Output pointer should always be aligned here.");

                if ptr_sub(inEnd, inPtr) < 10 {
                    if out >= outEnd {
                        self.inner.skip(ptr_sub(inPtr, bufferBegin));
                        return Some(mut_ptr_sub(out, outBuf.unsafe_mut_ref(0)));
                    }

                    if ptr_sub(inEnd, inPtr) == 0 {
                        refresh_buffer!(self.inner, size, inPtr, inEnd, out, outBuf, bufferBegin);
                        continue;
                    }

                    //# We have at least 1, but not 10, bytes availabe. We need to read
                    //# slowly, doing a bounds check on each byte.

                    tag = *inPtr;
                    inPtr = std::ptr::offset(inPtr, 1);

                    for i in range(0, 8) {
                        if (tag & (1u8 << i)) != 0 {
                            if ptr_sub(inEnd, inPtr) == 0 {
                                refresh_buffer!(self.inner, size, inPtr, inEnd,
                                                out, outBuf, bufferBegin);
                            }
                            *out = *inPtr;
                            out = std::ptr::mut_offset(out, 1);
                            inPtr = std::ptr::offset(inPtr, 1);
                        } else {
                            *out = 0;
                            out = std::ptr::mut_offset(out, 1);
                        }
                    }

                    if ptr_sub(inEnd, inPtr) == 0 && (tag == 0 || tag == 0xff) {
                        refresh_buffer!(self.inner, size, inPtr, inEnd,
                                        out, outBuf, bufferBegin);
                    }
                } else {
                    tag = *inPtr;
                    inPtr = std::ptr::offset(inPtr, 1);

                    for n in range(0, 8) {
                        let isNonzero = (tag & (1 as u8 << n)) != 0;
                        *out = (*inPtr) & ((-(isNonzero as i8)) as u8);
                        out = std::ptr::mut_offset(out, 1);
                        inPtr = std::ptr::offset(inPtr, isNonzero as int);
                    }
                }
                if (tag == 0) {
                    assert!(ptr_sub(inEnd, inPtr) > 0,
                            "Should always have non-empty buffer here");

                    let runLength : uint = (*inPtr) as uint * 8;
                    inPtr = std::ptr::offset(inPtr, 1);

                    assert!(runLength <= mut_ptr_sub(outEnd, out),
                            "Packed input did not end cleanly on a segment boundary");

                    std::ptr::set_memory(out, 0, runLength);
                    out = std::ptr::mut_offset(out, runLength as int);

                } else if (tag == 0xff) {
                    assert!(ptr_sub(inEnd, inPtr) > 0,
                            "Should always have non-empty buffer here");

                    let mut runLength : uint = (*inPtr) as uint * 8;
                    inPtr = std::ptr::offset(inPtr, 1);

                    assert!(runLength <= mut_ptr_sub(outEnd, out),
                            "Packed input did not end cleanly on a segment boundary");

                    let inRemaining = ptr_sub(inEnd, inPtr);
                    if (inRemaining >= runLength) {
                        //# Fast path.
                        std::ptr::copy_nonoverlapping_memory(out, inPtr, runLength);
                        out = std::ptr::mut_offset(out, runLength as int);
                        inPtr = std::ptr::offset(inPtr, runLength as int);
                    } else {
                        //# Copy over the first buffer, then do one big read for the rest.
                        std::ptr::copy_nonoverlapping_memory(out, inPtr, inRemaining);
                        out = std::ptr::mut_offset(out, inRemaining as int);
                        runLength -= inRemaining;

                        self.inner.skip(size);
                        do std::vec::raw::mut_buf_as_slice::<u8,()>(out, runLength) |buf| {
                            self.inner.read(buf);
                        }
                        out = std::ptr::mut_offset(out, runLength as int);

                        if (out == outEnd) {
                            return Some(len);
                        } else {
                            let (b, e) = self.inner.getReadBuffer();
                            inPtr = b;
                            inEnd = e;
                            size = ptr_sub(e, b);
                            bufferBegin = inPtr;
                            continue;
                        }
                    }
                }
            }
        }
    }
}

pub struct PackedOutputStream<'a, 'b, W> {
    inner : &'a mut io::BufferedOutputStream<'b, W>
}

impl <'a, 'b, W : std::io::Writer> std::io::Writer for PackedOutputStream<'a, 'b, W> {
    fn write(&mut self, inBuf : &[u8]) {
        unsafe {
            let (mut out, mut bufferEnd) = self.inner.getWriteBuffer();
            let mut bufferBegin = out;
            let mut slowBuffer : [u8,..20] = [0, ..20];

            let mut inPtr : *u8 = inBuf.unsafe_ref(0);
            let inEnd : *u8 = inBuf.unsafe_ref(inBuf.len());

            while (inPtr < inEnd) {

                if (mut_ptr_sub(bufferEnd, out) < 10) {
                    //# Oops, we're out of space. We need at least 10
                    //# bytes for the fast path, since we don't
                    //# bounds-check on every byte.
                    self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));

                    out = slowBuffer.unsafe_mut_ref(0);
                    bufferEnd = slowBuffer.unsafe_mut_ref(20);
                    bufferBegin = out;
                }

                let tagPos : *mut u8 = out;
                ptr_inc(&mut out, 1);

                let bit0 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit0 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit1 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit1 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit2 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit2 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit3 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit3 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit4 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit4 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit5 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit5 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit6 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit6 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let bit7 = (*inPtr != 0) as u8;
                *out = *inPtr;
                ptr_inc(&mut out, bit7 as int);
                inPtr = std::ptr::offset(inPtr, 1);

                let tag : u8 = (bit0 << 0) | (bit1 << 1) | (bit2 << 2) | (bit3 << 3)
                    | (bit4 << 4) | (bit5 << 5) | (bit6 << 6) | (bit7 << 7);

                *tagPos = tag;

                if (tag == 0) {
                    //# An all-zero word is followed by a count of
                    //# consecutive zero words (not including the first
                    //# one).

                    let mut inWord : *u64 = std::cast::transmute(inPtr);
                    let mut limit : *u64 = std::cast::transmute(inEnd);
                    if (ptr_sub(limit, inWord) > 255) {
                        limit = std::ptr::offset(inWord, 255);
                    }
                    while (inWord < limit && *inWord == 0) {
                        inWord = std::ptr::offset(inWord, 1)
                    }
                    *out = ptr_sub(inWord, std::cast::transmute::<*u8, *u64>(inPtr)) as u8;

                    ptr_inc(&mut out, 1);
                    inPtr = std::cast::transmute::<*u64, *u8>(inWord);

                } else if (tag == 0xff) {
                    //# An all-nonzero word is followed by a count of
                    //# consecutive uncompressed words, followed by the
                    //# uncompressed words themselves.

                    //# Count the number of consecutive words in the input
                    //# which have no more than a single zero-byte. We look
                    //# for at least two zeros because that's the point
                    //# where our compression scheme becomes a net win.
                    let runStart = inPtr;
                    let mut limit = inEnd;
                    if (ptr_sub(limit, inPtr) > 255 * 8) {
                        limit = std::ptr::offset(inPtr, 255 * 8);
                    }

                    while (inPtr < limit) {
                        let mut c = 0;

                        for _ in range(0,8) {
                            c += (*inPtr == 0) as u8;
                            inPtr = std::ptr::offset(inPtr, 1);
                        }

                        if (c >= 2) {
                            //# Un-read the word with multiple zeros, since
                            //# we'll want to compress that one.
                            inPtr = std::ptr::offset(inPtr, -8);
                            break;
                        }
                    }
                    let count : uint = ptr_sub(inPtr, runStart);
                    *out = (count / 8) as u8;
                    ptr_inc(&mut out, 1);

                    if (count <= mut_ptr_sub(bufferEnd, out)) {
                        //# There's enough space to memcpy.

                        let src : *u8 = runStart;
                        std::ptr::copy_nonoverlapping_memory(out, src, count);

                        ptr_inc(&mut out, count as int);
                    } else {
                        //# Input overruns the output buffer. We'll give it
                        //# to the output stream in one chunk and let it
                        //# decide what to do.
                        self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));

                        do std::vec::raw::buf_as_slice::<u8,()>(runStart, count) |buf| {
                            self.inner.write(buf);
                        }

                        let (out1, bufferEnd1) = self.inner.getWriteBuffer();
                        out = out1; bufferEnd = bufferEnd1;
                        bufferBegin = out;
                    }
                }
            }

            self.inner.write_ptr(bufferBegin, mut_ptr_sub(out, bufferBegin));
            self.inner.flush();
        }
    }

   fn flush(&mut self) { self.inner.flush(); }
}

pub trait WritePacked {
    fn writePackedMessage(&mut self, message : &MessageBuilder);
}

impl <'self, T : std::io::Writer> WritePacked for io::BufferedOutputStream<'self, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut packedOutputStream = PackedOutputStream {inner : self};
        writeMessage(&mut packedOutputStream, message);
    }
}

pub struct WritePackedWrapper<'a, T> {writer : &'a mut T }

impl <'a, T: std::io::Writer> WritePacked for WritePackedWrapper<'a, T> {
    fn writePackedMessage(&mut self, message : &MessageBuilder) {
        let mut buffered = io::BufferedOutputStream::new(self.writer);
        buffered.writePackedMessage(message);
    }
}
<|endoftext|>