<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::{Error,Result};
use token::Token;
use html::HtmlRenderer;
use book::Book;
use number::Number;
use zipper::Zipper;
use templates::epub::*;
use templates::epub3;

use mustache;
use chrono;
use uuid;

use std::io::{Read,Write};
use std::path::Path;
use std::fs::File;
use std::borrow::Cow;

/// Renderer for Epub
///
/// Uses part of the HTML renderer
pub struct EpubRenderer<'a> {
    book: &'a Book,
    toc: Vec<String>,
    html: HtmlRenderer<'a>,
}

impl<'a> EpubRenderer<'a> {
    /// Creates a new Epub renderer
    pub fn new(book: &'a Book) -> EpubRenderer<'a> {
        let mut html = HtmlRenderer::new(book);
        html.toc.numbered(true);
        html.handler.set_images_mapping(true);
        EpubRenderer {
            book: book,
            html: html,
            toc: vec!(),
        }
    }

    /// Render a book
    pub fn render_book(&mut self) -> Result<String> {
        for (i, filename) in self.book.filenames.iter().enumerate() {
            self.html.handler.add_link(filename.clone(), filenamer(i));
        }

        let mut zipper = try!(Zipper::new(&self.book.options.get_path("temp_dir").unwrap()));

        // Write mimetype
        try!(zipper.write("mimetype", b"application/epub+zip", true));

        // Write chapters
        for (i, &(n, ref v)) in self.book.chapters.iter().enumerate() {
            self.html.filename = filenamer(i);
            self.html.current_hide = false;
            let book_numbering = self.book.options.get_i32("numbering").unwrap();
            match n {
                Number::Unnumbered => self.html.current_numbering = 0,
                Number::Default => self.html.current_numbering = book_numbering,
                Number::Specified(n) => {
                    self.html.current_numbering = book_numbering;
                    self.html.current_chapter[0] = n - 1;
                },
                Number::Hidden => {
                    self.html.current_numbering = 0;
                    self.html.current_hide = true;
                }
            }
            let chapter = try!(self.render_chapter(v));

            try!(zipper.write(&filenamer(i), &chapter.as_bytes(), true));
        }

        // Write CSS file
        try!(zipper.write("stylesheet.css",
                          &try!(self.book.get_template("epub.css")).as_bytes(), true));

        // Write titlepage
        try!(zipper.write("title_page.xhtml", &try!(self.render_titlepage()).as_bytes(), true));

        // Write file for ibook (why?)
        try!(zipper.write("META-INF/com.apple.ibooks.display-options.xml", IBOOK.as_bytes(), true));

        // Write container.xml
        try!(zipper.write("META-INF/container.xml", CONTAINER.as_bytes(), true));

        // Write nav.xhtml
        try!(zipper.write("nav.xhtml", &try!(self.render_nav()).as_bytes(), true));

        // Write content.opf
        try!(zipper.write("content.opf", &try!(self.render_opf()).as_bytes(), true));

        // Write toc.ncx
        try!(zipper.write("toc.ncx", &try!(self.render_toc()).as_bytes(), true));

        // Write cover.xhtml (if needs be)
        if self.book.options.get_path("cover").is_ok() {
            try!(zipper.write("cover.xhtml", &try!(self.render_cover()).as_bytes(), true));
        }

        // Write all images (including cover)
        for (source, dest) in self.html.handler.images_mapping() {
            let mut f = try!(File::open(self.book.root.join(source)).map_err(|_| Error::FileNotFound(source.to_owned())));
            let mut content = vec!();
            try!(f.read_to_end(&mut content).map_err(|_| Error::Render("error while reading image file")));
            try!(zipper.write(dest, &content, true));
        }

        if let Ok(epub_file) = self.book.options.get_path("output.epub") {
            let res = try!(zipper.generate_epub(self.book.options.get_str("zip.command").unwrap(), &epub_file));
            Ok(res)
        } else {
            Err(Error::Render("no output epub file specified in book config"))
        }
    }

    /// Render the titlepgae
    fn render_titlepage(&self) -> Result<String> {
        let template = mustache::compile_str(if self.book.options.get_i32("epub.version").unwrap() == 3 {epub3::TITLE} else {TITLE});
        let data = self.book.get_mapbuilder("none")
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in titlepage was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Render toc.ncx
    fn render_toc(&self) -> Result<String> {
        let mut nav_points = String::new();

        for (n, ref title) in self.toc.iter().enumerate() {
            let filename = filenamer(n);
            let id = format!("navPoint-{}", n + 1);
            nav_points.push_str(&format!(
"   <navPoint id=\"{}\">
      <navLabel>
        <text>{}</text>
      </navLabel>
      <content src = \"{}\" />
    </navPoint>\n", id, title, filename));
        }
        let template = mustache::compile_str(TOC);
        let data = self.book.get_mapbuilder("none")
            .insert_str("nav_points", nav_points)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in toc.ncx was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Render content.opf
    fn render_opf(&mut self) -> Result<String> {
        // Optional metadata
        let mut cover_xhtml = String::new();
        let mut optional = String::new();
        if let Ok(s) = self.book.options.get_str("description") {
            optional.push_str(&format!("<dc:description>{}</dc:description>\n", s));
        }
        if let Ok(s) = self.book.options.get_str("subject") {
            optional.push_str(&format!("<dc:subject>{}</dc:subject>\n", s));
        }
        if let Ok(ref s) = self.book.options.get_path("cover") {
            optional.push_str(&format!("<meta name = \"cover\" content = \"{}\" />\n",
                                       self.html.handler.map_image(Cow::Borrowed(s))));
            cover_xhtml.push_str(&format!("<reference type=\"cover\" title=\"Cover\" href=\"cover.xhtml\" />"));
        }

        // date
        let date = chrono::UTC::now().format("%Y-%m-%dT%H:%M:%SZ");

        // uuid
        let uuid = uuid::Uuid::new_v4().to_urn_string();

        let mut items = String::new();
        let mut itemrefs = String::new();
        let mut coverref = String::new();
        if self.book.options.get("cover").is_ok() {
            items.push_str("<item id = \"cover_xhtml\" href = \"cover.xhtml\" media-type = \"application/xhtml+xml\" />\n");
            coverref.push_str("<itemref idref = \"cover_xhtml\" />");
        }
        for n in 0..self.toc.len() {
            let filename = filenamer(n);
            items.push_str(&format!("<item id = \"{}\" href = \"{}\" media-type=\"application/xhtml+xml\" />\n",
                                    to_id(&filename),
                                    filename));
            itemrefs.push_str(&format!("<itemref idref=\"{}\" />\n", to_id(&filename)));
        }
        // oh we must put cover in the manifest too
        if let Ok(ref cover) = self.book.options.get_path("cover") {
            let format = self.get_format(cover);
            let s= self.html.handler.map_image(Cow::Borrowed(cover));
            items.push_str(&format!("<item {} media-type = \"image/{}\" id =\"{}\" href = \"{}\" />\n",
                                    if self.book.options.get_i32("epub.version").unwrap() == 3 { "properties=\"cover-image\"" } else { "" },
                                    format,
                                    to_id(s.as_ref()),
                                    s));
        }

        // and the other images
        for image in self.html.handler.images_mapping().values() {
            let format = self.get_format(image);
            items.push_str(&format!("<item media-type = \"image/{}\" id = \"{}\" href = \"{}\" />\n",
                                    format, to_id(image), image));
        }

        let template = mustache::compile_str(if self.book.options.get_i32("epub.version").unwrap() == 3 {epub3::OPF} else {OPF});
        let data = self.book.get_mapbuilder("none")
            .insert_str("optional", optional)
            .insert_str("items", items)
            .insert_str("itemrefs", itemrefs)
            .insert_str("date", date)
            .insert_str("uuid", uuid)
            .insert_str("cover_xhtml", cover_xhtml)
            .insert_str("coverref", coverref)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in content.opf was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Render cover.xhtml
    fn render_cover(&mut self) -> Result<String> {
        if let Ok(cover) = self.book.options.get_path("cover") {
            let template = mustache::compile_str(if self.book.options.get_i32("epub.version").unwrap() == 3 {epub3::COVER} else {COVER});
            let data = self.book.get_mapbuilder("none")
                .insert_str("cover", self.html.handler.map_image(Cow::Owned(cover)).into_owned())
                .build();
            let mut res:Vec<u8> = vec!();
            template.render_data(&mut res, &data);
            match String::from_utf8(res) {
                Err(_) => Err(Error::Render("generated HTML for cover.xhtml was not utf-8 valid")),
                Ok(res) => Ok(res)
            }
        } else {
            panic!("Why is this method called if cover is None???");
        }
    }

    /// Render nav.xhtml
    fn render_nav(&self) -> Result<String> {
        let content = self.html.toc.render();

        let template = mustache::compile_str(if self.book.options.get_i32("epub.version").unwrap() == 3 {epub3::NAV} else {NAV});
        let data = self.book.get_mapbuilder("none")
            .insert_str("content", content)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in nav.xhtml was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Render a chapter
    pub fn render_chapter(&mut self, v: &[Token]) -> Result<String> {
        let mut content = String::new();
        let mut title = String::new();

        for token in v {
            content.push_str(&self.parse_token(&token, &mut title));
            self.html.render_side_notes(&mut content);
        }
        self.html.render_end_notes(&mut content);

        if title.is_empty() {
            if self.html.current_numbering >= 1 {
                let number = self.html.current_chapter[0] + 1;
                title = try!(self.book.get_header(number, ""));
            } else {
                return Err(Error::Render("chapter without h1 tag is not OK if numbering is off"));
            }
        }
        self.toc.push(title.clone());

        let template = mustache::compile_str(try!(self.book.get_template("epub.template")).as_ref());
        let data = self.book.get_mapbuilder("none")
            .insert_str("content", content)
            .insert_str("chapter_title", title)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    fn parse_token(&mut self, token: &Token, title: &mut String) -> String {
        match *token {
            Token::Header(n, ref vec) => {
                if n == 1 {
                    if self.html.current_hide || self.html.current_numbering == 0 {
                        if title.is_empty() {
                            *title = self.html.render_vec(vec);
                        } else {
                            self.book.logger.warning("EPUB: detected two chapter titles inside the same markdown file...");
                            self.book.logger.warning("EPUB: ...in a file where chapter titles are not even rendered.");
                        }
                    } else {
                        let res = self.book.get_header(self.html.current_chapter[0] + 1, &self.html.render_vec(vec));
                        let s = res.unwrap();
                        if title.is_empty() {
                            *title = s;
                        } else {
                            self.book.logger.warning("EPUB: detected two chapters inside the same markdown file.");
                            self.book.logger.warning(format!("EPUB: conflict between: {} and {}", title, s));
                        }
                    }
                }
                self.html.parse_token(token)
            },
            _ => self.html.parse_token(token)
        }
    }

    // Get the format of an image file, based on its extension
    fn get_format(&self, s: &str) -> &'static str {
        let format = if let Some(ext) = Path::new(s).extension() {
            match ext.to_string_lossy().as_ref() {
                "png" => Some("png"),
                "jpg" | "jpeg" => Some("jpeg"),
                "gif" => Some("gif"),
                _ => None,
            }
        } else {
            None
        };
        match format {
            Some(s) => s,
            None => {
                self.book.logger.warning(format!("EPUB: could not guess the format of {} based on extension. Assuming png.", s));
                "png"
            }
        }
    }
}

// generate an id compatible string, replacing / and . by _
fn to_id(s: &str) -> String {
    s.replace(".", "_").replace("/", "_")
}

/// Generate a file name given an int
fn filenamer(i: usize) -> String {
    format!("chapter_{:03}.xhtml", i)
}
<commit_msg>Fix EPUB rendering issues<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::{Error,Result};
use token::Token;
use html::HtmlRenderer;
use book::Book;
use number::Number;
use zipper::Zipper;
use templates::epub::*;
use templates::epub3;

use mustache;
use chrono;
use uuid;

use std::io::{Read,Write};
use std::path::Path;
use std::fs::File;
use std::borrow::Cow;

/// Renderer for Epub
///
/// Uses part of the HTML renderer
pub struct EpubRenderer<'a> {
    book: &'a Book,
    toc: Vec<String>,
    html: HtmlRenderer<'a>,
}

impl<'a> EpubRenderer<'a> {
    /// Creates a new Epub renderer
    pub fn new(book: &'a Book) -> EpubRenderer<'a> {
        let mut html = HtmlRenderer::new(book);
        html.toc.numbered(true);
        html.handler.set_images_mapping(true);
        EpubRenderer {
            book: book,
            html: html,
            toc: vec!(),
        }
    }

    /// Render a book
    pub fn render_book(&mut self) -> Result<String> {
        for (i, filename) in self.book.filenames.iter().enumerate() {
            self.html.handler.add_link(filename.clone(), filenamer(i));
        }

        let mut zipper = try!(Zipper::new(&self.book.options.get_path("temp_dir").unwrap()));

        // Write mimetype
        try!(zipper.write("mimetype", b"application/epub+zip", true));

        // Write chapters
        for (i, &(n, ref v)) in self.book.chapters.iter().enumerate() {
            self.html.filename = filenamer(i);
            self.html.current_hide = false;
            let book_numbering = self.book.options.get_i32("numbering").unwrap();
            match n {
                Number::Unnumbered => self.html.current_numbering = 0,
                Number::Default => self.html.current_numbering = book_numbering,
                Number::Specified(n) => {
                    self.html.current_numbering = book_numbering;
                    self.html.current_chapter[0] = n - 1;
                },
                Number::Hidden => {
                    self.html.current_numbering = 0;
                    self.html.current_hide = true;
                }
            }
            let chapter = try!(self.render_chapter(v));

            try!(zipper.write(&filenamer(i), &chapter.as_bytes(), true));
        }

        // Write CSS file
        try!(zipper.write("stylesheet.css",
                          &try!(self.book.get_template("epub.css")).as_bytes(), true));

        // Write titlepage
        try!(zipper.write("title_page.xhtml", &try!(self.render_titlepage()).as_bytes(), true));

        // Write file for ibook (why?)
        try!(zipper.write("META-INF/com.apple.ibooks.display-options.xml", IBOOK.as_bytes(), true));

        // Write container.xml
        try!(zipper.write("META-INF/container.xml", CONTAINER.as_bytes(), true));

        // Write nav.xhtml
        try!(zipper.write("nav.xhtml", &try!(self.render_nav()).as_bytes(), true));

        // Write content.opf
        try!(zipper.write("content.opf", &try!(self.render_opf()).as_bytes(), true));

        // Write toc.ncx
        try!(zipper.write("toc.ncx", &try!(self.render_toc()).as_bytes(), true));

        // Write cover.xhtml (if needs be)
        if self.book.options.get_path("cover").is_ok() {
            try!(zipper.write("cover.xhtml", &try!(self.render_cover()).as_bytes(), true));
        }

        // Write all images (including cover)
        for (source, dest) in self.html.handler.images_mapping() {
            let mut f = try!(File::open(self.book.root.join(source)).map_err(|_| Error::FileNotFound(source.to_owned())));
            let mut content = vec!();
            try!(f.read_to_end(&mut content).map_err(|_| Error::Render("error while reading image file")));
            try!(zipper.write(dest, &content, true));
        }

        if let Ok(epub_file) = self.book.options.get_path("output.epub") {
            let res = try!(zipper.generate_epub(self.book.options.get_str("zip.command").unwrap(), &epub_file));
            Ok(res)
        } else {
            Err(Error::Render("no output epub file specified in book config"))
        }
    }

    /// Render the titlepgae
    fn render_titlepage(&self) -> Result<String> {
        let template = mustache::compile_str(if self.book.options.get_i32("epub.version").unwrap() == 3 {epub3::TITLE} else {TITLE});
        let data = self.book.get_mapbuilder("none")
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in titlepage was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Render toc.ncx
    fn render_toc(&self) -> Result<String> {
        let mut nav_points = String::new();

        for (n, ref title) in self.toc.iter().enumerate() {
            let filename = filenamer(n);
            let id = format!("navPoint-{}", n + 1);
            nav_points.push_str(&format!(
"   <navPoint id=\"{}\">
      <navLabel>
        <text>{}</text>
      </navLabel>
      <content src = \"{}\" />
    </navPoint>\n", id, title, filename));
        }
        let template = mustache::compile_str(TOC);
        let data = self.book.get_mapbuilder("none")
            .insert_str("nav_points", nav_points)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in toc.ncx was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Render content.opf
    fn render_opf(&mut self) -> Result<String> {
        // Optional metadata
        let mut cover_xhtml = String::new();
        let mut optional = String::new();
        if let Ok(s) = self.book.options.get_str("description") {
            optional.push_str(&format!("<dc:description>{}</dc:description>\n", s));
        }
        if let Ok(s) = self.book.options.get_str("subject") {
            optional.push_str(&format!("<dc:subject>{}</dc:subject>\n", s));
        }
        if let Ok(ref s) = self.book.options.get_path("cover") {
            optional.push_str(&format!("<meta name = \"cover\" content = \"{}\" />\n",
                                       self.html.handler.map_image(Cow::Borrowed(s))));
            cover_xhtml.push_str(&format!("<reference type=\"cover\" title=\"Cover\" href=\"cover.xhtml\" />"));
        }

        // date
        let date = chrono::UTC::now().format("%Y-%m-%dT%H:%M:%SZ");

        // uuid
        let uuid = uuid::Uuid::new_v4().to_urn_string();

        let mut items = String::new();
        let mut itemrefs = String::new();
        let mut coverref = String::new();
        if self.book.options.get("cover").is_ok() {
            items.push_str("<item id = \"cover_xhtml\" href = \"cover.xhtml\" media-type = \"application/xhtml+xml\" />\n");
            coverref.push_str("<itemref idref = \"cover_xhtml\" />");
        }
        for n in 0..self.toc.len() {
            let filename = filenamer(n);
            items.push_str(&format!("<item id = \"{}\" href = \"{}\" media-type=\"application/xhtml+xml\" />\n",
                                    to_id(&filename),
                                    filename));
            itemrefs.push_str(&format!("<itemref idref=\"{}\" />\n", to_id(&filename)));
        }

        // put the images in the manifest too
        for image in self.html.handler.images_mapping().values() {
            let format = self.get_format(image);
            items.push_str(&format!("<item media-type = \"image/{}\" id = \"{}\" href = \"{}\" />\n",
                                    format, to_id(image), image));
        }

        let template = mustache::compile_str(if self.book.options.get_i32("epub.version").unwrap() == 3 {epub3::OPF} else {OPF});
        let data = self.book.get_mapbuilder("none")
            .insert_str("optional", optional)
            .insert_str("items", items)
            .insert_str("itemrefs", itemrefs)
            .insert_str("date", date)
            .insert_str("uuid", uuid)
            .insert_str("cover_xhtml", cover_xhtml)
            .insert_str("coverref", coverref)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in content.opf was not valid utf-8")),
            Ok(res) => Ok(res)
        }
    }

    /// Render cover.xhtml
    fn render_cover(&mut self) -> Result<String> {
        if let Ok(cover) = self.book.options.get_path("cover") {
            let template = mustache::compile_str(if self.book.options.get_i32("epub.version").unwrap() == 3 {epub3::COVER} else {COVER});
            let data = self.book.get_mapbuilder("none")
                .insert_str("cover", self.html.handler.map_image(Cow::Owned(cover)).into_owned())
                .build();
            let mut res:Vec<u8> = vec!();
            template.render_data(&mut res, &data);
            match String::from_utf8(res) {
                Err(_) => Err(Error::Render("generated HTML for cover.xhtml was not utf-8 valid")),
                Ok(res) => Ok(res)
            }
        } else {
            panic!("Why is this method called if cover is None???");
        }
    }

    /// Render nav.xhtml
    fn render_nav(&self) -> Result<String> {
        let content = self.html.toc.render();

        let template = mustache::compile_str(if self.book.options.get_i32("epub.version").unwrap() == 3 {epub3::NAV} else {NAV});
        let data = self.book.get_mapbuilder("none")
            .insert_str("content", content)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML in nav.xhtml was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    /// Render a chapter
    pub fn render_chapter(&mut self, v: &[Token]) -> Result<String> {
        let mut content = String::new();
        let mut title = String::new();

        for token in v {
            content.push_str(&self.parse_token(&token, &mut title));
            self.html.render_side_notes(&mut content);
        }
        self.html.render_end_notes(&mut content);

        if title.is_empty() {
            if self.html.current_numbering >= 1 {
                let number = self.html.current_chapter[0] + 1;
                title = try!(self.book.get_header(number, ""));
            }
        }
        self.toc.push(title.clone());

        let template = mustache::compile_str(try!(self.book.get_template("epub.template")).as_ref());
        let data = self.book.get_mapbuilder("none")
            .insert_str("content", content)
            .insert_str("chapter_title", title)
            .build();
        let mut res:Vec<u8> = vec!();
        template.render_data(&mut res, &data);
        match String::from_utf8(res) {
            Err(_) => Err(Error::Render("generated HTML was not utf-8 valid")),
            Ok(res) => Ok(res)
        }
    }

    fn parse_token(&mut self, token: &Token, title: &mut String) -> String {
        match *token {
            Token::Header(n, ref vec) => {
                if n == 1 {
                    if self.html.current_hide || self.html.current_numbering == 0 {
                        if title.is_empty() {
                            *title = self.html.render_vec(vec);
                        } else {
                            self.book.logger.warning("EPUB: detected two chapter titles inside the same markdown file...");
                            self.book.logger.warning("EPUB: ...in a file where chapter titles are not even rendered.");
                        }
                    } else {
                        let res = self.book.get_header(self.html.current_chapter[0] + 1, &self.html.render_vec(vec));
                        let s = res.unwrap();
                        if title.is_empty() {
                            *title = s;
                        } else {
                            self.book.logger.warning("EPUB: detected two chapters inside the same markdown file.");
                            self.book.logger.warning(format!("EPUB: conflict between: {} and {}", title, s));
                        }
                    }
                }
                self.html.parse_token(token)
            },
            _ => self.html.parse_token(token)
        }
    }

    // Get the format of an image file, based on its extension
    fn get_format(&self, s: &str) -> &'static str {
        let format = if let Some(ext) = Path::new(s).extension() {
            match ext.to_string_lossy().as_ref() {
                "png" => Some("png"),
                "jpg" | "jpeg" => Some("jpeg"),
                "gif" => Some("gif"),
                _ => None,
            }
        } else {
            None
        };
        match format {
            Some(s) => s,
            None => {
                self.book.logger.warning(format!("EPUB: could not guess the format of {} based on extension. Assuming png.", s));
                "png"
            }
        }
    }
}

// generate an id compatible string, replacing / and . by _
fn to_id(s: &str) -> String {
    s.replace(".", "_").replace("/", "_")
}

/// Generate a file name given an int
fn filenamer(i: usize) -> String {
    format!("chapter_{:03}.xhtml", i)
}
<|endoftext|>


<commit_before>// Interior vector utility functions.

import option::none;
import option::some;
import uint::next_power_of_two;
import ptr::addr_of;

native "rust-intrinsic" mod rusti {
    fn ivec_len[T](v: &[T]) -> uint;
}

native "rust" mod rustrt {
    fn ivec_reserve_shared[T](v: &mutable [mutable? T], n: uint);
    fn ivec_on_heap[T](v: &[T]) -> uint;
    fn ivec_to_ptr[T](v: &[T]) -> *T;
    fn ivec_copy_from_buf_shared[T](v: &mutable [mutable? T], ptr: *T,
                                    count: uint);
}

fn from_vec[@T](v: &vec[mutable? T]) -> [T] {
    let iv = ~[];
    for e in v {
        iv += ~[e];
    }
    ret iv;
}

fn to_vec[@T](iv: &[T]) -> vec[T] {
    let v: vec[T] = [];
    for e in iv {
        v += [e];
    }
    ret v;
}

/// Reserves space for `n` elements in the given vector.
fn reserve[@T](v: &mutable [mutable? T], n: uint) {
    rustrt::ivec_reserve_shared(v, n);
}

fn on_heap[T](v: &[T]) -> bool { ret rustrt::ivec_on_heap(v) != 0u; }

fn to_ptr[T](v: &[T]) -> *T { ret rustrt::ivec_to_ptr(v); }

fn len[T](v: &[mutable? T]) -> uint { ret rusti::ivec_len(v); }

type init_op[T] = fn(uint) -> T ;

fn init_fn[@T](op: &init_op[T], n_elts: uint) -> [T] {
    let v = ~[];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += ~[op(i)]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_fn_mut[@T](op: &init_op[T], n_elts: uint) -> [mutable T] {
    let v = ~[mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += ~[mutable op(i)]; i += 1u; }
    ret v;
}

fn init_elt[@T](t: &T, n_elts: uint) -> [T] {
    let v = ~[];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += ~[t]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_elt_mut[@T](t: &T, n_elts: uint) -> [mutable T] {
    let v = ~[mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += ~[mutable t]; i += 1u; }
    ret v;
}

fn to_mut[@T](v: &[T]) -> [mutable T] {
    let vres = ~[mutable];
    for t: T  in v { vres += ~[mutable t]; }
    ret vres;
}

fn from_mut[@T](v: &[mutable T]) -> [T] {
    let vres = ~[];
    for t: T  in v { vres += ~[t]; }
    ret vres;
}

// Predicates
pred is_empty[T](v: &[mutable? T]) -> bool {
    // FIXME: This would be easier if we could just call len
    for t: T in v { ret false; }
    ret true;
}

pred is_not_empty[T](v: &[mutable? T]) -> bool { ret !is_empty(v); }

// Accessors

/// Returns the first element of a vector
fn head[@T](v: &[mutable? T]) : is_not_empty(v) -> T { ret v.(0); }

/// Returns all but the first element of a vector
fn tail[@T](v: &[mutable? T]) : is_not_empty(v) -> [mutable? T] {
    ret slice(v, 1u, len(v));
}

/// Returns the last element of `v`.
fn last[@T](v: &[mutable? T]) -> option::t[T] {
    if len(v) == 0u { ret none; }
    ret some(v.(len(v) - 1u));
}

/// Returns a copy of the elements from [`start`..`end`) from `v`.
fn slice[@T](v: &[mutable? T], start: uint, end: uint) -> [T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = ~[];
    reserve(result, end - start);
    let i = start;
    while i < end { result += ~[v.(i)]; i += 1u; }
    ret result;
}

// TODO: Remove me once we have slots.
fn slice_mut[@T](v: &[mutable? T], start: uint, end: uint) -> [mutable T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = ~[mutable];
    reserve(result, end - start);
    let i = start;
    while i < end { result += ~[mutable v.(i)]; i += 1u; }
    ret result;
}

// Mutators

fn shift[@T](v: &mutable [mutable? T]) -> T {
    let ln = len[T](v);
    assert (ln > 0u);
    let e = v.(0);
    v = slice[T](v, 1u, ln);
    ret e;
}

// TODO: Write this, unsafely, in a way that's not O(n).
fn pop[@T](v: &mutable [mutable? T]) -> T {
    let ln = len(v);
    assert (ln > 0u);
    ln -= 1u;
    let e = v.(ln);
    v = slice(v, 0u, ln);
    ret e;
}

// TODO: More.

// Appending

/// Expands the given vector in-place by appending `n` copies of `initval`.
fn grow[@T](v: &mutable [T], n: uint, initval: &T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += ~[initval]; i += 1u; }
}

// TODO: Remove me once we have slots.
fn grow_mut[@T](v: &mutable [mutable T], n: uint, initval: &T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += ~[mutable initval]; i += 1u; }
}

/// Calls `f` `n` times and appends the results of these calls to the given
/// vector.
fn grow_fn[@T](v: &mutable [T], n: uint, init_fn: fn(uint) -> T ) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += ~[init_fn(i)]; i += 1u; }
}

/// Sets the element at position `index` to `val`. If `index` is past the end
/// of the vector, expands the vector by replicating `initval` to fill the
/// intervening space.
fn grow_set[@T](v: &mutable [mutable T], index: uint, initval: &T, val: &T) {
    if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); }
    v.(index) = val;
}

// Functional utilities

fn map[@T, @U](f: &block(&T) -> U , v: &[mutable? T]) -> [U] {
    let result = ~[];
    reserve(result, len(v));
    for elem: T  in v {
        let elem2 = elem; // satisfies alias checker
        result += ~[f(elem2)];
    }
    ret result;
}

fn map2[@T, @U, @V](f: &block(&T, &U) -> V, v0: &[T], v1: &[U])
    -> [V] {
    let v0_len = len[T](v0);
    if v0_len != len[U](v1) { fail; }
    let u: [V] = ~[];
    let i = 0u;
    while i < v0_len { u += ~[f({ v0.(i) }, { v1.(i) })]; i += 1u; }
    ret u;
}

fn filter_map[@T, @U](f: &block(&T) -> option::t[U],
                      v: &[mutable? T]) -> [U] {
    let result = ~[];
    for elem: T  in v {
        let elem2 = elem; // satisfies alias checker
        alt f(elem2) {
          none. {/* no-op */ }
          some(result_elem) { result += ~[result_elem]; }
        }
    }
    ret result;
}

fn foldl[@T, @U](p: &block(&U, &T) -> U , z: &U, v: &[mutable? T]) -> U {
    let sz = len(v);
    if sz == 0u { ret z; }
    let first = v.(0);
    let rest = slice(v, 1u, sz);
    ret p(foldl(p, z, rest), first);
}

fn any[T](f: &block(&T) -> bool , v: &[T]) -> bool {
    for elem: T  in v { if f(elem) { ret true; } }
    ret false;
}

fn all[T](f: &block(&T) -> bool , v: &[T]) -> bool {
    for elem: T  in v { if !f(elem) { ret false; } }
    ret true;
}

fn member[T](x: &T, v: &[T]) -> bool {
    for elt: T  in v { if x == elt { ret true; } }
    ret false;
}

fn count[T](x: &T, v: &[mutable? T]) -> uint {
    let cnt = 0u;
    for elt: T  in v { if x == elt { cnt += 1u; } }
    ret cnt;
}

fn find[@T](f: &block(&T) -> bool , v: &[T]) -> option::t[T] {
    for elt: T  in v { if f(elt) { ret some(elt); } }
    ret none;
}

fn position[@T](x: &T, v: &[T]) -> option::t[uint] {
    let i: uint = 0u;
    while i < len(v) { if x == v.(i) { ret some[uint](i); } i += 1u; }
    ret none[uint];
}

fn position_pred[T](f: fn(&T) -> bool , v: &[T]) -> option::t[uint] {
    let i: uint = 0u;
    while i < len(v) { if f(v.(i)) { ret some[uint](i); } i += 1u; }
    ret none[uint];
}

fn unzip[@T, @U](v: &[{_0: T, _1: U}]) -> {_0: [T], _1: [U]} {
    let sz = len(v);
    if sz == 0u {
        ret {_0: ~[], _1: ~[]};
    } else {
        let rest = slice(v, 1u, sz);
        let tl = unzip(rest);
        let a = ~[v.(0)._0];
        let b = ~[v.(0)._1];
        ret {_0: a + tl._0, _1: b + tl._1};
    }
}

// FIXME make the lengths being equal a constraint
fn zip[@T, @U](v: &[T], u: &[U]) -> [{_0: T, _1: U}] {
    let sz = len(v);
    assert (sz == len(u));
    if sz == 0u {
        ret ~[];
    } else {
        let rest = zip(slice(v, 1u, sz), slice(u, 1u, sz));
        ret ~[{_0: v.(0), _1: u.(0)}] + rest;
    }
}

// Swaps two elements in a vector
fn swap[@T](v: &[mutable T], a: uint, b: uint) {
    let t: T = v.(a);
    v.(a) = v.(b);
    v.(b) = t;
}

// In place vector reversal
fn reverse[@T](v: &[mutable T]) {
    let i: uint = 0u;
    let ln = len[T](v);
    while i < ln / 2u { swap(v, i, ln - i - 1u); i += 1u; }
}

// Functional vector reversal. Returns a reversed copy of v.
fn reversed[@T](v: &[T]) -> [T] {
    let rs: [T] = ~[];
    let i = len[T](v);
    if i == 0u { ret rs; } else { i -= 1u; }
    while i != 0u { rs += ~[v.(i)]; i -= 1u; }
    rs += ~[v.(0)];
    ret rs;
}

mod unsafe {
    type ivec_repr =
        {mutable fill: uint,
         mutable alloc: uint,
         heap_part: *mutable ivec_heap_part};
    type ivec_heap_part = {mutable fill: uint};

    fn copy_from_buf[T](v: &mutable [T], ptr: *T, count: uint) {
        ret rustrt::ivec_copy_from_buf_shared(v, ptr, count);
    }

    fn from_buf[T](ptr: *T, bytes: uint) -> [T] {
        let v = ~[];
        copy_from_buf(v, ptr, bytes);
        ret v;
    }

    fn set_len[T](v: &mutable [T], new_len: uint) {
        let new_fill = new_len * sys::size_of[T]();
        let stack_part: *mutable ivec_repr =
            ::unsafe::reinterpret_cast(addr_of(v));
        if (*stack_part).fill == 0u {
            (*(*stack_part).heap_part).fill = new_fill; // On heap.
        } else {
            (*stack_part).fill = new_fill; // On stack.
        }
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Remove std::ivec::to_vec<commit_after>// Interior vector utility functions.

import option::none;
import option::some;
import uint::next_power_of_two;
import ptr::addr_of;

native "rust-intrinsic" mod rusti {
    fn ivec_len[T](v: &[T]) -> uint;
}

native "rust" mod rustrt {
    fn ivec_reserve_shared[T](v: &mutable [mutable? T], n: uint);
    fn ivec_on_heap[T](v: &[T]) -> uint;
    fn ivec_to_ptr[T](v: &[T]) -> *T;
    fn ivec_copy_from_buf_shared[T](v: &mutable [mutable? T], ptr: *T,
                                    count: uint);
}

fn from_vec[@T](v: &vec[mutable? T]) -> [T] {
    let iv = ~[];
    for e in v {
        iv += ~[e];
    }
    ret iv;
}

/// Reserves space for `n` elements in the given vector.
fn reserve[@T](v: &mutable [mutable? T], n: uint) {
    rustrt::ivec_reserve_shared(v, n);
}

fn on_heap[T](v: &[T]) -> bool { ret rustrt::ivec_on_heap(v) != 0u; }

fn to_ptr[T](v: &[T]) -> *T { ret rustrt::ivec_to_ptr(v); }

fn len[T](v: &[mutable? T]) -> uint { ret rusti::ivec_len(v); }

type init_op[T] = fn(uint) -> T ;

fn init_fn[@T](op: &init_op[T], n_elts: uint) -> [T] {
    let v = ~[];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += ~[op(i)]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_fn_mut[@T](op: &init_op[T], n_elts: uint) -> [mutable T] {
    let v = ~[mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += ~[mutable op(i)]; i += 1u; }
    ret v;
}

fn init_elt[@T](t: &T, n_elts: uint) -> [T] {
    let v = ~[];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += ~[t]; i += 1u; }
    ret v;
}

// TODO: Remove me once we have slots.
fn init_elt_mut[@T](t: &T, n_elts: uint) -> [mutable T] {
    let v = ~[mutable];
    reserve(v, n_elts);
    let i: uint = 0u;
    while i < n_elts { v += ~[mutable t]; i += 1u; }
    ret v;
}

fn to_mut[@T](v: &[T]) -> [mutable T] {
    let vres = ~[mutable];
    for t: T  in v { vres += ~[mutable t]; }
    ret vres;
}

fn from_mut[@T](v: &[mutable T]) -> [T] {
    let vres = ~[];
    for t: T  in v { vres += ~[t]; }
    ret vres;
}

// Predicates
pred is_empty[T](v: &[mutable? T]) -> bool {
    // FIXME: This would be easier if we could just call len
    for t: T in v { ret false; }
    ret true;
}

pred is_not_empty[T](v: &[mutable? T]) -> bool { ret !is_empty(v); }

// Accessors

/// Returns the first element of a vector
fn head[@T](v: &[mutable? T]) : is_not_empty(v) -> T { ret v.(0); }

/// Returns all but the first element of a vector
fn tail[@T](v: &[mutable? T]) : is_not_empty(v) -> [mutable? T] {
    ret slice(v, 1u, len(v));
}

/// Returns the last element of `v`.
fn last[@T](v: &[mutable? T]) -> option::t[T] {
    if len(v) == 0u { ret none; }
    ret some(v.(len(v) - 1u));
}

/// Returns a copy of the elements from [`start`..`end`) from `v`.
fn slice[@T](v: &[mutable? T], start: uint, end: uint) -> [T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = ~[];
    reserve(result, end - start);
    let i = start;
    while i < end { result += ~[v.(i)]; i += 1u; }
    ret result;
}

// TODO: Remove me once we have slots.
fn slice_mut[@T](v: &[mutable? T], start: uint, end: uint) -> [mutable T] {
    assert (start <= end);
    assert (end <= len(v));
    let result = ~[mutable];
    reserve(result, end - start);
    let i = start;
    while i < end { result += ~[mutable v.(i)]; i += 1u; }
    ret result;
}

// Mutators

fn shift[@T](v: &mutable [mutable? T]) -> T {
    let ln = len[T](v);
    assert (ln > 0u);
    let e = v.(0);
    v = slice[T](v, 1u, ln);
    ret e;
}

// TODO: Write this, unsafely, in a way that's not O(n).
fn pop[@T](v: &mutable [mutable? T]) -> T {
    let ln = len(v);
    assert (ln > 0u);
    ln -= 1u;
    let e = v.(ln);
    v = slice(v, 0u, ln);
    ret e;
}

// TODO: More.

// Appending

/// Expands the given vector in-place by appending `n` copies of `initval`.
fn grow[@T](v: &mutable [T], n: uint, initval: &T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += ~[initval]; i += 1u; }
}

// TODO: Remove me once we have slots.
fn grow_mut[@T](v: &mutable [mutable T], n: uint, initval: &T) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += ~[mutable initval]; i += 1u; }
}

/// Calls `f` `n` times and appends the results of these calls to the given
/// vector.
fn grow_fn[@T](v: &mutable [T], n: uint, init_fn: fn(uint) -> T ) {
    reserve(v, next_power_of_two(len(v) + n));
    let i: uint = 0u;
    while i < n { v += ~[init_fn(i)]; i += 1u; }
}

/// Sets the element at position `index` to `val`. If `index` is past the end
/// of the vector, expands the vector by replicating `initval` to fill the
/// intervening space.
fn grow_set[@T](v: &mutable [mutable T], index: uint, initval: &T, val: &T) {
    if index >= len(v) { grow_mut(v, index - len(v) + 1u, initval); }
    v.(index) = val;
}

// Functional utilities

fn map[@T, @U](f: &block(&T) -> U , v: &[mutable? T]) -> [U] {
    let result = ~[];
    reserve(result, len(v));
    for elem: T  in v {
        let elem2 = elem; // satisfies alias checker
        result += ~[f(elem2)];
    }
    ret result;
}

fn map2[@T, @U, @V](f: &block(&T, &U) -> V, v0: &[T], v1: &[U])
    -> [V] {
    let v0_len = len[T](v0);
    if v0_len != len[U](v1) { fail; }
    let u: [V] = ~[];
    let i = 0u;
    while i < v0_len { u += ~[f({ v0.(i) }, { v1.(i) })]; i += 1u; }
    ret u;
}

fn filter_map[@T, @U](f: &block(&T) -> option::t[U],
                      v: &[mutable? T]) -> [U] {
    let result = ~[];
    for elem: T  in v {
        let elem2 = elem; // satisfies alias checker
        alt f(elem2) {
          none. {/* no-op */ }
          some(result_elem) { result += ~[result_elem]; }
        }
    }
    ret result;
}

fn foldl[@T, @U](p: &block(&U, &T) -> U , z: &U, v: &[mutable? T]) -> U {
    let sz = len(v);
    if sz == 0u { ret z; }
    let first = v.(0);
    let rest = slice(v, 1u, sz);
    ret p(foldl(p, z, rest), first);
}

fn any[T](f: &block(&T) -> bool , v: &[T]) -> bool {
    for elem: T  in v { if f(elem) { ret true; } }
    ret false;
}

fn all[T](f: &block(&T) -> bool , v: &[T]) -> bool {
    for elem: T  in v { if !f(elem) { ret false; } }
    ret true;
}

fn member[T](x: &T, v: &[T]) -> bool {
    for elt: T  in v { if x == elt { ret true; } }
    ret false;
}

fn count[T](x: &T, v: &[mutable? T]) -> uint {
    let cnt = 0u;
    for elt: T  in v { if x == elt { cnt += 1u; } }
    ret cnt;
}

fn find[@T](f: &block(&T) -> bool , v: &[T]) -> option::t[T] {
    for elt: T  in v { if f(elt) { ret some(elt); } }
    ret none;
}

fn position[@T](x: &T, v: &[T]) -> option::t[uint] {
    let i: uint = 0u;
    while i < len(v) { if x == v.(i) { ret some[uint](i); } i += 1u; }
    ret none[uint];
}

fn position_pred[T](f: fn(&T) -> bool , v: &[T]) -> option::t[uint] {
    let i: uint = 0u;
    while i < len(v) { if f(v.(i)) { ret some[uint](i); } i += 1u; }
    ret none[uint];
}

fn unzip[@T, @U](v: &[{_0: T, _1: U}]) -> {_0: [T], _1: [U]} {
    let sz = len(v);
    if sz == 0u {
        ret {_0: ~[], _1: ~[]};
    } else {
        let rest = slice(v, 1u, sz);
        let tl = unzip(rest);
        let a = ~[v.(0)._0];
        let b = ~[v.(0)._1];
        ret {_0: a + tl._0, _1: b + tl._1};
    }
}

// FIXME make the lengths being equal a constraint
fn zip[@T, @U](v: &[T], u: &[U]) -> [{_0: T, _1: U}] {
    let sz = len(v);
    assert (sz == len(u));
    if sz == 0u {
        ret ~[];
    } else {
        let rest = zip(slice(v, 1u, sz), slice(u, 1u, sz));
        ret ~[{_0: v.(0), _1: u.(0)}] + rest;
    }
}

// Swaps two elements in a vector
fn swap[@T](v: &[mutable T], a: uint, b: uint) {
    let t: T = v.(a);
    v.(a) = v.(b);
    v.(b) = t;
}

// In place vector reversal
fn reverse[@T](v: &[mutable T]) {
    let i: uint = 0u;
    let ln = len[T](v);
    while i < ln / 2u { swap(v, i, ln - i - 1u); i += 1u; }
}

// Functional vector reversal. Returns a reversed copy of v.
fn reversed[@T](v: &[T]) -> [T] {
    let rs: [T] = ~[];
    let i = len[T](v);
    if i == 0u { ret rs; } else { i -= 1u; }
    while i != 0u { rs += ~[v.(i)]; i -= 1u; }
    rs += ~[v.(0)];
    ret rs;
}

mod unsafe {
    type ivec_repr =
        {mutable fill: uint,
         mutable alloc: uint,
         heap_part: *mutable ivec_heap_part};
    type ivec_heap_part = {mutable fill: uint};

    fn copy_from_buf[T](v: &mutable [T], ptr: *T, count: uint) {
        ret rustrt::ivec_copy_from_buf_shared(v, ptr, count);
    }

    fn from_buf[T](ptr: *T, bytes: uint) -> [T] {
        let v = ~[];
        copy_from_buf(v, ptr, bytes);
        ret v;
    }

    fn set_len[T](v: &mutable [T], new_len: uint) {
        let new_fill = new_len * sys::size_of[T]();
        let stack_part: *mutable ivec_repr =
            ::unsafe::reinterpret_cast(addr_of(v));
        if (*stack_part).fill == 0u {
            (*(*stack_part).heap_part).fill = new_fill; // On heap.
        } else {
            (*stack_part).fill = new_fill; // On stack.
        }
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

use serde::{Serialize, Deserialize, Serializer, Deserializer};
use serde::de::{Visitor, MapAccess};
use serde::de::Error as DeError;
use serde::ser::SerializeStruct;
use serde_json::Value as JsonValue;
use std::fmt;

#[derive(Debug)]
pub enum LocationStrategy {
    Css,
    LinkText,
    PartialLinkText,
    XPath,
}

impl Serialize for LocationStrategy {
    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        match self {
            &LocationStrategy::Css => s.serialize_str("css selector"),
            &LocationStrategy::LinkText => s.serialize_str("link text"),
            &LocationStrategy::PartialLinkText => s.serialize_str("partial link text"),
            &LocationStrategy::XPath => s.serialize_str("xpath"),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct WebDriverError {
    pub error: String,
    pub message: String,
    pub stacktrace: Option<String>,
}

#[derive(Serialize)]
pub struct NewSessionCmd {
    capabilities: JsonValue,
}

impl NewSessionCmd {
    pub fn new() -> Self {
        NewSessionCmd {
            capabilities: json!({
                "alwaysMatch": {
                    // ask chrome to be w3c compliant
                    "goog:chromeOptions": {
                        "w3c": true
                    }
                }
            }),
        }
    }

// TODO firefox specifc prefs
// [moz:firefoxOptions][prefs][name] = value;

}

#[derive(Debug, Deserialize)]
pub struct Session {
    pub sessionId: String,
}

#[derive(Serialize)]
pub struct GoCmd {
    pub url: String,
}

#[derive(Debug, Deserialize)]
pub struct Value<T> {
    pub value: T,
}

#[derive(Debug, Deserialize)]
pub struct CurrentTitle {
    pub title: String,
}

#[derive(Serialize)]
pub struct SwitchFrameCmd {
    pub id: JsonValue,
}

impl SwitchFrameCmd {
    pub fn from(id: JsonValue) -> Self {
        SwitchFrameCmd { id: id }
    }
}

#[derive(Serialize)]
pub struct SwitchWindowCmd {
    handle: String,
}

impl SwitchWindowCmd {
    pub fn from(handle: &str) -> Self {
        SwitchWindowCmd { handle: handle.to_string() }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Empty {}

#[derive(Serialize)]
pub struct FindElementCmd<'a> {
    pub using: LocationStrategy,
    pub value: &'a str,
}

#[derive(PartialEq, Debug)]
pub struct ElementReference {
    pub reference: String,
}

impl ElementReference {
    pub fn from_str(handle: &str) -> ElementReference {
        ElementReference { reference: handle.to_string() }
    }
}

impl Serialize for ElementReference {
    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        let mut ss = s.serialize_struct("ElementReference", 1)?;
        ss.serialize_field("element-6066-11e4-a52e-4f735466cecf", &self.reference)?;
        ss.end()
    }
}

impl<'de> Deserialize<'de> for ElementReference {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
        enum Field { Reference };

        impl<'de> Deserialize<'de> for Field {
            fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
                struct FieldVisitor;
                impl<'de> Visitor<'de> for FieldVisitor {
                    type Value = Field;
                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        formatter.write_str("element-6066-11e4-a52e-4f735466cecf")
                    }

                    fn visit_str<E: DeError>(self, value: &str) -> Result<Field, E>
                    {
                        match value {
                            "element-6066-11e4-a52e-4f735466cecf" => Ok(Field::Reference),
                            _ => Err(DeError::unknown_field(value, FIELDS)),
                        }
                    }
                }

                d.deserialize_identifier(FieldVisitor)
            }
        }

        struct ElementReferenceVisitor;
        impl<'de> Visitor<'de> for ElementReferenceVisitor {
            type Value = ElementReference;

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

            fn visit_map<V>(self, mut visitor: V) -> Result<ElementReference, V::Error>
                where V: MapAccess<'de>
            {
                let mut reference = None;
                while let Some(key) = visitor.next_key()? {
                    match key {
                        Field::Reference => {
                            if reference.is_some() {
                                return Err(DeError::duplicate_field("element-6066-11e4-a52e-4f735466cecf"));
                            }
                            reference = Some(visitor.next_value()?);
                        }
                    }
                }
                match reference {
                    Some(r) => Ok(ElementReference { reference: r }),
                    None => return Err(DeError::missing_field("element-6066-11e4-a52e-4f735466cecf")),
                }
            }
        }

        const FIELDS: &'static [&'static str] = &["element-6066-11e4-a52e-4f735466cecf"];
        d.deserialize_struct("ElementReference", FIELDS, ElementReferenceVisitor)
    }
}

#[derive(Debug, Deserialize)]
pub struct Cookie {
    pub name: String,
    pub value: String,
    pub path: String,
    pub domain: String,
    pub secure: bool,
    pub httpOnly: bool,
    // TODO: expiry:
}

#[derive(Serialize)]
pub struct ExecuteCmd {
    pub script: String,
    pub args: Vec<JsonValue>,
}

#[cfg(test)]
mod tests {
    use serde_json::{from_str, to_string};
    use super::*;

    #[test]
    fn element_ref_serialize() {
        let r: ElementReference = from_str("{\"element-6066-11e4-a52e-4f735466cecf\": \"ZZZZ\"}").unwrap();
        assert_eq!(r.reference, "ZZZZ");
        let r2 = from_str(&to_string(&r).unwrap()).unwrap();
        assert_eq!(r, r2);
    }
}
<commit_msg>Workaround non-conformant chrome element ref<commit_after>#![allow(non_snake_case)]

use serde::{Serialize, Deserialize, Serializer, Deserializer};
use serde::de::{Visitor, MapAccess};
use serde::de::Error as DeError;
use serde::ser::SerializeStruct;
use serde_json::Value as JsonValue;
use std::fmt;

#[derive(Debug)]
pub enum LocationStrategy {
    Css,
    LinkText,
    PartialLinkText,
    XPath,
}

impl Serialize for LocationStrategy {
    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        match self {
            &LocationStrategy::Css => s.serialize_str("css selector"),
            &LocationStrategy::LinkText => s.serialize_str("link text"),
            &LocationStrategy::PartialLinkText => s.serialize_str("partial link text"),
            &LocationStrategy::XPath => s.serialize_str("xpath"),
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct WebDriverError {
    pub error: String,
    pub message: String,
    pub stacktrace: Option<String>,
}

#[derive(Serialize)]
pub struct NewSessionCmd {
    capabilities: JsonValue,
}

impl NewSessionCmd {
    pub fn new() -> Self {
        NewSessionCmd {
            capabilities: json!({
                "alwaysMatch": {
                    // ask chrome to be w3c compliant
                    "goog:chromeOptions": {
                        "w3c": true
                    }
                }
            }),
        }
    }

// TODO firefox specifc prefs
// [moz:firefoxOptions][prefs][name] = value;

}

#[derive(Debug, Deserialize)]
pub struct Session {
    pub sessionId: String,
}

#[derive(Serialize)]
pub struct GoCmd {
    pub url: String,
}

#[derive(Debug, Deserialize)]
pub struct Value<T> {
    pub value: T,
}

#[derive(Debug, Deserialize)]
pub struct CurrentTitle {
    pub title: String,
}

#[derive(Serialize)]
pub struct SwitchFrameCmd {
    pub id: JsonValue,
}

impl SwitchFrameCmd {
    pub fn from(id: JsonValue) -> Self {
        SwitchFrameCmd { id: id }
    }
}

#[derive(Serialize)]
pub struct SwitchWindowCmd {
    handle: String,
}

impl SwitchWindowCmd {
    pub fn from(handle: &str) -> Self {
        SwitchWindowCmd { handle: handle.to_string() }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Empty {}

#[derive(Serialize)]
pub struct FindElementCmd<'a> {
    pub using: LocationStrategy,
    pub value: &'a str,
}

#[derive(PartialEq, Debug)]
pub struct ElementReference {
    pub reference: String,
}

impl ElementReference {
    pub fn from_str(handle: &str) -> ElementReference {
        ElementReference { reference: handle.to_string() }
    }
}

impl Serialize for ElementReference {
    fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
        let mut ss = s.serialize_struct("ElementReference", 1)?;
        ss.serialize_field("element-6066-11e4-a52e-4f735466cecf", &self.reference)?;
        // even in w3c compliance mode chromedriver only accepts a reference name ELEMENT
        ss.serialize_field("ELEMENT", &self.reference)?;
        ss.end()
    }
}

impl<'de> Deserialize<'de> for ElementReference {
    fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
        enum Field { Reference };

        impl<'de> Deserialize<'de> for Field {
            fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
                struct FieldVisitor;
                impl<'de> Visitor<'de> for FieldVisitor {
                    type Value = Field;
                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        formatter.write_str("element-6066-11e4-a52e-4f735466cecf")
                    }

                    fn visit_str<E: DeError>(self, value: &str) -> Result<Field, E>
                    {
                        match value {
                            "element-6066-11e4-a52e-4f735466cecf" => Ok(Field::Reference),
                            _ => Err(DeError::unknown_field(value, FIELDS)),
                        }
                    }
                }

                d.deserialize_identifier(FieldVisitor)
            }
        }

        struct ElementReferenceVisitor;
        impl<'de> Visitor<'de> for ElementReferenceVisitor {
            type Value = ElementReference;

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

            fn visit_map<V>(self, mut visitor: V) -> Result<ElementReference, V::Error>
                where V: MapAccess<'de>
            {
                let mut reference = None;
                while let Some(key) = visitor.next_key()? {
                    match key {
                        Field::Reference => {
                            if reference.is_some() {
                                return Err(DeError::duplicate_field("element-6066-11e4-a52e-4f735466cecf"));
                            }
                            reference = Some(visitor.next_value()?);
                        }
                    }
                }
                match reference {
                    Some(r) => Ok(ElementReference { reference: r }),
                    None => return Err(DeError::missing_field("element-6066-11e4-a52e-4f735466cecf")),
                }
            }
        }

        const FIELDS: &'static [&'static str] = &["element-6066-11e4-a52e-4f735466cecf"];
        d.deserialize_struct("ElementReference", FIELDS, ElementReferenceVisitor)
    }
}

#[derive(Debug, Deserialize)]
pub struct Cookie {
    pub name: String,
    pub value: String,
    pub path: String,
    pub domain: String,
    pub secure: bool,
    pub httpOnly: bool,
    // TODO: expiry:
}

#[derive(Serialize)]
pub struct ExecuteCmd {
    pub script: String,
    pub args: Vec<JsonValue>,
}
<|endoftext|>


<commit_before>use crate::case::*;
use once_cell::sync::Lazy;
use std::{borrow::Cow, collections::HashMap, path::*};

static mut CRATE_NAME_OVERRIDES: Option<HashMap<String, String>> = None;

pub(crate) fn set_crate_name_overrides(overrides: HashMap<String, String>) {
    unsafe {
        if CRATE_NAME_OVERRIDES.is_some() {
            panic!("Crate name overrides already set;");
        }
        CRATE_NAME_OVERRIDES = Some(overrides);
    }
}

fn get_crate_name_override(crate_name: &str) -> Option<String> {
    unsafe {
        if let Some(ref overrides) = CRATE_NAME_OVERRIDES {
            if let Some(crate_name) = overrides.get(crate_name) {
                return Some(crate_name.clone());
            }
        }
        None
    }
}

pub fn split_namespace_name(name: &str) -> (Option<&str>, &str) {
    let mut parts = name.split('.');
    let name = parts.next_back().unwrap();
    let ns = parts.next_back();
    assert!(ns.is_none() || parts.next().is_none());
    (ns, name)
}

/* unused :(
pub fn strip_suffix<'a>(name: &'a str, suffix: &str) -> Option<&'a str> {
    if name.ends_with(suffix) {
        Some(&name[..name.len() - suffix.len()])
    }
    else {
        None
    }
}
*/

pub fn file_name_sys(name: &str) -> String {
    let mut path = PathBuf::from(name);
    let added = path.set_extension("rs");
    assert!(added);
    path.to_str().unwrap().into()
}

/// Crate name with undescores for `use` statement
pub fn crate_name(name: &str) -> String {
    let name = name.replace("-", "_").to_snake();
    let crate_name = if let Some(name_without_prefix) = name.strip_prefix("g_") {
        name_without_prefix.to_owned()
    } else {
        name
    };
    if let Some(crate_name) = get_crate_name_override(&crate_name) {
        crate_name
    } else {
        crate_name
    }
}

/// Crate name with '-' for Cargo.toml etc.
pub fn exported_crate_name(crate_name: &str) -> String {
    crate_name.replace("_", "-")
}

pub fn module_name(name: &str) -> String {
    mangle_keywords(name.to_snake()).into_owned()
}

pub fn enum_member_name(name: &str) -> String {
    if name.starts_with(char::is_alphabetic) {
        name.to_camel()
    } else {
        format!("_{}", name.to_camel())
    }
}

pub fn bitfield_member_name(name: &str) -> String {
    if name.starts_with(char::is_alphabetic) {
        name.to_uppercase()
    } else {
        format!("_{}", name.to_uppercase())
    }
}

pub fn needs_mangling(name: &str) -> bool {
    KEYWORDS.contains_key(name)
}

// If the mangling happened, guaranteed to return Owned.
pub fn mangle_keywords<'a, S: Into<Cow<'a, str>>>(name: S) -> Cow<'a, str> {
    let name = name.into();
    if let Some(s) = KEYWORDS.get(&*name) {
        s.clone().into()
    } else {
        name
    }
}

static KEYWORDS: Lazy<HashMap<&'static str, String>> = Lazy::new(|| {
    [
        "abstract", "alignof", "as", "become", "box", "break", "const", "continue", "crate", "do",
        "else", "enum", "extern", "false", "final", "fn", "for", "if", "impl", "in", "let", "loop",
        "macro", "match", "mod", "move", "mut", "offsetof", "override", "priv", "proc", "pub",
        "pure", "ref", "return", "Self", "self", "sizeof", "static", "struct", "super", "trait",
        "true", "type", "typeof", "unsafe", "unsized", "use", "virtual", "where", "while", "yield",
    ]
    .iter()
    .map(|k| (*k, format!("{}_", k)))
    .collect()
});

pub fn signal_to_snake(signal: &str) -> String {
    signal.replace("::", "_").replace('-', "_")
}

pub fn lib_name_to_toml(name: &str) -> String {
    name.to_string().replace("-", "_").replace(".", "_")
}

pub fn shared_lib_name_to_link_name(name: &str) -> &str {
    let mut s = name;

    if s.starts_with("lib") {
        s = &s[3..];
    }

    let offset = s.find(".so").unwrap_or_else(|| s.len());
    s = &s[..offset];

    s
}

pub fn shared_libs_to_links(shared_libs: &[String]) -> String {
    // https://github.com/rust-lang/cargo/issues/4533
    // links = ["foo", "bar"] or ['foo', 'bar'] is not supported.
    // Pick the first element
    if let Some(shared_lib) = shared_libs.get(0) {
        return format!("\"{}\"", shared_lib_name_to_link_name(&shared_lib));
    }

    panic!("empty list of shared library");
}

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

    #[test]
    fn split_no_namespace() {
        let (ns, name) = split_namespace_name("GObject");
        assert_eq!(ns, None);
        assert_eq!(name, "GObject");
    }

    #[test]
    fn split_full_name() {
        let (ns, name) = split_namespace_name("Gtk.StatusIcon");
        assert_eq!(ns, Some("Gtk"));
        assert_eq!(name, "StatusIcon");
    }

    /*
    #[test]
    fn strip_prefix_g() {
        assert_eq!(strip_prefix("G", "GBusType"), "BusType");
        assert_eq!(strip_prefix("G", "G_BUS_TYPE_NONE"), "BUS_TYPE_NONE");
    }

    #[test]
    fn strip_prefix_gtk() {
        assert_eq!(strip_prefix("Gtk", "GtkAlign"), "Align");
        assert_eq!(strip_prefix("Gtk", "GTK_ALIGN_FILL"), "ALIGN_FILL");
    }
    */

    #[test]
    fn crate_name_works() {
        assert_eq!(crate_name("GdkPixbuf"), "gdk_pixbuf");
        assert_eq!(crate_name("GLib"), "glib");
        assert_eq!(crate_name("GObject"), "gobject");
        assert_eq!(crate_name("Gtk"), "gtk");
    }

    #[test]
    fn file_name_sys_works() {
        assert_eq!(file_name_sys("funcs"), "funcs.rs");
    }

    #[test]
    fn signal_to_snake_works() {
        assert_eq!(signal_to_snake("changed"), "changed");
        assert_eq!(signal_to_snake("move-active"), "move_active");
    }

    #[test]
    fn lib_name_to_toml_works() {
        assert_eq!(lib_name_to_toml("gstreamer-1.0"), "gstreamer_1_0");
    }

    #[test]
    fn shared_lib_name_to_link_name_works() {
        assert_eq!(shared_lib_name_to_link_name("libatk-1.0.so.0"), "atk-1.0");
        assert_eq!(
            shared_lib_name_to_link_name("libgdk_pixbuf-2.0.so.0"),
            "gdk_pixbuf-2.0"
        );
    }

    #[test]
    fn shared_libs_to_links_works() {
        let libs = vec![
            String::from("libgobject-2.0.so.0"),
            String::from("libglib-2.0.so.0"),
        ];
        // https://github.com/rust-lang/cargo/issues/4533
        // list is not supported. Pick the first one
        assert_eq!(shared_libs_to_links(&libs), "\"gobject-2.0\"");

        let libs = vec![String::from("libgio-2.0.so.0")];
        assert_eq!(shared_libs_to_links(&libs), "\"gio-2.0\"");
    }

    #[test]
    #[should_panic]
    fn shared_libs_to_links_panic() {
        let libs = vec![];
        shared_libs_to_links(&libs);
    }
}
<commit_msg>Add async, await, dyn and try as new 2018 edition keywords<commit_after>use crate::case::*;
use once_cell::sync::Lazy;
use std::{borrow::Cow, collections::HashMap, path::*};

static mut CRATE_NAME_OVERRIDES: Option<HashMap<String, String>> = None;

pub(crate) fn set_crate_name_overrides(overrides: HashMap<String, String>) {
    unsafe {
        if CRATE_NAME_OVERRIDES.is_some() {
            panic!("Crate name overrides already set;");
        }
        CRATE_NAME_OVERRIDES = Some(overrides);
    }
}

fn get_crate_name_override(crate_name: &str) -> Option<String> {
    unsafe {
        if let Some(ref overrides) = CRATE_NAME_OVERRIDES {
            if let Some(crate_name) = overrides.get(crate_name) {
                return Some(crate_name.clone());
            }
        }
        None
    }
}

pub fn split_namespace_name(name: &str) -> (Option<&str>, &str) {
    let mut parts = name.split('.');
    let name = parts.next_back().unwrap();
    let ns = parts.next_back();
    assert!(ns.is_none() || parts.next().is_none());
    (ns, name)
}

/* unused :(
pub fn strip_suffix<'a>(name: &'a str, suffix: &str) -> Option<&'a str> {
    if name.ends_with(suffix) {
        Some(&name[..name.len() - suffix.len()])
    }
    else {
        None
    }
}
*/

pub fn file_name_sys(name: &str) -> String {
    let mut path = PathBuf::from(name);
    let added = path.set_extension("rs");
    assert!(added);
    path.to_str().unwrap().into()
}

/// Crate name with undescores for `use` statement
pub fn crate_name(name: &str) -> String {
    let name = name.replace("-", "_").to_snake();
    let crate_name = if let Some(name_without_prefix) = name.strip_prefix("g_") {
        name_without_prefix.to_owned()
    } else {
        name
    };
    if let Some(crate_name) = get_crate_name_override(&crate_name) {
        crate_name
    } else {
        crate_name
    }
}

/// Crate name with '-' for Cargo.toml etc.
pub fn exported_crate_name(crate_name: &str) -> String {
    crate_name.replace("_", "-")
}

pub fn module_name(name: &str) -> String {
    mangle_keywords(name.to_snake()).into_owned()
}

pub fn enum_member_name(name: &str) -> String {
    if name.starts_with(char::is_alphabetic) {
        name.to_camel()
    } else {
        format!("_{}", name.to_camel())
    }
}

pub fn bitfield_member_name(name: &str) -> String {
    if name.starts_with(char::is_alphabetic) {
        name.to_uppercase()
    } else {
        format!("_{}", name.to_uppercase())
    }
}

pub fn needs_mangling(name: &str) -> bool {
    KEYWORDS.contains_key(name)
}

// If the mangling happened, guaranteed to return Owned.
pub fn mangle_keywords<'a, S: Into<Cow<'a, str>>>(name: S) -> Cow<'a, str> {
    let name = name.into();
    if let Some(s) = KEYWORDS.get(&*name) {
        s.clone().into()
    } else {
        name
    }
}

static KEYWORDS: Lazy<HashMap<&'static str, String>> = Lazy::new(|| {
    [
        "abstract", "alignof", "as", "async", "await", "become", "box", "break", "const",
        "continue", "crate", "do", "dyn", "else", "enum", "extern", "false", "final", "fn", "for",
        "if", "impl", "in", "let", "loop", "macro", "match", "mod", "move", "mut", "offsetof",
        "override", "priv", "proc", "pub", "pure", "ref", "return", "Self", "self", "sizeof",
        "static", "struct", "super", "trait", "true", "try", "type", "typeof", "unsafe", "unsized",
        "use", "virtual", "where", "while", "yield",
    ]
    .iter()
    .map(|k| (*k, format!("{}_", k)))
    .collect()
});

pub fn signal_to_snake(signal: &str) -> String {
    signal.replace("::", "_").replace('-', "_")
}

pub fn lib_name_to_toml(name: &str) -> String {
    name.to_string().replace("-", "_").replace(".", "_")
}

pub fn shared_lib_name_to_link_name(name: &str) -> &str {
    let mut s = name;

    if s.starts_with("lib") {
        s = &s[3..];
    }

    let offset = s.find(".so").unwrap_or_else(|| s.len());
    s = &s[..offset];

    s
}

pub fn shared_libs_to_links(shared_libs: &[String]) -> String {
    // https://github.com/rust-lang/cargo/issues/4533
    // links = ["foo", "bar"] or ['foo', 'bar'] is not supported.
    // Pick the first element
    if let Some(shared_lib) = shared_libs.get(0) {
        return format!("\"{}\"", shared_lib_name_to_link_name(&shared_lib));
    }

    panic!("empty list of shared library");
}

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

    #[test]
    fn split_no_namespace() {
        let (ns, name) = split_namespace_name("GObject");
        assert_eq!(ns, None);
        assert_eq!(name, "GObject");
    }

    #[test]
    fn split_full_name() {
        let (ns, name) = split_namespace_name("Gtk.StatusIcon");
        assert_eq!(ns, Some("Gtk"));
        assert_eq!(name, "StatusIcon");
    }

    /*
    #[test]
    fn strip_prefix_g() {
        assert_eq!(strip_prefix("G", "GBusType"), "BusType");
        assert_eq!(strip_prefix("G", "G_BUS_TYPE_NONE"), "BUS_TYPE_NONE");
    }

    #[test]
    fn strip_prefix_gtk() {
        assert_eq!(strip_prefix("Gtk", "GtkAlign"), "Align");
        assert_eq!(strip_prefix("Gtk", "GTK_ALIGN_FILL"), "ALIGN_FILL");
    }
    */

    #[test]
    fn crate_name_works() {
        assert_eq!(crate_name("GdkPixbuf"), "gdk_pixbuf");
        assert_eq!(crate_name("GLib"), "glib");
        assert_eq!(crate_name("GObject"), "gobject");
        assert_eq!(crate_name("Gtk"), "gtk");
    }

    #[test]
    fn file_name_sys_works() {
        assert_eq!(file_name_sys("funcs"), "funcs.rs");
    }

    #[test]
    fn signal_to_snake_works() {
        assert_eq!(signal_to_snake("changed"), "changed");
        assert_eq!(signal_to_snake("move-active"), "move_active");
    }

    #[test]
    fn lib_name_to_toml_works() {
        assert_eq!(lib_name_to_toml("gstreamer-1.0"), "gstreamer_1_0");
    }

    #[test]
    fn shared_lib_name_to_link_name_works() {
        assert_eq!(shared_lib_name_to_link_name("libatk-1.0.so.0"), "atk-1.0");
        assert_eq!(
            shared_lib_name_to_link_name("libgdk_pixbuf-2.0.so.0"),
            "gdk_pixbuf-2.0"
        );
    }

    #[test]
    fn shared_libs_to_links_works() {
        let libs = vec![
            String::from("libgobject-2.0.so.0"),
            String::from("libglib-2.0.so.0"),
        ];
        // https://github.com/rust-lang/cargo/issues/4533
        // list is not supported. Pick the first one
        assert_eq!(shared_libs_to_links(&libs), "\"gobject-2.0\"");

        let libs = vec![String::from("libgio-2.0.so.0")];
        assert_eq!(shared_libs_to_links(&libs), "\"gio-2.0\"");
    }

    #[test]
    #[should_panic]
    fn shared_libs_to_links_panic() {
        let libs = vec![];
        shared_libs_to_links(&libs);
    }
}
<|endoftext|>


<commit_before>//! This module defines the `Bits`, `Dibits`, and `Tribits` iterators as well as the
//! wrapper types `Bit`, `Dibit`, and `Tribit`, for working with sub-byte values.
//!
//! The wrapped values of `Bit`, `Dibit`, and `Tribit, are guaranteed to have only one,
//! two, or three bits, respectively.

use std;

/// Iterate over the dibits of a byte source, MSB to LSB.
pub type Dibits<T> = SubByteIter<DibitParams, T>;
/// Iterates over the tribits in a byte source, MSB to LSB.
pub type Tribits<T> = SubByteIter<TribitParams, T>;

/// Defines parameters needed for (power of two) sub-byte iterators.
pub trait IterParams {
    /// Type to yield at each iteration.
    type IterType;

    /// Number of bits to consume at each iteration.
    fn bits() -> usize;

    /// Number of bytes to buffer, where the number of bits contained should be the lcm of
    /// 8 and the number of bits per iteration.
    fn buffer() -> usize { 1 }

    /// Amount to shift buffer after loading in bytes.
    fn buffer_shift() -> usize { 32 - 8 * Self::buffer() }

    /// Number of iterations needed for each byte.
    fn iterations() -> usize { 8 * Self::buffer() / Self::bits() }

    /// Wrap the given bits in container type.
    fn wrap(bits: u8) -> Self::IterType;

    /// Verify the parameters are supported.
    fn validate() {
        // Maximum buffer size is currently 32 bits.
        assert!(Self::buffer() <= 4);
    }
}

/// Two bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Dibit(u8);

impl Dibit {
    /// Construct a new `Dibit` with the two given bits in the LSB position.
    pub fn new(bits: u8) -> Dibit {
        assert!(bits >> 2 == 0);
        Dibit(bits)
    }

    /// Get the wrapped dibit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Dibits` iterator.
pub struct DibitParams;

impl IterParams for DibitParams {
    type IterType = Dibit;

    fn bits() -> usize { 2 }
    fn wrap(bits: u8) -> Dibit { Dibit::new(bits) }
}

/// Three bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Tribit(u8);

impl Tribit {
    /// Construct a new `Tribit` with the three given bits in the LSB position.
    pub fn new(bits: u8) -> Tribit {
        assert!(bits >> 3 == 0);
        Tribit(bits)
    }

    /// Get the wrapped tribit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Tribits` iterator.
pub struct TribitParams;

impl IterParams for TribitParams {
    type IterType = Tribit;

    fn bits() -> usize { 3 }
    fn buffer() -> usize { 3 }
    fn wrap(bits: u8) -> Tribit { Tribit::new(bits) }
}

/// An iterator for sub-byte (bit-level) values.
struct SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// Source of bytes.
    src: T,
    /// Current buffered bits.
    buf: u32,
    /// Current bit-level index into the current byte.
    idx: u8,
}

impl<P, T> SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter` over the given byte source. All bits are iterated
    /// over, so the number of bits must be a byte multiple.
    pub fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            buf: 0,
            idx: 0,
        }
    }

    /// Consume one or more bytes to create a buffer of bits, filled starting from the
    /// MSB.
    fn buffer(&mut self) -> Option<u32> {
        let (buf, added) = (&mut self.src)
            .take(P::buffer())
            .fold((0, 0), |(buf, added), byte| {
                (buf << 8 | byte as u32, added + 1)
            });

        // It's okay if there are no more source bits here, because we're on a safe
        // boundary.
        if added == 0 {
            return None;
        }

        assert!(added == P::buffer(), "incomplete source");

        Some(buf << P::buffer_shift())
    }
}

impl<P, T> Iterator for SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    type Item = P::IterType;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.buf = match self.buffer() {
                Some(b) => b,
                None => return None,
            };
        }

        // Extract MSBs.
        let bits = self.buf >> (32 - P::bits());

        // Strip off the MSBs for the next iteration.
        self.buf <<= P::bits();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations() as u8;

        Some(P::wrap(bits as u8))
    }
}

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

    #[test]
    fn validate_params() {
        DibitParams::validate();
        TribitParams::validate();
    }

    #[test]
    fn test_tribits() {
        let bytes = [
            0b00101001,
            0b11001011,
            0b10111000,
            0b00101001,
            0b11001011,
            0b10111000,
        ];
        let mut t = Tribits::new(bytes.iter().cloned());

        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert!(t.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_tribits_panic() {
        let bytes = [1, 2, 3, 4];
        let t = Tribits::new(bytes.iter().cloned());

        for _ in t {}
    }
}
<commit_msg>s/IterType/Output/<commit_after>//! This module defines the `Bits`, `Dibits`, and `Tribits` iterators as well as the
//! wrapper types `Bit`, `Dibit`, and `Tribit`, for working with sub-byte values.
//!
//! The wrapped values of `Bit`, `Dibit`, and `Tribit, are guaranteed to have only one,
//! two, or three bits, respectively.

use std;

/// Iterate over the dibits of a byte source, MSB to LSB.
pub type Dibits<T> = SubByteIter<DibitParams, T>;
/// Iterates over the tribits in a byte source, MSB to LSB.
pub type Tribits<T> = SubByteIter<TribitParams, T>;

/// Defines parameters needed for (power of two) sub-byte iterators.
pub trait IterParams {
    /// Type to yield at each iteration.
    type Output;

    /// Number of bits to consume at each iteration.
    fn bits() -> usize;

    /// Number of bytes to buffer, where the number of bits contained should be the lcm of
    /// 8 and the number of bits per iteration.
    fn buffer() -> usize { 1 }

    /// Amount to shift buffer after loading in bytes.
    fn buffer_shift() -> usize { 32 - 8 * Self::buffer() }

    /// Number of iterations needed for each byte.
    fn iterations() -> usize { 8 * Self::buffer() / Self::bits() }

    /// Wrap the given bits in container type.
    fn wrap(bits: u8) -> Self::IterType;

    /// Verify the parameters are supported.
    fn validate() {
        // Maximum buffer size is currently 32 bits.
        assert!(Self::buffer() <= 4);
    }
}

/// Two bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Dibit(u8);

impl Dibit {
    /// Construct a new `Dibit` with the two given bits in the LSB position.
    pub fn new(bits: u8) -> Dibit {
        assert!(bits >> 2 == 0);
        Dibit(bits)
    }

    /// Get the wrapped dibit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Dibits` iterator.
pub struct DibitParams;

impl IterParams for DibitParams {
    type Output = Dibit;

    fn bits() -> usize { 2 }
    fn wrap(bits: u8) -> Dibit { Dibit::new(bits) }
}

/// Three bits.
#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
pub struct Tribit(u8);

impl Tribit {
    /// Construct a new `Tribit` with the three given bits in the LSB position.
    pub fn new(bits: u8) -> Tribit {
        assert!(bits >> 3 == 0);
        Tribit(bits)
    }

    /// Get the wrapped tribit.
    pub fn bits(&self) -> u8 { self.0 }
}

/// Parameters for `Tribits` iterator.
pub struct TribitParams;

impl IterParams for TribitParams {
    type Output = Tribit;

    fn bits() -> usize { 3 }
    fn buffer() -> usize { 3 }
    fn wrap(bits: u8) -> Tribit { Tribit::new(bits) }
}

/// An iterator for sub-byte (bit-level) values.
struct SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    params: std::marker::PhantomData<P>,
    /// Source of bytes.
    src: T,
    /// Current buffered bits.
    buf: u32,
    /// Current bit-level index into the current byte.
    idx: u8,
}

impl<P, T> SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    /// Construct a new `SubByteIter` over the given byte source. All bits are iterated
    /// over, so the number of bits must be a byte multiple.
    pub fn new(src: T) -> SubByteIter<P, T> {
        SubByteIter {
            params: std::marker::PhantomData,
            src: src,
            buf: 0,
            idx: 0,
        }
    }

    /// Consume one or more bytes to create a buffer of bits, filled starting from the
    /// MSB.
    fn buffer(&mut self) -> Option<u32> {
        let (buf, added) = (&mut self.src)
            .take(P::buffer())
            .fold((0, 0), |(buf, added), byte| {
                (buf << 8 | byte as u32, added + 1)
            });

        // It's okay if there are no more source bits here, because we're on a safe
        // boundary.
        if added == 0 {
            return None;
        }

        assert!(added == P::buffer(), "incomplete source");

        Some(buf << P::buffer_shift())
    }
}

impl<P, T> Iterator for SubByteIter<P, T> where
    P: IterParams, T: Iterator<Item = u8>
{
    type Item = P::Output;

    fn next(&mut self) -> Option<Self::Item> {
        if self.idx == 0 {
            self.buf = match self.buffer() {
                Some(b) => b,
                None => return None,
            };
        }

        // Extract MSBs.
        let bits = self.buf >> (32 - P::bits());

        // Strip off the MSBs for the next iteration.
        self.buf <<= P::bits();

        // Move to the next item and reset after all have been visited.
        self.idx += 1;
        self.idx %= P::iterations() as u8;

        Some(P::wrap(bits as u8))
    }
}

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

    #[test]
    fn validate_params() {
        DibitParams::validate();
        TribitParams::validate();
    }

    #[test]
    fn test_tribits() {
        let bytes = [
            0b00101001,
            0b11001011,
            0b10111000,
            0b00101001,
            0b11001011,
            0b10111000,
        ];
        let mut t = Tribits::new(bytes.iter().cloned());

        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert_eq!(t.next().unwrap().bits(), 0b001);
        assert_eq!(t.next().unwrap().bits(), 0b010);
        assert_eq!(t.next().unwrap().bits(), 0b011);
        assert_eq!(t.next().unwrap().bits(), 0b100);
        assert_eq!(t.next().unwrap().bits(), 0b101);
        assert_eq!(t.next().unwrap().bits(), 0b110);
        assert_eq!(t.next().unwrap().bits(), 0b111);
        assert_eq!(t.next().unwrap().bits(), 0b000);
        assert!(t.next().is_none());
    }

    #[test]
    #[should_panic]
    fn test_tribits_panic() {
        let bytes = [1, 2, 3, 4];
        let t = Tribits::new(bytes.iter().cloned());

        for _ in t {}
    }
}
<|endoftext|>


<commit_before>#[feature(globs)];
#[feature(managed_boxes)];

use std::str;
use std::io::stdout;
use std::io::fs::File;
use std::os;
use peg::{compile_grammar};
use codegen::RustWriter;

mod peg;
mod codegen;
mod grammar;

fn main() {
	let args = os::args();
	let source_utf8 = File::open(&Path::new(args[1])).read_to_end();
	let source = str::from_utf8(source_utf8);
	let grammar_def = grammar::grammar(source).unwrap();
	let w = RustWriter::new(stdout());
	compile_grammar(&w, grammar_def);
}
<commit_msg>Print error message on parse failure.<commit_after>#[feature(globs)];
#[feature(managed_boxes)];

use std::str;
use std::io::{stdout,stderr};
use std::io::fs::File;
use std::os;
use peg::{compile_grammar};
use codegen::RustWriter;

mod peg;
mod codegen;
mod grammar;

fn main() {
	let args = os::args();
	let source_utf8 = File::open(&Path::new(args[1])).read_to_end();
	let source = str::from_utf8(source_utf8);
	let grammar_def = grammar::grammar(source);

	match grammar_def {
		Ok(grammar) => {
			let w = RustWriter::new(stdout());
			compile_grammar(&w, grammar);
		}

		Err(msg) => {
			writeln!(&mut stderr() as &mut Writer, "Error parsing language specification: {}", msg);
			os::set_exit_status(1);
		}
	}
}
<|endoftext|>


<commit_before>// For reference on linking to C++ functions, see https://github.com/rust-lang/rust/issues/5853#issuecomment-44365672

#[cfg(target_family = "windows")]
#[allow(non_snake_case)]
mod Platform {
    pub mod Details {
        #[link(name = "vccorlib")]
        #[cfg(target_arch="x86_64")]
        extern "C" {
            // This generates invalid program output causing a crash when this function is called. See https://github.com/rust-lang/rust/issues/23216 for details.
            #[link_name = "?GetCmdArguments@Details@Platform@@YAPEAPEA_WPEAH@Z"]
            pub fn GetCmdArguments(argc : *mut ::libc::c_int) -> *const *const ::libc::wchar_t;
        }

        #[link(name = "vccorlib")]
        #[cfg(target_arch = "x86")]
        extern "C" {
            // This generates invalid program output causing a crash when this function is called. See https://github.com/rust-lang/rust/issues/23216 for details.
            #[link_name = "?GetCmdArguments@Details@Platform@@YAPAPA_WPAH@Z"]
            pub fn GetCmdArguments(argc : *mut ::libc::c_int) -> *const *const ::libc::wchar_t;
        }
    }
}

pub fn get_command_arguments(argc : ::libc::c_int) -> Vec<String> {
    let mut argc = argc;
    let argv = unsafe { Platform::Details::GetCmdArguments(&mut argc) };
    let mut arguments : Vec<String> = Vec::with_capacity(argc as usize);
    /*
    // How do I make this code work?
    for arg in unsafe { ::std::slice::from_raw_parts(argv, argc as usize) }.into_iter() {
        let argument : &[::libc::wchar_t] = unsafe { ::std::slice::from_raw_parts(arg, ::libc::wcslen(arg) as usize) };
        arguments.push(String::from_utf16(unsafe { ::std::mem::transmute(argument) } ).unwrap())
    }
    */
    let args = unsafe { ::std::slice::from_raw_parts(argv, argc as usize) };
    for i in 0..args.len() {
        let argument : &[::libc::wchar_t] = unsafe { ::std::slice::from_raw_parts(args[i], ::libc::wcslen(args[i]) as usize) };
        arguments.push(String::from_utf16(unsafe { ::std::mem::transmute(argument) } ).unwrap())
    }
    arguments
}

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

    #[test]
    fn test_get_command_arguments() {
        let arguments = get_command_arguments(0);
        assert!(arguments.len() == 1);
        for argv in arguments {
            println!("{}", argv)
        }
    }
}<commit_msg>Fix for-loop to cleanly iterate over the arguments<commit_after>// For reference on linking to C++ functions, see https://github.com/rust-lang/rust/issues/5853#issuecomment-44365672

#[cfg(target_family = "windows")]
#[allow(non_snake_case)]
mod Platform {
    pub mod Details {
        #[link(name = "vccorlib")]
        #[cfg(target_arch="x86_64")]
        extern "C" {
            // This generates invalid program output causing a crash when this function is called. See https://github.com/rust-lang/rust/issues/23216 for details.
            #[link_name = "?GetCmdArguments@Details@Platform@@YAPEAPEA_WPEAH@Z"]
            pub fn GetCmdArguments(argc : *mut ::libc::c_int) -> *const *const ::libc::wchar_t;
        }

        #[link(name = "vccorlib")]
        #[cfg(target_arch = "x86")]
        extern "C" {
            // This generates invalid program output causing a crash when this function is called. See https://github.com/rust-lang/rust/issues/23216 for details.
            #[link_name = "?GetCmdArguments@Details@Platform@@YAPAPA_WPAH@Z"]
            pub fn GetCmdArguments(argc : *mut ::libc::c_int) -> *const *const ::libc::wchar_t;
        }
    }
}

pub fn get_command_arguments(argc : ::libc::c_int) -> Vec<String> {
    let mut argc = argc;
    let argv = unsafe { Platform::Details::GetCmdArguments(&mut argc) };
    let mut arguments : Vec<String> = Vec::with_capacity(argc as usize);
    for arg in unsafe { ::std::slice::from_raw_parts(argv, argc as usize) }.into_iter() {
        let argument : &[::libc::wchar_t] = unsafe { ::std::slice::from_raw_parts(*arg, ::libc::wcslen(*arg) as usize) };
        arguments.push(String::from_utf16(unsafe { ::std::mem::transmute(argument) } ).unwrap())
    }
    arguments
}

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

    #[test]
    fn test_get_command_arguments() {
        let arguments = get_command_arguments(0);
        assert!(arguments.len() == 1);
        for argv in arguments {
            println!("{}", argv)
        }
    }
}<|endoftext|>


<commit_before>use provider::service::inline::InlineProvider;
use provider::service::shell::ShellProvider;

pub struct ServiceProvider {
    pub inline: Box<InlineProvider>,
    pub shell: Box<ShellProvider>,
}

pub mod error;
pub mod inline;
pub mod shell;
<commit_msg>Implement ServiceProvider.is_running()<commit_after>use provider::HandleFunc;
use provider::service::inline::InlineProvider;
use provider::service::shell::ShellProvider;

pub struct ServiceProvider {
    pub inline: Box<InlineProvider>,
    pub shell: Box<ShellProvider>,
}

impl ServiceProvider {
    pub fn new(i: Box<InlineProvider>, s: Box<ShellProvider>) -> ServiceProvider {
        ServiceProvider {
            inline: i,
            shell: s,
        }
    }

    pub fn is_running(&self, name: &'static str) -> Box<HandleFunc> {
        let i = self.inline.clone();
        let s = self.shell.clone();
        Box::new(HandleFunc {
            inline: Box::new(move || i.is_running(name)),
            shell: Box::new(move |b| s.is_running(name, b)),
        })
    }
}

pub mod error;
pub mod inline;
pub mod shell;
<|endoftext|>