<commit_before>//! The Actual RethinkDB Commands

use errors::*;
use conn::{Connection, ConnectOpts};
use serde_json;
use ql2::proto;
use std::io::Write;
use byteorder::{WriteBytesExt, LittleEndian};
use std::io::Read;
use std::str;
use protobuf::ProtobufEnum;
use byteorder::ReadBytesExt;
use super::session::Client;
use super::{Result, r};

pub struct RootCommand(Result<String>);
pub struct Command;
pub struct Query;

impl Client {
    pub fn connection(&self) -> ConnectOpts {
        Self::config().read().clone()
    }

    pub fn db_create(&self, name: &str) -> RootCommand {
        RootCommand(Ok(Command::wrap(proto::Term_TermType::DB_CREATE,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     None)))
    }

    pub fn db_drop(&self, name: &str) -> RootCommand {
        RootCommand(Ok(Command::wrap(proto::Term_TermType::DB_DROP,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     None)))
    }

    pub fn db(&self, name: &str) -> RootCommand {
        RootCommand(Ok(Command::wrap(proto::Term_TermType::DB,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     None)))
    }

    pub fn table_create(&self, name: &str) -> RootCommand {
        let config = Client::config().read();
        r.db(config.db).table_create(name)
    }

    pub fn table(&self, name: &str) -> RootCommand {
        let config = Client::config().read();
        r.db(config.db).table(name)
    }

    pub fn object(&self) -> serde_json::builder::ObjectBuilder {
        serde_json::builder::ObjectBuilder::new()
    }

    pub fn array(&self) -> serde_json::builder::ArrayBuilder {
        serde_json::builder::ArrayBuilder::new()
    }
}

impl RootCommand {
    pub fn table_create(self, name: &str) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::TABLE_CREATE,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     Some(&commands))))
    }

    pub fn table(self, name: &str) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::TABLE,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     Some(&commands))))
    }

    pub fn insert(self, expr: serde_json::Value) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        let data = match serde_json::to_string(&expr) {
            Ok(f) => f,
            Err(e) => return RootCommand(Err(From::from(DriverError::Json(e)))),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::INSERT,
                                     Some(&data),
                                     None,
                                     Some(&commands))))
    }

    pub fn delete(self) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::DELETE, None, None, Some(&commands))))
    }

    pub fn filter(self, expr: serde_json::Value) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        let filter = match serde_json::to_string(&expr) {
            Ok(f) => f,
            Err(e) => return RootCommand(Err(From::from(DriverError::Json(e)))),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::FILTER,
                                     Some(&filter),
                                     None,
                                     Some(&commands))))
    }

    pub fn run(self) -> Result<String> {
        let logger = Client::logger().read();
        trace!(logger, "Calling r.run()");
        let commands = try!(self.0);
        let cfg = Client::config().read();
        let query = Query::wrap(proto::Query_QueryType::START, Some(&commands), None);
        debug!(logger, "{}", query);
        let mut conn = try!(Client::conn());
        // Try sending the query
        {
            let mut i = 0;
            let mut write = true;
            let mut connect = false;
            while i < cfg.retries {
                debug!(logger, "Getting connection...");
                if connect {
                    drop(&mut conn);
                    conn = match Client::conn() {
                        Ok(c) => c,
                        Err(error) => {
                            if i == cfg.retries - 1 {
                                // The last error
                                return Err(From::from(error));
                            } else {
                                debug!(logger, "Failed getting a connection. Retrying...");
                                i += 1;
                                continue;
                            }
                        }
                    };
                }
                debug!(logger, "Connection aquired.");
                conn.token += 1;
                if write {
                    debug!(logger, "Writing query...");
                    if let Err(error) = Query::write(&query, &mut conn) {
                        connect = true;
                        if i == cfg.retries - 1 {
                            // The last error
                            return Err(From::from(error));
                        } else {
                            debug!(logger, "Failed to write query. Retrying...");
                            i += 1;
                            continue;
                        }
                    }
                    debug!(logger, "Query written...");
                    connect = false;
                }
                debug!(logger, "Reading query...");
                match Query::read(&mut conn) {
                    Ok(resp) => {
                        let result = try!(str::from_utf8(&resp));
                        debug!(logger, "{}", result);
                        // If the write operation failed, retry it
                        // {"t":18,"e":4100000,"r":["Cannot perform write: primary replica for
                        // shard [\"\", +inf) not available"],"b":[]}
                        let msg = r#"{"t":18,"e":4100000,"r":["Cannot perform write: primary replica for shard"#;
                        if result.starts_with(msg) {
                            write = true;
                        if i == cfg.retries-1 { // The last error
                            return Err(
                                From::from(
                                    AvailabilityError::OpFailed(
                                        String::from("Not available")
                                        )));
                        } else {
                            debug!(logger, "Write operation failed. Retrying...");
                            i += 1;
                            continue;
                        }
                    } else {
                        debug!(logger, "Query successfully read.");
                        // This is a successful operation
                        break;
                    }
                    }
                    Err(error) => {
                        write = false;
                        if i == cfg.retries - 1 {
                            // The last error
                            return Err(From::from(error));
                        } else {
                            debug!(logger, "Failed to read query. Retrying...");
                            i += 1;
                            continue;
                        }
                    }
                }
            }
        }
        Ok(String::new())
    }
}

impl Command {
    pub fn wrap(command: proto::Term_TermType,
                arguments: Option<&str>,
                options: Option<&str>,
                commands: Option<&str>)
                -> String {
        let mut cmds = format!("[{},", command.value());
        let mut args = String::new();
        if let Some(commands) = commands {
            args.push_str(commands);
            if arguments.is_some() {
                args.push_str(",");
            }
        }
        if let Some(arguments) = arguments {
            args.push_str(arguments);
        }
        cmds.push_str(&format!("[{}]", args));
        if let Some(options) = options {
            cmds.push_str(&format!(",{{{}}}", options));
        }
        cmds.push(']');
        cmds
    }
}

impl Query {
    pub fn wrap(query_type: proto::Query_QueryType,
                query: Option<&str>,
                options: Option<&str>)
                -> String {
        let mut qry = format!("[{}", query_type.value());
        if let Some(query) = query {
            qry.push_str(&format!(",{}", query));
        }
        if let Some(options) = options {
            qry.push_str(&format!(",{}", options));
        }
        qry.push_str("]");
        qry
    }

    pub fn write(query: &str, conn: &mut Connection) -> Result<()> {
        let query = query.as_bytes();
        let token = conn.token;
        if let Err(error) = conn.stream.write_u64::<LittleEndian>(token) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.write_u32::<LittleEndian>(query.len() as u32) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.write_all(query) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.flush() {
            conn.broken = true;
            return Err(From::from(error));
        }
        Ok(())
    }

    pub fn read(conn: &mut Connection) -> Result<Vec<u8>> {
        // @TODO use response_token to implement parallel reads and writes?
        // let response_token = try!(conn.stream.read_u64::<LittleEndian>());
        let _ = match conn.stream.read_u64::<LittleEndian>() {
            Ok(token) => token,
            Err(error) => {
                conn.broken = true;
                return Err(From::from(error));
            }
        };
        let len = match conn.stream.read_u32::<LittleEndian>() {
            Ok(len) => len,
            Err(error) => {
                conn.broken = true;
                return Err(From::from(error));
            }
        };
        let mut resp = vec![0u8; len as usize];
        if let Err(error) = conn.stream.read_exact(&mut resp) {
            conn.broken = true;
            return Err(From::from(error));
        }
        Ok(resp)
    }
}
<commit_msg>Run rustfmt<commit_after>//! The Actual RethinkDB Commands

use errors::*;
use conn::{Connection, ConnectOpts};
use serde_json;
use ql2::proto;
use std::io::Write;
use byteorder::{WriteBytesExt, LittleEndian};
use std::io::Read;
use std::str;
use protobuf::ProtobufEnum;
use byteorder::ReadBytesExt;
use super::session::Client;
use super::{Result, r};

pub struct RootCommand(Result<String>);
pub struct Command;
pub struct Query;

impl Client {
    pub fn connection(&self) -> ConnectOpts {
        Self::config().read().clone()
    }

    pub fn db_create(&self, name: &str) -> RootCommand {
        RootCommand(Ok(Command::wrap(proto::Term_TermType::DB_CREATE,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     None)))
    }

    pub fn db_drop(&self, name: &str) -> RootCommand {
        RootCommand(Ok(Command::wrap(proto::Term_TermType::DB_DROP,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     None)))
    }

    pub fn db(&self, name: &str) -> RootCommand {
        RootCommand(Ok(Command::wrap(proto::Term_TermType::DB,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     None)))
    }

    pub fn table_create(&self, name: &str) -> RootCommand {
        let config = Client::config().read();
        r.db(config.db).table_create(name)
    }

    pub fn table(&self, name: &str) -> RootCommand {
        let config = Client::config().read();
        r.db(config.db).table(name)
    }

    pub fn object(&self) -> serde_json::builder::ObjectBuilder {
        serde_json::builder::ObjectBuilder::new()
    }

    pub fn array(&self) -> serde_json::builder::ArrayBuilder {
        serde_json::builder::ArrayBuilder::new()
    }
}

impl RootCommand {
    pub fn table_create(self, name: &str) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::TABLE_CREATE,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     Some(&commands))))
    }

    pub fn table(self, name: &str) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::TABLE,
                                     Some(&format!("{:?}", name)),
                                     None,
                                     Some(&commands))))
    }

    pub fn insert(self, expr: serde_json::Value) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        let data = match serde_json::to_string(&expr) {
            Ok(f) => f,
            Err(e) => return RootCommand(Err(From::from(DriverError::Json(e)))),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::INSERT,
                                     Some(&data),
                                     None,
                                     Some(&commands))))
    }

    pub fn delete(self) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::DELETE, None, None, Some(&commands))))
    }

    pub fn filter(self, expr: serde_json::Value) -> RootCommand {
        let commands = match self.0 {
            Ok(t) => t,
            Err(e) => return RootCommand(Err(e)),
        };
        let filter = match serde_json::to_string(&expr) {
            Ok(f) => f,
            Err(e) => return RootCommand(Err(From::from(DriverError::Json(e)))),
        };
        RootCommand(Ok(Command::wrap(proto::Term_TermType::FILTER,
                                     Some(&filter),
                                     None,
                                     Some(&commands))))
    }

    pub fn run(self) -> Result<String> {
        let logger = Client::logger().read();
        trace!(logger, "Calling r.run()");
        let commands = try!(self.0);
        let cfg = Client::config().read();
        let query = Query::wrap(proto::Query_QueryType::START, Some(&commands), None);
        debug!(logger, "{}", query);
        let mut conn = try!(Client::conn());
        // Try sending the query
        {
            let mut i = 0;
            let mut write = true;
            let mut connect = false;
            while i < cfg.retries {
                debug!(logger, "Getting connection...");
                if connect {
                    drop(&mut conn);
                    conn = match Client::conn() {
                        Ok(c) => c,
                        Err(error) => {
                            if i == cfg.retries - 1 {
                                // The last error
                                return Err(From::from(error));
                            } else {
                                debug!(logger, "Failed getting a connection. Retrying...");
                                i += 1;
                                continue;
                            }
                        }
                    };
                }
                debug!(logger, "Connection aquired.");
                conn.token += 1;
                if write {
                    debug!(logger, "Writing query...");
                    if let Err(error) = Query::write(&query, &mut conn) {
                        connect = true;
                        if i == cfg.retries - 1 {
                            // The last error
                            return Err(From::from(error));
                        } else {
                            debug!(logger, "Failed to write query. Retrying...");
                            i += 1;
                            continue;
                        }
                    }
                    debug!(logger, "Query written...");
                    connect = false;
                }
                debug!(logger, "Reading query...");
                match Query::read(&mut conn) {
                    Ok(resp) => {
                        let result = try!(str::from_utf8(&resp));
                        debug!(logger, "{}", result);
                        // If the write operation failed, retry it
                        // {"t":18,"e":4100000,"r":["Cannot perform write: primary replica for
                        // shard [\"\", +inf) not available"],"b":[]}
                        let msg = r#"{"t":18,"e":4100000,"r":["Cannot perform write: primary replica for shard"#;
                        if result.starts_with(msg) {
                            write = true;
                            if i == cfg.retries - 1 {
                                // The last error
                                return Err(
                                From::from(
                                    AvailabilityError::OpFailed(
                                        String::from("Not available")
                                        )));
                            } else {
                                debug!(logger, "Write operation failed. Retrying...");
                                i += 1;
                                continue;
                            }
                        } else {
                            debug!(logger, "Query successfully read.");
                            // This is a successful operation
                            break;
                        }
                    }
                    Err(error) => {
                        write = false;
                        if i == cfg.retries - 1 {
                            // The last error
                            return Err(From::from(error));
                        } else {
                            debug!(logger, "Failed to read query. Retrying...");
                            i += 1;
                            continue;
                        }
                    }
                }
            }
        }
        Ok(String::new())
    }
}

impl Command {
    pub fn wrap(command: proto::Term_TermType,
                arguments: Option<&str>,
                options: Option<&str>,
                commands: Option<&str>)
                -> String {
        let mut cmds = format!("[{},", command.value());
        let mut args = String::new();
        if let Some(commands) = commands {
            args.push_str(commands);
            if arguments.is_some() {
                args.push_str(",");
            }
        }
        if let Some(arguments) = arguments {
            args.push_str(arguments);
        }
        cmds.push_str(&format!("[{}]", args));
        if let Some(options) = options {
            cmds.push_str(&format!(",{{{}}}", options));
        }
        cmds.push(']');
        cmds
    }
}

impl Query {
    pub fn wrap(query_type: proto::Query_QueryType,
                query: Option<&str>,
                options: Option<&str>)
                -> String {
        let mut qry = format!("[{}", query_type.value());
        if let Some(query) = query {
            qry.push_str(&format!(",{}", query));
        }
        if let Some(options) = options {
            qry.push_str(&format!(",{}", options));
        }
        qry.push_str("]");
        qry
    }

    pub fn write(query: &str, conn: &mut Connection) -> Result<()> {
        let query = query.as_bytes();
        let token = conn.token;
        if let Err(error) = conn.stream.write_u64::<LittleEndian>(token) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.write_u32::<LittleEndian>(query.len() as u32) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.write_all(query) {
            conn.broken = true;
            return Err(From::from(error));
        }
        if let Err(error) = conn.stream.flush() {
            conn.broken = true;
            return Err(From::from(error));
        }
        Ok(())
    }

    pub fn read(conn: &mut Connection) -> Result<Vec<u8>> {
        // @TODO use response_token to implement parallel reads and writes?
        // let response_token = try!(conn.stream.read_u64::<LittleEndian>());
        let _ = match conn.stream.read_u64::<LittleEndian>() {
            Ok(token) => token,
            Err(error) => {
                conn.broken = true;
                return Err(From::from(error));
            }
        };
        let len = match conn.stream.read_u32::<LittleEndian>() {
            Ok(len) => len,
            Err(error) => {
                conn.broken = true;
                return Err(From::from(error));
            }
        };
        let mut resp = vec![0u8; len as usize];
        if let Err(error) = conn.stream.read_exact(&mut resp) {
            conn.broken = true;
            return Err(From::from(error));
        }
        Ok(resp)
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io::ErrorKind::NotFound;
use std::io::Read;
use std::fs::File;
use std::str;

use parser::{Parser, Token};
use super::Context;

/// `Compiler` is a object that compiles a string into a `Vec<Token>`.
pub struct Compiler<T> {
    ctx: Context,
    reader: T,
    partials: HashMap<String, Vec<Token>>,
    otag: String,
    ctag: String,
}

impl<T: Iterator<Item = char>> Compiler<T> {
    /// Construct a default compiler.
    pub fn new(ctx: Context, reader: T) -> Compiler<T> {
        Compiler {
            ctx: ctx,
            reader: reader,
            partials: HashMap::new(),
            otag: "{{".to_string(),
            ctag: "}}".to_string(),
        }
    }

    /// Construct a default compiler.
    pub fn new_with(ctx: Context,
                    reader: T,
                    partials: HashMap<String, Vec<Token>>,
                    otag: String,
                    ctag: String)
                    -> Compiler<T> {
        Compiler {
            ctx: ctx,
            reader: reader,
            partials: partials,
            otag: otag,
            ctag: ctag,
        }
    }

    /// Compiles a template into a series of tokens.
    pub fn compile(mut self) -> (Vec<Token>, HashMap<String, Vec<Token>>) {
        let (tokens, partials) = {
            let parser = Parser::new(&mut self.reader, &self.otag, &self.ctag);
            parser.parse()
        };

        // Compile the partials if we haven't done so already.
        for name in partials.into_iter() {
            let path =
                self.ctx.template_path.join(&(name.clone() + "." + &self.ctx.template_extension));

            if !self.partials.contains_key(&name) {
                // Insert a placeholder so we don't recurse off to infinity.
                self.partials.insert(name.to_string(), Vec::new());

                match File::open(&path) {
                    Ok(mut file) => {
                        let mut contents = vec![];
                        file.read_to_end(&mut contents).unwrap();
                        let string = match str::from_utf8(&contents) {
                            Ok(string) => string.to_string(),
                            Err(_) => {
                                panic!("Failed to parse file as UTF-8");
                            }
                        };

                        let compiler = Compiler {
                            ctx: self.ctx.clone(),
                            reader: string.chars(),
                            partials: self.partials.clone(),
                            otag: "{{".to_string(),
                            ctag: "}}".to_string(),
                        };

                        let (tokens, subpartials) = compiler.compile();

                        // Include subpartials
                        self.partials.extend(subpartials.into_iter());

                        // Set final compiled tokens for *this* partial
                        self.partials.insert(name, tokens);
                    }
                    Err(e) => {
                        // Ignore missing files.
                        if e.kind() != NotFound {
                            panic!("error reading file: {}", e);
                        }
                    }
                }
            }
        }

        let Compiler { partials, .. } = self;

        (tokens, partials)
    }
}

#[cfg(test)]
mod tests {
    use parser::{Token, Text, ETag, UTag, Section, IncompleteSection, Partial};
    use super::Compiler;
    use super::super::Context;
    use std::path::PathBuf;

    fn compile_str(template: &str) -> Vec<Token> {
        let ctx = Context::new(PathBuf::from("."));
        let (tokens, _) = Compiler::new(ctx, template.chars()).compile();
        tokens
    }

    fn token_to_str(token: &Token) -> String {
        match *token {
            // recursive enums crash %?
            Section(ref name,
                    inverted,
                    ref children,
                    ref otag,
                    ref osection,
                    ref src,
                    ref tag,
                    ref ctag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                let children = children.iter().map(|x| token_to_str(x)).collect::<Vec<String>>();
                format!("Section(vec!({}), {}, vec!({}), {}, {}, {}, {}, {})",
                        name.join(", "),
                        inverted,
                        children.join(", "),
                        otag,
                        osection,
                        src,
                        tag,
                        ctag)
            }
            ETag(ref name, ref tag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("ETag(vec!({}), {})", name.join(", "), *tag)
            }
            UTag(ref name, ref tag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("UTag(vec!({}), {})", name.join(", "), *tag)
            }
            IncompleteSection(ref name, ref inverted, ref osection, ref newlined) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("IncompleteSection(vec!({}), {}, {}, {})",
                        name.join(", "),
                        *inverted,
                        *osection,
                        *newlined)
            }
            _ => format!("{:?}", token),
        }
    }

    fn check_tokens(_actual: Vec<Token>, _expected: &[Token]) {
        // TODO: equality is currently broken for enums
        // let actual: Vec<String> = actual.iter().map(token_to_str).collect();
        // let expected = expected.iter().map(token_to_str).collect();

        // assert_eq!(actual, expected);
    }

    #[test]
    fn test_compile_texts() {
        check_tokens(compile_str("hello world"),
                     &[Text("hello world".to_string())]);
        check_tokens(compile_str("hello {world"),
                     &[Text("hello {world".to_string())]);
        check_tokens(compile_str("hello world}"),
                     &[Text("hello world}".to_string())]);
        check_tokens(compile_str("hello world}}"),
                     &[Text("hello world}}".to_string())]);
    }

    #[test]
    fn test_compile_etags() {
        check_tokens(compile_str("{{ name }}"),
                     &[ETag(vec!["name".to_string()], "{{ name }}".to_string())]);

        check_tokens(compile_str("before {{name}} after"),
                     &[Text("before ".to_string()),
                       ETag(vec!["name".to_string()], "{{name}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{name}}"),
                     &[Text("before ".to_string()),
                       ETag(vec!["name".to_string()], "{{name}}".to_string())]);

        check_tokens(compile_str("{{name}} after"),
                     &[ETag(vec!["name".to_string()], "{{name}}".to_string()),
                       Text(" after".to_string())]);
    }

    #[test]
    fn test_compile_utags() {
        check_tokens(compile_str("{{{name}}}"),
                     &[UTag(vec!["name".to_string()], "{{{name}}}".to_string())]);

        check_tokens(compile_str("before {{{name}}} after"),
                     &[Text("before ".to_string()),
                       UTag(vec!["name".to_string()], "{{{name}}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{{name}}}"),
                     &[Text("before ".to_string()),
                       UTag(vec!["name".to_string()], "{{{name}}}".to_string())]);

        check_tokens(compile_str("{{{name}}} after"),
                     &[UTag(vec!["name".to_string()], "{{{name}}}".to_string()),
                       Text(" after".to_string())]);
    }

    #[test]
    fn test_compile_sections() {
        check_tokens(compile_str("{{# name}}{{/name}}"),
                     &[Section(vec!["name".to_string()],
                               false,
                               Vec::new(),
                               "{{".to_string(),
                               "{{# name}}".to_string(),
                               "".to_string(),
                               "{{/name}}".to_string(),
                               "}}".to_string())]);

        check_tokens(compile_str("before {{^name}}{{/name}} after"),
                     &[Text("before ".to_string()),
                       Section(vec!["name".to_string()],
                               true,
                               Vec::new(),
                               "{{".to_string(),
                               "{{^name}}".to_string(),
                               "".to_string(),
                               "{{/name}}".to_string(),
                               "}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{#name}}{{/name}}"),
                     &[Text("before ".to_string()),
                       Section(vec!["name".to_string()],
                               false,
                               Vec::new(),
                               "{{".to_string(),
                               "{{#name}}".to_string(),
                               "".to_string(),
                               "{{/name}}".to_string(),
                               "}}".to_string())]);

        check_tokens(compile_str("{{#name}}{{/name}} after"),
                     &[Section(vec!["name".to_string()],
                               false,
                               Vec::new(),
                               "{{".to_string(),
                               "{{#name}}".to_string(),
                               "".to_string(),
                               "{{/name}}".to_string(),
                               "}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{#a}} 1 {{^b}} 2 {{/b}} {{/a}} after"),
                     &[Text("before ".to_string()),
                       Section(vec!["a".to_string()],
                               false,
                               vec![Text(" 1 ".to_string()),
                                    Section(vec!["b".to_string()],
                                            true,
                                            vec![Text(" 2 ".to_string())],
                                            "{{".to_string(),
                                            "{{^b}}".to_string(),
                                            " 2 ".to_string(),
                                            "{{/b}}".to_string(),
                                            "}}".to_string()),
                                    Text(" ".to_string())],
                               "{{".to_string(),
                               "{{#a}}".to_string(),
                               " 1 {{^b}} 2 {{/b}} ".to_string(),
                               "{{/a}}".to_string(),
                               "}}".to_string()),
                       Text(" after".to_string())]);
    }

    #[test]
    fn test_compile_partials() {
        check_tokens(compile_str("{{> test}}"),
                     &[Partial("test".to_string(), "".to_string(), "{{> test}}".to_string())]);

        check_tokens(compile_str("before {{>test}} after"),
                     &[Text("before ".to_string()),
                       Partial("test".to_string(), "".to_string(), "{{>test}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{> test}}"),
                     &[Text("before ".to_string()),
                       Partial("test".to_string(), "".to_string(), "{{> test}}".to_string())]);

        check_tokens(compile_str("{{>test}} after"),
                     &[Partial("test".to_string(), "".to_string(), "{{>test}}".to_string()),
                       Text(" after".to_string())]);
    }

    #[test]
    fn test_compile_delimiters() {
        check_tokens(compile_str("before {{=<% %>=}}<%name%> after"),
                     &[Text("before ".to_string()),
                       ETag(vec!["name".to_string()], "<%name%>".to_string()),
                       Text(" after".to_string())]);
    }
}
<commit_msg>style(compiler): add type alias for PartialsMap<commit_after>use std::collections::HashMap;
use std::io::ErrorKind::NotFound;
use std::io::Read;
use std::fs::File;
use std::str;

use parser::{Parser, Token};
use super::Context;

pub type PartialsMap = HashMap<String, Vec<Token>>;

/// `Compiler` is a object that compiles a string into a `Vec<Token>`.
pub struct Compiler<T> {
    ctx: Context,
    reader: T,
    partials: PartialsMap,
    otag: String,
    ctag: String,
}

impl<T: Iterator<Item = char>> Compiler<T> {
    /// Construct a default compiler.
    pub fn new(ctx: Context, reader: T) -> Compiler<T> {
        Compiler {
            ctx: ctx,
            reader: reader,
            partials: HashMap::new(),
            otag: "{{".to_string(),
            ctag: "}}".to_string(),
        }
    }

    /// Construct a default compiler.
    pub fn new_with(ctx: Context,
                    reader: T,
                    partials: PartialsMap,
                    otag: String,
                    ctag: String)
                    -> Compiler<T> {
        Compiler {
            ctx: ctx,
            reader: reader,
            partials: partials,
            otag: otag,
            ctag: ctag,
        }
    }

    /// Compiles a template into a series of tokens.
    pub fn compile(mut self) -> (Vec<Token>, PartialsMap) {
        let (tokens, partials) = {
            let parser = Parser::new(&mut self.reader, &self.otag, &self.ctag);
            parser.parse()
        };

        // Compile the partials if we haven't done so already.
        for name in partials.into_iter() {
            let path =
                self.ctx.template_path.join(&(name.clone() + "." + &self.ctx.template_extension));

            if !self.partials.contains_key(&name) {
                // Insert a placeholder so we don't recurse off to infinity.
                self.partials.insert(name.to_string(), Vec::new());

                match File::open(&path) {
                    Ok(mut file) => {
                        let mut contents = vec![];
                        file.read_to_end(&mut contents).unwrap();
                        let string = match str::from_utf8(&contents) {
                            Ok(string) => string.to_string(),
                            Err(_) => {
                                panic!("Failed to parse file as UTF-8");
                            }
                        };

                        let compiler = Compiler {
                            ctx: self.ctx.clone(),
                            reader: string.chars(),
                            partials: self.partials.clone(),
                            otag: "{{".to_string(),
                            ctag: "}}".to_string(),
                        };

                        let (tokens, subpartials) = compiler.compile();

                        // Include subpartials
                        self.partials.extend(subpartials.into_iter());

                        // Set final compiled tokens for *this* partial
                        self.partials.insert(name, tokens);
                    }
                    Err(e) => {
                        // Ignore missing files.
                        if e.kind() != NotFound {
                            panic!("error reading file: {}", e);
                        }
                    }
                }
            }
        }

        let Compiler { partials, .. } = self;

        (tokens, partials)
    }
}

#[cfg(test)]
mod tests {
    use parser::{Token, Text, ETag, UTag, Section, IncompleteSection, Partial};
    use super::Compiler;
    use super::super::Context;
    use std::path::PathBuf;

    fn compile_str(template: &str) -> Vec<Token> {
        let ctx = Context::new(PathBuf::from("."));
        let (tokens, _) = Compiler::new(ctx, template.chars()).compile();
        tokens
    }

    fn token_to_str(token: &Token) -> String {
        match *token {
            // recursive enums crash %?
            Section(ref name,
                    inverted,
                    ref children,
                    ref otag,
                    ref osection,
                    ref src,
                    ref tag,
                    ref ctag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                let children = children.iter().map(|x| token_to_str(x)).collect::<Vec<String>>();
                format!("Section(vec!({}), {}, vec!({}), {}, {}, {}, {}, {})",
                        name.join(", "),
                        inverted,
                        children.join(", "),
                        otag,
                        osection,
                        src,
                        tag,
                        ctag)
            }
            ETag(ref name, ref tag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("ETag(vec!({}), {})", name.join(", "), *tag)
            }
            UTag(ref name, ref tag) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("UTag(vec!({}), {})", name.join(", "), *tag)
            }
            IncompleteSection(ref name, ref inverted, ref osection, ref newlined) => {
                let name = name.iter().map(|e| format!("{}", *e)).collect::<Vec<String>>();
                format!("IncompleteSection(vec!({}), {}, {}, {})",
                        name.join(", "),
                        *inverted,
                        *osection,
                        *newlined)
            }
            _ => format!("{:?}", token),
        }
    }

    fn check_tokens(_actual: Vec<Token>, _expected: &[Token]) {
        // TODO: equality is currently broken for enums
        // let actual: Vec<String> = actual.iter().map(token_to_str).collect();
        // let expected = expected.iter().map(token_to_str).collect();

        // assert_eq!(actual, expected);
    }

    #[test]
    fn test_compile_texts() {
        check_tokens(compile_str("hello world"),
                     &[Text("hello world".to_string())]);
        check_tokens(compile_str("hello {world"),
                     &[Text("hello {world".to_string())]);
        check_tokens(compile_str("hello world}"),
                     &[Text("hello world}".to_string())]);
        check_tokens(compile_str("hello world}}"),
                     &[Text("hello world}}".to_string())]);
    }

    #[test]
    fn test_compile_etags() {
        check_tokens(compile_str("{{ name }}"),
                     &[ETag(vec!["name".to_string()], "{{ name }}".to_string())]);

        check_tokens(compile_str("before {{name}} after"),
                     &[Text("before ".to_string()),
                       ETag(vec!["name".to_string()], "{{name}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{name}}"),
                     &[Text("before ".to_string()),
                       ETag(vec!["name".to_string()], "{{name}}".to_string())]);

        check_tokens(compile_str("{{name}} after"),
                     &[ETag(vec!["name".to_string()], "{{name}}".to_string()),
                       Text(" after".to_string())]);
    }

    #[test]
    fn test_compile_utags() {
        check_tokens(compile_str("{{{name}}}"),
                     &[UTag(vec!["name".to_string()], "{{{name}}}".to_string())]);

        check_tokens(compile_str("before {{{name}}} after"),
                     &[Text("before ".to_string()),
                       UTag(vec!["name".to_string()], "{{{name}}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{{name}}}"),
                     &[Text("before ".to_string()),
                       UTag(vec!["name".to_string()], "{{{name}}}".to_string())]);

        check_tokens(compile_str("{{{name}}} after"),
                     &[UTag(vec!["name".to_string()], "{{{name}}}".to_string()),
                       Text(" after".to_string())]);
    }

    #[test]
    fn test_compile_sections() {
        check_tokens(compile_str("{{# name}}{{/name}}"),
                     &[Section(vec!["name".to_string()],
                               false,
                               Vec::new(),
                               "{{".to_string(),
                               "{{# name}}".to_string(),
                               "".to_string(),
                               "{{/name}}".to_string(),
                               "}}".to_string())]);

        check_tokens(compile_str("before {{^name}}{{/name}} after"),
                     &[Text("before ".to_string()),
                       Section(vec!["name".to_string()],
                               true,
                               Vec::new(),
                               "{{".to_string(),
                               "{{^name}}".to_string(),
                               "".to_string(),
                               "{{/name}}".to_string(),
                               "}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{#name}}{{/name}}"),
                     &[Text("before ".to_string()),
                       Section(vec!["name".to_string()],
                               false,
                               Vec::new(),
                               "{{".to_string(),
                               "{{#name}}".to_string(),
                               "".to_string(),
                               "{{/name}}".to_string(),
                               "}}".to_string())]);

        check_tokens(compile_str("{{#name}}{{/name}} after"),
                     &[Section(vec!["name".to_string()],
                               false,
                               Vec::new(),
                               "{{".to_string(),
                               "{{#name}}".to_string(),
                               "".to_string(),
                               "{{/name}}".to_string(),
                               "}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{#a}} 1 {{^b}} 2 {{/b}} {{/a}} after"),
                     &[Text("before ".to_string()),
                       Section(vec!["a".to_string()],
                               false,
                               vec![Text(" 1 ".to_string()),
                                    Section(vec!["b".to_string()],
                                            true,
                                            vec![Text(" 2 ".to_string())],
                                            "{{".to_string(),
                                            "{{^b}}".to_string(),
                                            " 2 ".to_string(),
                                            "{{/b}}".to_string(),
                                            "}}".to_string()),
                                    Text(" ".to_string())],
                               "{{".to_string(),
                               "{{#a}}".to_string(),
                               " 1 {{^b}} 2 {{/b}} ".to_string(),
                               "{{/a}}".to_string(),
                               "}}".to_string()),
                       Text(" after".to_string())]);
    }

    #[test]
    fn test_compile_partials() {
        check_tokens(compile_str("{{> test}}"),
                     &[Partial("test".to_string(), "".to_string(), "{{> test}}".to_string())]);

        check_tokens(compile_str("before {{>test}} after"),
                     &[Text("before ".to_string()),
                       Partial("test".to_string(), "".to_string(), "{{>test}}".to_string()),
                       Text(" after".to_string())]);

        check_tokens(compile_str("before {{> test}}"),
                     &[Text("before ".to_string()),
                       Partial("test".to_string(), "".to_string(), "{{> test}}".to_string())]);

        check_tokens(compile_str("{{>test}} after"),
                     &[Partial("test".to_string(), "".to_string(), "{{>test}}".to_string()),
                       Text(" after".to_string())]);
    }

    #[test]
    fn test_compile_delimiters() {
        check_tokens(compile_str("before {{=<% %>=}}<%name%> after"),
                     &[Text("before ".to_string()),
                       ETag(vec!["name".to_string()], "<%name%>".to_string()),
                       Text(" after".to_string())]);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! Parser for Intecture data files.
//!
//! # Examples
//!
//! ```no_run
//! ```

// pub mod ffi;

use error::{Error, Result};
use serde_json::{Map, self, Value};
use std::fs;
use std::path::Path;

/// Parser for Intecture data files.
pub struct DataParser;

impl DataParser {
    /// Open a new file and recursively parse its contents.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// ```
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Value> {
        let mut file = try!(DataFile::new(path));

        for dep in try!(file.dependencies()) {
            try!(file.merge_files(dep));
        }

        Ok(file.into_inner())
    }
}

struct DataFile {
    v: Value,
}

impl DataFile {
    fn new<P: AsRef<Path>>(path: P) -> Result<DataFile> {
        let mut fh = try!(fs::File::open(path.as_ref()));
        let data: Value = try!(serde_json::from_reader(&mut fh));

        if !data.is_object() {
            Err(Error::Generic("Value is not an object".into()))
        } else {
            Ok(DataFile {
                v: data
            })
        }
    }

    fn into_inner(self) -> Value {
        self.v
    }

    fn dependencies(&self) -> Result<Vec<DataFile>> {
        let mut deps = Vec::new();

        if let Some(inc) = self.v.find("_include") {
            if !inc.is_array() {
                return Err(Error::Generic("Value of `_include` is not an array".into()));
            }

            // Loop in reverse order to get lowest importance first
            for i in inc.as_array().unwrap().iter().rev() {
                deps.push(try!(DataFile::new(i.as_str().unwrap())));
            }
        }

        Ok(deps)
    }

    fn merge_files(&mut self, mut child: DataFile) -> Result<()> {
        for dep in try!(child.dependencies()) {
            try!(child.merge_files(dep));
        }

        let mut obj = self.v.as_object_mut().unwrap();
        let child_obj = child.v.as_object().unwrap();

        // Merge values
        for (mut key, value) in obj.iter_mut() {
            Self::merge_values(&mut *key, value, child_obj);
        }

        // Insert any missing values
        for (key, value) in child_obj {
            if obj.contains_key(key) {
                obj.insert(key.clone(), value.clone());
            }
        }

        Ok(())
    }

    fn merge_values(key: &mut String, value: &mut Value, from: &Map<String, Value>) {
        let mut merge_flag = false;

        if key.starts_with("+") {
            key.remove(0);
            merge_flag = true;
        }

        if let Some(cval) = from.get(key) {
            if value != cval {
                // match
            }
        }
    }
}

// #[cfg(test)]
// mod tests {
//     use super::*;
// }
<commit_msg>Finished merge/overwrite logic for data mod<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

//! Parser for Intecture data files.
//!
//! # Examples
//!
//! ```no_run
//! ```

// pub mod ffi;

use error::{Error, Result};
use serde_json::{self, Value};
use std::fs;
use std::path::Path;

/// Parser for Intecture data files.
pub struct DataParser;

impl DataParser {
    /// Open a new file and recursively parse its contents.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// ```
    pub fn open<P: AsRef<Path>>(path: P) -> Result<Value> {
        let mut file = try!(DataFile::new(path));
        try!(file.merge(Value::Null));
        Ok(file.into_inner())
    }
}

struct DataFile {
    v: Value,
}

impl DataFile {
    fn new<P: AsRef<Path>>(path: P) -> Result<DataFile> {
        let mut fh = try!(fs::File::open(path.as_ref()));
        let data: Value = try!(serde_json::from_reader(&mut fh));

        if !data.is_object() {
            Err(Error::Generic("Value is not an object".into()))
        } else {
            Ok(DataFile {
                v: data,
            })
        }
    }

    fn into_inner(self) -> Value {
        self.v
    }

    fn dependencies(&self) -> Result<Vec<DataFile>> {
        let mut deps = Vec::new();

        if let Some(inc) = self.v.find("_include") {
            if !inc.is_array() {
                return Err(Error::Generic("Value of `_include` is not an array".into()));
            }

            // Loop in reverse order to get lowest importance first
            for i in inc.as_array().unwrap().iter().rev() {
                deps.push(try!(DataFile::new(i.as_str().unwrap())));
            }
        }

        Ok(deps)
    }

    fn merge(&mut self, mut last_value: Value) -> Result<()> {
        for mut dep in try!(self.dependencies()) {
            try!(dep.merge(last_value));
            last_value = dep.v;
        }

        Self::merge_values(&mut self.v, last_value);

        Ok(())
    }

    fn merge_values(into: &mut Value, mut from: Value) {
        match *into {
            Value::Null |
            Value::Bool(_) |
            Value::I64(_) |
            Value::U64(_) |
            Value::F64(_) |
            Value::String(_) => (),
            Value::Array(ref mut a) => {
                if from.is_array() {
                    a.append(from.as_array_mut().unwrap());
                } else {
                    a.push(from);
                }
            },
            Value::Object(ref mut o) => {
                let mut overwrite_keys = Vec::new();

                for (key, value) in o.iter_mut() {
                    if key.ends_with("!") {
                        // Cache key for later removal
                        let mut new_key = key.clone();
                        new_key.pop();
                        overwrite_keys.push(new_key);
                    }
                    else if let Some(o1) = from.find(key) {
                        Self::merge_values(value, o1.clone());
                    }
                }

                for key in overwrite_keys {
                    // Insert new key+value
                    let value = o.remove(&format!("{}!", key)).unwrap();
                    o.insert(key, value);
                }

                // Insert any missing values
                if let Some(o1) = from.as_object() {
                    for (key, value) in o1 {
                        if !o.contains_key(key) {
                            o.insert(key.clone(), value.clone());
                        }
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use serde_json::{self, Value};
    use std::fs::File;
    use std::io::Write;
    use std::path::PathBuf;
    use super::*;
    use tempdir::TempDir;

    #[test]
    fn test_parser() {
        let tempdir = TempDir::new("parser_test").unwrap();
        let mut path = tempdir.path().to_owned();
        let expected_value = create_data(&mut path);

        path.push("top.json");
        let value = DataParser::open(&path).unwrap();

        assert_eq!(value, expected_value);
    }

    fn create_data(path: &mut PathBuf) -> Value {
        path.push("top.json");
        let mut fh = File::create(&path).unwrap();
        path.pop();
        fh.write_all(format!("{{
            \"a\": 1,
            \"payload\": {{
                \"b\": [ 1, 2 ],
                \"c!\": [ 1, 2 ],
                \"d\": [ 123 ]
            }},
            \"variable\": {{
                \"one!\": true,
                \"two\": false
            }},
            \"_include\": [
                \"{0}/middle.json\",
                \"{0}/bottom.json\"
            ]
        }}", &path.to_str().unwrap()).as_bytes()).unwrap();

        path.push("middle.json");
        let mut fh = File::create(&path).unwrap();
        path.pop();
        fh.write_all(b"{
            \"payload\": {
                \"b!\": [ 3, 4 ],
                \"c\": [
                    {
                        \"_\": [ 6, 7 ],
                        \"?\": \"telemetry/os/family=linux\"
                    },
                    {
                        \"_\": [ 8, 9 ],
                        \"?\": \"\"
                    }
                ],
                \"d\": [ 987 ]
            },
            \"variable\": false,
            \"d\": 4
        }").unwrap();

        path.push("bottom.json");
        let mut fh = File::create(&path).unwrap();
        path.pop();
        fh.write_all(b"{
            \"moo\": \"cow\",
            \"payload\": {
                \"b\": [ 5 ],
                \"d\": [ 999 ]
            }
        }").unwrap();

        serde_json::from_str(&format!("{{
            \"_include\": [
                \"{0}/middle.json\",
                \"{0}/bottom.json\"
            ],
            \"a\": 1,
            \"d\": 4,
            \"moo\": \"cow\",
            \"payload\": {{
                \"b\": [ 1, 2, 3, 4 ],
                \"c\": [ 1, 2 ],
                \"d\": [ 123, 987, 999 ]
            }},
            \"variable\": {{
                \"one\": true,
                \"two\": false
            }}
        }}", &path.to_str().unwrap())).unwrap()
    }
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::string::String;
use std::path::Path;
use std::vec::Vec;
use json::{parse};

use game::data::Rectangle;

fn read_sprite_file(filename: &str) -> String {
  let path = Path::new(&filename);
  let mut file = match File::open(&path) {
    Ok(f) => f,
    Err(e) => panic!("File {} not found: {}", filename, e),
  };
  let mut buf = String::new();
  match file.read_to_string(&mut buf) {
    Ok(_) => buf,
    Err(_) => panic!("Couldn't read file {}", filename),
  }
}

pub fn load_character() -> Vec<Rectangle> {
  let mut sprites = Vec::with_capacity(256);
  let mut sprite_names = Vec::with_capacity(256);
  let character_json = read_sprite_file("./assets/character.json");
  let character = match parse(&character_json) {
    Ok(res) => res,
    Err(e) => panic!("Character JSON parse error {:?}", e),
  };
  for x in 0..15 {
    for y in 0..13 {
      sprite_names.push(format!("run_{}_{}", x, y));
    }
  }
  for &ref sprite in &sprite_names {
    let x = character["frames"][sprite]["frame"]["x"].as_f64();
    let y = character["frames"][sprite]["frame"]["y"].as_f64();
    let w = character["frames"][sprite]["frame"]["w"].as_f64();
    let h = character["frames"][sprite]["frame"]["h"].as_f64();
    sprites.push(Rectangle {
      w: w.unwrap() as f64,
      h: h.unwrap() as f64,
      x: x.unwrap() as f64,
      y: y.unwrap() as f64,
    });
  }
  sprites
}

<commit_msg>Refactor unwraps<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::string::String;
use std::path::Path;
use std::vec::Vec;
use json::{parse};

use game::data::Rectangle;

fn read_sprite_file(filename: &str) -> String {
  let path = Path::new(&filename);
  let mut file = match File::open(&path) {
    Ok(f) => f,
    Err(e) => panic!("File {} not found: {}", filename, e),
  };
  let mut buf = String::new();
  match file.read_to_string(&mut buf) {
    Ok(_) => buf,
    Err(_) => panic!("Couldn't read file {}", filename),
  }
}

pub fn load_character() -> Vec<Rectangle> {
  let mut sprites = Vec::with_capacity(256);
  let mut sprite_names = Vec::with_capacity(256);
  let character_json = read_sprite_file("./assets/character.json");
  let character = match parse(&character_json) {
    Ok(res) => res,
    Err(e) => panic!("Character JSON parse error {:?}", e),
  };
  for x in 0..15 {
    for y in 0..13 {
      sprite_names.push(format!("run_{}_{}", x, y));
    }
  }
  for &ref sprite in &sprite_names {
    let x = character["frames"][sprite]["frame"]["x"].as_f64().unwrap();
    let y = character["frames"][sprite]["frame"]["y"].as_f64().unwrap();
    let w = character["frames"][sprite]["frame"]["w"].as_f64().unwrap();
    let h = character["frames"][sprite]["frame"]["h"].as_f64().unwrap();
    sprites.push(Rectangle {
      w: w,
      h: h,
      x: x,
      y: y,
    });
  }
  sprites
}

<|endoftext|>


<commit_before>use std::fmt;
use std::str::{self, FromStr};
use std::error;

use serde::{de, ser};

/// A parsed TOML datetime value
///
/// This structure is intended to represent the datetime primitive type that can
/// be encoded into TOML documents. This type is a parsed version that contains
/// all metadata internally.
///
/// Currently this type is intentionally conservative and only supports
/// `to_string` as an accessor. Over time though it's intended that it'll grow
/// more support!
///
/// Note that if you're using `Deserialize` to deserialize a TOML document, you
/// can use this as a placeholder for where you're expecting a datetime to be
/// specified.
///
/// Also note though that while this type implements `Serialize` and
/// `Deserialize` it's only recommended to use this type with the TOML format,
/// otherwise encoded in other formats it may look a little odd.
#[derive(PartialEq, Clone)]
pub struct Datetime {
    date: Option<Date>,
    time: Option<Time>,
    offset: Option<Offset>,
}

/// Error returned from parsing a `Datetime` in the `FromStr` implementation.
#[derive(Debug, Clone)]
pub struct DatetimeParseError {
    _private: (),
}

// Currently serde itself doesn't have a datetime type, so we map our `Datetime`
// to a special valid in the serde data model. Namely one with thiese special
// fields/struct names.
//
// In general the TOML encoder/decoder will catch this and not literally emit
// these strings but rather emit datetimes as they're intended.
pub const SERDE_STRUCT_FIELD_NAME: &'static str = "$__toml_private_datetime";
pub const SERDE_STRUCT_NAME: &'static str = "$__toml_private_Datetime";

#[derive(PartialEq, Clone)]
struct Date {
    year: u16,
    month: u8,
    day: u8,
}

#[derive(PartialEq, Clone)]
struct Time {
    hour: u8,
    minute: u8,
    second: u8,
    secfract: Option<f64>,
}

#[derive(PartialEq, Clone)]
enum Offset {
    Z,
    Custom { hours: i8, minutes: u8 },
}

impl fmt::Debug for Datetime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl fmt::Display for Datetime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref date) = self.date {
            write!(f, "{}", date)?;
        }
        if let Some(ref time) = self.time {
            if self.date.is_some() {
                write!(f, "T")?;
            }
            write!(f, "{}", time)?;
        }
        if let Some(ref offset) = self.offset {
            write!(f, "{}", offset)?;
        }
        Ok(())
    }
}

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:04}-{:02}-{:02}", self.year, self.month, self.day)
    }
}

impl fmt::Display for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:02}:{:02}:{:02}", self.hour, self.minute, self.second)?;
        if let Some(i) = self.secfract {
            let s = format!("{}", i);
            write!(f, "{}", s.trim_left_matches("0"))?;
        }
        Ok(())
    }
}

impl fmt::Display for Offset {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Offset::Z => write!(f, "Z"),
            Offset::Custom { hours, minutes } => {
                write!(f, "{:+03}:{:02}", hours, minutes)
            }
        }
    }
}

impl FromStr for Datetime {
    type Err = DatetimeParseError;

    fn from_str(date: &str) -> Result<Datetime, DatetimeParseError> {
        // Accepted formats:
        //
        // 0000-00-00T00:00:00.00Z
        // 0000-00-00T00:00:00.00
        // 0000-00-00
        // 00:00:00.00
        if date.len() < 3 {
            return Err(DatetimeParseError { _private: () })
        }
        let mut offset_allowed = true;
        let mut chars = date.chars();

        // First up, parse the full date if we can
        let full_date = if chars.clone().nth(2) == Some(':') {
            offset_allowed = false;
            None
        } else {
            let y1 = digit(&mut chars)? as u16;
            let y2 = digit(&mut chars)? as u16;
            let y3 = digit(&mut chars)? as u16;
            let y4 = digit(&mut chars)? as u16;

            match chars.next() {
                Some('-') => {}
                _ => return Err(DatetimeParseError { _private: () }),
            }

            let m1 = digit(&mut chars)?;
            let m2 = digit(&mut chars)?;

            match chars.next() {
                Some('-') => {}
                _ => return Err(DatetimeParseError { _private: () }),
            }

            let d1 = digit(&mut chars)?;
            let d2 = digit(&mut chars)?;

            let date = Date {
                year: y1 * 1000 + y2 * 100 + y3 * 10 + y4,
                month: m1 * 10 + m2,
                day: d1 * 10 + d2,
            };

            if date.month < 1 || date.month > 12 {
                return Err(DatetimeParseError { _private: () })
            }
            if date.day < 1 || date.day > 31 {
                return Err(DatetimeParseError { _private: () })
            }

            Some(date)
        };

        // Next parse the "partial-time" if available
        let partial_time = if full_date.is_some() &&
                              chars.clone().next() == Some('T') {
            chars.next();
            true
        } else {
            full_date.is_none()
        };

        let time = if partial_time {
            let h1 = digit(&mut chars)?;
            let h2 = digit(&mut chars)?;
            match chars.next() {
                Some(':') => {}
                _ => return Err(DatetimeParseError { _private: () }),
            }
            let m1 = digit(&mut chars)?;
            let m2 = digit(&mut chars)?;
            match chars.next() {
                Some(':') => {}
                _ => return Err(DatetimeParseError { _private: () }),
            }
            let s1 = digit(&mut chars)?;
            let s2 = digit(&mut chars)?;

            let secfract = if chars.clone().next() == Some('.') {
                chars.next();
                let mut first = true;
                let whole = chars.as_str();
                let mut end = whole.len();
                for (i, c) in whole.char_indices() {
                    match c {
                        '0' ... '9' => {}
                        _ => {
                            end = i;
                            break
                        }
                    }
                    first = false;
                }
                if first {
                    return Err(DatetimeParseError { _private: () })
                }
                chars = whole[end..].chars();
                match format!("0.{}", &whole[..end]).parse() {
                    Ok(f) => Some(f),
                    Err(_) => return Err(DatetimeParseError { _private: () }),
                }
            } else {
                None
            };

            let time = Time {
                hour: h1 * 10 + h2,
                minute: m1 * 10 + m2,
                second: s1 * 10 + s2,
                secfract: secfract,
            };

            if time.hour > 24 {
                return Err(DatetimeParseError { _private: () })
            }
            if time.minute > 59 {
                return Err(DatetimeParseError { _private: () })
            }
            if time.second > 60 {
                return Err(DatetimeParseError { _private: () })
            }

            Some(time)
        } else {
            offset_allowed = false;
            None
        };

        // And finally, parse the offset
        let offset = if offset_allowed {
            let next = chars.clone().next();
            if next == Some('Z') {
                chars.next();
                Some(Offset::Z)
            } else if next.is_none() {
                None
            } else {
                let sign = match next {
                    Some('+') => 1,
                    Some('-') => -1,
                    _ => return Err(DatetimeParseError { _private: () }),
                };
                chars.next();
                let h1 = digit(&mut chars)? as i8;
                let h2 = digit(&mut chars)? as i8;
                match chars.next() {
                    Some(':') => {}
                    _ => return Err(DatetimeParseError { _private: () }),
                }
                let m1 = digit(&mut chars)?;
                let m2 = digit(&mut chars)?;

                Some(Offset::Custom {
                    hours: sign * (h1 * 10 + h2),
                    minutes: m1 * 10 + m2,
                })
            }
        } else {
            None
        };

        // Return an error if we didn't hit eof, otherwise return our parsed
        // date
        if chars.next().is_some() {
            return Err(DatetimeParseError { _private: () })
        }

        Ok(Datetime {
            date: full_date,
            time: time,
            offset: offset,
        })
    }
}

fn digit(chars: &mut str::Chars) -> Result<u8, DatetimeParseError> {
    match chars.next() {
        Some(c) if '0' <= c && c <= '9' => Ok(c as u8 - b'0'),
        _ => Err(DatetimeParseError { _private: () }),
    }
}

impl ser::Serialize for Datetime {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        use serde::ser::SerializeStruct;

        let mut s = serializer.serialize_struct(SERDE_STRUCT_NAME, 1)?;
        s.serialize_field(SERDE_STRUCT_FIELD_NAME, &self.to_string())?;
        s.end()
    }
}

impl<'de> de::Deserialize<'de> for Datetime {
    fn deserialize<D>(deserializer: D) -> Result<Datetime, D::Error>
        where D: de::Deserializer<'de>
    {
        struct DatetimeVisitor;

        impl<'de> de::Visitor<'de> for DatetimeVisitor {
            type Value = Datetime;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a TOML datetime")
            }

            fn visit_map<V>(self, mut visitor: V) -> Result<Datetime, V::Error>
                where V: de::MapAccess<'de>
            {
                let value = visitor.next_key::<DatetimeKey>()?;
                if value.is_none() {
                    return Err(de::Error::custom("datetime key not found"))
                }
                let v: DatetimeFromString = visitor.next_value()?;
                Ok(v.value)

            }
        }

        static FIELDS: [&'static str; 1] = [SERDE_STRUCT_FIELD_NAME];
        deserializer.deserialize_struct(SERDE_STRUCT_NAME,
                                        &FIELDS,
                                        DatetimeVisitor)
    }
}

struct DatetimeKey;

impl<'de> de::Deserialize<'de> for DatetimeKey {
    fn deserialize<D>(deserializer: D) -> Result<DatetimeKey, D::Error>
        where D: de::Deserializer<'de>
    {
        struct FieldVisitor;

        impl<'de> de::Visitor<'de> for FieldVisitor {
            type Value = ();

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a valid datetime field")
            }

            fn visit_str<E>(self, s: &str) -> Result<(), E>
                where E: de::Error
            {
                if s == SERDE_STRUCT_FIELD_NAME {
                    Ok(())
                } else {
                    Err(de::Error::custom("expected field with custom name"))
                }
            }
        }

        deserializer.deserialize_identifier(FieldVisitor)?;
        Ok(DatetimeKey)
    }
}

pub struct DatetimeFromString {
    pub value: Datetime,
}

impl<'de> de::Deserialize<'de> for DatetimeFromString {
    fn deserialize<D>(deserializer: D) -> Result<DatetimeFromString, D::Error>
        where D: de::Deserializer<'de>
    {
        struct Visitor;

        impl<'de> de::Visitor<'de> for Visitor {
            type Value = DatetimeFromString;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("string containing a datetime")
            }

            fn visit_str<E>(self, s: &str) -> Result<DatetimeFromString, E>
                where E: de::Error,
            {
                match s.parse() {
                    Ok(date) => Ok(DatetimeFromString { value: date }),
                    Err(e) => Err(de::Error::custom(e)),
                }
            }
        }

        deserializer.deserialize_str(Visitor)
    }
}

impl fmt::Display for DatetimeParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "failed to parse datetime".fmt(f)
    }
}

impl error::Error for DatetimeParseError {
    fn description(&self) -> &str {
        "failed to parse datetime"
    }
}
<commit_msg>Store fraction of seconds in times unconditionally<commit_after>use std::fmt;
use std::str::{self, FromStr};
use std::error;

use serde::{de, ser};

/// A parsed TOML datetime value
///
/// This structure is intended to represent the datetime primitive type that can
/// be encoded into TOML documents. This type is a parsed version that contains
/// all metadata internally.
///
/// Currently this type is intentionally conservative and only supports
/// `to_string` as an accessor. Over time though it's intended that it'll grow
/// more support!
///
/// Note that if you're using `Deserialize` to deserialize a TOML document, you
/// can use this as a placeholder for where you're expecting a datetime to be
/// specified.
///
/// Also note though that while this type implements `Serialize` and
/// `Deserialize` it's only recommended to use this type with the TOML format,
/// otherwise encoded in other formats it may look a little odd.
#[derive(PartialEq, Clone)]
pub struct Datetime {
    date: Option<Date>,
    time: Option<Time>,
    offset: Option<Offset>,
}

/// Error returned from parsing a `Datetime` in the `FromStr` implementation.
#[derive(Debug, Clone)]
pub struct DatetimeParseError {
    _private: (),
}

// Currently serde itself doesn't have a datetime type, so we map our `Datetime`
// to a special valid in the serde data model. Namely one with thiese special
// fields/struct names.
//
// In general the TOML encoder/decoder will catch this and not literally emit
// these strings but rather emit datetimes as they're intended.
pub const SERDE_STRUCT_FIELD_NAME: &'static str = "$__toml_private_datetime";
pub const SERDE_STRUCT_NAME: &'static str = "$__toml_private_Datetime";

#[derive(PartialEq, Clone)]
struct Date {
    year: u16,
    month: u8,
    day: u8,
}

#[derive(PartialEq, Clone)]
struct Time {
    hour: u8,
    minute: u8,
    second: u8,
    secfract: f64,
}

#[derive(PartialEq, Clone)]
enum Offset {
    Z,
    Custom { hours: i8, minutes: u8 },
}

impl fmt::Debug for Datetime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl fmt::Display for Datetime {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(ref date) = self.date {
            write!(f, "{}", date)?;
        }
        if let Some(ref time) = self.time {
            if self.date.is_some() {
                write!(f, "T")?;
            }
            write!(f, "{}", time)?;
        }
        if let Some(ref offset) = self.offset {
            write!(f, "{}", offset)?;
        }
        Ok(())
    }
}

impl fmt::Display for Date {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:04}-{:02}-{:02}", self.year, self.month, self.day)
    }
}

impl fmt::Display for Time {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:02}:{:02}:{:02}", self.hour, self.minute, self.second)?;
        if self.secfract != 0.0 {
            let s = format!("{}", self.secfract);
            write!(f, "{}", s.trim_left_matches("0"))?;
        }
        Ok(())
    }
}

impl fmt::Display for Offset {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Offset::Z => write!(f, "Z"),
            Offset::Custom { hours, minutes } => {
                write!(f, "{:+03}:{:02}", hours, minutes)
            }
        }
    }
}

impl FromStr for Datetime {
    type Err = DatetimeParseError;

    fn from_str(date: &str) -> Result<Datetime, DatetimeParseError> {
        // Accepted formats:
        //
        // 0000-00-00T00:00:00.00Z
        // 0000-00-00T00:00:00.00
        // 0000-00-00
        // 00:00:00.00
        if date.len() < 3 {
            return Err(DatetimeParseError { _private: () })
        }
        let mut offset_allowed = true;
        let mut chars = date.chars();

        // First up, parse the full date if we can
        let full_date = if chars.clone().nth(2) == Some(':') {
            offset_allowed = false;
            None
        } else {
            let y1 = digit(&mut chars)? as u16;
            let y2 = digit(&mut chars)? as u16;
            let y3 = digit(&mut chars)? as u16;
            let y4 = digit(&mut chars)? as u16;

            match chars.next() {
                Some('-') => {}
                _ => return Err(DatetimeParseError { _private: () }),
            }

            let m1 = digit(&mut chars)?;
            let m2 = digit(&mut chars)?;

            match chars.next() {
                Some('-') => {}
                _ => return Err(DatetimeParseError { _private: () }),
            }

            let d1 = digit(&mut chars)?;
            let d2 = digit(&mut chars)?;

            let date = Date {
                year: y1 * 1000 + y2 * 100 + y3 * 10 + y4,
                month: m1 * 10 + m2,
                day: d1 * 10 + d2,
            };

            if date.month < 1 || date.month > 12 {
                return Err(DatetimeParseError { _private: () })
            }
            if date.day < 1 || date.day > 31 {
                return Err(DatetimeParseError { _private: () })
            }

            Some(date)
        };

        // Next parse the "partial-time" if available
        let partial_time = if full_date.is_some() &&
                              chars.clone().next() == Some('T') {
            chars.next();
            true
        } else {
            full_date.is_none()
        };

        let time = if partial_time {
            let h1 = digit(&mut chars)?;
            let h2 = digit(&mut chars)?;
            match chars.next() {
                Some(':') => {}
                _ => return Err(DatetimeParseError { _private: () }),
            }
            let m1 = digit(&mut chars)?;
            let m2 = digit(&mut chars)?;
            match chars.next() {
                Some(':') => {}
                _ => return Err(DatetimeParseError { _private: () }),
            }
            let s1 = digit(&mut chars)?;
            let s2 = digit(&mut chars)?;

            let secfract = if chars.clone().next() == Some('.') {
                chars.next();
                let mut first = true;
                let whole = chars.as_str();
                let mut end = whole.len();
                for (i, c) in whole.char_indices() {
                    match c {
                        '0' ... '9' => {}
                        _ => {
                            end = i;
                            break
                        }
                    }
                    first = false;
                }
                if first {
                    return Err(DatetimeParseError { _private: () })
                }
                chars = whole[end..].chars();
                match format!("0.{}", &whole[..end]).parse() {
                    Ok(f) => f,
                    Err(_) => return Err(DatetimeParseError { _private: () }),
                }
            } else {
                0.0
            };

            let time = Time {
                hour: h1 * 10 + h2,
                minute: m1 * 10 + m2,
                second: s1 * 10 + s2,
                secfract: secfract,
            };

            if time.hour > 24 {
                return Err(DatetimeParseError { _private: () })
            }
            if time.minute > 59 {
                return Err(DatetimeParseError { _private: () })
            }
            if time.second > 60 {
                return Err(DatetimeParseError { _private: () })
            }

            Some(time)
        } else {
            offset_allowed = false;
            None
        };

        // And finally, parse the offset
        let offset = if offset_allowed {
            let next = chars.clone().next();
            if next == Some('Z') {
                chars.next();
                Some(Offset::Z)
            } else if next.is_none() {
                None
            } else {
                let sign = match next {
                    Some('+') => 1,
                    Some('-') => -1,
                    _ => return Err(DatetimeParseError { _private: () }),
                };
                chars.next();
                let h1 = digit(&mut chars)? as i8;
                let h2 = digit(&mut chars)? as i8;
                match chars.next() {
                    Some(':') => {}
                    _ => return Err(DatetimeParseError { _private: () }),
                }
                let m1 = digit(&mut chars)?;
                let m2 = digit(&mut chars)?;

                Some(Offset::Custom {
                    hours: sign * (h1 * 10 + h2),
                    minutes: m1 * 10 + m2,
                })
            }
        } else {
            None
        };

        // Return an error if we didn't hit eof, otherwise return our parsed
        // date
        if chars.next().is_some() {
            return Err(DatetimeParseError { _private: () })
        }

        Ok(Datetime {
            date: full_date,
            time: time,
            offset: offset,
        })
    }
}

fn digit(chars: &mut str::Chars) -> Result<u8, DatetimeParseError> {
    match chars.next() {
        Some(c) if '0' <= c && c <= '9' => Ok(c as u8 - b'0'),
        _ => Err(DatetimeParseError { _private: () }),
    }
}

impl ser::Serialize for Datetime {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: ser::Serializer
    {
        use serde::ser::SerializeStruct;

        let mut s = serializer.serialize_struct(SERDE_STRUCT_NAME, 1)?;
        s.serialize_field(SERDE_STRUCT_FIELD_NAME, &self.to_string())?;
        s.end()
    }
}

impl<'de> de::Deserialize<'de> for Datetime {
    fn deserialize<D>(deserializer: D) -> Result<Datetime, D::Error>
        where D: de::Deserializer<'de>
    {
        struct DatetimeVisitor;

        impl<'de> de::Visitor<'de> for DatetimeVisitor {
            type Value = Datetime;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a TOML datetime")
            }

            fn visit_map<V>(self, mut visitor: V) -> Result<Datetime, V::Error>
                where V: de::MapAccess<'de>
            {
                let value = visitor.next_key::<DatetimeKey>()?;
                if value.is_none() {
                    return Err(de::Error::custom("datetime key not found"))
                }
                let v: DatetimeFromString = visitor.next_value()?;
                Ok(v.value)

            }
        }

        static FIELDS: [&'static str; 1] = [SERDE_STRUCT_FIELD_NAME];
        deserializer.deserialize_struct(SERDE_STRUCT_NAME,
                                        &FIELDS,
                                        DatetimeVisitor)
    }
}

struct DatetimeKey;

impl<'de> de::Deserialize<'de> for DatetimeKey {
    fn deserialize<D>(deserializer: D) -> Result<DatetimeKey, D::Error>
        where D: de::Deserializer<'de>
    {
        struct FieldVisitor;

        impl<'de> de::Visitor<'de> for FieldVisitor {
            type Value = ();

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a valid datetime field")
            }

            fn visit_str<E>(self, s: &str) -> Result<(), E>
                where E: de::Error
            {
                if s == SERDE_STRUCT_FIELD_NAME {
                    Ok(())
                } else {
                    Err(de::Error::custom("expected field with custom name"))
                }
            }
        }

        deserializer.deserialize_identifier(FieldVisitor)?;
        Ok(DatetimeKey)
    }
}

pub struct DatetimeFromString {
    pub value: Datetime,
}

impl<'de> de::Deserialize<'de> for DatetimeFromString {
    fn deserialize<D>(deserializer: D) -> Result<DatetimeFromString, D::Error>
        where D: de::Deserializer<'de>
    {
        struct Visitor;

        impl<'de> de::Visitor<'de> for Visitor {
            type Value = DatetimeFromString;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("string containing a datetime")
            }

            fn visit_str<E>(self, s: &str) -> Result<DatetimeFromString, E>
                where E: de::Error,
            {
                match s.parse() {
                    Ok(date) => Ok(DatetimeFromString { value: date }),
                    Err(e) => Err(de::Error::custom(e)),
                }
            }
        }

        deserializer.deserialize_str(Visitor)
    }
}

impl fmt::Display for DatetimeParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        "failed to parse datetime".fmt(f)
    }
}

impl error::Error for DatetimeParseError {
    fn description(&self) -> &str {
        "failed to parse datetime"
    }
}
<|endoftext|>