<commit_before>use quote::{ToTokens, Tokens};
use syn::{Field, Lit, MetaItem};

#[derive(Debug)]
pub struct Request {
    fields: Vec<RequestField>,
}

impl Request {
    pub fn has_body_fields(&self) -> bool {
        self.fields.iter().any(|field| field.is_body())
    }

    pub fn request_body_init_fields(&self) -> Tokens {
        let mut tokens = Tokens::new();

        for request_field in self.body_fields() {
            let field =  match *request_field {
                RequestField::Body(ref field) => field,
                _ => panic!("expected body field"),
            };

            let field_name = field.ident.as_ref().expect("expected body field to have a name");

            tokens.append(quote! {
                #field_name: request.#field_name,
            });
        }

        tokens
    }

    fn body_fields(&self) -> RequestBodyFields {
        RequestBodyFields::new(&self.fields)
    }
}

impl From<Vec<Field>> for Request {
    fn from(fields: Vec<Field>) -> Self {
        let request_fields = fields.into_iter().map(|field| {
            for attr in field.attrs.clone().iter() {
                match attr.value {
                    MetaItem::Word(ref ident) => {
                        if ident == "query" {
                            return RequestField::Query(field);
                        }
                    }
                    MetaItem::List(_, _) => {}
                    MetaItem::NameValue(ref ident, ref lit) => {
                        if ident == "header" {
                            if let Lit::Str(ref name, _) = *lit {
                                return RequestField::Header(name.clone(), field);
                            } else {
                                panic!("ruma_api! header attribute expects a string value");
                            }
                        } else if ident == "path" {
                            if let Lit::Str(ref name, _) = *lit {
                                return RequestField::Path(name.clone(), field);
                            } else {
                                panic!("ruma_api! path attribute expects a string value");
                            }
                        }
                    }
                }
            }

            return RequestField::Body(field);
        }).collect();

        Request {
            fields: request_fields,
        }
    }
}

impl ToTokens for Request {
    fn to_tokens(&self, mut tokens: &mut Tokens) {
        tokens.append(quote! {
            /// Data for a request to this API endpoint.
            #[derive(Debug)]
            pub struct Request
        });

        if self.fields.len() == 0 {
            tokens.append(";");
        } else {
            tokens.append("{");

            for request_field in self.fields.iter() {
                match *request_field {
                    RequestField::Body(ref field) => field.to_tokens(&mut tokens),
                    RequestField::Header(_, ref field) => field.to_tokens(&mut tokens),
                    RequestField::Path(_, ref field) => field.to_tokens(&mut tokens),
                    RequestField::Query(ref field) => field.to_tokens(&mut tokens),
                }

                tokens.append(",");
            }

            tokens.append("}");
        }

        if self.has_body_fields() {
            tokens.append(quote! {
                /// Data in the request body.
                #[derive(Debug, Serialize)]
                struct RequestBody
            });

            tokens.append("{");

            for request_field in self.fields.iter() {
                match *request_field {
                    RequestField::Body(ref field) => {
                        field.to_tokens(&mut tokens);

                        tokens.append(",");
                    }
                    _ => {}
                }
            }

            tokens.append("}");
        }
    }
}

#[derive(Debug)]
pub enum RequestField {
    Body(Field),
    Header(String, Field),
    Path(String, Field),
    Query(Field),
}

impl RequestField {
    fn is_body(&self) -> bool {
        match *self {
            RequestField::Body(_) => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct RequestBodyFields<'a> {
    fields: &'a [RequestField],
    index: usize,
}

impl<'a> RequestBodyFields<'a> {
    pub fn new(fields: &'a [RequestField]) -> Self {
        RequestBodyFields {
            fields,
            index: 0,
        }
    }
}

impl<'a> Iterator for RequestBodyFields<'a> {
    type Item = &'a RequestField;

    fn next(&mut self) -> Option<&'a RequestField> {
        let value = self.fields.get(self.index);

        self.index += 1;

        value
    }
}
<commit_msg>Yield only body fields from RequestBodyFields.<commit_after>use quote::{ToTokens, Tokens};
use syn::{Field, Lit, MetaItem};

#[derive(Debug)]
pub struct Request {
    fields: Vec<RequestField>,
}

impl Request {
    pub fn has_body_fields(&self) -> bool {
        self.fields.iter().any(|field| field.is_body())
    }

    pub fn request_body_init_fields(&self) -> Tokens {
        let mut tokens = Tokens::new();

        for request_field in self.body_fields() {
            let field =  match *request_field {
                RequestField::Body(ref field) => field,
                _ => panic!("expected body field"),
            };

            let field_name = field.ident.as_ref().expect("expected body field to have a name");

            tokens.append(quote! {
                #field_name: request.#field_name,
            });
        }

        tokens
    }

    fn body_fields(&self) -> RequestBodyFields {
        RequestBodyFields::new(&self.fields)
    }
}

impl From<Vec<Field>> for Request {
    fn from(fields: Vec<Field>) -> Self {
        let request_fields = fields.into_iter().map(|field| {
            for attr in field.attrs.clone().iter() {
                match attr.value {
                    MetaItem::Word(ref ident) => {
                        if ident == "query" {
                            return RequestField::Query(field);
                        }
                    }
                    MetaItem::List(_, _) => {}
                    MetaItem::NameValue(ref ident, ref lit) => {
                        if ident == "header" {
                            if let Lit::Str(ref name, _) = *lit {
                                return RequestField::Header(name.clone(), field);
                            } else {
                                panic!("ruma_api! header attribute expects a string value");
                            }
                        } else if ident == "path" {
                            if let Lit::Str(ref name, _) = *lit {
                                return RequestField::Path(name.clone(), field);
                            } else {
                                panic!("ruma_api! path attribute expects a string value");
                            }
                        }
                    }
                }
            }

            return RequestField::Body(field);
        }).collect();

        Request {
            fields: request_fields,
        }
    }
}

impl ToTokens for Request {
    fn to_tokens(&self, mut tokens: &mut Tokens) {
        tokens.append(quote! {
            /// Data for a request to this API endpoint.
            #[derive(Debug)]
            pub struct Request
        });

        if self.fields.len() == 0 {
            tokens.append(";");
        } else {
            tokens.append("{");

            for request_field in self.fields.iter() {
                match *request_field {
                    RequestField::Body(ref field) => field.to_tokens(&mut tokens),
                    RequestField::Header(_, ref field) => field.to_tokens(&mut tokens),
                    RequestField::Path(_, ref field) => field.to_tokens(&mut tokens),
                    RequestField::Query(ref field) => field.to_tokens(&mut tokens),
                }

                tokens.append(",");
            }

            tokens.append("}");
        }

        if self.has_body_fields() {
            tokens.append(quote! {
                /// Data in the request body.
                #[derive(Debug, Serialize)]
                struct RequestBody
            });

            tokens.append("{");

            for request_field in self.fields.iter() {
                match *request_field {
                    RequestField::Body(ref field) => {
                        field.to_tokens(&mut tokens);

                        tokens.append(",");
                    }
                    _ => {}
                }
            }

            tokens.append("}");
        }
    }
}

#[derive(Debug)]
pub enum RequestField {
    Body(Field),
    Header(String, Field),
    Path(String, Field),
    Query(Field),
}

impl RequestField {
    fn is_body(&self) -> bool {
        match *self {
            RequestField::Body(_) => true,
            _ => false,
        }
    }
}

#[derive(Debug)]
pub struct RequestBodyFields<'a> {
    fields: &'a [RequestField],
    index: usize,
}

impl<'a> RequestBodyFields<'a> {
    pub fn new(fields: &'a [RequestField]) -> Self {
        RequestBodyFields {
            fields,
            index: 0,
        }
    }
}

impl<'a> Iterator for RequestBodyFields<'a> {
    type Item = &'a RequestField;

    fn next(&mut self) -> Option<&'a RequestField> {
        while let Some(value) = self.fields.get(self.index) {
            self.index += 1;

            if value.is_body() {
                return Some(value);
            }
        }

        None
    }
}
<|endoftext|>


<commit_before>use token::Token;
use book::{Book, compile_str};
use number::Number;
use error::Result;
use templates::odt;
use zipper::Zipper;
use parser::Parser;
use book_renderer::BookRenderer;

use crowbook_text_processing::escape;

use std::io::Write;

/// Rendererer for ODT
///
/// Still very experimental.
pub struct OdtRenderer<'a> {
    book: &'a Book,
    current_numbering: i32,
    current_hide: bool,
    current_chapter: i32,
    automatic_styles: String,
}

impl<'a> OdtRenderer<'a> {
    /// Creates a new OdtRenderer
    pub fn new(book: &'a Book) -> OdtRenderer {
        OdtRenderer {
            book: book,
            current_chapter: 1,
            current_numbering: book.options.get_i32("rendering.num_depth").unwrap(),
            current_hide: false,
            automatic_styles: String::from("
<style:style style:name=\"T1\" \
                                            style:family=\"text\">
  <style:text-properties \
                                            fo:font-style=\"italic\" \
                                            style:font-style-asian=\"italic\" \
                                            style:font-style-complex=\"italic\"/>
</style:style>
\
                                            <style:style style:name=\"T2\" \
                                            style:family=\"text\">
  <style:text-properties \
                                            fo:font-weight=\"bold\" \
                                            style:font-weight-asian=\"bold\" \
                                            style:font-weight-complex=\"bold\"/>
</style:style>"),
        }
    }

    /// Renders a full book
    ///
    /// This will try to generate an ODT file according to self.book options.
    ///
    /// # Returns
    /// * `Ok(s)` where `s` contains the output of the `zip` command
    ///   used to create the ODT file.
    /// * An error if there was somel problem during either the rendering to
    ///   ODT format, or the generation of the ODT file itself.
    pub fn render_book(&mut self, to: &mut Write) -> Result<String> {
        let content = self.render_content()?;

        let mut zipper =
            Zipper::new(&self.book.options.get_path("crowbook.temp_dir").unwrap(),
                        &self.book.logger)?;

        // Write template.odt there
        zipper.write("template.odt", odt::ODT, false)?;
        // unzip it
        zipper.unzip("template.odt")?;
        // Complete it with content.xml
        zipper.write("content.xml", content.as_bytes(), false)?;
        // Zip and copy
        zipper.generate_odt(self.book.options.get_str("crowbook.zip.command").unwrap(),
                            to)
    }

    /// Render content.xml
    fn render_content(&mut self) -> Result<String> {
        // Print a warning for the features that aren't supported in ODT.
        let mut missing = vec![];
        if self.book.features.image { missing.push(lformat!("images")); }
        if self.book.features.blockquote { missing.push(lformat!("blockquotes")); }
        if self.book.features.codeblock { missing.push(lformat!("codeblocks")); }
        if self.book.features.ordered_list { missing.push(lformat!("ordered lists")); }
        if self.book.features.footnote { missing.push(lformat!("footnotes")); }
        if self.book.features.table { missing.push(lformat!("tables")); }

        if !missing.is_empty() {
            let missing = missing.join(", ");
            self.book.logger.warning(lformat!("The document uses the following features, that are not implemented for ODT output: {features}",
                                         features = missing));
            self.book.logger.warning(lformat!("They will be ignored in the generated document."));
        }

        let mut content = String::new();

        for chapter in &self.book.chapters {
            let n = chapter.number;
            let v = &chapter.content;
            self.current_hide = false;
            match n {
                Number::Unnumbered | Number::UnnumberedPart => self.current_numbering = 0,
                Number::Default | Number::DefaultPart => {
                    self.current_numbering =
                        self.book.options.get_i32("rendering.num_depth").unwrap()
                }
                Number::Specified(n) | Number::SpecifiedPart(n) => {
                    self.current_numbering = self.book.options.get_i32("numbering").unwrap();
                    self.current_chapter = n;
                }
                Number::Hidden => {
                    self.current_numbering = 0;
                    self.current_hide = true;
                }
           }
            if n.is_part() {
                self.book.logger.error(lformat!("Parts are not supported yet in ODT"));
            }

            for token in v {
                content.push_str(&self.parse_token(token));
            }
        }

        let template = compile_str(odt::CONTENT,
                                   &self.book.source,
                                   "could not compile template for content.xml")?;
        let data = self.book.get_metadata(|s| Ok(s.to_owned()))?
            .insert_str("content", content)
            .insert_str("automatic_styles", &self.automatic_styles)
            .build();

        let mut res: Vec<u8> = vec![];
        template.render_data(&mut res, &data)?;
        match String::from_utf8(res) {
            Err(_) => panic!(lformat!("generated content.xml was not utf-8 valid")),
            Ok(res) => Ok(res),
        }
    }

    /// Transform a vector of `Token`s to Odt format
    fn render_vec(&mut self, tokens: &[Token]) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(token));
        }
        res
    }

    fn parse_token(&mut self, token: &Token) -> String {
        match *token {
            Token::Str(ref text) => escape::html(self.book.clean(text.as_str(), false)).into_owned(),
            Token::Paragraph(ref vec) => {
                format!("<text:p text:style-name=\"Text_20_body\">{}</text:p>\n",
                        self.render_vec(vec))
            }
            Token::Header(n, ref vec) => {
                if n == 1 && self.current_hide {
                    return String::new();
                }
                let s = if n == 1 && self.current_numbering >= 1 {
                    let chapter = self.current_chapter;
                    self.current_chapter += 1;
                    let res = self.book.get_chapter_header(chapter, self.render_vec(vec), |s| {
                        Ok(self.render_vec(&Parser::new().parse_inline(s)?))
                    });
                    res.unwrap()
                } else {
                    self.render_vec(vec)
                };
                format!("<text:h text:style-name=\"Heading_20_{}\">\n{}</text:h>\n",
                        n,
                        s)
            }
            Token::Emphasis(ref vec) => {
                format!("<text:span text:style-name=\"T1\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::Strong(ref vec) => {
                format!("<text:span text:style-name=\"T2\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::List(ref vec) => format!("<text:list>\n{}</text:list>\n", self.render_vec(vec)),
            Token::OrderedList(_, ref vec) => {
                format!("<text:list>\n{}</text:list>\n", self.render_vec(vec))
            }
            Token::Item(ref vec) => {
                format!("<text:list-item>\n<text:p>{}</text:p></text:list-item>",
                        self.render_vec(vec))
            }
            Token::Link(ref url, _, ref vec) => {
                format!("<text:a xlink:type=\"simple\"  xlink:href=\"{}\">{}</text:a>",
                        url,
                        self.render_vec(vec))
            }
            Token::Code(ref vec) => {
                format!("<text:span text:style-name=\"Preformatted_20_Text\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::Subscript(ref vec) | Token::Superscript(ref vec) => self.render_vec(vec),
            Token::BlockQuote(ref vec) |
            Token::CodeBlock(_, ref vec) => {
                format!("<text:p text:style-name=\"Text_20_Body\">{}</text:p>\n",
                        self.render_vec(vec))
            }
            Token::SoftBreak | Token::HardBreak => String::from(" "),
            Token::Rule => String::from("<text:p /><text:p>***</text:p><text:p />"),
            Token::Image(_, _, _) |
            Token::StandaloneImage(_, _, _) => {
                String::from(" ")
            }
            Token::Table(_, _) |
            Token::TableHead(_) |
            Token::TableRow(_) |
            Token::TableCell(_) => {
                String::from(" ")
            }
            Token::Footnote(_) => {
                String::new()
            }
            Token::Annotation(_, ref vec) => self.render_vec(vec),
            Token::__NonExhaustive => unreachable!(),
        }
    }
}

pub struct Odt {}

impl BookRenderer for Odt {
    fn render(&self, book: &Book, to: &mut Write) -> Result<()> {
        OdtRenderer::new(book)
            .render_book(to)?;
        Ok(())
    }
}
<commit_msg>Detect subscript and superscript in odt missing features<commit_after>use token::Token;
use book::{Book, compile_str};
use number::Number;
use error::Result;
use templates::odt;
use zipper::Zipper;
use parser::Parser;
use book_renderer::BookRenderer;

use crowbook_text_processing::escape;

use std::io::Write;

/// Rendererer for ODT
///
/// Still very experimental.
pub struct OdtRenderer<'a> {
    book: &'a Book,
    current_numbering: i32,
    current_hide: bool,
    current_chapter: i32,
    automatic_styles: String,
}

impl<'a> OdtRenderer<'a> {
    /// Creates a new OdtRenderer
    pub fn new(book: &'a Book) -> OdtRenderer {
        OdtRenderer {
            book: book,
            current_chapter: 1,
            current_numbering: book.options.get_i32("rendering.num_depth").unwrap(),
            current_hide: false,
            automatic_styles: String::from("
<style:style style:name=\"T1\" \
                                            style:family=\"text\">
  <style:text-properties \
                                            fo:font-style=\"italic\" \
                                            style:font-style-asian=\"italic\" \
                                            style:font-style-complex=\"italic\"/>
</style:style>
\
                                            <style:style style:name=\"T2\" \
                                            style:family=\"text\">
  <style:text-properties \
                                            fo:font-weight=\"bold\" \
                                            style:font-weight-asian=\"bold\" \
                                            style:font-weight-complex=\"bold\"/>
</style:style>"),
        }
    }

    /// Renders a full book
    ///
    /// This will try to generate an ODT file according to self.book options.
    ///
    /// # Returns
    /// * `Ok(s)` where `s` contains the output of the `zip` command
    ///   used to create the ODT file.
    /// * An error if there was somel problem during either the rendering to
    ///   ODT format, or the generation of the ODT file itself.
    pub fn render_book(&mut self, to: &mut Write) -> Result<String> {
        let content = self.render_content()?;

        let mut zipper =
            Zipper::new(&self.book.options.get_path("crowbook.temp_dir").unwrap(),
                        &self.book.logger)?;

        // Write template.odt there
        zipper.write("template.odt", odt::ODT, false)?;
        // unzip it
        zipper.unzip("template.odt")?;
        // Complete it with content.xml
        zipper.write("content.xml", content.as_bytes(), false)?;
        // Zip and copy
        zipper.generate_odt(self.book.options.get_str("crowbook.zip.command").unwrap(),
                            to)
    }

    /// Render content.xml
    fn render_content(&mut self) -> Result<String> {
        // Print a warning for the features that aren't supported in ODT.
        let mut missing = vec![];
        if self.book.features.image { missing.push(lformat!("images")); }
        if self.book.features.blockquote { missing.push(lformat!("blockquotes")); }
        if self.book.features.codeblock { missing.push(lformat!("codeblocks")); }
        if self.book.features.ordered_list { missing.push(lformat!("ordered lists")); }
        if self.book.features.footnote { missing.push(lformat!("footnotes")); }
        if self.book.features.table { missing.push(lformat!("tables")); }
        if self.book.features.superscript { missing.push(lformat!("superscript")); }
        if self.book.features.subscript { missing.push(lformat!("subscript")); }

        if !missing.is_empty() {
            let missing = missing.join(", ");
            self.book.logger.warning(lformat!("The document uses the following features, that are not implemented for ODT output: {features}",
                                         features = missing));
            self.book.logger.warning(lformat!("They will be ignored in the generated document."));
        }

        let mut content = String::new();

        for chapter in &self.book.chapters {
            let n = chapter.number;
            let v = &chapter.content;
            self.current_hide = false;
            match n {
                Number::Unnumbered | Number::UnnumberedPart => self.current_numbering = 0,
                Number::Default | Number::DefaultPart => {
                    self.current_numbering =
                        self.book.options.get_i32("rendering.num_depth").unwrap()
                }
                Number::Specified(n) | Number::SpecifiedPart(n) => {
                    self.current_numbering = self.book.options.get_i32("numbering").unwrap();
                    self.current_chapter = n;
                }
                Number::Hidden => {
                    self.current_numbering = 0;
                    self.current_hide = true;
                }
           }
            if n.is_part() {
                self.book.logger.error(lformat!("Parts are not supported yet in ODT"));
            }

            for token in v {
                content.push_str(&self.parse_token(token));
            }
        }

        let template = compile_str(odt::CONTENT,
                                   &self.book.source,
                                   "could not compile template for content.xml")?;
        let data = self.book.get_metadata(|s| Ok(s.to_owned()))?
            .insert_str("content", content)
            .insert_str("automatic_styles", &self.automatic_styles)
            .build();

        let mut res: Vec<u8> = vec![];
        template.render_data(&mut res, &data)?;
        match String::from_utf8(res) {
            Err(_) => panic!(lformat!("generated content.xml was not utf-8 valid")),
            Ok(res) => Ok(res),
        }
    }

    /// Transform a vector of `Token`s to Odt format
    fn render_vec(&mut self, tokens: &[Token]) -> String {
        let mut res = String::new();

        for token in tokens {
            res.push_str(&self.parse_token(token));
        }
        res
    }

    fn parse_token(&mut self, token: &Token) -> String {
        match *token {
            Token::Str(ref text) => escape::html(self.book.clean(text.as_str(), false)).into_owned(),
            Token::Paragraph(ref vec) => {
                format!("<text:p text:style-name=\"Text_20_body\">{}</text:p>\n",
                        self.render_vec(vec))
            }
            Token::Header(n, ref vec) => {
                if n == 1 && self.current_hide {
                    return String::new();
                }
                let s = if n == 1 && self.current_numbering >= 1 {
                    let chapter = self.current_chapter;
                    self.current_chapter += 1;
                    let res = self.book.get_chapter_header(chapter, self.render_vec(vec), |s| {
                        Ok(self.render_vec(&Parser::new().parse_inline(s)?))
                    });
                    res.unwrap()
                } else {
                    self.render_vec(vec)
                };
                format!("<text:h text:style-name=\"Heading_20_{}\">\n{}</text:h>\n",
                        n,
                        s)
            }
            Token::Emphasis(ref vec) => {
                format!("<text:span text:style-name=\"T1\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::Strong(ref vec) => {
                format!("<text:span text:style-name=\"T2\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::List(ref vec) => format!("<text:list>\n{}</text:list>\n", self.render_vec(vec)),
            Token::OrderedList(_, ref vec) => {
                format!("<text:list>\n{}</text:list>\n", self.render_vec(vec))
            }
            Token::Item(ref vec) => {
                format!("<text:list-item>\n<text:p>{}</text:p></text:list-item>",
                        self.render_vec(vec))
            }
            Token::Link(ref url, _, ref vec) => {
                format!("<text:a xlink:type=\"simple\"  xlink:href=\"{}\">{}</text:a>",
                        url,
                        self.render_vec(vec))
            }
            Token::Code(ref vec) => {
                format!("<text:span text:style-name=\"Preformatted_20_Text\">{}</text:span>",
                        self.render_vec(vec))
            }
            Token::Subscript(ref vec) | Token::Superscript(ref vec) => self.render_vec(vec),
            Token::BlockQuote(ref vec) |
            Token::CodeBlock(_, ref vec) => {
                format!("<text:p text:style-name=\"Text_20_Body\">{}</text:p>\n",
                        self.render_vec(vec))
            }
            Token::SoftBreak | Token::HardBreak => String::from(" "),
            Token::Rule => String::from("<text:p /><text:p>***</text:p><text:p />"),
            Token::Image(_, _, _) |
            Token::StandaloneImage(_, _, _) => {
                String::from(" ")
            }
            Token::Table(_, _) |
            Token::TableHead(_) |
            Token::TableRow(_) |
            Token::TableCell(_) => {
                String::from(" ")
            }
            Token::Footnote(_) => {
                String::new()
            }
            Token::Annotation(_, ref vec) => self.render_vec(vec),
            Token::__NonExhaustive => unreachable!(),
        }
    }
}

pub struct Odt {}

impl BookRenderer for Odt {
    fn render(&self, book: &Book, to: &mut Write) -> Result<()> {
        OdtRenderer::new(book)
            .render_book(to)?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate "termbox-sys" as termbox;

use termbox::RawEvent;
use libc::{c_int, c_uint};

#[deriving(Copy)]
pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

#[deriving(Copy)]
pub enum Color {
    Default,
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Magenta,
    Cyan,
    White
}

#[deriving(Copy)]
pub enum Style {
    Normal,
    Bold,
    Underline,
    BoldUnderline,
    Reverse
}

fn nil_raw_event() -> RawEvent {
    RawEvent{etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0}
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> Event {
    match ev_type {
        0 => Event::NoEvent,
        1 => Event::KeyEvent(ev.emod, ev.key, ev.ch),
        2 => Event::ResizeEvent(ev.w, ev.h),
        _ => panic!("Unknown event")
    }
}

pub fn convert_color(c: Color) -> u16 {
    match c {
        Color::Default => 0x00,
        Color::Black   => 0x01,
        Color::Red     => 0x02,
        Color::Green   => 0x03,
        Color::Yellow  => 0x04,
        Color::Blue    => 0x05,
        Color::Magenta => 0x06,
        Color::Cyan    => 0x07,
        Color::White   => 0x08,
    }
}

pub fn convert_style(sty: Style) -> u16 {
    match sty {
        Style::Normal         => 0x0000,
        Style::Bold           => 0x0100,
        Style::Underline      => 0x0200,
        Style::BoldUnderline  => 0x0300,
        Style::Reverse        => 0x0400,
    }
}

pub fn init() -> int {
    unsafe {
        termbox::tb_init() as int
    }
}

pub fn shutdown() {
    unsafe { termbox::tb_shutdown() }
}

pub fn width() -> uint {
    unsafe { termbox::tb_width() as uint }
}

pub fn height() -> uint {
    unsafe { termbox::tb_height() as uint }
}

pub fn clear() {
    unsafe { termbox::tb_clear() }
}

pub fn present() {
    unsafe { termbox::tb_present() }
}

pub fn set_cursor(x: int, y: int) {
    unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
}

pub fn change_cell(x: uint, y: uint, ch: u32, fg: u16, bg: u16) {
    unsafe {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }
}

pub fn print(x: uint, y: uint, sty: Style, fg: Color, bg: Color, s: &str) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    for (i, ch) in s.chars().enumerate() {
        change_cell(x+i, y, ch as u32, fg, bg);
    }
}

pub fn print_char(x: uint, y: uint, sty: Style, fg: Color, bg: Color, ch: char) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    change_cell(x, y, ch as u32, fg, bg);
}

pub fn poll_event() -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_poll_event(&ev as *const RawEvent);
        unpack_event(rc, &ev)
    }
}

pub fn peek_event(timeout: uint) -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_peek_event(&ev as *const RawEvent, timeout as c_uint);
        unpack_event(rc, &ev)
    }
}
<commit_msg>Make use of the ability to assign values to enum variants.<commit_after>extern crate libc;
extern crate "termbox-sys" as termbox;

use termbox::RawEvent;
use libc::{c_int, c_uint};

#[deriving(Copy)]
pub enum Event {
    KeyEvent(u8, u16, u32),
    ResizeEvent(i32, i32),
    NoEvent
}

#[deriving(Copy)]
pub enum Color {
    Default = 0,
    Black   = 1,
    Red     = 2,
    Green   = 3,
    Yellow  = 4,
    Blue    = 5,
    Magenta = 6,
    Cyan    = 7,
    White   = 8
}

#[deriving(Copy)]
pub enum Style {
    Normal        = 0x0000,
    Bold          = 0x0100,
    Underline     = 0x0200,
    BoldUnderline = 0x0300,
    Reverse       = 0x0400
}

fn nil_raw_event() -> RawEvent {
    RawEvent{etype: 0, emod: 0, key: 0, ch: 0, w: 0, h: 0}
}

fn unpack_event(ev_type: c_int, ev: &RawEvent) -> Event {
    match ev_type {
        0 => Event::NoEvent,
        1 => Event::KeyEvent(ev.emod, ev.key, ev.ch),
        2 => Event::ResizeEvent(ev.w, ev.h),
        _ => panic!("Unknown event")
    }
}

pub fn convert_color(c: Color) -> u16 {
    c as u16
}

pub fn convert_style(sty: Style) -> u16 {
    sty as u16
}

pub fn init() -> int {
    unsafe {
        termbox::tb_init() as int
    }
}

pub fn shutdown() {
    unsafe { termbox::tb_shutdown() }
}

pub fn width() -> uint {
    unsafe { termbox::tb_width() as uint }
}

pub fn height() -> uint {
    unsafe { termbox::tb_height() as uint }
}

pub fn clear() {
    unsafe { termbox::tb_clear() }
}

pub fn present() {
    unsafe { termbox::tb_present() }
}

pub fn set_cursor(x: int, y: int) {
    unsafe { termbox::tb_set_cursor(x as c_int, y as c_int) }
}

pub fn change_cell(x: uint, y: uint, ch: u32, fg: u16, bg: u16) {
    unsafe {
        termbox::tb_change_cell(x as c_uint, y as c_uint, ch, fg, bg)
    }
}

pub fn print(x: uint, y: uint, sty: Style, fg: Color, bg: Color, s: &str) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    for (i, ch) in s.chars().enumerate() {
        change_cell(x+i, y, ch as u32, fg, bg);
    }
}

pub fn print_char(x: uint, y: uint, sty: Style, fg: Color, bg: Color, ch: char) {
    let fg: u16 = convert_color(fg) | convert_style(sty);
    let bg: u16 = convert_color(bg);
    change_cell(x, y, ch as u32, fg, bg);
}

pub fn poll_event() -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_poll_event(&ev as *const RawEvent);
        unpack_event(rc, &ev)
    }
}

pub fn peek_event(timeout: uint) -> Event {
    unsafe {
        let ev = nil_raw_event();
        let rc = termbox::tb_peek_event(&ev as *const RawEvent, timeout as c_uint);
        unpack_event(rc, &ev)
    }
}
<|endoftext|>


<commit_before>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError, LuaTable, PushGuard};
use hlua::any::AnyLuaValue;

use rustc_serialize::json::Json;

use std::collections::BTreeMap;

use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::borrow::Borrow;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

#[macro_use]
mod funcs;
#[cfg(test)]
mod tests;

mod types;
pub use self::types::{LuaQuery, LuaFunc, LuaIdent, LuaResponse};

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Struct sent to the lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Errors which may arise from attempting
/// to sending a message to the lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !thread_running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().unwrap();
        match *maybe_sender {
            Some(ref real_sender) => {
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    let (tx, rx) = channel();
    let message = LuaMessage { reply: tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaMessage>();
    {
        let mut sender = SENDER.lock().unwrap();
        *sender = Some(query_tx);
    }

    thread::spawn(move || {
        thread_init(query_rx);
    });
    trace!("Created thread. Init finished.");
}

fn thread_init(receiver: Receiver<LuaMessage>) {
    trace!("thread: initializing.");
    let mut lua = Lua::new();
    //unsafe {
    //    hlua_ffi::lua_atpanic(&mut lua.as_mut_lua().0, thread_on_panic);
    //}
    debug!("thread: Loading Lua libraries...");
    lua.openlibs();
    trace!("thread: Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua").unwrap()
    ).unwrap();
    trace!("thread: loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().unwrap() = true;
    debug!("thread: entering main loop...");
    thread_main_loop(receiver, &mut lua);
}

fn thread_main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(message, lua);
            }
        }
    }
}

fn thread_handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            thread_send(request.reply, LuaResponse::Pong);
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;
            thread_send(request.reply, LuaResponse::Pong);

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("thread: Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetValue(varname) => {
            trace!("thread: Received request to get variable {:?}", varname);

            if varname.len() == 0 {
                thread_send(request.reply, LuaResponse::InvalidName);
                return;
            }
            // Table[0] String had to be cloned, it'd be nice if Rust let us
            // borrow out parts of memory
            match lua.get::<AnyLuaValue, _>(varname[0].clone()) {
                Some(table) => {
                    let full_table = walk_table(table, &varname[1..]);
                    thread_send(request.reply,
                                LuaResponse::Variable(full_table));
                },
                None => thread_send(request.reply, LuaResponse::Variable(None))
            }
        },
        LuaQuery::ExecWithLua(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(result));
        },
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}

/// Converts a Json map into an AnyLuaValue
pub fn json_to_lua(json: Json) -> AnyLuaValue {
    match json {
        Json::String(val)  => AnyLuaValue::LuaString(val),
        Json::Boolean(val) => AnyLuaValue::LuaBoolean(val),
        Json::F64(val)     => AnyLuaValue::LuaNumber(val),
        Json::I64(val)     => AnyLuaValue::LuaNumber((val as i32) as f64),
        Json::U64(val)     => AnyLuaValue::LuaNumber((val as u32) as f64),
        Json::Null         => AnyLuaValue::LuaNil,
        Json::Array(vals)  => {
            let mut lua_arr = Vec::with_capacity(vals.len());
            for (ix, val) in vals.into_iter().enumerate() {
                lua_arr.push((AnyLuaValue::LuaNumber(ix as f64 + 1.0),
                              json_to_lua(val)));
            }
            AnyLuaValue::LuaArray(lua_arr)
        },
        Json::Object(vals) => {
            let mut lua_table = Vec::with_capacity(vals.len());
            for (key, val) in vals.into_iter() {
                lua_table.push((AnyLuaValue::LuaString(key),
                                json_to_lua(val)));
            }
            AnyLuaValue::LuaArray(lua_table)
        }
    }
}

/// Converts an `AnyLuaValue` to a `Json`.
///
/// For an already-matched `LuaArray`, use `lua_array_to_json`.
///
/// For a `LuaArray` that should be mapped to a `JsonObject`,
/// use `lua_object_to_json`.
pub fn lua_to_json(lua: AnyLuaValue) -> Result<Json, ()> {
    match lua {
        AnyLuaValue::LuaNil => Ok(Json::Null),
        AnyLuaValue::LuaString(val) => Ok(Json::String(val)),
        AnyLuaValue::LuaNumber(val) => Ok(Json::F64(val)),
        AnyLuaValue::LuaBoolean(val) => Ok(Json::Boolean(val)),
        AnyLuaValue::LuaArray(arr) => lua_array_to_json(arr),
        AnyLuaValue::LuaOther => Err(())
    }
}

pub fn lua_array_to_json(arr: Vec<(AnyLuaValue, AnyLuaValue)>)
                         -> Result<Json, ()> {
    // Check if every key is a number
    let mut counter = 0.0; // Account for first index?

    for &(ref key, ref _val) in &arr {
        match *key {
            AnyLuaValue::LuaNumber(num) => {
                counter += num;
            }
            AnyLuaValue::LuaString(_) => {
                break;
            }
            // Non-string keys are not allowed
            _ => {
                return Err(());
            }
        }
    }

    // Gauss' trick
    let desired_sum = ((arr.len()) * (arr.len() + 1)) / 2;
    if counter != desired_sum as f64 {
        return lua_object_to_json(arr);
    }

    let mut json_arr: Vec<Json> = Vec::with_capacity(arr.len());

    for (_key, val) in arr.into_iter() {
        let lua_val = try!(lua_to_json(val));
        json_arr.push(lua_val);
    }
    Ok(Json::Array(json_arr))
}

pub fn lua_object_to_json(obj: Vec<(AnyLuaValue, AnyLuaValue)>)
                          -> Result<Json, ()> {
    let mut json_obj: BTreeMap<String, Json> = BTreeMap::new();

    for (key, val) in obj.into_iter() {
        match key {
            AnyLuaValue::LuaString(text) => {
                json_obj.insert(text, try!(lua_to_json(val)));
            },
            AnyLuaValue::LuaNumber(ix) => {
                json_obj.insert(format!("{}", ix), try!(lua_to_json(val)));
            }
            _ => { return Err(()); }
        }
    }
    Ok(Json::Object(json_obj))
}
<commit_msg>Fixed build<commit_after>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError, LuaTable, PushGuard};
use hlua::any::AnyLuaValue;

use rustc_serialize::json::Json;

use std::collections::BTreeMap;

use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::borrow::Borrow;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

#[macro_use]
mod funcs;
#[cfg(test)]
mod tests;

mod types;
pub use self::types::{LuaQuery, LuaFunc, LuaIdent, LuaResponse};

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Struct sent to the lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Errors which may arise from attempting
/// to sending a message to the lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !thread_running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().unwrap();
        match *maybe_sender {
            Some(ref real_sender) => {
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    let (tx, rx) = channel();
    let message = LuaMessage { reply: tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaMessage>();
    {
        let mut sender = SENDER.lock().unwrap();
        *sender = Some(query_tx);
    }

    thread::spawn(move || {
        thread_init(query_rx);
    });
    trace!("Created thread. Init finished.");
}

fn thread_init(receiver: Receiver<LuaMessage>) {
    trace!("thread: initializing.");
    let mut lua = Lua::new();
    //unsafe {
    //    hlua_ffi::lua_atpanic(&mut lua.as_mut_lua().0, thread_on_panic);
    //}
    debug!("thread: Loading Lua libraries...");
    lua.openlibs();
    trace!("thread: Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua").unwrap()
    ).unwrap();
    trace!("thread: loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().unwrap() = true;
    debug!("thread: entering main loop...");
    thread_main_loop(receiver, &mut lua);
}

fn thread_main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(message, lua);
            }
        }
    }
}

fn thread_handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            thread_send(request.reply, LuaResponse::Pong);
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;
            thread_send(request.reply, LuaResponse::Pong);

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("thread: Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetValue(varname) => {
            trace!("thread: Received request to get variable {:?}", varname);

            if varname.len() == 0 {
                thread_send(request.reply, LuaResponse::InvalidName);
                return;
            }
            // Table[0] String had to be cloned, it'd be nice if Rust let us
            // borrow out parts of memory
            match lua.get::<AnyLuaValue, _>(varname[0].clone()) {
                Some(table) => {
                    let full_table = walk_table(table, &varname[1..]);
                    thread_send(request.reply,
                                LuaResponse::Variable(full_table));
                },
                None => thread_send(request.reply, LuaResponse::Variable(None))
            }
        },
        LuaQuery::ExecWithLua(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}

fn walk_table(table: AnyLuaValue, names: &[String]) -> Option<AnyLuaValue> {
    if let Some(name) = names.first() {
        if let AnyLuaValue::LuaArray(arr) = table {
            for (key, val) in arr {
                if let AnyLuaValue::LuaString(key_str) = key {
                    if *key_str == *name {
                        return walk_table(val, &names[1..]);
                    }
                }
            }
        }
        return None;
    }
    return Some(table);
}
/// Converts a Json map into an AnyLuaValue
pub fn json_to_lua(json: Json) -> AnyLuaValue {
    match json {
        Json::String(val)  => AnyLuaValue::LuaString(val),
        Json::Boolean(val) => AnyLuaValue::LuaBoolean(val),
        Json::F64(val)     => AnyLuaValue::LuaNumber(val),
        Json::I64(val)     => AnyLuaValue::LuaNumber((val as i32) as f64),
        Json::U64(val)     => AnyLuaValue::LuaNumber((val as u32) as f64),
        Json::Null         => AnyLuaValue::LuaNil,
        Json::Array(vals)  => {
            let mut lua_arr = Vec::with_capacity(vals.len());
            for (ix, val) in vals.into_iter().enumerate() {
                lua_arr.push((AnyLuaValue::LuaNumber(ix as f64 + 1.0),
                              json_to_lua(val)));
            }
            AnyLuaValue::LuaArray(lua_arr)
        },
        Json::Object(vals) => {
            let mut lua_table = Vec::with_capacity(vals.len());
            for (key, val) in vals.into_iter() {
                lua_table.push((AnyLuaValue::LuaString(key),
                                json_to_lua(val)));
            }
            AnyLuaValue::LuaArray(lua_table)
        }
    }
}

/// Converts an `AnyLuaValue` to a `Json`.
///
/// For an already-matched `LuaArray`, use `lua_array_to_json`.
///
/// For a `LuaArray` that should be mapped to a `JsonObject`,
/// use `lua_object_to_json`.
pub fn lua_to_json(lua: AnyLuaValue) -> Result<Json, ()> {
    match lua {
        AnyLuaValue::LuaNil => Ok(Json::Null),
        AnyLuaValue::LuaString(val) => Ok(Json::String(val)),
        AnyLuaValue::LuaNumber(val) => Ok(Json::F64(val)),
        AnyLuaValue::LuaBoolean(val) => Ok(Json::Boolean(val)),
        AnyLuaValue::LuaArray(arr) => lua_array_to_json(arr),
        AnyLuaValue::LuaOther => Err(())
    }
}

pub fn lua_array_to_json(arr: Vec<(AnyLuaValue, AnyLuaValue)>)
                         -> Result<Json, ()> {
    // Check if every key is a number
    let mut counter = 0.0; // Account for first index?

    for &(ref key, ref _val) in &arr {
        match *key {
            AnyLuaValue::LuaNumber(num) => {
                counter += num;
            }
            AnyLuaValue::LuaString(_) => {
                break;
            }
            // Non-string keys are not allowed
            _ => {
                return Err(());
            }
        }
    }

    // Gauss' trick
    let desired_sum = ((arr.len()) * (arr.len() + 1)) / 2;
    if counter != desired_sum as f64 {
        return lua_object_to_json(arr);
    }

    let mut json_arr: Vec<Json> = Vec::with_capacity(arr.len());

    for (_key, val) in arr.into_iter() {
        let lua_val = try!(lua_to_json(val));
        json_arr.push(lua_val);
    }
    Ok(Json::Array(json_arr))
}

pub fn lua_object_to_json(obj: Vec<(AnyLuaValue, AnyLuaValue)>)
                          -> Result<Json, ()> {
    let mut json_obj: BTreeMap<String, Json> = BTreeMap::new();

    for (key, val) in obj.into_iter() {
        match key {
            AnyLuaValue::LuaString(text) => {
                json_obj.insert(text, try!(lua_to_json(val)));
            },
            AnyLuaValue::LuaNumber(ix) => {
                json_obj.insert(format!("{}", ix), try!(lua_to_json(val)));
            }
            _ => { return Err(()); }
        }
    }
    Ok(Json::Object(json_obj))
}
<|endoftext|>


<commit_before>
use rand::thread_rng;

use std::io;
use std::fmt;

use opcode::{Opcode, OpcodeError, SetRegMode};

const PROGRAM_START: u16 = 0x200;

const MEMORY_SIZE: usize = 4096;
const REGISTER_COUNT: usize = 16;

pub enum RuntimeError {
    EmptyCallStack,
    InvalidRegister(u8),
    AddressOutOfBounds(u16),
    OpcodeErr(OpcodeError),
}

pub struct Chip8 {
    memory: [u8; MEMORY_SIZE],
    regs: [u8; REGISTER_COUNT], // registers V0 - V15
    addressReg: u16, // register I

    pc: u16,
    // Stores thebbkbb vbfcvgbhnjm,k,mjnhbgvfbgnm,.
    // program counters of sub routine calls, used to return after a sub routine ends
    stack: Vec<u16>,

    screen: [[bool; 64]; 32],
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            memory: [0; 4096],
            regs: [0; 16],
            addressReg: 0,

            pc: PROGRAM_START,
            stack: Vec::new(),

            screen: [[false; 64]; 32],
        }
    }

    pub fn load_program<R: io::Read>(&mut self, mut program: R) -> io::Result<()> {
        let mut bytes = Vec::new();
        try!(program.read_to_end(&mut bytes));

        for (offset, byte) in bytes.iter().enumerate() {
            self.memory[offset + PROGRAM_START as usize] = *byte;
        }

        Ok(())
    }

    pub fn cycle(&mut self) -> Result<(), RuntimeError> {
        use self::RuntimeError::*;

        let pc_index = self.pc as usize;
        let opcode_bytes = (self.memory[pc_index] as u16) << 8 | (self.memory[pc_index + 1] as u16);

        let opcode = match Opcode::from_u16(opcode_bytes) {
            Ok(opcode) => opcode,
            Err(err) => return Err(OpcodeErr(err)),
        };

        try!(self.execute_opcode(opcode));

        Ok(())
    }

    pub fn clear_screen(&mut self) {
        for row in self.screen.iter_mut() {
            for col in row.iter_mut() {
                *col = false;
            }
        }
    }

    // Wrapping is performed in this function, no need to perform it outside
    pub fn toggle_pixel(x: usize, y: usize) {
        let x = x % 64;
        let y = y % 32;

    }

    pub fn execute_opcode(&mut self, opcode: Opcode) -> Result<(), RuntimeError> {
        use self::RuntimeError::*;
        use opcode::Opcode::*;

        match opcode {
            ClearScreen => self.clear_screen(),
            Return => {
                self.pc = match self.stack.pop() {
                    Some(addr) => addr,
                    None => return Err(EmptyCallStack),
                };
            },

            JumpTo { addr, plus_v0 } => {
                self.pc = addr;

                if plus_v0 {
                    self.pc += self.regs[0] as u16;
                }
            },
            Call(addr) => {
                self.stack.push(self.pc);
                self.pc = addr;
            },

            SkipIfRegEqualConst { not_equal, reg, value } => {
                let mut should_jump = self.regs[reg as usize] == value;

                if not_equal {
                    should_jump = !should_jump; // Effectively computes self.regs[reg] != value
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },
            SkipIfRegsEqual { not_equal, regs: (v_x, v_y) } => {
                let mut should_jump = self.regs[v_x as usize] == self.regs[v_y as usize];

                if not_equal {
                    should_jump = !should_jump;
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },

            SetRegToConst { add, reg, value } => {
                if add {
                    self.regs[reg as usize] += value;
                } else {
                    self.regs[reg as usize] = value;
                }
            },
            SetRegToReg { regs: (v_x, v_y), mode } => {
                let v_x = v_x as usize;
                let v_y = v_y as usize;

                match mode {
                    SetRegMode::Copy => self.regs[v_x] = self.regs[v_y],

                    SetRegMode::Or => self.regs[v_x] |= self.regs[v_y],
                    SetRegMode::And => self.regs[v_x] &= self.regs[v_y],
                    SetRegMode::Xor => self.regs[v_x] ^= self.regs[v_y],

                    SetRegMode::Add => {
                        let mut reg_value = self.regs[v_x] as usize + self.regs[v_y] as usize;
                        if reg_value > 255 {
                            reg_value -= 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },
                    SetRegMode::Subtract | SetRegMode::InverseSubtract => {
                        let mut reg_value = if mode == SetRegMode::Subtract {
                            self.regs[v_x] as isize - self.regs[v_y] as isize
                        } else { // Must be InverseSubtract
                            self.regs[v_y] as isize - self.regs[v_x] as isize
                        };

                        if reg_value < 0 {
                            reg_value += 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },

                    // v_y is ignored for the shift opcodes, not sure why
                    SetRegMode::ShiftLeft => {
                        self.regs[0xF] = self.regs[v_x] & 0xF0 >> 4;
                        self.regs[v_x] <<= 1;
                    },
                    SetRegMode::ShiftRight => {
                        self.regs[0xF] = self.regs[v_x] & 0x0F;
                        self.regs[v_x] >>= 1;
                    }
                }
            },
            _ => unreachable!(),
        }

        self.pc += 2;
        Ok(())
    }
}

impl fmt::Debug for Chip8 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(fmt, "Program Counter: 0x{:X}", self.pc));
        try!(writeln!(fmt, "Address Register: 0x{:X}", self.addressReg));
        try!(writeln!(fmt, "Stack: {:?}", self.stack));

        write!(fmt, "Register Contents: {:?}", self.regs)
    }
}
<commit_msg>Work on implementing more opcodes, still need to figure out keyboard handling<commit_after>
use rand::{thread_rng, Rng};

use std::io;
use std::fmt;

use opcode::{Opcode, OpcodeError, SetRegMode};

const PROGRAM_START: u16 = 0x200;

const MEMORY_SIZE: usize = 4096;
const REGISTER_COUNT: usize = 16;

pub enum RuntimeError {
    EmptyCallStack,
    InvalidRegister(u8),
    AddressOutOfBounds(u16),
    OpcodeErr(OpcodeError),
}

pub struct Chip8 {
    memory: [u8; MEMORY_SIZE],
    regs: [u8; REGISTER_COUNT], // registers V0 - V15
    addressReg: u16, // register I

    pc: u16,
    stack: Vec<u16>,

    delay_timer: u16,
    sound_timer: u16,

    screen: [[bool; 64]; 32],
}

impl Chip8 {
    pub fn new() -> Chip8 {
        Chip8 {
            memory: [0; 4096],
            regs: [0; 16],
            addressReg: 0,

            pc: PROGRAM_START,
            stack: Vec::new(),

            delay_timer: 0,
            sound_timer: 0,

            screen: [[false; 64]; 32],
        }
    }

    pub fn load_program<R: io::Read>(&mut self, mut program: R) -> io::Result<()> {
        let mut bytes = Vec::new();
        try!(program.read_to_end(&mut bytes));

        for (offset, byte) in bytes.iter().enumerate() {
            self.memory[offset + PROGRAM_START as usize] = *byte;
        }

        Ok(())
    }

    pub fn cycle(&mut self) -> Result<(), RuntimeError> {
        use self::RuntimeError::*;

        let pc_index = self.pc as usize;
        let opcode_bytes = (self.memory[pc_index] as u16) << 8 | (self.memory[pc_index + 1] as u16);

        let opcode = match Opcode::from_u16(opcode_bytes) {
            Ok(opcode) => opcode,
            Err(err) => return Err(OpcodeErr(err)),
        };

        try!(self.execute_opcode(opcode));

        Chip8::decrement_timer(&mut self.delay_timer);
        Chip8::decrement_timer(&mut self.sound_timer);

        Ok(())
    }

    pub fn clear_screen(&mut self) {
        for row in self.screen.iter_mut() {
            for col in row.iter_mut() {
                *col = false;
            }
        }
    }

    // Wrapping is performed in this function, no need to perform it outside
    pub fn set_pixel(&mut self, x: usize, y: usize, state: bool) {
        // Equivalent to using the mod operator, but faster
        let x = x & 64;
        let y = y & 32;

        let previous_state = self.screen[y][x];
        self.screen[y][x] ^= state;

        // If a pixel was previously set and then now unset, set VF
        if previous_state && !self.screen[y][x] {
            self.regs[0xF] = 1;
            return;
        }

        self.regs[0xF] = 0;
    }

    pub fn execute_opcode(&mut self, opcode: Opcode) -> Result<(), RuntimeError> {
        use self::RuntimeError::*;
        use opcode::Opcode::*;

        match opcode {
            ClearScreen => self.clear_screen(),
            Return => {
                self.pc = match self.stack.pop() {
                    Some(addr) => addr,
                    None => return Err(EmptyCallStack),
                };
            },

            JumpTo { addr, plus_v0 } => {
                self.pc = addr;

                if plus_v0 {
                    self.pc += self.regs[0] as u16;
                }
            },
            Call(addr) => {
                self.stack.push(self.pc);
                self.pc = addr;
            },

            SkipIfRegEqualConst { not_equal, reg, value } => {
                let mut should_jump = self.regs[reg as usize] == value;

                if not_equal {
                    should_jump = !should_jump; // Effectively computes self.regs[reg] != value
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },
            SkipIfRegsEqual { not_equal, regs: (v_x, v_y) } => {
                let mut should_jump = self.regs[v_x as usize] == self.regs[v_y as usize];

                if not_equal {
                    should_jump = !should_jump;
                }

                if should_jump {
                    self.pc += 4;
                    return Ok(());
                }
            },

            SetRegToConst { add, reg, value } => {
                if add {
                    self.regs[reg as usize] += value;
                } else {
                    self.regs[reg as usize] = value;
                }
            },
            SetRegToReg { regs: (v_x, v_y), mode } => {
                let v_x = v_x as usize;
                let v_y = v_y as usize;

                match mode {
                    SetRegMode::Copy => self.regs[v_x] = self.regs[v_y],

                    SetRegMode::Or => self.regs[v_x] |= self.regs[v_y],
                    SetRegMode::And => self.regs[v_x] &= self.regs[v_y],
                    SetRegMode::Xor => self.regs[v_x] ^= self.regs[v_y],

                    SetRegMode::Add => {
                        let mut reg_value = self.regs[v_x] as usize + self.regs[v_y] as usize;
                        if reg_value > 255 {
                            reg_value -= 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },
                    SetRegMode::Subtract | SetRegMode::InverseSubtract => {
                        let mut reg_value = if mode == SetRegMode::Subtract {
                            self.regs[v_x] as isize - self.regs[v_y] as isize
                        } else { // Must be InverseSubtract
                            self.regs[v_y] as isize - self.regs[v_x] as isize
                        };

                        if reg_value < 0 {
                            reg_value += 255;
                            self.regs[0xF] = 1;
                        }

                        self.regs[v_x] = reg_value as u8;
                    },

                    // v_y is ignored for the shift opcodes, not sure why
                    SetRegMode::ShiftLeft => {
                        self.regs[0xF] = self.regs[v_x] & 0xF0 >> 4;
                        self.regs[v_x] <<= 1;
                    },
                    SetRegMode::ShiftRight => {
                        self.regs[0xF] = self.regs[v_x] & 0x0F;
                        self.regs[v_x] >>= 1;
                    }
                }
            },

            SetAddressReg(addr) => self.addressReg = addr,
            SetRegToRandom { reg, mask } => {
                let rand: u8 = thread_rng().gen();
                self.regs[reg as usize] = rand & mask;
            },

            DrawSprite { regs: (v_x, v_y), rows } => {
                let x = self.regs[v_x as usize] as usize;
                let y = self.regs[v_y as usize] as usize;

                for row in 0..rows {
                    let sprite_slice = self.memory[self.addressReg + row];

                    for col in 0..8 {
                        let bit = (sprite_slice & (1 << col)) > 0;
                        self.set_pixel(x + col, y + row, bit);
                    }
                }
            },

            SetRegToDelayTimer(reg) => self.regs[reg] = self.delay_timer,
            SetSoundTimerToReg(reg) => self.regs[reg] = self.sound_timer,

            AddRegToAddressReg(reg) => self.addressReg += self.regs[reg],
            SetAddressRegToCharInReg(reg) => (), // TODO

            // See http://en.wikipedia.org/wiki/Binary-coded_decimal
            // n mod 10 => Gets the ones digit out of a number
            RegToBCD(reg) => {
                let number = self.regs[reg];

                let hundreds_digit = number / 100;
                let tens_digit = (number / 10) % 10; // Dividing by ten slides the tens digit into the ones digit
                let ones_digit = numbers % 10;

                self.memory[self.addressReg] = hundreds_digit;
                self.memory[self.addressReg + 1] = tens_digit;
                self.memory[self.addressReg + 2] = ones_digit;
            },

            DumpRegsToAddr(reg) => {
                for cur_reg in 0..(reg + 1) {
                    self.memory[self.addressReg + cur_reg] = self.regs[cur_reg];
                }
            },
            LoadRegsFromAddr(reg) => {
                for cur_reg in 0..(reg + 1) {
                    self.regs[cur_reg] = self.memory[self.addressReg + cur_reg];
                }
            }
            _ => unreachable!(),
        }

        self.pc += 2;
        Ok(())
    }

    fn decrement_timer(timer: &mut u16) {
        if *timer != 0 {
            *timer -= 1;
        }
    }
}

impl fmt::Debug for Chip8 {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        try!(writeln!(fmt, "Program Counter: 0x{:X}", self.pc));
        try!(writeln!(fmt, "Address Register: 0x{:X}", self.addressReg));
        try!(writeln!(fmt, "Stack: {:?}", self.stack));

        write!(fmt, "Register Contents: {:?}", self.regs)
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap};
use std::io::{Read, BufRead, Error as IoError, ErrorKind};
use std::string::{FromUtf8Error};

use num::{Zero};
use num::bigint::{BigInt, ToBigInt, Sign};
use byteorder::{ReadBytesExt, LittleEndian, BigEndian, Error as ByteorderError};
use from_ascii::{FromAscii, ParseIntError, ParseFloatError};

use string::{unescape, Error as UnescapeError};
use value::{Value};

use opcodes::*;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        EmptyMarker
        StackTooSmall
        EmptyStack
        InvalidValueOnStack
        InvalidMemoValue
        NotImplemented

        Read(err: ByteorderError) {
            from()
        }
        Io(err: IoError) {
            from()
        }
        UnknownOpcode(opcode: u8) {}

        InvalidInt {
            from(ParseIntError)
        }
        InvalidLong
        InvalidFloat {
            from(ParseFloatError)
        }

        InvalidString {
            from(FromUtf8Error)
        }
        UnescapeError(err: UnescapeError) {
            from()
        }

        InvalidProto(proto: u8)
        NegativeLength
    }
}

#[derive(Debug, PartialEq)]
pub enum BooleanOrInt {
    Boolean(bool),
    Int(i64),
}

fn read_exact<R>(rd: &mut R, mut buf: &mut [u8]) -> Result<(), IoError> where R: Read {
    while !buf.is_empty() {
        match rd.read(buf) {
            Ok(0) => break,
            Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            Err(e) => return Err(e),
        }
    }
    if !buf.is_empty() {
        Err(IoError::new(ErrorKind::Other,
                       "failed to fill whole buffer"))
    } else {
        Ok(())
    }
}

fn read_until_newline<R>(rd: &mut R) -> Result<Vec<u8>, Error> where R: Read + BufRead {
    let mut buf = Vec::new();
    try!(rd.read_until('\n' as u8, &mut buf));

    // Skip last symbol — \n
    match buf.split_last() {
        Some((&b'\n', init)) => Ok(init.to_vec()),
        _ => return Err(Error::InvalidString),
    }
}

fn read_decimal_int<R>(rd: &mut R) -> Result<BooleanOrInt, Error> where R: Read + BufRead {
    let s = try!(read_until_newline(rd));
    let val = match &s[..] {
        b"00" => BooleanOrInt::Boolean(false),
        b"01" => BooleanOrInt::Boolean(true),
        _ => BooleanOrInt::Int(try!(i64::from_ascii(&s)))
    };
    Ok(val)
}

fn read_decimal_long<R>(rd: &mut R) -> Result<BigInt, Error> where R: Read + BufRead {
    let s = try!(read_until_newline(rd));
    let init = match s.split_last() {
        None => return Err(Error::InvalidString),
        Some((&b'L', init)) => init,
        Some(_) => &s[..],
    };

    match BigInt::parse_bytes(&init, 10) {
        Some(i) => Ok(i),
        None => Err(Error::InvalidLong)
    }
}

fn read_long<R>(rd: &mut R, length: usize) -> Result<BigInt, Error> where R: Read + BufRead {
    let mut buf = vec![0; length];
    try!(read_exact(rd, buf.as_mut()));

    let mut n = BigInt::from_bytes_le(Sign::Plus, &buf);

    let last = match buf.last_mut() {
        None => return Err(Error::InvalidLong),
        Some(last) => last,
    };

    if *last > 127 {
        n = n - (1.to_bigint().unwrap() << (length * 8))
    }

    Ok(n)
}

pub struct Machine {
    stack: Vec<Value>,
    memo: HashMap<usize, Value>,
    marker: Option<usize>,
}

impl Machine {
    pub fn new() -> Self {
        Machine {
            stack: Vec::new(),
            memo: HashMap::new(),
            marker: None,
        }
    }

    fn split_off(&mut self) -> Result<Vec<Value>, Error> {
        let at = match self.marker {
            None => return Err(Error::EmptyMarker),
            Some(marker) => marker,
        };

        if at > self.stack.len() {
            return Err(Error::StackTooSmall);
        }

        Ok(self.stack.split_off(at))
    }

    pub fn pop(&mut self) -> Result<Value, Error> {
        match self.stack.pop() {
            None => return Err(Error::EmptyStack),
            Some(value) => Ok(value),
        }
    }

    fn handle_get(&mut self, i: usize) -> Result<(), Error> {
        let value = match self.memo.get(&i) {
            None => return Err(Error::InvalidMemoValue),
            Some(ref v) => (*v).clone(),
        };
        self.stack.push(value);
        Ok(())
    }

    fn handle_put(&mut self, i: usize) -> Result<(), Error> {
        let value = match self.stack.last() {
            None => return Err(Error::EmptyStack),
            Some(ref v) => (*v).clone(),
        };
        self.memo.insert(i, value);
        Ok(())
    }

    fn execute<R>(&mut self, rd: &mut R) -> Result<bool, Error> where R: Read + BufRead {
        macro_rules! ensure_not_negative {
            ($n: expr) => ({
                if $n < Zero::zero() {
                    return Err(Error::NegativeLength)
                }
            })
        }

        let marker = try!(rd.read_u8());
        match marker {
            PROTO => {
                let version = try!(rd.read_u8());
                if version < 2 {
                    return Err(Error::InvalidProto(version))
                }
            },
            STOP => (),

            INT => {
                self.stack.push(match try!(read_decimal_int(rd)) {
                    BooleanOrInt::Boolean(v) => Value::Bool(v),
                    BooleanOrInt::Int(v) => Value::Int(BigInt::from(v)),
                })
            },
            BININT => self.stack.push(Value::Int(BigInt::from(try!(rd.read_i32::<LittleEndian>())))),
            BININT1 => self.stack.push(Value::Int(BigInt::from(try!(rd.read_u8())))),
            BININT2 => self.stack.push(Value::Int(BigInt::from(try!(rd.read_u16::<LittleEndian>())))),
            LONG => self.stack.push(Value::Int(BigInt::from(try!(read_decimal_long(rd))))),
            LONG1 => {
                let length = try!(rd.read_u8());
                self.stack.push(Value::Int(BigInt::from(try!(read_long(rd, length as usize)))))
            }
            LONG4 => {
                let length = try!(rd.read_i32::<LittleEndian>());
                self.stack.push(Value::Int(BigInt::from(try!(read_long(rd, length as usize)))))
            }

            STRING => self.stack.push(Value::String(try!(unescape(&try!(read_until_newline(rd)), false)))),
            BINSTRING => {
                let length = try!(rd.read_i32::<LittleEndian>());
                ensure_not_negative!(length);

                let mut buf = vec![0; length as usize];
                try!(read_exact(rd, &mut buf));
                self.stack.push(Value::String(buf))
            },
            SHORT_BINSTRING => {
                let length = try!(rd.read_u8());
                let mut buf = vec![0; length as usize];
                try!(read_exact(rd, &mut buf));
                self.stack.push(Value::String(buf))
            },

            NONE => self.stack.push(Value::None),
            NEWTRUE => self.stack.push(Value::Bool(true)),
            NEWFALSE => self.stack.push(Value::Bool(false)),

            UNICODE => {
                let buf = try!(unescape(&try!(read_until_newline(rd)), true));
                self.stack.push(Value::Unicode(try!(String::from_utf8(buf))))
            },
            BINUNICODE => {
                let length = try!(rd.read_i32::<LittleEndian>());
                ensure_not_negative!(length);
                let mut buf = vec![0; length as usize];
                try!(read_exact(rd, buf.as_mut()));
                self.stack.push(Value::Unicode(try!(String::from_utf8(buf))))
            },

            FLOAT => {
                let s = try!(read_until_newline(rd));
                self.stack.push(Value::Float(try!(f64::from_ascii(&s))))
            },
            BINFLOAT => {
                self.stack.push(Value::Float(try!(rd.read_f64::<BigEndian>())))
            },

            EMPTY_LIST => {
                self.stack.push(Value::List(Vec::new()))
            },
            APPEND => {
                let v = try!(self.pop());
                match self.stack.last_mut() {
                    None => return Err(Error::EmptyStack),
                    Some(&mut Value::List(ref mut list)) => list.push(v),
                    _ => return Err(Error::InvalidValueOnStack),
                }
            },
            APPENDS => {
                let values = try!(self.split_off());
                match self.stack.last_mut() {
                    None => return Err(Error::EmptyStack),
                    Some(&mut Value::List(ref mut list)) => {
                        list.extend(values);
                    },
                    _ => return Err(Error::InvalidValueOnStack),
                }
            },
            LIST => {
                let values = try!(self.split_off());
                self.stack.push(Value::List(values));
            },

            EMPTY_TUPLE => self.stack.push(Value::Tuple(Vec::new())),
            TUPLE => {
                let values = try!(self.split_off());
                self.stack.push(Value::Tuple(values));
            },
            TUPLE1 => {
                let v1 = try!(self.pop());
                self.stack.push(Value::Tuple(vec![v1]))
            },
            TUPLE2 => {
                let v1 = try!(self.pop());
                let v2 = try!(self.pop());
                self.stack.push(Value::Tuple(vec![v1, v2]))
            },
            TUPLE3 => {
                let v1 = try!(self.pop());
                let v2 = try!(self.pop());
                let v3 = try!(self.pop());
                self.stack.push(Value::Tuple(vec![v1, v2, v3]))
            }

            EMPTY_DICT => self.stack.push(Value::Dict(Vec::new())),
            DICT => {
                let mut values = try!(self.split_off());
                let mut dict = Vec::new();

                for i in 0 .. values.len() / 2 { // TODO: Check panic
                    let key = values.remove(2 * i);
                    let value = values.remove(2 * i + 1);
                    dict.push((key, value));
                }
                self.stack.push(Value::Dict(dict));
            },
            SETITEM => {
                let value = try!(self.pop());
                let key = try!(self.pop());
                match self.stack.last_mut() {
                    None => return Err(Error::EmptyStack),
                    Some(&mut Value::Dict(ref mut dict)) => dict.push((key, value)),
                    _ => return Err(Error::InvalidValueOnStack),
                }
            },
            SETITEMS => {
                let mut values = try!(self.split_off());

                match self.stack.last_mut() {
                    None => return Err(Error::EmptyStack),
                    Some(&mut Value::Dict(ref mut dict)) => {
                        for i in 0 .. values.len() / 2 { // TODO: Check panic
                            let key = values.remove(2 * i);
                            let value = values.remove(2 * i + 1);
                            dict.push((key, value));
                        }
                    },
                    _ => return Err(Error::InvalidValueOnStack),
                }
            },

            POP => {
                try!(self.pop());
            },
            DUP => {
                let value = match self.stack.last() {
                    None => return Err(Error::EmptyStack),
                    Some(ref v) => (*v).clone(),
                };
                self.stack.push(value)
            },
            MARK => {
                self.marker = Some(self.stack.len())
            },
            POP_MARK => {
                try!(self.split_off());
            },

            GET => {
                let n = match try!(read_decimal_int(rd)) {
                    BooleanOrInt::Int(n) => n,
                    BooleanOrInt::Boolean(false) => 0,
                    BooleanOrInt::Boolean(true) => 1,
                };
                ensure_not_negative!(n);
                try!(self.handle_get(n as usize))
            }
            BINGET => {
                try!(self.handle_get(try!(rd.read_u8()) as usize))
            }
            LONG_BINGET => {
                let n = try!(rd.read_i32::<LittleEndian>());
                ensure_not_negative!(n);
                try!(self.handle_get(n as usize))
            }

            PUT => {
                let n = match try!(read_decimal_int(rd)) {
                    BooleanOrInt::Int(n) => n,
                    BooleanOrInt::Boolean(false) => 0,
                    BooleanOrInt::Boolean(true) => 1,
                };
                ensure_not_negative!(n);
                try!(self.handle_put(n as usize))
            }
            BINPUT => {
                try!(self.handle_put(try!(rd.read_u8()) as usize))
            }
            LONG_BINPUT => {
                let n = try!(rd.read_i32::<LittleEndian>());
                ensure_not_negative!(n);
                try!(self.handle_put(n as usize))
            }

            c => return Err(Error::UnknownOpcode(c)),
        }
        Ok(false)
    }
}
<commit_msg>Make execute public again<commit_after>use std::collections::{HashMap};
use std::io::{Read, BufRead, Error as IoError, ErrorKind};
use std::string::{FromUtf8Error};

use num::{Zero};
use num::bigint::{BigInt, ToBigInt, Sign};
use byteorder::{ReadBytesExt, LittleEndian, BigEndian, Error as ByteorderError};
use from_ascii::{FromAscii, ParseIntError, ParseFloatError};

use string::{unescape, Error as UnescapeError};
use value::{Value};

use opcodes::*;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        EmptyMarker
        StackTooSmall
        EmptyStack
        InvalidValueOnStack
        InvalidMemoValue
        NotImplemented

        Read(err: ByteorderError) {
            from()
        }
        Io(err: IoError) {
            from()
        }
        UnknownOpcode(opcode: u8) {}

        InvalidInt {
            from(ParseIntError)
        }
        InvalidLong
        InvalidFloat {
            from(ParseFloatError)
        }

        InvalidString {
            from(FromUtf8Error)
        }
        UnescapeError(err: UnescapeError) {
            from()
        }

        InvalidProto(proto: u8)
        NegativeLength
    }
}

#[derive(Debug, PartialEq)]
pub enum BooleanOrInt {
    Boolean(bool),
    Int(i64),
}

fn read_exact<R>(rd: &mut R, mut buf: &mut [u8]) -> Result<(), IoError> where R: Read {
    while !buf.is_empty() {
        match rd.read(buf) {
            Ok(0) => break,
            Ok(n) => { let tmp = buf; buf = &mut tmp[n..]; }
            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
            Err(e) => return Err(e),
        }
    }
    if !buf.is_empty() {
        Err(IoError::new(ErrorKind::Other,
                       "failed to fill whole buffer"))
    } else {
        Ok(())
    }
}

fn read_until_newline<R>(rd: &mut R) -> Result<Vec<u8>, Error> where R: Read + BufRead {
    let mut buf = Vec::new();
    try!(rd.read_until('\n' as u8, &mut buf));

    // Skip last symbol — \n
    match buf.split_last() {
        Some((&b'\n', init)) => Ok(init.to_vec()),
        _ => return Err(Error::InvalidString),
    }
}

fn read_decimal_int<R>(rd: &mut R) -> Result<BooleanOrInt, Error> where R: Read + BufRead {
    let s = try!(read_until_newline(rd));
    let val = match &s[..] {
        b"00" => BooleanOrInt::Boolean(false),
        b"01" => BooleanOrInt::Boolean(true),
        _ => BooleanOrInt::Int(try!(i64::from_ascii(&s)))
    };
    Ok(val)
}

fn read_decimal_long<R>(rd: &mut R) -> Result<BigInt, Error> where R: Read + BufRead {
    let s = try!(read_until_newline(rd));
    let init = match s.split_last() {
        None => return Err(Error::InvalidString),
        Some((&b'L', init)) => init,
        Some(_) => &s[..],
    };

    match BigInt::parse_bytes(&init, 10) {
        Some(i) => Ok(i),
        None => Err(Error::InvalidLong)
    }
}

fn read_long<R>(rd: &mut R, length: usize) -> Result<BigInt, Error> where R: Read + BufRead {
    let mut buf = vec![0; length];
    try!(read_exact(rd, buf.as_mut()));

    let mut n = BigInt::from_bytes_le(Sign::Plus, &buf);

    let last = match buf.last_mut() {
        None => return Err(Error::InvalidLong),
        Some(last) => last,
    };

    if *last > 127 {
        n = n - (1.to_bigint().unwrap() << (length * 8))
    }

    Ok(n)
}

pub struct Machine {
    stack: Vec<Value>,
    memo: HashMap<usize, Value>,
    marker: Option<usize>,
}

impl Machine {
    pub fn new() -> Self {
        Machine {
            stack: Vec::new(),
            memo: HashMap::new(),
            marker: None,
        }
    }

    fn split_off(&mut self) -> Result<Vec<Value>, Error> {
        let at = match self.marker {
            None => return Err(Error::EmptyMarker),
            Some(marker) => marker,
        };

        if at > self.stack.len() {
            return Err(Error::StackTooSmall);
        }

        Ok(self.stack.split_off(at))
    }

    pub fn pop(&mut self) -> Result<Value, Error> {
        match self.stack.pop() {
            None => return Err(Error::EmptyStack),
            Some(value) => Ok(value),
        }
    }

    fn handle_get(&mut self, i: usize) -> Result<(), Error> {
        let value = match self.memo.get(&i) {
            None => return Err(Error::InvalidMemoValue),
            Some(ref v) => (*v).clone(),
        };
        self.stack.push(value);
        Ok(())
    }

    fn handle_put(&mut self, i: usize) -> Result<(), Error> {
        let value = match self.stack.last() {
            None => return Err(Error::EmptyStack),
            Some(ref v) => (*v).clone(),
        };
        self.memo.insert(i, value);
        Ok(())
    }

    pub fn execute<R>(&mut self, rd: &mut R) -> Result<bool, Error> where R: Read + BufRead {
        macro_rules! ensure_not_negative {
            ($n: expr) => ({
                if $n < Zero::zero() {
                    return Err(Error::NegativeLength)
                }
            })
        }

        let marker = try!(rd.read_u8());
        match marker {
            PROTO => {
                let version = try!(rd.read_u8());
                if version < 2 {
                    return Err(Error::InvalidProto(version))
                }
            },
            STOP => return Ok(true),

            INT => {
                self.stack.push(match try!(read_decimal_int(rd)) {
                    BooleanOrInt::Boolean(v) => Value::Bool(v),
                    BooleanOrInt::Int(v) => Value::Int(BigInt::from(v)),
                })
            },
            BININT => self.stack.push(Value::Int(BigInt::from(try!(rd.read_i32::<LittleEndian>())))),
            BININT1 => self.stack.push(Value::Int(BigInt::from(try!(rd.read_u8())))),
            BININT2 => self.stack.push(Value::Int(BigInt::from(try!(rd.read_u16::<LittleEndian>())))),
            LONG => self.stack.push(Value::Int(BigInt::from(try!(read_decimal_long(rd))))),
            LONG1 => {
                let length = try!(rd.read_u8());
                self.stack.push(Value::Int(BigInt::from(try!(read_long(rd, length as usize)))))
            }
            LONG4 => {
                let length = try!(rd.read_i32::<LittleEndian>());
                self.stack.push(Value::Int(BigInt::from(try!(read_long(rd, length as usize)))))
            }

            STRING => self.stack.push(Value::String(try!(unescape(&try!(read_until_newline(rd)), false)))),
            BINSTRING => {
                let length = try!(rd.read_i32::<LittleEndian>());
                ensure_not_negative!(length);

                let mut buf = vec![0; length as usize];
                try!(read_exact(rd, &mut buf));
                self.stack.push(Value::String(buf))
            },
            SHORT_BINSTRING => {
                let length = try!(rd.read_u8());
                let mut buf = vec![0; length as usize];
                try!(read_exact(rd, &mut buf));
                self.stack.push(Value::String(buf))
            },

            NONE => self.stack.push(Value::None),
            NEWTRUE => self.stack.push(Value::Bool(true)),
            NEWFALSE => self.stack.push(Value::Bool(false)),

            UNICODE => {
                let buf = try!(unescape(&try!(read_until_newline(rd)), true));
                self.stack.push(Value::Unicode(try!(String::from_utf8(buf))))
            },
            BINUNICODE => {
                let length = try!(rd.read_i32::<LittleEndian>());
                ensure_not_negative!(length);
                let mut buf = vec![0; length as usize];
                try!(read_exact(rd, buf.as_mut()));
                self.stack.push(Value::Unicode(try!(String::from_utf8(buf))))
            },

            FLOAT => {
                let s = try!(read_until_newline(rd));
                self.stack.push(Value::Float(try!(f64::from_ascii(&s))))
            },
            BINFLOAT => {
                self.stack.push(Value::Float(try!(rd.read_f64::<BigEndian>())))
            },

            EMPTY_LIST => {
                self.stack.push(Value::List(Vec::new()))
            },
            APPEND => {
                let v = try!(self.pop());
                match self.stack.last_mut() {
                    None => return Err(Error::EmptyStack),
                    Some(&mut Value::List(ref mut list)) => list.push(v),
                    _ => return Err(Error::InvalidValueOnStack),
                }
            },
            APPENDS => {
                let values = try!(self.split_off());
                match self.stack.last_mut() {
                    None => return Err(Error::EmptyStack),
                    Some(&mut Value::List(ref mut list)) => {
                        list.extend(values);
                    },
                    _ => return Err(Error::InvalidValueOnStack),
                }
            },
            LIST => {
                let values = try!(self.split_off());
                self.stack.push(Value::List(values));
            },

            EMPTY_TUPLE => self.stack.push(Value::Tuple(Vec::new())),
            TUPLE => {
                let values = try!(self.split_off());
                self.stack.push(Value::Tuple(values));
            },
            TUPLE1 => {
                let v1 = try!(self.pop());
                self.stack.push(Value::Tuple(vec![v1]))
            },
            TUPLE2 => {
                let v1 = try!(self.pop());
                let v2 = try!(self.pop());
                self.stack.push(Value::Tuple(vec![v1, v2]))
            },
            TUPLE3 => {
                let v1 = try!(self.pop());
                let v2 = try!(self.pop());
                let v3 = try!(self.pop());
                self.stack.push(Value::Tuple(vec![v1, v2, v3]))
            }

            EMPTY_DICT => self.stack.push(Value::Dict(Vec::new())),
            DICT => {
                let mut values = try!(self.split_off());
                let mut dict = Vec::new();

                for i in 0 .. values.len() / 2 { // TODO: Check panic
                    let key = values.remove(2 * i);
                    let value = values.remove(2 * i + 1);
                    dict.push((key, value));
                }
                self.stack.push(Value::Dict(dict));
            },
            SETITEM => {
                let value = try!(self.pop());
                let key = try!(self.pop());
                match self.stack.last_mut() {
                    None => return Err(Error::EmptyStack),
                    Some(&mut Value::Dict(ref mut dict)) => dict.push((key, value)),
                    _ => return Err(Error::InvalidValueOnStack),
                }
            },
            SETITEMS => {
                let mut values = try!(self.split_off());

                match self.stack.last_mut() {
                    None => return Err(Error::EmptyStack),
                    Some(&mut Value::Dict(ref mut dict)) => {
                        for i in 0 .. values.len() / 2 { // TODO: Check panic
                            let key = values.remove(2 * i);
                            let value = values.remove(2 * i + 1);
                            dict.push((key, value));
                        }
                    },
                    _ => return Err(Error::InvalidValueOnStack),
                }
            },

            POP => {
                try!(self.pop());
            },
            DUP => {
                let value = match self.stack.last() {
                    None => return Err(Error::EmptyStack),
                    Some(ref v) => (*v).clone(),
                };
                self.stack.push(value)
            },
            MARK => {
                self.marker = Some(self.stack.len())
            },
            POP_MARK => {
                try!(self.split_off());
            },

            GET => {
                let n = match try!(read_decimal_int(rd)) {
                    BooleanOrInt::Int(n) => n,
                    BooleanOrInt::Boolean(false) => 0,
                    BooleanOrInt::Boolean(true) => 1,
                };
                ensure_not_negative!(n);
                try!(self.handle_get(n as usize))
            }
            BINGET => {
                try!(self.handle_get(try!(rd.read_u8()) as usize))
            }
            LONG_BINGET => {
                let n = try!(rd.read_i32::<LittleEndian>());
                ensure_not_negative!(n);
                try!(self.handle_get(n as usize))
            }

            PUT => {
                let n = match try!(read_decimal_int(rd)) {
                    BooleanOrInt::Int(n) => n,
                    BooleanOrInt::Boolean(false) => 0,
                    BooleanOrInt::Boolean(true) => 1,
                };
                ensure_not_negative!(n);
                try!(self.handle_put(n as usize))
            }
            BINPUT => {
                try!(self.handle_put(try!(rd.read_u8()) as usize))
            }
            LONG_BINPUT => {
                let n = try!(rd.read_i32::<LittleEndian>());
                ensure_not_negative!(n);
                try!(self.handle_put(n as usize))
            }

            c => return Err(Error::UnknownOpcode(c)),
        }
        Ok(false)
    }
}
<|endoftext|>