<commit_before>#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate reqwest;
extern crate rs_release;
extern crate semver;

#[macro_use]
mod util;

mod client;
mod dispatch;
mod error;
mod fs;
mod monger;
mod os;
mod process;
mod url;

use clap::{App, AppSettings, Arg, SubCommand};

use dispatch::dispatch;
use error::Result;

quick_main!(run);

fn run() -> Result<i32> {
    let matches = App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about(crate_description!())
        .setting(AppSettings::ArgRequiredElseHelp)
        .subcommand(
            SubCommand::with_name("delete")
                .help("deletes an installed MongoDB version")
                .arg(
                    Arg::with_name("VERSION")
                        .help("the MongoDB version to delete")
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("get")
                .help("downloads a MongoDB version")
                .arg(
                    Arg::with_name("VERSION")
                        .help("the MongoDB version to download")
                        .required(true),
                )
                .arg(
                    Arg::with_name("force")
                        .help(
                            "download the MongoDB version even if it already is installed",
                        )
                        .short("f")
                        .long("force"),
                ),
        )
        .subcommand(
            SubCommand::with_name("run")
                .help("run a binary of a downloaded MongoDB version")
                .arg(
                    Arg::with_name("VERSION")
                        .help("the MongoDB version of the binary being run")
                        .required(true)
                        .index(1),
                )
                .arg(
                    Arg::with_name("BIN")
                        .help("the MongoDB binary to run")
                        .required(true)
                        .index(2),
                )
                .arg(
                    Arg::with_name("BIN_ARGS")
                        .help("arguments for the MongoDB binary being run")
                        .multiple(true)
                        .last(true),
                ),
        )
        .get_matches();

    dispatch(matches)?;
    Ok(0)
}
<commit_msg>fix help for subcommands<commit_after>#[macro_use]
extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate reqwest;
extern crate rs_release;
extern crate semver;

#[macro_use]
mod util;

mod client;
mod dispatch;
mod error;
mod fs;
mod monger;
mod os;
mod process;
mod url;

use clap::{App, AppSettings, Arg, SubCommand};

use dispatch::dispatch;
use error::Result;

quick_main!(run);

fn run() -> Result<i32> {
    let matches = App::new(crate_name!())
        .version(crate_version!())
        .author(crate_authors!("\n"))
        .about(crate_description!())
        .setting(AppSettings::ArgRequiredElseHelp)
        .subcommand(
            SubCommand::with_name("delete")
                .about("deletes an installed MongoDB version")
                .arg(
                    Arg::with_name("VERSION")
                        .help("the MongoDB version to delete")
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("get")
                .about("downloads a MongoDB version")
                .arg(
                    Arg::with_name("VERSION")
                        .help("the MongoDB version to download")
                        .required(true),
                )
                .arg(
                    Arg::with_name("force")
                        .help(
                            "download the MongoDB version even if it already is installed",
                        )
                        .short("f")
                        .long("force"),
                ),
        )
        .subcommand(
            SubCommand::with_name("run")
                .about("run a binary of a downloaded MongoDB version")
                .arg(
                    Arg::with_name("VERSION")
                        .help("the MongoDB version of the binary being run")
                        .required(true)
                        .index(1),
                )
                .arg(
                    Arg::with_name("BIN")
                        .help("the MongoDB binary to run")
                        .required(true)
                        .index(2),
                )
                .arg(
                    Arg::with_name("BIN_ARGS")
                        .help("arguments for the MongoDB binary being run")
                        .multiple(true)
                        .last(true),
                ),
        )
        .get_matches();

    dispatch(matches)?;
    Ok(0)
}
<|endoftext|>


<commit_before>extern crate byteorder;
extern crate env_logger;
#[macro_use]
extern crate log;

mod splay;

use byteorder::{BigEndian as BE, ReadBytesExt};
use splay::Splay;

struct LevelConfig {
	name: String,
	path_vpr: String,
	path_vmc: String,
	size_power: (u32, u32),
	geo_power: u32,
	section_power: u32,
}

struct Level {
	size: (u32, u32),
	flood_map: Vec<u32>,
	data: Vec<u8>,
	splay: Splay,
}

fn load(config: &LevelConfig) -> Level {
	use std::fs::File;
	use std::io::{Read, Seek, SeekFrom};

	let size = (1 << config.size_power.0, 1 << config.size_power.1);

	info!("Loading vpr...");
	let flood = {
		let mut vpr = File::open(&config.path_vpr).unwrap();
		let flood_size = size.1 >> config.section_power;
		let net_size = size.0 * size.1 >> (2*config.geo_power);
		let flood_offset = (2*4 + (1 + 4 + 4)*4 + 2*net_size + 2*config.geo_power*4 + 2*flood_size*config.geo_power*4) as u64;
		let expected_file_size = flood_offset + (flood_size*4) as u64;
		assert_eq!(vpr.metadata().unwrap().len(), expected_file_size as u64);
		vpr.seek(SeekFrom::Start(flood_offset)).unwrap();
		(0..flood_size).map(|_|
			vpr.read_u32::<BE>().unwrap()
		).collect()
	};

	info!("Loading vmc...");
	let (data, splay) = {
		let mut vpc = File::open(&config.path_vmc).unwrap();
		info!("\tLoading compression tables...");
		let mut st_table = Vec::<i32>::with_capacity(size.1 as usize);
		let mut sz_table = Vec::<i16>::with_capacity(size.1 as usize);
		for _ in 0 .. size.1 {
			st_table.push(vpc.read_i32::<BE>().unwrap());
			sz_table.push(vpc.read_i16::<BE>().unwrap());
		}
		let data_size = vpc.metadata().unwrap().len() - vpc.seek(SeekFrom::Current(0)).unwrap();
		let splay = Splay::new(&mut vpc);
		let mut data = Vec::with_capacity(data_size as usize);
		vpc.read_to_end(&mut data).unwrap();
		(data, splay)
	};

	info!("Done.");
	Level {
		size: size,
		flood_map: flood,
		data: data,
		splay: splay,
	}
}

fn main() {
	env_logger::init().unwrap();
	let name = "fostral";
	let base = "D:/gog/Vangers/thechain";
	let config = LevelConfig {
		name: name.to_owned(),
		path_vpr: format!("{}/{}/output.vpr", base, name),
		path_vmc: format!("{}/{}/output.vmc", base, name),
		size_power: (11, 14),
		geo_power: 5,
		section_power: 7,
	};
    let _lev = load(&config);
}
<commit_msg>Added Power type<commit_after>extern crate byteorder;
extern crate env_logger;
#[macro_use]
extern crate log;

mod splay;

use byteorder::{BigEndian as BE, ReadBytesExt};
use splay::Splay;

struct Power(i32);
impl Power {
	fn as_value(&self) -> i32 {
		1 << self.0
	}
	fn as_power(&self) -> i32 {
		self.0
	}
}

struct LevelConfig {
	name: String,
	path_vpr: String,
	path_vmc: String,
	size: (Power, Power),
	geo: Power,
	section: Power,
}

struct Level {
	size: (i32, i32),
	flood_map: Vec<u32>,
	data: Vec<u8>,
	splay: Splay,
}

fn load(config: &LevelConfig) -> Level {
	use std::fs::File;
	use std::io::{Read, Seek, SeekFrom};

	let size = (config.size.0.as_value(), config.size.1.as_value());

	info!("Loading vpr...");
	let flood = {
		let mut vpr = File::open(&config.path_vpr).unwrap();
		let flood_size = size.1 >> config.section.as_power();
		let geo_pow = config.geo.as_power();
		let net_size = size.0 * size.1 >> (2 * geo_pow);
		let flood_offset = (2*4 + (1 + 4 + 4)*4 + 2*net_size + 2*geo_pow*4 + 2*flood_size*geo_pow*4) as u64;
		let expected_file_size = flood_offset + (flood_size*4) as u64;
		assert_eq!(vpr.metadata().unwrap().len(), expected_file_size as u64);
		vpr.seek(SeekFrom::Start(flood_offset)).unwrap();
		(0..flood_size).map(|_|
			vpr.read_u32::<BE>().unwrap()
		).collect()
	};

	info!("Loading vmc...");
	let (data, splay) = {
		let mut vpc = File::open(&config.path_vmc).unwrap();
		info!("\tLoading compression tables...");
		let mut st_table = Vec::<i32>::with_capacity(size.1 as usize);
		let mut sz_table = Vec::<i16>::with_capacity(size.1 as usize);
		for _ in 0 .. size.1 {
			st_table.push(vpc.read_i32::<BE>().unwrap());
			sz_table.push(vpc.read_i16::<BE>().unwrap());
		}
		let data_size = vpc.metadata().unwrap().len() - vpc.seek(SeekFrom::Current(0)).unwrap();
		let splay = Splay::new(&mut vpc);
		let mut data = Vec::with_capacity(data_size as usize);
		vpc.read_to_end(&mut data).unwrap();
		(data, splay)
	};

	info!("Done.");
	Level {
		size: size,
		flood_map: flood,
		data: data,
		splay: splay,
	}
}

fn main() {
	env_logger::init().unwrap();
	let name = "fostral";
	let base = "D:/gog/Vangers/thechain";
	let config = LevelConfig {
		name: name.to_owned(),
		path_vpr: format!("{}/{}/output.vpr", base, name),
		path_vmc: format!("{}/{}/output.vmc", base, name),
		size: (Power(11), Power(14)),
		geo: Power(5),
		section: Power(7),
	};
    let _lev = load(&config);
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate llvm_sys;

use std::io::{self, Write};
use std::ptr;

mod parser;

macro_rules! c_str {
    ($string:expr) => (concat!($string, '\0').as_ptr() as *const ::libc::c_char)
}

// TODO(tsion): Use the readline library.
fn prompt(line: &mut String) -> io::Result<usize> {
    print!("rl> ");
    try!(io::stdout().flush());
    io::stdin().read_line(line)
}

fn compile_expr(expr: parser::Expr) {
    use llvm_sys::core::*;
    use llvm_sys::analysis::*;
    use llvm_sys::analysis::LLVMVerifierFailureAction::*;

    let n = match expr {
        parser::Expr::Number(n) => n,
        _ => unimplemented!(),
    };

    unsafe {
        let context = LLVMContextCreate();
        let module = LLVMModuleCreateWithName(c_str!("rl"));
        let builder = LLVMCreateBuilderInContext(context);

        let i64_type = LLVMInt64TypeInContext(context);
        let function_type = LLVMFunctionType(i64_type, ptr::null_mut(), 0, 0);
        let function = LLVMAddFunction(module, c_str!("foo"), function_type);

        let bb = LLVMAppendBasicBlockInContext(context, function, c_str!("entry"));
        LLVMPositionBuilderAtEnd(builder, bb);

        let number = LLVMConstInt(i64_type, n, 0);
        LLVMBuildRet(builder, number);

        LLVMVerifyModule(module, LLVMPrintMessageAction, ptr::null_mut());
        LLVMDumpModule(module);

        LLVMDisposeBuilder(builder);
        LLVMDisposeModule(module);
        LLVMContextDispose(context);
    }
}

fn main() {
    let mut line = String::new();

    loop {
        prompt(&mut line).unwrap();

        {
            let parser = parser::Parser::new(&line);
            let expr_results: Vec<parser::ParseResult<parser::Expr>> = parser.collect();
            for expr_result in expr_results {
                match expr_result {
                    Ok(expr) => compile_expr(expr),
                    Err(e)   => println!("error: {:?}", e),
                }
            }
        }

        line.clear();
    }
}
<commit_msg>Create the LLVM module in the right context.<commit_after>extern crate libc;
extern crate llvm_sys;

use std::io::{self, Write};
use std::ptr;

mod parser;

macro_rules! c_str {
    ($string:expr) => (concat!($string, '\0').as_ptr() as *const ::libc::c_char)
}

// TODO(tsion): Use the readline library.
fn prompt(line: &mut String) -> io::Result<usize> {
    print!("rl> ");
    try!(io::stdout().flush());
    io::stdin().read_line(line)
}

fn compile_expr(expr: parser::Expr) {
    use llvm_sys::core::*;
    use llvm_sys::analysis::*;
    use llvm_sys::analysis::LLVMVerifierFailureAction::*;

    let n = match expr {
        parser::Expr::Number(n) => n,
        _ => unimplemented!(),
    };

    unsafe {
        let context = LLVMContextCreate();
        let module = LLVMModuleCreateWithNameInContext(c_str!("rl"), context);
        let builder = LLVMCreateBuilderInContext(context);

        let i64_type = LLVMInt64TypeInContext(context);
        let function_type = LLVMFunctionType(i64_type, ptr::null_mut(), 0, 0);
        let function = LLVMAddFunction(module, c_str!("foo"), function_type);

        let bb = LLVMAppendBasicBlockInContext(context, function, c_str!("entry"));
        LLVMPositionBuilderAtEnd(builder, bb);

        let number = LLVMConstInt(i64_type, n, 0);
        LLVMBuildRet(builder, number);

        LLVMVerifyModule(module, LLVMPrintMessageAction, ptr::null_mut());
        LLVMDumpModule(module);

        LLVMDisposeBuilder(builder);
        LLVMDisposeModule(module);
        LLVMContextDispose(context);
    }
}

fn main() {
    let mut line = String::new();

    loop {
        prompt(&mut line).unwrap();

        {
            let parser = parser::Parser::new(&line);
            let expr_results: Vec<parser::ParseResult<parser::Expr>> = parser.collect();
            for expr_result in expr_results {
                match expr_result {
                    Ok(expr) => compile_expr(expr),
                    Err(e)   => println!("error: {:?}", e),
                }
            }
        }

        line.clear();
    }
}
<|endoftext|>


<commit_before>extern crate rand;

pub mod badvestments;
pub mod ast;

use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashMap;

use rand::Rng;

struct SubstitutionMap {
    map: HashMap<String, Vec<Vec<String>>>
}

impl SubstitutionMap {
    fn new() -> SubstitutionMap {
        SubstitutionMap { map: HashMap::new() }
    }

    fn add_substitution(&mut self, substitution : ast::Substitution) {
        let mut insert_as_new = false;
        match self.map.get_mut(&substitution.s) {
            Some(ref mut substitutions) => {
                substitutions.push(substitution.v.clone());
            },
            None => {
                insert_as_new = true;
            }
        }
        if insert_as_new {
            self.map.insert(substitution.s, vec![substitution.v]);
        }
    }

    fn apply_substitutions(&self, symbols : Vec<String>) -> Vec<String> {
        let mut results: Vec<String> = vec![];
        for symbol in symbols {
            match self.map.get(&symbol) {
                Some(substitutions) => {
                    let chosen = rand::thread_rng().choose(&substitutions).unwrap();
                    for s in chosen.iter() {
                        results.push(s.clone());
                    }
                },
                None => {
                    results.push(symbol);
                }
            }
        }
        return results;
    }
}

fn main() {
    let file = File::open("badvestments.rules").unwrap();
    let reader = BufReader::new(&file);
    let mut substitutions = SubstitutionMap::new();
    for line in reader.lines() {
        let l = line.unwrap();
        let result = badvestments::parse_Rule(l.as_str());
        println!("{:?}", result);
        match result {
            Ok(substitution) => {
                substitutions.add_substitution(substitution);
            },
            _ => {
                println!("(error parsing)");
            }
        }
    };
    let mut badvestment = vec![String::from("Badvestment")];
    let mut next = substitutions.apply_substitutions(badvestment.clone());
    while badvestment != next {
        badvestment = next;
        next = substitutions.apply_substitutions(badvestment.clone());
    }
    let results: Vec<String> = badvestment.into_iter()
                                          .map(|s| { s.replace('"', "") })
                                          .collect();

    println!("{}", results.join(" "));
}
<commit_msg>don't need to print out parsed rules any more<commit_after>extern crate rand;

pub mod badvestments;
pub mod ast;

use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use std::collections::HashMap;

use rand::Rng;

struct SubstitutionMap {
    map: HashMap<String, Vec<Vec<String>>>
}

impl SubstitutionMap {
    fn new() -> SubstitutionMap {
        SubstitutionMap { map: HashMap::new() }
    }

    fn add_substitution(&mut self, substitution : ast::Substitution) {
        let mut insert_as_new = false;
        match self.map.get_mut(&substitution.s) {
            Some(ref mut substitutions) => {
                substitutions.push(substitution.v.clone());
            },
            None => {
                insert_as_new = true;
            }
        }
        if insert_as_new {
            self.map.insert(substitution.s, vec![substitution.v]);
        }
    }

    fn apply_substitutions(&self, symbols : Vec<String>) -> Vec<String> {
        let mut results: Vec<String> = vec![];
        for symbol in symbols {
            match self.map.get(&symbol) {
                Some(substitutions) => {
                    let chosen = rand::thread_rng().choose(&substitutions).unwrap();
                    for s in chosen.iter() {
                        results.push(s.clone());
                    }
                },
                None => {
                    results.push(symbol);
                }
            }
        }
        return results;
    }
}

fn main() {
    let file = File::open("badvestments.rules").unwrap();
    let reader = BufReader::new(&file);
    let mut substitutions = SubstitutionMap::new();
    for line in reader.lines() {
        let l = line.unwrap();
        let result = badvestments::parse_Rule(l.as_str());
        match result {
            Ok(substitution) => {
                substitutions.add_substitution(substitution);
            },
            _ => {
                println!("(error parsing)");
            }
        }
    };
    let mut badvestment = vec![String::from("Badvestment")];
    let mut next = substitutions.apply_substitutions(badvestment.clone());
    while badvestment != next {
        badvestment = next;
        next = substitutions.apply_substitutions(badvestment.clone());
    }
    let results: Vec<String> = badvestment.into_iter()
                                          .map(|s| { s.replace('"', "") })
                                          .collect();

    println!("{}", results.join(" "));
}
<|endoftext|>


<commit_before>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.
use client::HttpRequest as ClientRequest;
use client::HttpStream as ClientStream;

use server::HttpRequest as ServerRequest;

use rand::Rng;
use rand::distributions::{Range, Sample};

use std::collections::HashMap;
use std::io;
use std::io::prelude::*;

#[derive(Debug)]
struct TestFields {
    texts: HashMap<String, String>,
    files: HashMap<String, Vec<u8>>,
}

#[test]
fn local_test() {
    let _ = ::env_logger::init();

    let test_fields = gen_test_fields();

    let buf = test_client(&test_fields);

    trace!(
        "\n--Test Buffer Begin--\n{}\n--Test Buffer End--",
        String::from_utf8_lossy(&buf.buf)
    );

    test_server(buf, test_fields);
}

fn gen_test_fields() -> TestFields {
    const MIN_FIELDS: usize = 1;
    const MAX_FIELDS: usize = 3;

    let texts_count = gen_range(MIN_FIELDS, MAX_FIELDS);
    let files_count = gen_range(MIN_FIELDS, MAX_FIELDS);

    TestFields {
        texts: (0..texts_count).map(|_| (gen_string(), gen_string())).collect(),
        files: (0..files_count).map(|_| (gen_string(), gen_bytes())).collect(),
    }
}

fn gen_range(min: usize, max: usize) -> usize {
    Range::new(min, max).sample(&mut ::rand::weak_rng())
}

fn gen_string() -> String {
    const MIN_LEN: usize = 3;
    const MAX_LEN: usize = 8;

    let mut rng = ::rand::weak_rng();
    let str_len = gen_range(MIN_LEN, MAX_LEN);

    rng.gen_ascii_chars().take(str_len).collect()
}

fn gen_bytes() -> Vec<u8> {
    const MIN_LEN: usize = 8;
    const MAX_LEN: usize = 16;

    let mut rng = ::rand::weak_rng();
    let bytes_len = gen_range(MIN_LEN, MAX_LEN);

    rng.gen_ascii_chars().take(bytes_len)
        .map(|c| c as u8).collect()
}

fn test_client(test_fields: &TestFields) -> HttpBuffer {
    use client::Multipart;

    let request = MockClientRequest::default();

    let mut test_files = test_fields.files.iter();

    let mut multipart = Multipart::from_request(request).unwrap();

    // Intersperse file fields amongst text fields
    for (name, text) in &test_fields.texts {
        if let Some((file_name, file)) = test_files.next() {
            multipart.write_stream(file_name, &mut &**file, None, None).unwrap();
        }

        multipart.write_text(name, text).unwrap();
    }

    // Write remaining files
    for (file_name, file) in test_files {
       multipart.write_stream(file_name, &mut &**file, None, None).unwrap();
    }

    multipart.send().unwrap()
}

fn test_server(buf: HttpBuffer, mut fields: TestFields) {
    use server::{Multipart, MultipartData};

    let mut multipart = Multipart::from_request(buf.for_server())
        .unwrap_or_else(|_| panic!("Buffer should be multipart!"));

    trace!("Fields for server test: {:?}", fields);

    while let Ok(Some(mut field)) = multipart.read_entry() {
        match field.data {
            MultipartData::Text(text) => {
                let test_text = fields.texts.remove(&field.name);

                assert!(
                    test_text.is_some(),
                    "Got text field that wasn't in original dataset: {:?} : {:?} ",
                    field.name, text
                );

                let test_text = test_text.unwrap();

                assert!(
                    text == test_text,
                    "Unexpected data for field {:?}: Expected {:?}, got {:?}",
                    field.name, test_text, text
                );

            },
            MultipartData::File(ref mut file) => {
                let test_bytes = fields.files.remove(&field.name).unwrap();

                let mut bytes = Vec::with_capacity(test_bytes.len());
                file.read_to_end(&mut bytes).unwrap();

                assert!(bytes == test_bytes, "Unexpected data for file {:?}: Expected {:?}, Got {:?}",
                        field.name, String::from_utf8_lossy(&test_bytes), String::from_utf8_lossy(&bytes)
                );
            },
        }
    }

    assert!(fields.texts.is_empty(), "Text fields were not exhausted! Text fields: {:?}", fields.texts);
    assert!(fields.files.is_empty(), "File fields were not exhausted! File fields: {:?}", fields.files);
}

#[derive(Default, Debug)]
pub struct MockClientRequest {
    boundary: Option<String>,
    content_len: Option<u64>,
}

impl ClientRequest for MockClientRequest {
    type Stream = HttpBuffer;
    type Error = io::Error;

    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool {
        self.boundary = Some(boundary.into());
        self.content_len = content_len;
        true
    }

    fn open_stream(self) -> Result<HttpBuffer, io::Error> {
        debug!("MockClientRequest::open_stream called! {:?}", self);
        let boundary = self.boundary.expect("HttpRequest::set_headers() was not called!");

        Ok(HttpBuffer { buf: Vec::new(), boundary: boundary, content_len: self.content_len })
    }
}

#[derive(Debug)]
pub struct HttpBuffer {
    buf: Vec<u8>,
    boundary: String,
    content_len: Option<u64>,
}

impl HttpBuffer {
    pub fn for_server(&self) -> ServerBuffer {
        ServerBuffer {
            data: &self.buf,
            boundary: &self.boundary,
            content_len: self.content_len,
        }
    }
}

impl Write for HttpBuffer {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        self.buf.write(data)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buf.flush()
    }
}

impl Read for HttpBuffer {
    fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
        unimplemented!()
    }
}

impl ClientStream for HttpBuffer {
    type Request = MockClientRequest;
    type Response = HttpBuffer;
    type Error = io::Error;

    fn finish(self) -> Result<Self, io::Error> { Ok(self) }
}

#[derive(Debug)]
pub struct ServerBuffer<'a> {
    data: &'a [u8],
    boundary: &'a str,
    content_len: Option<u64>,
}

impl<'a> Read for ServerBuffer<'a> {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        self.data.read(out)
    }
}

impl<'a> ServerRequest for ServerBuffer<'a> {
    type Body = Self;

    fn multipart_boundary(&self) -> Option<&str> { Some(&self.boundary) }

    fn body(self) -> Self::Body {
        self
    }
}

<commit_msg>Add a random number of hyphens to field and filenames<commit_after>// Copyright 2016 `multipart` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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.
use client::HttpRequest as ClientRequest;
use client::HttpStream as ClientStream;

use server::HttpRequest as ServerRequest;

use rand::{self, Rng};

use std::collections::HashMap;
use std::io::prelude::*;
use std::{io, iter};

#[derive(Debug)]
struct TestFields {
    texts: HashMap<String, String>,
    files: HashMap<String, Vec<u8>>,
}

#[test]
fn local_test() {
    let _ = ::env_logger::init();

    let test_fields = gen_test_fields();

    let buf = test_client(&test_fields);

    trace!(
        "\n--Test Buffer Begin--\n{}\n--Test Buffer End--",
        String::from_utf8_lossy(&buf.buf)
    );

    test_server(buf, test_fields);
}

fn gen_test_fields() -> TestFields {
    const MIN_FIELDS: usize = 1;
    const MAX_FIELDS: usize = 3;

    let mut rng = rand::weak_rng();

    let texts_count = rng.gen_range(MIN_FIELDS, MAX_FIELDS);
    let files_count = rng.gen_range(MIN_FIELDS, MAX_FIELDS);

    TestFields {
        texts: (0..texts_count).map(|_| (gen_string(), gen_string())).collect(),
        files: (0..files_count).map(|_| (gen_string(), gen_bytes())).collect(),
    }
}

fn gen_string() -> String {
    const MIN_LEN: usize = 3;
    const MAX_LEN: usize = 8;
    const MAX_DASHES: usize = 3;

    let mut rng_1 = rand::weak_rng();
    let mut rng_2 = rand::weak_rng();

    let str_len_1 = rng_1.gen_range(MIN_LEN, MAX_LEN + 1);
    let str_len_2 = rng_2.gen_range(MIN_LEN, MAX_LEN + 1);
    let num_dashes = rng_1.gen_range(0, MAX_DASHES + 1);

    rng_1.gen_ascii_chars().take(str_len_1)
        .chain(iter::repeat('-').take(num_dashes))
        .chain(rng_2.gen_ascii_chars().take(str_len_2))
        .collect()
}

fn gen_bytes() -> Vec<u8> {
    gen_string().into_bytes()
}

fn test_client(test_fields: &TestFields) -> HttpBuffer {
    use client::Multipart;

    let request = MockClientRequest::default();

    let mut test_files = test_fields.files.iter();

    let mut multipart = Multipart::from_request(request).unwrap();

    // Intersperse file fields amongst text fields
    for (name, text) in &test_fields.texts {
        if let Some((file_name, file)) = test_files.next() {
            multipart.write_stream(file_name, &mut &**file, Some(file_name), None).unwrap();
        }

        multipart.write_text(name, text).unwrap();
    }

    // Write remaining files
    for (file_name, file) in test_files {
       multipart.write_stream(file_name, &mut &**file, None, None).unwrap();
    }

    multipart.send().unwrap()
}

fn test_server(buf: HttpBuffer, mut fields: TestFields) {
    use server::{Multipart, MultipartData};

    let mut multipart = Multipart::from_request(buf.for_server())
        .unwrap_or_else(|_| panic!("Buffer should be multipart!"));

    trace!("Fields for server test: {:?}", fields);

    while let Ok(Some(mut field)) = multipart.read_entry() {
        match field.data {
            MultipartData::Text(text) => {
                let test_text = fields.texts.remove(&field.name);

                assert!(
                    test_text.is_some(),
                    "Got text field that wasn't in original dataset: {:?} : {:?} ",
                    field.name, text
                );

                let test_text = test_text.unwrap();

                assert!(
                    text == test_text,
                    "Unexpected data for field {:?}: Expected {:?}, got {:?}",
                    field.name, test_text, text
                );

            },
            MultipartData::File(ref mut file) => {
                let test_bytes = fields.files.remove(&field.name).unwrap();

                let mut bytes = Vec::with_capacity(test_bytes.len());
                file.read_to_end(&mut bytes).unwrap();

                assert!(bytes == test_bytes, "Unexpected data for file {:?}: Expected {:?}, Got {:?}",
                        field.name, String::from_utf8_lossy(&test_bytes), String::from_utf8_lossy(&bytes)
                );
            },
        }
    }

    assert!(fields.texts.is_empty(), "Text fields were not exhausted! Text fields: {:?}", fields.texts);
    assert!(fields.files.is_empty(), "File fields were not exhausted! File fields: {:?}", fields.files);
}

#[derive(Default, Debug)]
pub struct MockClientRequest {
    boundary: Option<String>,
    content_len: Option<u64>,
}

impl ClientRequest for MockClientRequest {
    type Stream = HttpBuffer;
    type Error = io::Error;

    fn apply_headers(&mut self, boundary: &str, content_len: Option<u64>) -> bool {
        self.boundary = Some(boundary.into());
        self.content_len = content_len;
        true
    }

    fn open_stream(self) -> Result<HttpBuffer, io::Error> {
        debug!("MockClientRequest::open_stream called! {:?}", self);
        let boundary = self.boundary.expect("HttpRequest::set_headers() was not called!");

        Ok(HttpBuffer { buf: Vec::new(), boundary: boundary, content_len: self.content_len })
    }
}

#[derive(Debug)]
pub struct HttpBuffer {
    buf: Vec<u8>,
    boundary: String,
    content_len: Option<u64>,
}

impl HttpBuffer {
    pub fn for_server(&self) -> ServerBuffer {
        ServerBuffer {
            data: &self.buf,
            boundary: &self.boundary,
            content_len: self.content_len,
        }
    }
}

impl Write for HttpBuffer {
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        self.buf.write(data)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.buf.flush()
    }
}

impl Read for HttpBuffer {
    fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
        unimplemented!()
    }
}

impl ClientStream for HttpBuffer {
    type Request = MockClientRequest;
    type Response = HttpBuffer;
    type Error = io::Error;

    fn finish(self) -> Result<Self, io::Error> { Ok(self) }
}

#[derive(Debug)]
pub struct ServerBuffer<'a> {
    data: &'a [u8],
    boundary: &'a str,
    content_len: Option<u64>,
}

impl<'a> Read for ServerBuffer<'a> {
    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
        self.data.read(out)
    }
}

impl<'a> ServerRequest for ServerBuffer<'a> {
    type Body = Self;

    fn multipart_boundary(&self) -> Option<&str> { Some(&self.boundary) }

    fn body(self) -> Self::Body {
        self
    }
}

<|endoftext|>


<commit_before>use nom::{
  be_u8, be_u16, be_u32, be_u64,
  le_u32,
  IResult,
  ErrorCode, Err,
  Needed,
};

use std::str::from_utf8;

use metadata::{
  Block, BlockData,
  StreamInfo, Application, VorbisComment, CueSheet, Picture,
  SeekPoint, CueSheetTrack, CueSheetTrackIndex, PictureType,
};

use utility::to_u32;

named!(stream_info <&[u8], BlockData>,
  chain!(
    min_block_size: be_u16 ~
    max_block_size: be_u16 ~
    min_frame_size: map!(take!(3), to_u32) ~
    max_frame_size: map!(take!(3), to_u32) ~
    bytes: take!(8) ~
    md5_sum: take_str!(16),
    || {
      let sample_rate     = ((bytes[0] as u32) << 12) +
                            ((bytes[1] as u32) << 4)  +
                            (bytes[2] as u32) >> 4;
      let channels        = (bytes[2] >> 1) & 0b0111;
      let bits_per_sample = ((bytes[2] & 0b01) << 4) +
                            bytes[3] >> 4;
      let total_samples   = (((bytes[3] as u64) & 0x0f) << 32) +
                            ((bytes[4] as u64) << 24) +
                            ((bytes[5] as u64) << 16) +
                            ((bytes[6] as u64) << 8) +
                            (bytes[7] as u64);

      BlockData::StreamInfo(StreamInfo {
        min_block_size: min_block_size,
        max_block_size: max_block_size,
        min_frame_size: min_frame_size,
        max_frame_size: max_frame_size,
        sample_rate: sample_rate,
        channels: channels + 1,
        bits_per_sample: bits_per_sample + 1,
        total_samples: total_samples,
        md5_sum: md5_sum,
      })
    }
  )
);

fn padding(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  map!(input, take!(length), |_| BlockData::Padding(0))
}

fn application(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  chain!(input,
    id: take_str!(4) ~
    data: take!(length - 4),
    || {
      BlockData::Application(Application {
        id: id,
        data: data,
      })
    }
  )
}

named!(seek_point <&[u8], SeekPoint>,
  chain!(
    sample_number: be_u64 ~
    stream_offset: be_u64 ~
    frame_samples: be_u16,
    || {
      SeekPoint {
        sample_number: sample_number,
        stream_offset: stream_offset,
        frame_samples: frame_samples,
      }
    }
  )
);

fn seek_table(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  let seek_count = (length / 18) as usize;

  map!(input, count!(seek_point, seek_count), BlockData::SeekTable)
}

named!(vorbis_comment <&[u8], BlockData>,
  chain!(
    vendor_string_length: le_u32 ~
    vendor_string: take_str!(vendor_string_length)  ~
    number_of_comments: le_u32 ~
    comments: count!(comment_field, number_of_comments as usize),
    || {
      BlockData::VorbisComment(VorbisComment {
        vendor_string: vendor_string,
        comments: comments,
      })
    }
  )
);

named!(comment_field <&[u8], &str>,
  chain!(
    comment_length: le_u32 ~
    comment: take_str!(comment_length),
    || { comment }
  )
);

named!(cue_sheet <&[u8], BlockData>,
  chain!(
    media_catalog_number: take_str!(128) ~
    lead_in: be_u64 ~
    bytes: take!(259) ~ // TODO: last (7 + 258 * 8) bits must be 0
    num_tracks: be_u8 ~
    tracks: count!(cue_sheet_track, num_tracks as usize),
    || {
      let is_cd = ((bytes[0] >> 7) & 0b01) == 1;

      BlockData::CueSheet(CueSheet {
        media_catalog_number: media_catalog_number,
        lead_in: lead_in,
        is_cd: is_cd,
        tracks: tracks,
      })
    }
  )
);

named!(cue_sheet_track <&[u8], CueSheetTrack>,
  chain!(
    offset: be_u64 ~
    number: be_u8 ~
    isrc: take_str!(12) ~
    bytes: take!(14) ~ // TODO: last (6 + 13 * 8) bits must be 0
    num_indices: be_u8 ~
    indices: count!(cue_sheet_track_index, num_indices as usize),
    || {
      let isnt_audio      = ((bytes[0] >> 7) & 0b01) == 1;
      let is_pre_emphasis = ((bytes[0] >> 6) & 0b01) == 1;

      CueSheetTrack {
        offset: offset,
        number: number,
        isrc: isrc,
        isnt_audio: isnt_audio,
        is_pre_emphasis: is_pre_emphasis,
        indices: indices,
      }
    }
  )
);

named!(cue_sheet_track_index <&[u8], CueSheetTrackIndex>,
  chain!(
    offset: be_u64 ~
    number: be_u8 ~
    take!(3), // TODO: these bytes must be 0
    || {
      CueSheetTrackIndex {
        offset: offset,
        number: number,
      }
    }
  )
);

named!(picture <&[u8], BlockData>,
  chain!(
    picture_type_num: be_u32 ~
    mime_type_length:  be_u32 ~
    mime_type: take_str!(mime_type_length) ~
    description_length: be_u32 ~
    description: take_str!(description_length) ~
    width: be_u32 ~
    height: be_u32 ~
    depth: be_u32 ~
    colors: be_u32 ~
    data_length: be_u32 ~
    data: take!(data_length),
    || {
      let picture_type = match picture_type_num {
        0  => PictureType::Other,
        1  => PictureType::FileIconStandard,
        2  => PictureType::FileIcon,
        3  => PictureType::FrontCover,
        4  => PictureType::BackCover,
        5  => PictureType::LeafletPage,
        6  => PictureType::Media,
        7  => PictureType::LeadArtist,
        8  => PictureType::Artist,
        9  => PictureType::Conductor,
        10 => PictureType::Band,
        11 => PictureType::Composer,
        12 => PictureType::Lyricist,
        13 => PictureType::RecordingLocation,
        14 => PictureType::DuringRecording,
        15 => PictureType::DuringPerformace,
        16 => PictureType::VideoScreenCapture,
        17 => PictureType::Fish,
        18 => PictureType::Illustration,
        19 => PictureType::BandLogoType,
        20 => PictureType::PublisherLogoType,
        _  => PictureType::Other,
      };

      BlockData::Picture(Picture {
        picture_type: picture_type,
        mime_type: mime_type,
        description: description,
        width: width,
        height: height,
        depth: depth,
        colors: colors,
        data: data,
      })
    }
  )
);

fn unknown(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  map!(input, take!(length), BlockData::Unknown)
}

named!(header <&[u8], (u8, bool, u32)>,
  chain!(
    block_byte: be_u8 ~
    length: map!(take!(3), to_u32),
    || {
      let is_last    = (block_byte >> 7) == 1;
      let block_type = block_byte & 0b01111111;

      (block_type, is_last, length)
    }
  )
);

fn block_data(input: &[u8], block_type: u8, length: u32)
              -> IResult<&[u8], BlockData> {
  match block_type {
    0       => stream_info(input),
    1       => padding(input, length),
    2       => application(input, length),
    3       => seek_table(input, length),
    4       => vorbis_comment(input),
    5       => cue_sheet(input),
    6       => picture(input),
    7...126 => unknown(input, length),
    _       => IResult::Error(Err::Position(ErrorCode::Alt as u32, input)),
  }
}

named!(block <&[u8], Block>,
  chain!(
    block_header: header ~
    data: apply!(block_data, block_header.0, block_header.2),
    || {
      Block {
        is_last: block_header.1,
        length: block_header.2,
        data: data
      }
    }
  )
);

pub fn many_blocks(input: &[u8]) -> IResult<&[u8], Vec<Block>> {
  let mut is_last   = false;
  let mut blocks    = Vec::new();
  let mut start     = 0;
  let mut remaining = input.len();

  while !is_last {
    match block(&input[start..]) {
      IResult::Done(i, block) => {
        let result_len = i.len();

        if result_len == input[start..].len() {
          break;
        }

        start    += remaining - result_len;
        remaining = result_len;
        is_last   = block.is_last;

        blocks.push(block);
      }
      _                       => break,
    }
  }

  if blocks.len() == 0 {
    IResult::Error(Err::Position(ErrorCode::Many1 as u32, input))
  } else if is_last {
    IResult::Done(&input[start..], blocks)
  } else {
    IResult::Incomplete(Needed::Unknown)
  }
}
<commit_msg>Remove the conversion from bytes to str<commit_after>use nom::{
  be_u8, be_u16, be_u32, be_u64,
  le_u32,
  IResult,
  ErrorCode, Err,
  Needed,
};

use std::str::from_utf8;

use metadata::{
  Block, BlockData,
  StreamInfo, Application, VorbisComment, CueSheet, Picture,
  SeekPoint, CueSheetTrack, CueSheetTrackIndex, PictureType,
};

use utility::to_u32;

named!(stream_info <&[u8], BlockData>,
  chain!(
    min_block_size: be_u16 ~
    max_block_size: be_u16 ~
    min_frame_size: map!(take!(3), to_u32) ~
    max_frame_size: map!(take!(3), to_u32) ~
    bytes: take!(8) ~
    md5_sum: take!(16),
    || {
      let sample_rate     = ((bytes[0] as u32) << 12) +
                            ((bytes[1] as u32) << 4)  +
                            (bytes[2] as u32) >> 4;
      let channels        = (bytes[2] >> 1) & 0b0111;
      let bits_per_sample = ((bytes[2] & 0b01) << 4) +
                            bytes[3] >> 4;
      let total_samples   = (((bytes[3] as u64) & 0x0f) << 32) +
                            ((bytes[4] as u64) << 24) +
                            ((bytes[5] as u64) << 16) +
                            ((bytes[6] as u64) << 8) +
                            (bytes[7] as u64);

      BlockData::StreamInfo(StreamInfo {
        min_block_size: min_block_size,
        max_block_size: max_block_size,
        min_frame_size: min_frame_size,
        max_frame_size: max_frame_size,
        sample_rate: sample_rate,
        channels: channels + 1,
        bits_per_sample: bits_per_sample + 1,
        total_samples: total_samples,
        md5_sum: md5_sum,
      })
    }
  )
);

fn padding(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  map!(input, take!(length), |_| BlockData::Padding(0))
}

fn application(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  chain!(input,
    id: take_str!(4) ~
    data: take!(length - 4),
    || {
      BlockData::Application(Application {
        id: id,
        data: data,
      })
    }
  )
}

named!(seek_point <&[u8], SeekPoint>,
  chain!(
    sample_number: be_u64 ~
    stream_offset: be_u64 ~
    frame_samples: be_u16,
    || {
      SeekPoint {
        sample_number: sample_number,
        stream_offset: stream_offset,
        frame_samples: frame_samples,
      }
    }
  )
);

fn seek_table(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  let seek_count = (length / 18) as usize;

  map!(input, count!(seek_point, seek_count), BlockData::SeekTable)
}

named!(vorbis_comment <&[u8], BlockData>,
  chain!(
    vendor_string_length: le_u32 ~
    vendor_string: take_str!(vendor_string_length)  ~
    number_of_comments: le_u32 ~
    comments: count!(comment_field, number_of_comments as usize),
    || {
      BlockData::VorbisComment(VorbisComment {
        vendor_string: vendor_string,
        comments: comments,
      })
    }
  )
);

named!(comment_field <&[u8], &str>,
  chain!(
    comment_length: le_u32 ~
    comment: take_str!(comment_length),
    || { comment }
  )
);

named!(cue_sheet <&[u8], BlockData>,
  chain!(
    media_catalog_number: take_str!(128) ~
    lead_in: be_u64 ~
    bytes: take!(259) ~ // TODO: last (7 + 258 * 8) bits must be 0
    num_tracks: be_u8 ~
    tracks: count!(cue_sheet_track, num_tracks as usize),
    || {
      let is_cd = ((bytes[0] >> 7) & 0b01) == 1;

      BlockData::CueSheet(CueSheet {
        media_catalog_number: media_catalog_number,
        lead_in: lead_in,
        is_cd: is_cd,
        tracks: tracks,
      })
    }
  )
);

named!(cue_sheet_track <&[u8], CueSheetTrack>,
  chain!(
    offset: be_u64 ~
    number: be_u8 ~
    isrc: take_str!(12) ~
    bytes: take!(14) ~ // TODO: last (6 + 13 * 8) bits must be 0
    num_indices: be_u8 ~
    indices: count!(cue_sheet_track_index, num_indices as usize),
    || {
      let isnt_audio      = ((bytes[0] >> 7) & 0b01) == 1;
      let is_pre_emphasis = ((bytes[0] >> 6) & 0b01) == 1;

      CueSheetTrack {
        offset: offset,
        number: number,
        isrc: isrc,
        isnt_audio: isnt_audio,
        is_pre_emphasis: is_pre_emphasis,
        indices: indices,
      }
    }
  )
);

named!(cue_sheet_track_index <&[u8], CueSheetTrackIndex>,
  chain!(
    offset: be_u64 ~
    number: be_u8 ~
    take!(3), // TODO: these bytes must be 0
    || {
      CueSheetTrackIndex {
        offset: offset,
        number: number,
      }
    }
  )
);

named!(picture <&[u8], BlockData>,
  chain!(
    picture_type_num: be_u32 ~
    mime_type_length:  be_u32 ~
    mime_type: take_str!(mime_type_length) ~
    description_length: be_u32 ~
    description: take_str!(description_length) ~
    width: be_u32 ~
    height: be_u32 ~
    depth: be_u32 ~
    colors: be_u32 ~
    data_length: be_u32 ~
    data: take!(data_length),
    || {
      let picture_type = match picture_type_num {
        0  => PictureType::Other,
        1  => PictureType::FileIconStandard,
        2  => PictureType::FileIcon,
        3  => PictureType::FrontCover,
        4  => PictureType::BackCover,
        5  => PictureType::LeafletPage,
        6  => PictureType::Media,
        7  => PictureType::LeadArtist,
        8  => PictureType::Artist,
        9  => PictureType::Conductor,
        10 => PictureType::Band,
        11 => PictureType::Composer,
        12 => PictureType::Lyricist,
        13 => PictureType::RecordingLocation,
        14 => PictureType::DuringRecording,
        15 => PictureType::DuringPerformace,
        16 => PictureType::VideoScreenCapture,
        17 => PictureType::Fish,
        18 => PictureType::Illustration,
        19 => PictureType::BandLogoType,
        20 => PictureType::PublisherLogoType,
        _  => PictureType::Other,
      };

      BlockData::Picture(Picture {
        picture_type: picture_type,
        mime_type: mime_type,
        description: description,
        width: width,
        height: height,
        depth: depth,
        colors: colors,
        data: data,
      })
    }
  )
);

fn unknown(input: &[u8], length: u32) -> IResult<&[u8], BlockData> {
  map!(input, take!(length), BlockData::Unknown)
}

named!(header <&[u8], (u8, bool, u32)>,
  chain!(
    block_byte: be_u8 ~
    length: map!(take!(3), to_u32),
    || {
      let is_last    = (block_byte >> 7) == 1;
      let block_type = block_byte & 0b01111111;

      (block_type, is_last, length)
    }
  )
);

fn block_data(input: &[u8], block_type: u8, length: u32)
              -> IResult<&[u8], BlockData> {
  match block_type {
    0       => stream_info(input),
    1       => padding(input, length),
    2       => application(input, length),
    3       => seek_table(input, length),
    4       => vorbis_comment(input),
    5       => cue_sheet(input),
    6       => picture(input),
    7...126 => unknown(input, length),
    _       => IResult::Error(Err::Position(ErrorCode::Alt as u32, input)),
  }
}

named!(block <&[u8], Block>,
  chain!(
    block_header: header ~
    data: apply!(block_data, block_header.0, block_header.2),
    || {
      Block {
        is_last: block_header.1,
        length: block_header.2,
        data: data
      }
    }
  )
);

pub fn many_blocks(input: &[u8]) -> IResult<&[u8], Vec<Block>> {
  let mut is_last   = false;
  let mut blocks    = Vec::new();
  let mut start     = 0;
  let mut remaining = input.len();

  while !is_last {
    match block(&input[start..]) {
      IResult::Done(i, block) => {
        let result_len = i.len();

        if result_len == input[start..].len() {
          break;
        }

        start    += remaining - result_len;
        remaining = result_len;
        is_last   = block.is_last;

        blocks.push(block);
      }
      _                       => break,
    }
  }

  if blocks.len() == 0 {
    IResult::Error(Err::Position(ErrorCode::Many1 as u32, input))
  } else if is_last {
    IResult::Done(&input[start..], blocks)
  } else {
    IResult::Incomplete(Needed::Unknown)
  }
}
<|endoftext|>


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

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

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

#[deriving(Clone)]
pub enum TintSource {
    NoTint,
    GrassTint,
    FoliageTint,
    RedstoneTint
}

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 {
    TextureVariable(String),
    TextureCoords(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 == Opaque
    }

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

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

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.find_equiv(&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("#") {
                    TextureVariable(tex.slice_from(1).to_string())
                } else {
                    let (u, v) = atlas.load(tex);
                    TextureCoords(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_list()) {
            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_list().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_list().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 => fail!("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 => fail!("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.find(tex) {
                        Some(&TextureVariable(ref tex)) => texture_coords(textures, tex),
                        Some(&TextureCoords(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 = [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] == 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 opacity = match atlas.min_alpha(u0, v0, u1 - u0, v1 - v0) {
                        0 => TransparentSolid,
                        255 => Opaque,
                        _ => 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_") => GrassTint,
                    "reeds" | "fern" | "tall_grass" => GrassTint,
                    name if name.ends_with("_leaves") || name.ends_with("_stem_fruit") ||
                            name.starts_with("vine_") || name.starts_with("stem_") => FoliageTint,
                    "waterlily" => FoliageTint,
                    name if name.starts_with("redstone_") => RedstoneTint,
                    _ => {
                        println!("tint source not known for '{}'", name);
                        NoTint
                    }
                }
            } else {
                NoTint
            };

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

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

    pub fn is_empty(&self) -> bool {
        self.faces.is_empty()
    }
}
<commit_msg>Upgrade to latest gfx_voxel<commit_after>
use serialize::json;
use std::collections::HashMap;
use std::collections::hashmap::{ Occupied, Vacant };
use std::f32::consts::{PI, SQRT2};
use std::f32::INFINITY;
use std::io::fs::File;

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

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

#[deriving(Clone)]
pub enum TintSource {
    NoTint,
    GrassTint,
    FoliageTint,
    RedstoneTint
}

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 {
    TextureVariable(String),
    TextureCoords(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 == Opaque
    }

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

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

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.find_equiv(&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("#") {
                    TextureVariable(tex.slice_from(1).to_string())
                } else {
                    let (u, v) = atlas.load(tex);
                    TextureCoords(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_list()) {
            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_list().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_list().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 => fail!("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 => fail!("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.find(tex) {
                        Some(&TextureVariable(ref tex)) => texture_coords(textures, tex),
                        Some(&TextureCoords(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 = [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] == 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 => TransparentSolid,
                        255 => Opaque,
                        _ => 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_") => GrassTint,
                    "reeds" | "fern" | "tall_grass" => GrassTint,
                    name if name.ends_with("_leaves") || name.ends_with("_stem_fruit") ||
                            name.starts_with("vine_") || name.starts_with("stem_") => FoliageTint,
                    "waterlily" => FoliageTint,
                    name if name.starts_with("redstone_") => RedstoneTint,
                    _ => {
                        println!("tint source not known for '{}'", name);
                        NoTint
                    }
                }
            } else {
                NoTint
            };

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

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

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


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::iter::FromIterator;
use std::ops::Deref;

use syntax::ast;
use syntax::ptr::P;
use syntax::ast_util::empty_generics;
use syntax::codemap::{respan, mk_sp};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::utils;
use super::super::node;

/// A visitor to build the struct for each register
pub struct BuildRegStructs<'a> {
  builder: &'a mut Builder,
  cx: &'a ExtCtxt<'a>,
}

impl<'a> node::RegVisitor for BuildRegStructs<'a> {
  fn visit_prim_reg(&mut self, path: &Vec<String>, reg: &node::Reg,
                    width: &node::RegWidth, fields: &Vec<node::Field>) {
    for field in fields.iter() {
      for item in build_field_type(self.cx, path, reg, field).into_iter() {
        self.builder.push_item(item);
      }
    }

    for item in build_reg_struct(self.cx, path, reg, width).into_iter() {
      self.builder.push_item(item);
    }
  }
}

impl<'a> BuildRegStructs<'a> {
  pub fn new(builder: &'a mut Builder, cx: &'a ExtCtxt<'a>)
             -> BuildRegStructs<'a> {
    BuildRegStructs {builder: builder, cx: cx}
  }
}

/// Build a field type if necessary (e.g. in the case of an `EnumField`)
fn build_field_type(cx: &ExtCtxt, path: &Vec<String>,
                    reg: &node::Reg, field: &node::Field)
                    -> Vec<P<ast::Item>> {
  match field.ty.node {
    node::FieldType::EnumField { ref variants, .. } => {
      // FIXME(bgamari): We construct a path, then only take the last
      // segment, this could be more efficient
      let name: ast::Ident =
        utils::field_type_path(cx, path, reg, field)
        .segments.last().unwrap().identifier;
      let enum_def: ast::EnumDef = ast::EnumDef {
        variants: FromIterator::from_iter(
          variants.iter().map(|v| P(build_enum_variant(cx, v)))),
      };
      let attrs: Vec<ast::Attribute> = vec!(
        utils::list_attribute(cx, "derive", vec!("FromPrimitive")),
        utils::list_attribute(cx, "allow",
                              vec!("dead_code",
                                   "non_camel_case_types",
                                   "missing_docs")));
      let ty_item: P<ast::Item> = P(ast::Item {
        ident: name,
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemEnum(enum_def, empty_generics()),
        vis: ast::Public,
        attrs: attrs,
        span: field.ty.span,
      });
      vec!(ty_item)
    },
    _ => Vec::new()
  }
}

/// Produce a register struct if necessary (for primitive typed registers).
/// In this case `None` indicates no struct is necessary, not failure.
/// For instance,
///
///     pub struct REG {_value: u32}
fn build_reg_struct(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _width: &node::RegWidth) -> Vec<P<ast::Item>> {
  let packed_ty =
    utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive reg");

  let reg_doc = match reg.docstring {
    Some(d) => token::get_ident(d.node).get().to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Register `{}`: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let ty_name = utils::path_ident(cx, path);
  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types)]
    pub struct $ty_name {
      value: VolatileCell<$packed_ty>,
    }
  );
  let mut item: ast::Item = item.unwrap().deref().clone();
  item.span = reg.name.span;
  // let copy_impl = quote_item!(cx, impl ::core::marker::Copy for $ty_name {}).unwrap();
  vec!(P(item))
}

/// Build a variant of an `EnumField`
fn build_enum_variant(cx: &ExtCtxt, variant: &node::Variant)
                      -> ast::Variant {
  let doc = match variant.docstring {
    Some(d) => token::get_ident(d.node).get().to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("`0x{:x}`. {}",
                          variant.value.node,
                          doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));
  respan(
    mk_sp(variant.name.span.lo, variant.value.span.hi),
    ast::Variant_ {
      name: cx.ident_of(variant.name.node.as_slice()),
      attrs: vec!(doc_attr),
      kind: ast::TupleVariantKind(Vec::new()),
      id: ast::DUMMY_NODE_ID,
      disr_expr: Some(utils::expr_int(cx, variant.value.node as i64)),
      vis: ast::Inherited,
    }
  )
}
<commit_msg>ioreg: Add Copy impl for primitive register structs<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::iter::FromIterator;
use std::ops::Deref;

use syntax::ast;
use syntax::ptr::P;
use syntax::ast_util::empty_generics;
use syntax::codemap::{respan, mk_sp};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::quote::rt::ToTokens;
use syntax::parse::token;

use super::Builder;
use super::utils;
use super::super::node;

/// A visitor to build the struct for each register
pub struct BuildRegStructs<'a> {
  builder: &'a mut Builder,
  cx: &'a ExtCtxt<'a>,
}

impl<'a> node::RegVisitor for BuildRegStructs<'a> {
  fn visit_prim_reg(&mut self, path: &Vec<String>, reg: &node::Reg,
                    width: &node::RegWidth, fields: &Vec<node::Field>) {
    for field in fields.iter() {
      for item in build_field_type(self.cx, path, reg, field).into_iter() {
        self.builder.push_item(item);
      }
    }

    for item in build_reg_struct(self.cx, path, reg, width).into_iter() {
      self.builder.push_item(item);
    }
  }
}

impl<'a> BuildRegStructs<'a> {
  pub fn new(builder: &'a mut Builder, cx: &'a ExtCtxt<'a>)
             -> BuildRegStructs<'a> {
    BuildRegStructs {builder: builder, cx: cx}
  }
}

/// Build a field type if necessary (e.g. in the case of an `EnumField`)
fn build_field_type(cx: &ExtCtxt, path: &Vec<String>,
                    reg: &node::Reg, field: &node::Field)
                    -> Vec<P<ast::Item>> {
  match field.ty.node {
    node::FieldType::EnumField { ref variants, .. } => {
      // FIXME(bgamari): We construct a path, then only take the last
      // segment, this could be more efficient
      let name: ast::Ident =
        utils::field_type_path(cx, path, reg, field)
        .segments.last().unwrap().identifier;
      let enum_def: ast::EnumDef = ast::EnumDef {
        variants: FromIterator::from_iter(
          variants.iter().map(|v| P(build_enum_variant(cx, v)))),
      };
      let attrs: Vec<ast::Attribute> = vec!(
        utils::list_attribute(cx, "derive", vec!("FromPrimitive")),
        utils::list_attribute(cx, "allow",
                              vec!("dead_code",
                                   "non_camel_case_types",
                                   "missing_docs")));
      let ty_item: P<ast::Item> = P(ast::Item {
        ident: name,
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemEnum(enum_def, empty_generics()),
        vis: ast::Public,
        attrs: attrs,
        span: field.ty.span,
      });
      vec!(ty_item)
    },
    _ => Vec::new()
  }
}

/// Produce a register struct if necessary (for primitive typed registers).
/// In this case `None` indicates no struct is necessary, not failure.
/// For instance,
///
///     pub struct REG {_value: u32}
fn build_reg_struct(cx: &ExtCtxt, path: &Vec<String>,
    reg: &node::Reg, _width: &node::RegWidth) -> Vec<P<ast::Item>> {
  let packed_ty =
    utils::reg_primitive_type(cx, reg)
    .expect("Unexpected non-primitive reg");

  let reg_doc = match reg.docstring {
    Some(d) => token::get_ident(d.node).get().to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("Register `{}`: {}",
                          reg.name.node,
                          reg_doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));

  let ty_name = utils::path_ident(cx, path);
  let item = quote_item!(cx,
    $doc_attr
    #[allow(non_camel_case_types)]
    pub struct $ty_name {
      value: VolatileCell<$packed_ty>,
    }
  );
  let mut item: ast::Item = item.unwrap().deref().clone();
  item.span = reg.name.span;
  let copy_impl = quote_item!(cx, impl ::core::marker::Copy for $ty_name {}).unwrap();
  vec!(P(item), copy_impl)
}

/// Build a variant of an `EnumField`
fn build_enum_variant(cx: &ExtCtxt, variant: &node::Variant)
                      -> ast::Variant {
  let doc = match variant.docstring {
    Some(d) => token::get_ident(d.node).get().to_string(),
    None => "no documentation".to_string(),
  };
  let docstring = format!("`0x{:x}`. {}",
                          variant.value.node,
                          doc);
  let doc_attr = utils::doc_attribute(cx, utils::intern_string(cx, docstring));
  respan(
    mk_sp(variant.name.span.lo, variant.value.span.hi),
    ast::Variant_ {
      name: cx.ident_of(variant.name.node.as_slice()),
      attrs: vec!(doc_attr),
      kind: ast::TupleVariantKind(Vec::new()),
      id: ast::DUMMY_NODE_ID,
      disr_expr: Some(utils::expr_int(cx, variant.value.node as i64)),
      vis: ast::Inherited,
    }
  )
}
<|endoftext|>