<commit_before>use color::PuyoColor;
use column_puyo_list::ColumnPuyoList;
use field::{self, BitField, FieldHeight, FieldIsEmpty};
use std;

#[derive(Clone, Debug, PartialEq)]
pub struct CoreField {
    field: BitField,
    height: [i16; 8],
}

impl CoreField {
    pub fn new() -> CoreField {
        CoreField {
            field: BitField::new(),
            height: [0; 8],
        }
    }

    pub fn from_str(s: &str) -> CoreField {
        let mut cf = CoreField {
            field: BitField::from_str(s),
            height: [0; 8],
        };

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. 15 {
                if cf.is_empty(x, y) {
                    cf.height[x] = (y - 1) as i16;
                    break
                }
            }
        }

        cf
    }

    pub fn color(&self, x: usize, y: usize) -> PuyoColor {
        self.field.color(x, y)
    }

    pub fn height(&self, x: usize) -> usize {
        self.height[x] as usize
    }

    pub fn is_color(&self, x: usize, y: usize, c: PuyoColor) -> bool {
        self.field.is_color(x, y, c)
    }

    pub fn is_normal_color(&self, x: usize, y: usize) -> bool {
        self.field.is_normal_color(x, y)
    }

    pub fn is_empty(&self, x: usize, y: usize) -> bool {
        self.field.is_empty(x, y)
    }

    pub fn field(&self) -> &BitField {
        &self.field
    }

    pub fn is_connected(&self, x: usize, y: usize) -> bool {
        self.field.is_connected(x, y)
    }

    pub fn count_connected_max4(&self, x: usize, y: usize) -> usize {
        self.field.count_connected_max4(x, y)
    }

    pub fn count_connected_max4_with_color(&self, x: usize, y: usize, c: PuyoColor) -> usize {
        self.field.count_connected_max4_with_color(x, y, c)
    }

    pub fn drop_puyo_on_with_max_height(&mut self, x: usize, c: PuyoColor, max_height: usize) -> bool {
        debug_assert!(c != PuyoColor::EMPTY);
        debug_assert!(max_height <= 14);

        if self.height(x) >= std::cmp::min(13, max_height) {
            return false;
        }

        debug_assert!(self.color(x, self.height(x) + 1) == PuyoColor::EMPTY,
                      "x={} max_height={}", x, max_height);

        self.height[x] += 1;
        self.field.set_color(x, self.height[x] as usize, c);

        true
    }

    pub fn drop_column_puyo_list(&mut self, cpl: &ColumnPuyoList) -> bool {
        self.drop_column_puyo_list_with_max_height(cpl, 13)
    }

    pub fn drop_column_puyo_list_with_max_height(&mut self, cpl: &ColumnPuyoList, max_height: usize) -> bool {
        // check size
        for x in 1..7 {
            if self.height(x) + cpl.size_on(x) > max_height {
                return false;
            }
        }

        for x in 1..7 {
            let s = cpl.size_on(x);
            for i in 0..s {
                self.height[x] += 1;
                let c = cpl.get(x, i);
                let h = self.height(x);
                self.field.set_color(x, h, c);
            }
        }

        true
    }
}

impl FieldHeight for CoreField {
    fn height(&self, x: usize) -> usize {
        CoreField::height(self, x)
    }
}

impl FieldIsEmpty for CoreField {
    fn is_empty(&self, x: usize, y: usize) -> bool {
        CoreField::is_empty(self, x, y)
    }
}

#[cfg(test)]
mod tests {
    use super::CoreField;
    use color::PuyoColor;
    use column_puyo_list::ColumnPuyoList;
    use field;

    #[test]
    fn test_constructor() {
        let cf = CoreField::new();

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. field::HEIGHT + 1 {
                assert!(cf.is_empty(x, y));
                assert!(cf.is_color(x, y, PuyoColor::EMPTY));
                assert_eq!(PuyoColor::EMPTY, cf.color(x, y));
            }
        }

        for x in 1 .. field::WIDTH + 1 {
            assert_eq!(0, cf.height(x));
        }
    }

    #[test]
    fn test_from_str() {
        let cf = CoreField::from_str(concat!(
            "R.....",
            "RRRB.."));

        assert_eq!(PuyoColor::WALL, cf.color(0, 1));
        assert_eq!(PuyoColor::RED, cf.color(1, 1));
        assert_eq!(PuyoColor::RED, cf.color(2, 1));
        assert_eq!(PuyoColor::RED, cf.color(3, 1));
        assert_eq!(PuyoColor::BLUE, cf.color(4, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(5, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(6, 1));
        assert_eq!(PuyoColor::WALL, cf.color(7, 1));

        assert_eq!(2, cf.height(1));
        assert_eq!(1, cf.height(2));
        assert_eq!(1, cf.height(3));
        assert_eq!(1, cf.height(4));
        assert_eq!(0, cf.height(5));
        assert_eq!(0, cf.height(6));
    }

    #[test]
    fn test_drop_puyo_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert!(cf.drop_puyo_on_with_max_height(3, PuyoColor::BLUE, 13));
        assert!(cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(6, PuyoColor::BLUE, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }

    #[test]
    fn test_drop_column_puyo_list_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        let mut cpl = ColumnPuyoList::new();
        assert!(cpl.add(3, PuyoColor::BLUE));
        assert!(cpl.add(4, PuyoColor::BLUE));
        assert!(cf.drop_column_puyo_list_with_max_height(&cpl, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }
}
<commit_msg>Add CoreField::is_chigiri_decision<commit_after>use color::PuyoColor;
use column_puyo_list::ColumnPuyoList;
use decision::Decision;
use field::{self, BitField, FieldHeight, FieldIsEmpty};
use std;

#[derive(Clone, Debug, PartialEq)]
pub struct CoreField {
    field: BitField,
    height: [i16; 8],
}

impl CoreField {
    pub fn new() -> CoreField {
        CoreField {
            field: BitField::new(),
            height: [0; 8],
        }
    }

    pub fn from_str(s: &str) -> CoreField {
        let mut cf = CoreField {
            field: BitField::from_str(s),
            height: [0; 8],
        };

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. 15 {
                if cf.is_empty(x, y) {
                    cf.height[x] = (y - 1) as i16;
                    break
                }
            }
        }

        cf
    }

    pub fn color(&self, x: usize, y: usize) -> PuyoColor {
        self.field.color(x, y)
    }

    pub fn height(&self, x: usize) -> usize {
        self.height[x] as usize
    }

    pub fn is_color(&self, x: usize, y: usize, c: PuyoColor) -> bool {
        self.field.is_color(x, y, c)
    }

    pub fn is_normal_color(&self, x: usize, y: usize) -> bool {
        self.field.is_normal_color(x, y)
    }

    pub fn is_empty(&self, x: usize, y: usize) -> bool {
        self.field.is_empty(x, y)
    }

    pub fn field(&self) -> &BitField {
        &self.field
    }

    pub fn is_chigiri_decision(&self, decision: &Decision) -> bool {
        debug_assert!(decision.valid(), "decision {:?} should be valid", decision);
        let axis_x = decision.axis_x();
        let child_x = decision.child_x();
        if axis_x == child_x {
            return false;
        }

        self.height(axis_x) != self.height(child_x)
    }

    pub fn is_connected(&self, x: usize, y: usize) -> bool {
        self.field.is_connected(x, y)
    }

    pub fn count_connected_max4(&self, x: usize, y: usize) -> usize {
        self.field.count_connected_max4(x, y)
    }

    pub fn count_connected_max4_with_color(&self, x: usize, y: usize, c: PuyoColor) -> usize {
        self.field.count_connected_max4_with_color(x, y, c)
    }

    pub fn drop_puyo_on_with_max_height(&mut self, x: usize, c: PuyoColor, max_height: usize) -> bool {
        debug_assert!(c != PuyoColor::EMPTY);
        debug_assert!(max_height <= 14);

        if self.height(x) >= std::cmp::min(13, max_height) {
            return false;
        }

        debug_assert!(self.color(x, self.height(x) + 1) == PuyoColor::EMPTY,
                      "x={} max_height={}", x, max_height);

        self.height[x] += 1;
        self.field.set_color(x, self.height[x] as usize, c);

        true
    }

    pub fn drop_column_puyo_list(&mut self, cpl: &ColumnPuyoList) -> bool {
        self.drop_column_puyo_list_with_max_height(cpl, 13)
    }

    pub fn drop_column_puyo_list_with_max_height(&mut self, cpl: &ColumnPuyoList, max_height: usize) -> bool {
        // check size
        for x in 1..7 {
            if self.height(x) + cpl.size_on(x) > max_height {
                return false;
            }
        }

        for x in 1..7 {
            let s = cpl.size_on(x);
            for i in 0..s {
                self.height[x] += 1;
                let c = cpl.get(x, i);
                let h = self.height(x);
                self.field.set_color(x, h, c);
            }
        }

        true
    }
}

impl FieldHeight for CoreField {
    fn height(&self, x: usize) -> usize {
        CoreField::height(self, x)
    }
}

impl FieldIsEmpty for CoreField {
    fn is_empty(&self, x: usize, y: usize) -> bool {
        CoreField::is_empty(self, x, y)
    }
}

#[cfg(test)]
mod tests {
    use super::CoreField;
    use color::PuyoColor;
    use column_puyo_list::ColumnPuyoList;
    use decision::Decision;
    use field;

    #[test]
    fn test_constructor() {
        let cf = CoreField::new();

        for x in 1 .. field::WIDTH + 1 {
            for y in 1 .. field::HEIGHT + 1 {
                assert!(cf.is_empty(x, y));
                assert!(cf.is_color(x, y, PuyoColor::EMPTY));
                assert_eq!(PuyoColor::EMPTY, cf.color(x, y));
            }
        }

        for x in 1 .. field::WIDTH + 1 {
            assert_eq!(0, cf.height(x));
        }
    }

    #[test]
    fn test_from_str() {
        let cf = CoreField::from_str(concat!(
            "R.....",
            "RRRB.."));

        assert_eq!(PuyoColor::WALL, cf.color(0, 1));
        assert_eq!(PuyoColor::RED, cf.color(1, 1));
        assert_eq!(PuyoColor::RED, cf.color(2, 1));
        assert_eq!(PuyoColor::RED, cf.color(3, 1));
        assert_eq!(PuyoColor::BLUE, cf.color(4, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(5, 1));
        assert_eq!(PuyoColor::EMPTY, cf.color(6, 1));
        assert_eq!(PuyoColor::WALL, cf.color(7, 1));

        assert_eq!(2, cf.height(1));
        assert_eq!(1, cf.height(2));
        assert_eq!(1, cf.height(3));
        assert_eq!(1, cf.height(4));
        assert_eq!(0, cf.height(5));
        assert_eq!(0, cf.height(6));
    }

    #[test]
    fn test_drop_puyo_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert!(cf.drop_puyo_on_with_max_height(3, PuyoColor::BLUE, 13));
        assert!(cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(4, PuyoColor::BLUE, 13));
        assert!(!cf.drop_puyo_on_with_max_height(6, PuyoColor::BLUE, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }

    #[test]
    fn test_drop_column_puyo_list_on() {
        let mut cf = CoreField::from_str(concat!(
            ".....R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        let mut cpl = ColumnPuyoList::new();
        assert!(cpl.add(3, PuyoColor::BLUE));
        assert!(cpl.add(4, PuyoColor::BLUE));
        assert!(cf.drop_column_puyo_list_with_max_height(&cpl, 13));

        let expected = CoreField::from_str(concat!(
            "..BB.R", // 13
            "OOOOOR", // 12
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 8
            "OOOOOO",
            "OOOOOO",
            "OOOOOO",
            "OOOOOO", // 4
            "OOOOOO",
            "OOOOOO",
            "OOOOOO"));

        assert_eq!(cf, expected);
    }

    #[test]
    fn test_is_chigiri_decision_1() {
        let cf = CoreField::new();

        assert!(!cf.is_chigiri_decision(&Decision::new(3, 0)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 1)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 2)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 3)));
    }

    #[test]
    fn test_is_chigiri_decision_2() {
        let cf = CoreField::from_str("..O...");

        assert!(!cf.is_chigiri_decision(&Decision::new(3, 0)));
        assert!(cf.is_chigiri_decision(&Decision::new(3, 1)));
        assert!(!cf.is_chigiri_decision(&Decision::new(3, 2)));
        assert!(cf.is_chigiri_decision(&Decision::new(3, 3)));
    }
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Debug, PartialEq)]
pub struct Clock;

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        unimplemented!(
            "Construct a new Clock from {} hours and {} minutes",
            hours,
            minutes
        );
    }

    pub fn add_minutes(self, minutes: i32) -> Self {
        unimplemented!("Add {} minutes to existing Clock time", minutes);
    }
}

impl fmt::Display for Clock {
    fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
        unimplemented!("Implement 'hh:mm' display format for the Clock.");
    }
}
<commit_msg>Removed traits implementation<commit_after>pub struct Clock;

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        unimplemented!(
            "Construct a new Clock from {} hours and {} minutes",
            hours,
            minutes
        );
    }

    pub fn add_minutes(self, minutes: i32) -> Self {
        unimplemented!("Add {} minutes to existing Clock time", minutes);
    }
}
<|endoftext|>


<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 book::{Book, Number};
use error::{Error,Result};
use token::Token;
use zipper::Zipper;
use escape::escape_tex;

use std::path::Path;
use std::iter::Iterator;

use mustache;

/// LaTeX renderer
pub struct LatexRenderer<'a> {
    book: &'a Book,
    current_chapter: Number,
}

impl<'a> LatexRenderer<'a> {
    /// Creates new LatexRenderer
    pub fn new(book: &'a Book) -> LatexRenderer<'a> {
        LatexRenderer {
            book: book,
            current_chapter: Number::Default,
        }
    }

    /// Render pdf in a file
    pub fn render_pdf(&mut self) -> Result<String> {
        if let Ok(pdf_file) = self.book.get_str("output.pdf") {
            let base_file = try!(Path::new(pdf_file).file_stem().ok_or(Error::Render("could not stem pdf filename")));
            let tex_file = format!("{}.tex", base_file.to_str().unwrap());
            let content = try!(self.render_book());
            let mut zipper = try!(Zipper::new(self.book.get_str("temp_dir").unwrap()));
            try!(zipper.write(&tex_file, &content.as_bytes(), false));
            zipper.generate_pdf(&self.book.get_str("tex.command").unwrap(), &tex_file, pdf_file)
        } else {
            Err(Error::Render("no output pdf file specified in book config"))
        }
    }

    /// Render latex in a string
    pub fn render_book(&mut self) -> Result<String> {
        let mut content = String::from("");
        for &(n, ref v) in &self.book.chapters {
            self.current_chapter = n;
            content.push_str(&self.render_vec(v, true));
        }

        let tex_lang = String::from(match self.book.get_str("lang").unwrap() {
            "en" => "english",
            "fr" => "francais",
            _ => {
                self.book.debug(&format!("Warning: can't find a tex equivalent for lang '{}', fallbacking on english", self.book.get_str("lang").unwrap()));
                "english"
            }
        });

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

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

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

    fn parse_token(&mut self, token: &Token, escape: bool) -> String {
        match *token {
            Token::Str(ref text) => if escape {escape_tex(text)} else {text.clone()},
            Token::Paragraph(ref vec) => format!("{}\n\n",
                                                 self.render_vec(vec, escape)),
            Token::Header(n, ref vec) => {
                let mut content = String::new();
                if n == 1 && self.current_chapter == Number::Hidden {
                    return String::new();
                }
                if n == 1 {
                    if let Number::Specified(n) = self.current_chapter {
                        content.push_str(r"\setcounter{chapter}{");
                        content.push_str(&format!("{}", n - 1));
                        content.push_str("}\n");
                    }
                }
                match n {
                    1 => content.push_str(r"\chapter"),
                    2 => content.push_str(r"\section"),
                    3 => content.push_str(r"\subsection"),
                    4 => content.push_str(r"\subsubsection"),
                    _ => panic!("header level not implemented"),
                }
                if self.current_chapter == Number::Unnumbered {
                    content.push_str("*");
                }
                content.push_str(r"{");
                content.push_str(&self.render_vec(vec, true));
                content.push_str("}\n");
                content
            },
            Token::Emphasis(ref vec) => format!("\\emph{{{}}}", self.render_vec(vec, escape)),
            Token::Strong(ref vec) => format!("\\textbf{{{}}}", self.render_vec(vec, escape)),
            Token::Code(ref vec) => format!("\\texttt{{{}}}", self.render_vec(vec, escape)),
            Token::BlockQuote(ref vec) => format!("\\begin{{quotation}}\n{}\\end{{quotation}}\n", self.render_vec(vec, escape)),
            Token::CodeBlock(_, ref vec) => format!("\\begin{{verbatim}}\n{}\\end{{verbatim}}\n", self.render_vec(vec, false)),
            Token::Rule => String::from("\\HRule\n"),
            Token::SoftBreak => String::from(" "),
            Token::HardBreak => String::from("\n"),
            Token::List(ref vec) => format!("\\begin{{itemize}}\n{}\\end{{itemize}}", self.render_vec(vec, escape)),
            Token::OrderedList(_, ref vec) => format!("\\begin{{enumerate}}\n{}\\end{{enumerate}}\n", self.render_vec(vec, escape)),
            Token::Item(ref vec) => format!("\\item {}\n", self.render_vec(vec, escape)),
            Token::Link(ref url, _, ref vec) => if self.book.get_bool("tex.links_as_footnotes").unwrap() {
                format!("\\href{{{}}}{{{}}}\\footnote{{\\url{{{}}}}}", escape_tex(url), self.render_vec(vec, escape), escape_tex(url))
            } else {
                format!("\\href{{{}}}{{{}}}", escape_tex(url), self.render_vec(vec, escape))
            },
            Token::Image(_, _, _) => {
                self.book.debug("warning: including images is not yet supported for tex output");
                String::from(" ")
            },
            Token::Footnote(ref vec) => format!("\\footnote{{{}}}", self.render_vec(vec, escape)),
            Token::Table(n, ref vec) => {
                let mut cols = String::new();
                for _ in 0..n {
                    cols.push_str("|c");
                }
                cols.push_str("|");
                format!("\\begin{{center}}
\\begin{{tabular}}{{{}}}
\\hline
{}
\\hline
\\end{{tabular}}
\\end{{center}}\n\n", cols, self.render_vec(vec, escape))
            },
            Token::TableRow(ref vec) | Token::TableHead(ref vec) => {
                let mut res:String = vec.iter().map(|v| {self.parse_token(v, escape)})
                    .collect::<Vec<_>>()
                    .join(" & ");
                res.push_str("\\\\ \n");
                if let Token::TableHead(_) = *token {
                    res.push_str("\\hline\n");
                }
                res
            }
            Token::TableCell(ref vec) => self.render_vec(vec, escape),
        }
    }
}
<commit_msg>latex rendering now handles headers up to level 6<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 book::{Book, Number};
use error::{Error,Result};
use token::Token;
use zipper::Zipper;
use escape::escape_tex;

use std::path::Path;
use std::iter::Iterator;

use mustache;

/// LaTeX renderer
pub struct LatexRenderer<'a> {
    book: &'a Book,
    current_chapter: Number,
}

impl<'a> LatexRenderer<'a> {
    /// Creates new LatexRenderer
    pub fn new(book: &'a Book) -> LatexRenderer<'a> {
        LatexRenderer {
            book: book,
            current_chapter: Number::Default,
        }
    }

    /// Render pdf in a file
    pub fn render_pdf(&mut self) -> Result<String> {
        if let Ok(pdf_file) = self.book.get_str("output.pdf") {
            let base_file = try!(Path::new(pdf_file).file_stem().ok_or(Error::Render("could not stem pdf filename")));
            let tex_file = format!("{}.tex", base_file.to_str().unwrap());
            let content = try!(self.render_book());
            let mut zipper = try!(Zipper::new(self.book.get_str("temp_dir").unwrap()));
            try!(zipper.write(&tex_file, &content.as_bytes(), false));
            zipper.generate_pdf(&self.book.get_str("tex.command").unwrap(), &tex_file, pdf_file)
        } else {
            Err(Error::Render("no output pdf file specified in book config"))
        }
    }

    /// Render latex in a string
    pub fn render_book(&mut self) -> Result<String> {
        let mut content = String::from("");
        for &(n, ref v) in &self.book.chapters {
            self.current_chapter = n;
            content.push_str(&self.render_vec(v, true));
        }

        let tex_lang = String::from(match self.book.get_str("lang").unwrap() {
            "en" => "english",
            "fr" => "francais",
            _ => {
                self.book.debug(&format!("Warning: can't find a tex equivalent for lang '{}', fallbacking on english", self.book.get_str("lang").unwrap()));
                "english"
            }
        });

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

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

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

    fn parse_token(&mut self, token: &Token, escape: bool) -> String {
        match *token {
            Token::Str(ref text) => if escape {escape_tex(text)} else {text.clone()},
            Token::Paragraph(ref vec) => format!("{}\n\n",
                                                 self.render_vec(vec, escape)),
            Token::Header(n, ref vec) => {
                let mut content = String::new();
                if n == 1 && self.current_chapter == Number::Hidden {
                    return String::new();
                }
                if n == 1 {
                    if let Number::Specified(n) = self.current_chapter {
                        content.push_str(r"\setcounter{chapter}{");
                        content.push_str(&format!("{}", n - 1));
                        content.push_str("}\n");
                    }
                }
                match n {
                    1 => content.push_str(r"\chapter"),
                    2 => content.push_str(r"\section"),
                    3 => content.push_str(r"\subsection"),
                    4 => content.push_str(r"\subsubsection"),
                    _ => content.push_str(r"\paragraph"),
                }
                if self.current_chapter == Number::Unnumbered {
                    content.push_str("*");
                }
                content.push_str(r"{");
                content.push_str(&self.render_vec(vec, true));
                content.push_str("}\n");
                content
            },
            Token::Emphasis(ref vec) => format!("\\emph{{{}}}", self.render_vec(vec, escape)),
            Token::Strong(ref vec) => format!("\\textbf{{{}}}", self.render_vec(vec, escape)),
            Token::Code(ref vec) => format!("\\texttt{{{}}}", self.render_vec(vec, escape)),
            Token::BlockQuote(ref vec) => format!("\\begin{{quotation}}\n{}\\end{{quotation}}\n", self.render_vec(vec, escape)),
            Token::CodeBlock(_, ref vec) => format!("\\begin{{verbatim}}\n{}\\end{{verbatim}}\n", self.render_vec(vec, false)),
            Token::Rule => String::from("\\HRule\n"),
            Token::SoftBreak => String::from(" "),
            Token::HardBreak => String::from("\n"),
            Token::List(ref vec) => format!("\\begin{{itemize}}\n{}\\end{{itemize}}", self.render_vec(vec, escape)),
            Token::OrderedList(_, ref vec) => format!("\\begin{{enumerate}}\n{}\\end{{enumerate}}\n", self.render_vec(vec, escape)),
            Token::Item(ref vec) => format!("\\item {}\n", self.render_vec(vec, escape)),
            Token::Link(ref url, _, ref vec) => if self.book.get_bool("tex.links_as_footnotes").unwrap() {
                format!("\\href{{{}}}{{{}}}\\footnote{{\\url{{{}}}}}", escape_tex(url), self.render_vec(vec, escape), escape_tex(url))
            } else {
                format!("\\href{{{}}}{{{}}}", escape_tex(url), self.render_vec(vec, escape))
            },
            Token::Image(_, _, _) => {
                self.book.debug("warning: including images is not yet supported for tex output");
                String::from(" ")
            },
            Token::Footnote(ref vec) => format!("\\footnote{{{}}}", self.render_vec(vec, escape)),
            Token::Table(n, ref vec) => {
                let mut cols = String::new();
                for _ in 0..n {
                    cols.push_str("|c");
                }
                cols.push_str("|");
                format!("\\begin{{center}}
\\begin{{tabular}}{{{}}}
\\hline
{}
\\hline
\\end{{tabular}}
\\end{{center}}\n\n", cols, self.render_vec(vec, escape))
            },
            Token::TableRow(ref vec) | Token::TableHead(ref vec) => {
                let mut res:String = vec.iter().map(|v| {self.parse_token(v, escape)})
                    .collect::<Vec<_>>()
                    .join(" & ");
                res.push_str("\\\\ \n");
                if let Token::TableHead(_) = *token {
                    res.push_str("\\hline\n");
                }
                res
            }
            Token::TableCell(ref vec) => self.render_vec(vec, escape),
        }
    }
}
<|endoftext|>


<commit_before>use core::raw::Slice;

use self::syscalls::wait;

#[derive(Clone,Copy)]
struct Chunk {
    inuse: bool,
    slice: Slice<u8>
}

struct App {
    mem: Slice<u8>,
    offset: usize,
    chunks: [Option<Chunk>; 100]
}

static mut app : *mut App = 0 as *mut App;

pub fn _start(mem_start: *mut u8, mem_size: usize) {
    let myapp = unsafe {
        app = mem_start as *mut App;
        &mut *app
    };
    myapp.mem = Slice { data: mem_start, len: mem_size };
    myapp.offset = 0;
    myapp.chunks = [None; 100];

    init();

    loop {
        wait();
    }
}

fn init(){
}

struct Box<T: ?Sized>{ pointer: *mut T }

impl<T> Box<T> {

    fn new(x: T) -> Box<T> {
        use core::mem;
        let myapp = unsafe { &mut *app };
        let size = mem::size_of::<T>();

        // First, see if there is an available chunk of the right size
        for chunk in myapp.chunks.iter_mut() {
            match *chunk {
                Some(mut chunk) => {
                    if !chunk.inuse && chunk.slice.len >= size {
                        chunk.inuse = true;
                        return Box { pointer: chunk.slice.data as *mut T };
                    }
                },
                None => { }
            }
        }

        // No existing chunks match, so allocate a new one
        match myapp.chunks.iter_mut().filter(|c| c.is_none()).next() {
            Some(slot) => {
                let chunk = Chunk {
                    slice: Slice {
                        data: unsafe {
                            myapp.mem.data.offset(myapp.offset as isize)
                        },
                        len: size
                    },
                    inuse: true
                };
                myapp.offset += size;
                *slot = Some(chunk);
                Box{ pointer: chunk.slice.data as *mut T }
            },
            None => {
                panic!("OOM")
            }
        }
    }
}

mod syscalls {

    #[allow(improper_ctypes)]
    extern {
        fn __allow(driver_num: usize, allownum: usize, ptr: *mut (), len: usize) -> isize;
        fn __subscribe(driver_num: usize, subnum: usize, cb: usize) -> isize;
        fn __command(driver_num: usize, cmdnum: usize, arg1: usize) -> isize;
        fn __wait() -> isize;
    }

    pub fn allow(driver_num: usize, allownum: usize, ptr: *mut (), len: usize) -> isize {
        unsafe {
            __allow(driver_num, allownum, ptr, len)
        }
    }

    pub fn command(driver_num: usize, cmdnum: usize, arg1: usize) -> isize {
        unsafe {
            __command(driver_num, cmdnum, arg1)
        }
    }

    pub fn subscribe(driver_num: usize, cmdnum: usize, callback: usize) -> isize {
        unsafe {
            __subscribe(driver_num, cmdnum, callback)
        }
    }

    pub fn wait() -> isize {
        unsafe {
            __wait()
        }
    }
}

mod tmp006 {
    use super::syscalls::{command, subscribe};

    pub fn enable_tmp006() {
        command(2, 0, 0);
    }

    pub fn subscribe_temperature(f: fn(i16)) {
        subscribe(2, 0, f as usize);
    }
}

mod console {
    use super::syscalls::{allow, command, subscribe};

    pub fn putc(c: char) {
        command(0, 0, c as usize);
    }

    pub fn subscribe_read_line(buf: *mut u8, len: usize,
                               f: fn(usize, *mut u8)) -> isize {
        let res =  allow(0, 0, buf as *mut (), len);
        if res < 0 {
            res
        } else {
            subscribe(0, 0, f as usize)
        }
    }

    pub fn subscribe_write_done(f: fn()) -> isize {
        subscribe(0, 1, f as usize)
    }
}

mod gpio {
    use super::syscalls::command;

    pub fn enable_pin(pin: usize) {
        command(1, 0, pin);
    }

    pub fn set_pin(pin: usize) {
        command(1, 2, pin);
    }

    pub fn clear_pin(pin: usize) {
        command(1, 3, pin);
    }

    pub fn toggle_pin(pin: usize) {
        command(1, 4, pin);
    }
}

<commit_msg>checkpoint<commit_after>use core::fmt::{self, Write};
use core::raw::Slice;
use core::ops::{Deref,DerefMut};

use self::syscalls::wait;

#[derive(Clone,Copy)]
struct Chunk {
    inuse: bool,
    slice: Slice<u8>
}

struct App {
    mem: Slice<u8>,
    offset: usize,
    chunks: [*mut Chunk; 100]
}

static mut app : *mut App = 0 as *mut App;

pub fn _start(mem_start: *mut u8, mem_size: usize) {
    let myapp = unsafe {
        app = mem_start as *mut App;
        &mut *app
    };
    myapp.mem = Slice { data: mem_start, len: mem_size };
    myapp.offset = 0;
    myapp.chunks = [0 as *mut Chunk; 100];

    init();

    loop {
        wait();
    }
}

fn dummy() {}

fn init() {
    use self::console::{puts, subscribe_write_done};
    //print(format_args!("Welcome to Tock\r\n"));
    puts("Welcome to Tock\r\n");
}

struct Box<T: ?Sized>{ pointer: *mut T }

impl<T> Box<T> {

    pub unsafe fn uninitialized(size: usize) -> Box<T> {
        use core::mem;
        unsafe {
            let myapp = &mut *app;

            // First, see if there is an available chunk of the right size
            for chunk in myapp.chunks.iter_mut().filter(|c| !c.is_null()) {
                let c = &mut **chunk;
                if !c.inuse && c.slice.len >= size {
                    c.inuse = true;
                    return Box { pointer: c.slice.data as *mut T };
                }
            }

            // No existing chunks match, so allocate a new one
            match myapp.chunks.iter_mut().filter(|c| c.is_null()).next() {
                Some(slot) => {
                    let freemem = myapp.mem.data.offset(myapp.offset as isize);
                    let chunk = &mut *(freemem as *mut Chunk);
                    myapp.offset += mem::size_of::<Chunk>();

                    chunk.slice = Slice {
                        data: unsafe {
                            myapp.mem.data.offset(myapp.offset as isize)
                        },
                        len: size
                    };
                    myapp.offset += size;

                    chunk.inuse = true;
                    *slot = chunk;
                    let data = chunk.slice.data as *mut T;
                    Box{ pointer: data }
                },
                None => {
                    panic!("OOM")
                }
            }
        }
    }

    pub fn new(x: T) -> Box<T> {
        use core::mem;
        let size = mem::size_of::<T>();
        let mut d = unsafe { Self::uninitialized(size) };
        *d = x;
        d
    }
}

impl<T> Deref for Box<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe {
            &*self.pointer
        }
    }
}

impl<T> DerefMut for Box<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe {
            &mut *self.pointer
        }
    }
}

impl<T: ?Sized> Drop for Box<T> {
    fn drop(&mut self) {
        unsafe {
            use core::mem;
            let chunk_size = mem::size_of::<Chunk>() as isize;
            let chunk = (self.pointer as *mut T as *mut u8)
                            .offset(0 - chunk_size) as *mut Chunk;
            (&mut *chunk).inuse = false;
        }
    }
}

unsafe fn uninitialized_box_slice<T>(size: usize) -> Box<&'static mut [T]> {
    use core::mem;
    use core::slice;
    let slice_size = mem::size_of::<Slice<u8>>();
    let mut bx : Box<Slice<u8>> =
        Box::uninitialized(slice_size + size * mem::size_of::<T>());
    bx.len = size;
    bx.data = (bx.pointer as *const u8).offset(slice_size as isize);
    mem::transmute(bx)
}

pub struct String { bx: Option<Box<&'static mut [u8]>> }

impl String {
    pub fn new(x: &str) -> String {
        if x.len() == 0 {
            return String { bx: None };
        }
        unsafe {
            let mut slice = uninitialized_box_slice(x.len());
            for (i,c) in x.bytes().enumerate() {
                slice[i] = c;
            }
            String { bx: Some(slice) }
        }
    }

    pub fn len(&self) -> usize {
        self.bx.as_ref().map(|b| b.len()).unwrap_or(0)
    }

    pub fn as_str(&self) -> &str {
        use core::mem;
        use core::raw::Repr;

        match self.bx.as_ref() {
            Some(bx) => unsafe {
                mem::transmute((*bx.pointer).repr())
            },
            None => ""
        }
    }
}

impl Write for String {
    fn write_char(&mut self, c: char) -> fmt::Result {
        let charlen = c.len_utf8();
        let oldlen = self.len();
        let mut newbox = unsafe { uninitialized_box_slice(oldlen + charlen) };

        self.bx.as_ref().map(|bx| {
            for (i, c) in bx.iter().enumerate() {
                newbox[i] = *c;
            }
        });

        match charlen {
            1 => newbox[oldlen] = c as u8,
            len => {
                c.encode_utf8(&mut newbox[oldlen..]);
            }
        }

        self.bx = Some(newbox);
        Ok(())
    }

    fn write_str(&mut self, s: &str) -> fmt::Result {
        let oldlen = self.len();
        let mut newbox = unsafe { uninitialized_box_slice(oldlen + s.len()) };

        self.bx.as_ref().map(|bx| {
            for (i, c) in bx.iter().enumerate() {
                newbox[i] = *c;
            }
        });

        for (i,c) in s.bytes().enumerate() {
            newbox[i + oldlen] = c;
        }

        self.bx = Some(newbox);

        Ok(())
    }
}

pub trait ToString {
    fn to_string(&self) -> String;
}

impl<T: fmt::Display + ?Sized> ToString for T {
    fn to_string(&self) -> String {
        use core::fmt::Write;
        let mut buf = String::new("");
        let _ = buf.write_fmt(format_args!("{}", self));
        buf
    }
}

mod syscalls {

    #[allow(improper_ctypes)]
    extern {
        fn __allow(driver_num: usize, allownum: usize, ptr: *mut (), len: usize) -> isize;
        fn __subscribe(driver_num: usize, subnum: usize, cb: usize) -> isize;
        fn __command(driver_num: usize, cmdnum: usize, arg1: usize) -> isize;
        fn __wait() -> isize;
    }

    pub fn allow(driver_num: usize, allownum: usize, ptr: *mut (), len: usize) -> isize {
        unsafe {
            __allow(driver_num, allownum, ptr, len)
        }
    }

    pub fn command(driver_num: usize, cmdnum: usize, arg1: usize) -> isize {
        unsafe {
            __command(driver_num, cmdnum, arg1)
        }
    }

    pub fn subscribe(driver_num: usize, cmdnum: usize, callback: usize) -> isize {
        unsafe {
            __subscribe(driver_num, cmdnum, callback)
        }
    }

    pub fn wait() -> isize {
        unsafe {
            __wait()
        }
    }
}

mod tmp006 {
    use super::syscalls::{command, subscribe};

    pub fn enable_tmp006() {
        command(2, 0, 0);
    }

    pub fn subscribe_temperature(f: fn(i16)) {
        subscribe(2, 0, f as usize);
    }
}

mod console {
    use core::mem;
    use super::syscalls::*;
    use super::*;

    pub fn putc(c: char) {
        command(0, 0, c as usize);
    }

    pub fn print(args: ::core::fmt::Arguments) {
        use core::fmt::Write;
        let mut buf = String::new("");
        buf.write_fmt(args);
        puts("hello");
    }

    pub fn puts(string: &str) {
        unsafe {
            let bstr = String::new(string);
            allow(0, 1, bstr.as_str() as *const str as *mut (), string.len());
            mem::forget(bstr);
            command(0, 1, 0);
        }
    }

    pub fn subscribe_read_line(buf: *mut u8, len: usize,
                               f: fn(usize, *mut u8)) -> isize {
        let res =  allow(0, 0, buf as *mut (), len);
        if res < 0 {
            res
        } else {
            subscribe(0, 0, f as usize)
        }
    }

    pub fn subscribe_write_done(f: fn()) -> isize {
        subscribe(0, 1, f as usize)
    }
}

mod gpio {
    use super::syscalls::command;

    pub fn enable_pin(pin: usize) {
        command(1, 0, pin);
    }

    pub fn set_pin(pin: usize) {
        command(1, 2, pin);
    }

    pub fn clear_pin(pin: usize) {
        command(1, 3, pin);
    }

    pub fn toggle_pin(pin: usize) {
        command(1, 4, pin);
    }
}

<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::counters::Metrics;
use libra_logger::{debug, error, info};
use std::{env, sync::Arc, thread, thread::JoinHandle, time::Duration};

const DEFAULT_PUSH_FREQUENCY_SECS: u64 = 15;

/// MetricsPusher provides a function to push a list of Metrics to a configurable
/// pushgateway endpoint.
pub struct MetricsPusher {
    metrics: Arc<dyn Metrics + Send + Sync>,
}

impl MetricsPusher {
    pub fn new(metrics: Arc<dyn Metrics + Send + Sync>) -> Self {
        Self { metrics }
    }

    fn run(self, push_metrics_endpoint: String, push_metrics_frequency_secs: u64) {
        loop {
            let mut data = String::new();
            for metric in self.metrics.get_metrics() {
                let metric_data = metric.get_push_metric_format();
                data.push_str(&metric_data);
            }
            debug!("Metrics sent to server:\n{}", data);
            let response = ureq::post(&push_metrics_endpoint)
                .timeout_connect(10_000)
                .send_string(&data);
            if let Some(error) = response.synthetic_error() {
                error!(
                    "Failed to push metrics to {}. Error: {}",
                    push_metrics_endpoint, error
                );
            }
            thread::sleep(Duration::from_secs(push_metrics_frequency_secs));
        }
    }

    /// start starts a new thread and periodically pushes the metrics to a pushgateway endpoint
    pub fn start(self) -> Option<JoinHandle<()>> {
        // eg value for PUSH_METRICS_ENDPOINT: "http://pushgatewar.server.com:9091/metrics/job/safety_rules"
        let push_metrics_endpoint = match env::var("PUSH_METRICS_ENDPOINT") {
            Ok(s) => s,
            Err(_) => {
                info!("PUSH_METRICS_ENDPOINT env var is not set. Skipping sending metrics.");
                return None;
            }
        };
        let push_metrics_frequency_secs = match env::var("PUSH_METRICS_FREQUENCY_SECS") {
            Ok(s) => match s.parse::<u64>() {
                Ok(i) => i,
                Err(_) => {
                    error!("Invalid value for PUSH_METRICS_FREQUENCY_SECS: {}", s);
                    return None;
                }
            },
            Err(_) => DEFAULT_PUSH_FREQUENCY_SECS,
        };
        info!(
            "Starting push metrics loop. Sending metrics to {} with a frequency of {} seconds",
            push_metrics_endpoint, push_metrics_frequency_secs
        );
        Some(thread::spawn(move || {
            self.run(push_metrics_endpoint, push_metrics_frequency_secs)
        }))
    }
}
<commit_msg>[push-metrics] Remove debug log of metrics<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::counters::Metrics;
use libra_logger::{error, info};
use std::{env, sync::Arc, thread, thread::JoinHandle, time::Duration};

const DEFAULT_PUSH_FREQUENCY_SECS: u64 = 15;

/// MetricsPusher provides a function to push a list of Metrics to a configurable
/// pushgateway endpoint.
pub struct MetricsPusher {
    metrics: Arc<dyn Metrics + Send + Sync>,
}

impl MetricsPusher {
    pub fn new(metrics: Arc<dyn Metrics + Send + Sync>) -> Self {
        Self { metrics }
    }

    fn run(self, push_metrics_endpoint: String, push_metrics_frequency_secs: u64) {
        loop {
            let mut data = String::new();
            for metric in self.metrics.get_metrics() {
                let metric_data = metric.get_push_metric_format();
                data.push_str(&metric_data);
            }
            let response = ureq::post(&push_metrics_endpoint)
                .timeout_connect(10_000)
                .send_string(&data);
            if let Some(error) = response.synthetic_error() {
                error!(
                    "Failed to push metrics to {}. Error: {}",
                    push_metrics_endpoint, error
                );
            }
            thread::sleep(Duration::from_secs(push_metrics_frequency_secs));
        }
    }

    /// start starts a new thread and periodically pushes the metrics to a pushgateway endpoint
    pub fn start(self) -> Option<JoinHandle<()>> {
        // eg value for PUSH_METRICS_ENDPOINT: "http://pushgatewar.server.com:9091/metrics/job/safety_rules"
        let push_metrics_endpoint = match env::var("PUSH_METRICS_ENDPOINT") {
            Ok(s) => s,
            Err(_) => {
                info!("PUSH_METRICS_ENDPOINT env var is not set. Skipping sending metrics.");
                return None;
            }
        };
        let push_metrics_frequency_secs = match env::var("PUSH_METRICS_FREQUENCY_SECS") {
            Ok(s) => match s.parse::<u64>() {
                Ok(i) => i,
                Err(_) => {
                    error!("Invalid value for PUSH_METRICS_FREQUENCY_SECS: {}", s);
                    return None;
                }
            },
            Err(_) => DEFAULT_PUSH_FREQUENCY_SECS,
        };
        info!(
            "Starting push metrics loop. Sending metrics to {} with a frequency of {} seconds",
            push_metrics_endpoint, push_metrics_frequency_secs
        );
        Some(thread::spawn(move || {
            self.run(push_metrics_endpoint, push_metrics_frequency_secs)
        }))
    }
}
<|endoftext|>


<commit_before>//! Mappings of objects received from the API, with optional helper methods for
//! ease of use.
//!
//! Models can optionally have additional helper methods compiled, by enabling
//! the `model` feature.

#[macro_use]
mod utils;

pub mod event;
pub mod permissions;

mod channel;
mod error;
mod gateway;
mod guild;
mod invite;
mod misc;
mod user;
mod voice;
mod webhook;

pub use self::channel::*;
pub use self::error::Error as ModelError;
pub use self::gateway::*;
pub use self::guild::*;
pub use self::invite::*;
pub use self::misc::*;
pub use self::permissions::Permissions;
pub use self::user::*;
pub use self::voice::*;
pub use self::webhook::*;

use chrono::NaiveDateTime;
use self::utils::*;
use serde::de::Visitor;
use std::collections::HashMap;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::sync::{Arc, RwLock};
use internal::prelude::*;

#[cfg(feature = "utils")]
use utils::Colour;

fn default_true() -> bool { true }

macro_rules! id_u64 {
    ($(#[$attr:meta] $name:ident;)*) => {
        $(
            #[$attr]
            #[derive(Copy, Clone, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
            #[allow(derive_hash_xor_eq)]
            pub struct $name(pub u64);

            impl $name {
                /// Retrieves the time that the Id was created at.
                pub fn created_at(&self) -> NaiveDateTime {
                    let offset = (self.0 >> 22) / 1000;

                    NaiveDateTime::from_timestamp(1_420_070_400 + offset as i64, 0)
                }
            }

            // This is a hack so that functions can accept `IntoIterator<Item=IdType>`, or `IntoIterator<Item=&IdType>`
            impl AsRef<$name> for $name {
                fn as_ref(&self) -> &Self {
                    self
                }
            }

            impl From<u64> for $name {
                fn from(id_as_u64: u64) -> $name {
                    $name(id_as_u64)
                }
            }

            impl PartialEq for $name {
                fn eq(&self, other: &Self) -> bool {
                    self.0 == other.0
                }
            }

            impl PartialEq<u64> for $name {
                fn eq(&self, u: &u64) -> bool {
                    self.0 == *u
                }
            }

            impl Display for $name {
                fn fmt(&self, f: &mut Formatter) -> FmtResult {
                    Display::fmt(&self.0, f)
                }
            }

            impl<'de> Deserialize<'de> for $name {
                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
                    deserializer.deserialize_u64(U64Visitor).map($name)
                }
            }
        )*
    }
}

id_u64! {
    /// An identifier for a Channel
    ChannelId;
    /// An identifier for an Emoji
    EmojiId;
    /// An identifier for a Guild
    GuildId;
    /// An identifier for an Integration
    IntegrationId;
    /// An identifier for a Message
    MessageId;
    /// An identifier for a Role
    RoleId;
    /// An identifier for a User
    UserId;
    /// An identifier for a [`Webhook`](struct.Webhook.html).
    WebhookId;
    /// An identifier for an audit log entry.
    AuditLogEntryId;
}

/// A container for guilds.
///
/// This is used to differentiate whether a guild itself can be used or whether
/// a guild needs to be retrieved from the cache.
#[allow(large_enum_variant)]
#[derive(Clone, Debug)]
pub enum GuildContainer {
    /// A guild which can have its contents directly searched.
    Guild(PartialGuild),
    /// A guild's id, which can be used to search the cache for a guild.
    Id(GuildId),
}

/// Information about a user's application. An application does not necessarily
/// have an associated bot user.
#[derive(Clone, Debug, Deserialize)]
pub struct ApplicationInfo {
    /// The bot user associated with the application. See [`BotApplication`] for
    /// more information.
    ///
    /// [`BotApplication`]: struct.BotApplication.html
    pub bot: Option<BotApplication>,
    /// Indicator of whether the bot is public.
    ///
    /// If a bot is public, anyone may invite it to their [`Guild`]. While a bot
    /// is private, only the owner may add it to a guild.
    ///
    /// [`Guild`]: struct.Guild.html
    #[serde(default = "default_true")]
    pub bot_public: bool,
    /// Indicator of whether the bot requires an OAuth2 code grant.
    pub bot_require_code_grant: bool,
    /// A description of the application, assigned by the application owner.
    pub description: String,
    /// A set of bitflags assigned to the application, which represent gated
    /// feature flags that have been enabled for the application.
    pub flags: Option<u64>,
    /// A hash pointing to the application's icon.
    ///
    /// This is not necessarily equivalent to the bot user's avatar.
    pub icon: Option<String>,
    /// The unique numeric Id of the application.
    pub id: UserId,
    /// The name assigned to the application by the application owner.
    pub name: String,
    /// A list of redirect URIs assigned to the application.
    pub redirect_uris: Vec<String>,
    /// A list of RPC Origins assigned to the application.
    pub rpc_origins: Vec<String>,
    /// The given secret to the application.
    ///
    /// This is not equivalent to the application's bot user's token.
    pub secret: String,
}

/// Information about an application with an application's bot user.
#[derive(Clone, Debug, Deserialize)]
pub struct BotApplication {
    /// The unique Id of the bot user.
    pub id: UserId,
    /// A hash of the avatar, if one is assigned.
    ///
    /// Can be used to generate a full URL to the avatar.
    pub avatar: Option<String>,
    /// Indicator of whether it is a bot.
    #[serde(default)]
    pub bot: bool,
    /// The discriminator assigned to the bot user.
    ///
    /// While discriminators are not unique, the `username#discriminator` pair
    /// is.
    pub discriminator: u16,
    /// The bot user's username.
    pub name: String,
    /// The token used to authenticate as the bot user.
    ///
    /// **Note**: Keep this information private, as untrusted sources can use it
    /// to perform any action with a bot user.
    pub token: String,
}

/// Information about the current application and its owner.
#[derive(Clone, Debug, Deserialize)]
pub struct CurrentApplicationInfo {
    pub description: String,
    pub icon: Option<String>,
    pub id: UserId,
    pub name: String,
    pub owner: User,
    #[serde(default)] pub rpc_origins: Vec<String>,
}

/// The name of a region that a voice server can be located in.
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub enum Region {
    #[serde(rename = "amsterdam")] Amsterdam,
    #[serde(rename = "brazil")] Brazil,
    #[serde(rename = "eu-central")] EuCentral,
    #[serde(rename = "eu-west")] EuWest,
    #[serde(rename = "frankfurt")] Frankfurt,
    #[serde(rename = "london")] London,
    #[serde(rename = "sydney")] Sydney,
    #[serde(rename = "us-central")] UsCentral,
    #[serde(rename = "us-east")] UsEast,
    #[serde(rename = "us-south")] UsSouth,
    #[serde(rename = "us-west")] UsWest,
    #[serde(rename = "vip-amsterdam")] VipAmsterdam,
    #[serde(rename = "vip-us-east")] VipUsEast,
    #[serde(rename = "vip-us-west")] VipUsWest,
}

impl Region {
    pub fn name(&self) -> &str {
        match *self {
            Region::Amsterdam => "amsterdam",
            Region::Brazil => "brazil",
            Region::EuCentral => "eu-central",
            Region::EuWest => "eu-west",
            Region::Frankfurt => "frankfurt",
            Region::London => "london",
            Region::Sydney => "sydney",
            Region::UsCentral => "us-central",
            Region::UsEast => "us-east",
            Region::UsSouth => "us-south",
            Region::UsWest => "us-west",
            Region::VipAmsterdam => "vip-amsterdam",
            Region::VipUsEast => "vip-us-east",
            Region::VipUsWest => "vip-us-west",
        }
    }
}

use serde::{Deserialize, Deserializer};
use std::result::Result as StdResult;

fn deserialize_sync_user<'de, D: Deserializer<'de>>(deserializer: D)
                                                    -> StdResult<Arc<RwLock<User>>, D::Error> {
    Ok(Arc::new(RwLock::new(User::deserialize(deserializer)?)))
}
<commit_msg>Add an and<commit_after>//! Mappings of objects received from the API, with optional helper methods for
//! ease of use.
//!
//! Models can optionally have additional helper methods compiled, by enabling
//! the `model` feature.

#[macro_use]
mod utils;

pub mod event;
pub mod permissions;

mod channel;
mod error;
mod gateway;
mod guild;
mod invite;
mod misc;
mod user;
mod voice;
mod webhook;

pub use self::channel::*;
pub use self::error::Error as ModelError;
pub use self::gateway::*;
pub use self::guild::*;
pub use self::invite::*;
pub use self::misc::*;
pub use self::permissions::Permissions;
pub use self::user::*;
pub use self::voice::*;
pub use self::webhook::*;

use chrono::NaiveDateTime;
use self::utils::*;
use serde::de::Visitor;
use std::collections::HashMap;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::sync::{Arc, RwLock};
use internal::prelude::*;

#[cfg(feature = "utils")]
use utils::Colour;

fn default_true() -> bool { true }

macro_rules! id_u64 {
    ($(#[$attr:meta] $name:ident;)*) => {
        $(
            #[$attr]
            #[derive(Copy, Clone, Debug, Eq, Hash, PartialOrd, Ord, Serialize)]
            #[allow(derive_hash_xor_eq)]
            pub struct $name(pub u64);

            impl $name {
                /// Retrieves the time that the Id was created at.
                pub fn created_at(&self) -> NaiveDateTime {
                    let offset = (self.0 >> 22) / 1000;

                    NaiveDateTime::from_timestamp(1_420_070_400 + offset as i64, 0)
                }
            }

            // This is a hack so that functions can accept `IntoIterator<Item=IdType>`, and or `IntoIterator<Item=&IdType>`
            impl AsRef<$name> for $name {
                fn as_ref(&self) -> &Self {
                    self
                }
            }

            impl From<u64> for $name {
                fn from(id_as_u64: u64) -> $name {
                    $name(id_as_u64)
                }
            }

            impl PartialEq for $name {
                fn eq(&self, other: &Self) -> bool {
                    self.0 == other.0
                }
            }

            impl PartialEq<u64> for $name {
                fn eq(&self, u: &u64) -> bool {
                    self.0 == *u
                }
            }

            impl Display for $name {
                fn fmt(&self, f: &mut Formatter) -> FmtResult {
                    Display::fmt(&self.0, f)
                }
            }

            impl<'de> Deserialize<'de> for $name {
                fn deserialize<D: Deserializer<'de>>(deserializer: D) -> StdResult<Self, D::Error> {
                    deserializer.deserialize_u64(U64Visitor).map($name)
                }
            }
        )*
    }
}

id_u64! {
    /// An identifier for a Channel
    ChannelId;
    /// An identifier for an Emoji
    EmojiId;
    /// An identifier for a Guild
    GuildId;
    /// An identifier for an Integration
    IntegrationId;
    /// An identifier for a Message
    MessageId;
    /// An identifier for a Role
    RoleId;
    /// An identifier for a User
    UserId;
    /// An identifier for a [`Webhook`](struct.Webhook.html).
    WebhookId;
    /// An identifier for an audit log entry.
    AuditLogEntryId;
}

/// A container for guilds.
///
/// This is used to differentiate whether a guild itself can be used or whether
/// a guild needs to be retrieved from the cache.
#[allow(large_enum_variant)]
#[derive(Clone, Debug)]
pub enum GuildContainer {
    /// A guild which can have its contents directly searched.
    Guild(PartialGuild),
    /// A guild's id, which can be used to search the cache for a guild.
    Id(GuildId),
}

/// Information about a user's application. An application does not necessarily
/// have an associated bot user.
#[derive(Clone, Debug, Deserialize)]
pub struct ApplicationInfo {
    /// The bot user associated with the application. See [`BotApplication`] for
    /// more information.
    ///
    /// [`BotApplication`]: struct.BotApplication.html
    pub bot: Option<BotApplication>,
    /// Indicator of whether the bot is public.
    ///
    /// If a bot is public, anyone may invite it to their [`Guild`]. While a bot
    /// is private, only the owner may add it to a guild.
    ///
    /// [`Guild`]: struct.Guild.html
    #[serde(default = "default_true")]
    pub bot_public: bool,
    /// Indicator of whether the bot requires an OAuth2 code grant.
    pub bot_require_code_grant: bool,
    /// A description of the application, assigned by the application owner.
    pub description: String,
    /// A set of bitflags assigned to the application, which represent gated
    /// feature flags that have been enabled for the application.
    pub flags: Option<u64>,
    /// A hash pointing to the application's icon.
    ///
    /// This is not necessarily equivalent to the bot user's avatar.
    pub icon: Option<String>,
    /// The unique numeric Id of the application.
    pub id: UserId,
    /// The name assigned to the application by the application owner.
    pub name: String,
    /// A list of redirect URIs assigned to the application.
    pub redirect_uris: Vec<String>,
    /// A list of RPC Origins assigned to the application.
    pub rpc_origins: Vec<String>,
    /// The given secret to the application.
    ///
    /// This is not equivalent to the application's bot user's token.
    pub secret: String,
}

/// Information about an application with an application's bot user.
#[derive(Clone, Debug, Deserialize)]
pub struct BotApplication {
    /// The unique Id of the bot user.
    pub id: UserId,
    /// A hash of the avatar, if one is assigned.
    ///
    /// Can be used to generate a full URL to the avatar.
    pub avatar: Option<String>,
    /// Indicator of whether it is a bot.
    #[serde(default)]
    pub bot: bool,
    /// The discriminator assigned to the bot user.
    ///
    /// While discriminators are not unique, the `username#discriminator` pair
    /// is.
    pub discriminator: u16,
    /// The bot user's username.
    pub name: String,
    /// The token used to authenticate as the bot user.
    ///
    /// **Note**: Keep this information private, as untrusted sources can use it
    /// to perform any action with a bot user.
    pub token: String,
}

/// Information about the current application and its owner.
#[derive(Clone, Debug, Deserialize)]
pub struct CurrentApplicationInfo {
    pub description: String,
    pub icon: Option<String>,
    pub id: UserId,
    pub name: String,
    pub owner: User,
    #[serde(default)] pub rpc_origins: Vec<String>,
}

/// The name of a region that a voice server can be located in.
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize)]
pub enum Region {
    #[serde(rename = "amsterdam")] Amsterdam,
    #[serde(rename = "brazil")] Brazil,
    #[serde(rename = "eu-central")] EuCentral,
    #[serde(rename = "eu-west")] EuWest,
    #[serde(rename = "frankfurt")] Frankfurt,
    #[serde(rename = "london")] London,
    #[serde(rename = "sydney")] Sydney,
    #[serde(rename = "us-central")] UsCentral,
    #[serde(rename = "us-east")] UsEast,
    #[serde(rename = "us-south")] UsSouth,
    #[serde(rename = "us-west")] UsWest,
    #[serde(rename = "vip-amsterdam")] VipAmsterdam,
    #[serde(rename = "vip-us-east")] VipUsEast,
    #[serde(rename = "vip-us-west")] VipUsWest,
}

impl Region {
    pub fn name(&self) -> &str {
        match *self {
            Region::Amsterdam => "amsterdam",
            Region::Brazil => "brazil",
            Region::EuCentral => "eu-central",
            Region::EuWest => "eu-west",
            Region::Frankfurt => "frankfurt",
            Region::London => "london",
            Region::Sydney => "sydney",
            Region::UsCentral => "us-central",
            Region::UsEast => "us-east",
            Region::UsSouth => "us-south",
            Region::UsWest => "us-west",
            Region::VipAmsterdam => "vip-amsterdam",
            Region::VipUsEast => "vip-us-east",
            Region::VipUsWest => "vip-us-west",
        }
    }
}

use serde::{Deserialize, Deserializer};
use std::result::Result as StdResult;

fn deserialize_sync_user<'de, D: Deserializer<'de>>(deserializer: D)
                                                    -> StdResult<Arc<RwLock<User>>, D::Error> {
    Ok(Arc::new(RwLock::new(User::deserialize(deserializer)?)))
}
<|endoftext|>


<commit_before>use clap::{SubCommand, App, Arg, ArgMatches};

use std::path::Path;
use std::marker::PhantomData;
use std::fs;
use std::net::SocketAddr;

use config::ConfigFile;
use node::NodeConfig;
use storage::Storage;
use helpers::generate_testnet_config;

pub struct GenerateCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

// TODO avoid unwraps here, implement Error chain

impl<'a, 'b> GenerateCommand<'a, 'b>
    where 'a: 'b
{
    pub fn new() -> App<'a, 'b> {
        SubCommand::with_name("generate")
            .about("Generates genesis configuration")
            .arg(Arg::with_name("OUTPUT_DIR")
                     .short("o")
                     .long("output-dir")
                     .value_name("OUTPUT_DIR")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("START_PORT")
                     .short("p")
                     .long("start-port")
                     .value_name("START_PORT")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("COUNT")
                     .help("Validators count")
                     .required(true)
                     .index(1))
    }

    pub fn output_dir(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("OUTPUT_DIR").unwrap())
    }

    pub fn validators_count(matches: &'a ArgMatches<'a>) -> u8 {
        matches.value_of("COUNT").unwrap().parse().unwrap()
    }

    pub fn start_port(matches: &'a ArgMatches<'a>) -> Option<u16> {
        matches.value_of("START_PORT").map(|p| p.parse().unwrap())
    }

    pub fn execute(matches: &'a ArgMatches<'a>) {
        let dir = Self::output_dir(matches);
        let count = Self::validators_count(matches);
        let start_port = Self::start_port(matches).unwrap_or_else(|| 2000);

        let dir = dir.join("validators");
        if !dir.exists() {
            fs::create_dir_all(&dir).unwrap();
        }

        let configs = generate_testnet_config(count, start_port);
        for (idx, cfg) in configs.into_iter().enumerate() {
            let file_name = format!("{}.toml", idx);
            ConfigFile::save(&cfg, &dir.join(file_name)).unwrap();
        }
    }
}

pub struct RunCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

impl<'a, 'b> RunCommand<'a, 'b>
    where 'a: 'b
{
    pub fn new() -> App<'a, 'b> {
        SubCommand::with_name("run")
            .about("Run node with given configuration")
            .arg(Arg::with_name("NODE_CONFIG_PATH")
                     .short("c")
                     .long("node-config")
                     .value_name("NODE_CONFIG_PATH")
                     .help("Path to node configuration file")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("LEVELDB_PATH")
                     .short("d")
                     .long("leveldb-path")
                     .help("Use leveldb database with the given path")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PUBLIC_API_ADDRESS")
                     .short("p")
                     .long("public-api-address")
                     .help("Listen address for public api")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PRIVATE_API_ADDRESS")
                     .short("s")
                     .long("private-api-address")
                     .help("Listen address for private api")
                     .required(false)
                     .takes_value(true))
    }

    pub fn node_config_path(matches: &'a ArgMatches<'a>) -> &'a Path {
        matches
            .value_of("NODE_CONFIG_PATH")
            .map(Path::new)
            .expect("Path to node configuration is no setted")
    }

    pub fn node_config(matches: &'a ArgMatches<'a>) -> NodeConfig {
        let path = Self::node_config_path(matches);
        ConfigFile::load(path).unwrap()
    }

    pub fn public_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PUBLIC_API_ADDRESS")
            .map(|s| s.parse().expect("Public api address has incorrect format"))
    }

    pub fn private_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PRIVATE_API_ADDRESS")
            .map(|s| s.parse().expect("Private api address has incorrect format"))
    }

    pub fn leveldb_path(matches: &'a ArgMatches<'a>) -> Option<&'a Path> {
        matches.value_of("LEVELDB_PATH").map(Path::new)
    }

    #[cfg(not(feature="memorydb"))]
    pub fn db(matches: &'a ArgMatches<'a>) -> Storage {
        use storage::{LevelDB, LevelDBOptions};

        let path = Self::leveldb_path(matches).unwrap();
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        LevelDB::new(path, options).unwrap()
    }

    #[cfg(feature="memorydb")]
    pub fn db(_: &'a ArgMatches<'a>) -> Storage {
        use storage::MemoryDB;
        MemoryDB::new()
    }
}
<commit_msg>Override api options by clap<commit_after>use clap::{SubCommand, App, Arg, ArgMatches};

use std::path::Path;
use std::marker::PhantomData;
use std::fs;
use std::net::SocketAddr;

use config::ConfigFile;
use node::NodeConfig;
use storage::Storage;
use helpers::generate_testnet_config;

pub struct GenerateCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

// TODO avoid unwraps here, implement Error chain

impl<'a, 'b> GenerateCommand<'a, 'b>
    where 'a: 'b
{
    pub fn new() -> App<'a, 'b> {
        SubCommand::with_name("generate")
            .about("Generates genesis configuration")
            .arg(Arg::with_name("OUTPUT_DIR")
                     .short("o")
                     .long("output-dir")
                     .value_name("OUTPUT_DIR")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("START_PORT")
                     .short("p")
                     .long("start-port")
                     .value_name("START_PORT")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("COUNT")
                     .help("Validators count")
                     .required(true)
                     .index(1))
    }

    pub fn output_dir(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("OUTPUT_DIR").unwrap())
    }

    pub fn validators_count(matches: &'a ArgMatches<'a>) -> u8 {
        matches.value_of("COUNT").unwrap().parse().unwrap()
    }

    pub fn start_port(matches: &'a ArgMatches<'a>) -> Option<u16> {
        matches.value_of("START_PORT").map(|p| p.parse().unwrap())
    }

    pub fn execute(matches: &'a ArgMatches<'a>) {
        let dir = Self::output_dir(matches);
        let count = Self::validators_count(matches);
        let start_port = Self::start_port(matches).unwrap_or_else(|| 2000);

        let dir = dir.join("validators");
        if !dir.exists() {
            fs::create_dir_all(&dir).unwrap();
        }

        let configs = generate_testnet_config(count, start_port);
        for (idx, cfg) in configs.into_iter().enumerate() {
            let file_name = format!("{}.toml", idx);
            ConfigFile::save(&cfg, &dir.join(file_name)).unwrap();
        }
    }
}

pub struct RunCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

impl<'a, 'b> RunCommand<'a, 'b>
    where 'a: 'b
{
    pub fn new() -> App<'a, 'b> {
        SubCommand::with_name("run")
            .about("Run node with given configuration")
            .arg(Arg::with_name("NODE_CONFIG_PATH")
                     .short("c")
                     .long("node-config")
                     .value_name("NODE_CONFIG_PATH")
                     .help("Path to node configuration file")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("LEVELDB_PATH")
                     .short("d")
                     .long("leveldb-path")
                     .help("Use leveldb database with the given path")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PUBLIC_API_ADDRESS")
                     .short("p")
                     .long("public-api-address")
                     .help("Listen address for public api")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PRIVATE_API_ADDRESS")
                     .short("s")
                     .long("private-api-address")
                     .help("Listen address for private api")
                     .required(false)
                     .takes_value(true))
    }

    pub fn node_config_path(matches: &'a ArgMatches<'a>) -> &'a Path {
        matches
            .value_of("NODE_CONFIG_PATH")
            .map(Path::new)
            .expect("Path to node configuration is no setted")
    }

    pub fn node_config(matches: &'a ArgMatches<'a>) -> NodeConfig {
        let path = Self::node_config_path(matches);
        let mut cfg: NodeConfig = ConfigFile::load(path).unwrap();
        // Override api options
        if let Some(addr) = Self::public_api_address(matches) {
            cfg.api.public_api_address = Some(addr);
        }
        if let Some(addr) = Self::private_api_address(matches) {
            cfg.api.private_api_address = Some(addr);
        }
        cfg
    }

    pub fn public_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PUBLIC_API_ADDRESS")
            .map(|s| s.parse().expect("Public api address has incorrect format"))
    }

    pub fn private_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PRIVATE_API_ADDRESS")
            .map(|s| s.parse().expect("Private api address has incorrect format"))
    }

    pub fn leveldb_path(matches: &'a ArgMatches<'a>) -> Option<&'a Path> {
        matches.value_of("LEVELDB_PATH").map(Path::new)
    }

    #[cfg(not(feature="memorydb"))]
    pub fn db(matches: &'a ArgMatches<'a>) -> Storage {
        use storage::{LevelDB, LevelDBOptions};

        let path = Self::leveldb_path(matches).unwrap();
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        LevelDB::new(path, options).unwrap()
    }

    #[cfg(feature="memorydb")]
    pub fn db(_: &'a ArgMatches<'a>) -> Storage {
        use storage::MemoryDB;
        MemoryDB::new()
    }
}
<|endoftext|>


<commit_before>use common::util::*;
use std::fs::{metadata, OpenOptions, set_permissions};
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::sync::Mutex;

extern crate libc;
use self::libc::umask;

static TEST_FILE: &'static str = "file";
static REFERENCE_FILE: &'static str = "reference";
static REFERENCE_PERMS: u32 = 0o247;
lazy_static! {
    static ref UMASK_MUTEX: Mutex<()> = Mutex::new(());
}

struct TestCase {
    args: Vec<&'static str>,
    before: u32,
    after: u32
}

fn mkfile(file: &str, mode: u32) {
    OpenOptions::new().mode(mode).create(true).write(true).open(file).unwrap();
    let mut perms = metadata(file).unwrap().permissions();
    perms.set_mode(mode);
    set_permissions(file, perms).unwrap();
}

fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
        mkfile(&at.plus_as_string(TEST_FILE), test.before);
        let perms = at.metadata(TEST_FILE).permissions().mode();
        if perms != test.before {
            panic!(format!("{}: expected: {:o} got: {:o}", "setting permissions failed", test.after, perms));
        }

        for arg in &test.args {
            ucmd.arg(arg);
        }
        let r = ucmd.run();
        if !r.success {
            println!("{}", r.stderr);
            panic!(format!("{:?}: failed", ucmd.raw));
        }

        let perms = at.metadata(TEST_FILE).permissions().mode();
        if perms != test.after {
            panic!(format!("{:?}: expected: {:o} got: {:o}", ucmd.raw, test.after, perms));
        }
}

fn run_tests(tests: Vec<TestCase>) {
    for test in tests {
        let (at, ucmd) = at_and_ucmd!();
        run_single_test(&test, at, ucmd);
    }
}

#[test]
fn test_chmod_octal() {
    let tests = vec!{
        TestCase{args: vec!{"0700",  TEST_FILE}, before: 0o000, after: 0o700},
        TestCase{args: vec!{"0070",  TEST_FILE}, before: 0o000, after: 0o070},
        TestCase{args: vec!{"0007",  TEST_FILE}, before: 0o000, after: 0o007},
        TestCase{args: vec!{"-0700", TEST_FILE}, before: 0o700, after: 0o000},
        TestCase{args: vec!{"-0070", TEST_FILE}, before: 0o060, after: 0o000},
        TestCase{args: vec!{"-0007", TEST_FILE}, before: 0o001, after: 0o000},
        TestCase{args: vec!{"+0100", TEST_FILE}, before: 0o600, after: 0o700},
        TestCase{args: vec!{"+0020", TEST_FILE}, before: 0o050, after: 0o070},
        TestCase{args: vec!{"+0004", TEST_FILE}, before: 0o003, after: 0o007},
    };
    run_tests(tests);
}

#[test]
fn test_chmod_ugoa() {
    let _guard = UMASK_MUTEX.lock();

    let last = unsafe {
        umask(0)
    };
    let tests = vec!{
        TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o000, after: 0o700},
        TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o000, after: 0o070},
        TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o000, after: 0o007},
        TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o000, after: 0o777},
        TestCase{args: vec!{"-r", TEST_FILE}, before: 0o777, after: 0o333},
        TestCase{args: vec!{"-w", TEST_FILE}, before: 0o777, after: 0o555},
        TestCase{args: vec!{"-x", TEST_FILE}, before: 0o777, after: 0o666},
    };
    run_tests(tests);

    unsafe {
        umask(0o022);
    }
    let tests = vec!{
        TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o000, after: 0o700},
        TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o000, after: 0o070},
        TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o000, after: 0o007},
        TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o000, after: 0o777},
        TestCase{args: vec!{"+rw", TEST_FILE}, before: 0o000, after: 0o644},
        TestCase{args: vec!{"=rwx", TEST_FILE}, before: 0o000, after: 0o755},
        TestCase{args: vec!{"-w", TEST_FILE}, before: 0o777, after: 0o577},
        TestCase{args: vec!{"-x", TEST_FILE}, before: 0o777, after: 0o666},
    };
    run_tests(tests);
    unsafe {
        umask(last);
    }
}

#[test]
fn test_chmod_ugo_copy() {
    let tests = vec!{
        TestCase{args: vec!{"u=g", TEST_FILE}, before: 0o070, after: 0o770},
        TestCase{args: vec!{"g=o", TEST_FILE}, before: 0o005, after: 0o055},
        TestCase{args: vec!{"o=u", TEST_FILE}, before: 0o200, after: 0o202},
        TestCase{args: vec!{"u-g", TEST_FILE}, before: 0o710, after: 0o610},
        TestCase{args: vec!{"u+g", TEST_FILE}, before: 0o250, after: 0o750},
    };
    run_tests(tests);
}

#[test]
fn test_chmod_many_options() {
    let _guard = UMASK_MUTEX.lock();

    let original_umask = unsafe {
        umask(0)
    };
    let tests = vec!{
        TestCase{args: vec!{"-r,a+w", TEST_FILE}, before: 0o444, after: 0o222},
    };
    run_tests(tests);
    unsafe {
        umask(original_umask);
    }
}

#[test]
fn test_chmod_reference_file() {
    let tests = vec!{
        TestCase{args: vec!{"--reference", REFERENCE_FILE, TEST_FILE}, before: 0o070, after: 0o247},
        TestCase{args: vec!{"a-w", "--reference", REFERENCE_FILE, TEST_FILE}, before: 0o070, after: 0o247},
    };
    let (at, ucmd) = at_and_ucmd!();
    mkfile(&at.plus_as_string(REFERENCE_FILE), REFERENCE_PERMS);
    run_single_test(&tests[0], at, ucmd);
}
<commit_msg>chmod: add 100 to permissions in chmod tests<commit_after>use common::util::*;
use std::fs::{metadata, OpenOptions, set_permissions};
use std::os::unix::fs::{OpenOptionsExt, PermissionsExt};
use std::sync::Mutex;

extern crate libc;
use self::libc::umask;

static TEST_FILE: &'static str = "file";
static REFERENCE_FILE: &'static str = "reference";
static REFERENCE_PERMS: u32 = 0o247;
lazy_static! {
    static ref UMASK_MUTEX: Mutex<()> = Mutex::new(());
}

struct TestCase {
    args: Vec<&'static str>,
    before: u32,
    after: u32
}

fn mkfile(file: &str, mode: u32) {
    OpenOptions::new().mode(mode).create(true).write(true).open(file).unwrap();
    let mut perms = metadata(file).unwrap().permissions();
    perms.set_mode(mode);
    set_permissions(file, perms).unwrap();
}

fn run_single_test(test: &TestCase, at: AtPath, mut ucmd: UCommand) {
        mkfile(&at.plus_as_string(TEST_FILE), test.before);
        let perms = at.metadata(TEST_FILE).permissions().mode();
        if perms != test.before {
            panic!(format!("{}: expected: {:o} got: {:o}", "setting permissions failed", test.after, perms));
        }

        for arg in &test.args {
            ucmd.arg(arg);
        }
        let r = ucmd.run();
        if !r.success {
            println!("{}", r.stderr);
            panic!(format!("{:?}: failed", ucmd.raw));
        }

        let perms = at.metadata(TEST_FILE).permissions().mode();
        if perms != test.after {
            panic!(format!("{:?}: expected: {:o} got: {:o}", ucmd.raw, test.after, perms));
        }
}

fn run_tests(tests: Vec<TestCase>) {
    for test in tests {
        let (at, ucmd) = at_and_ucmd!();
        run_single_test(&test, at, ucmd);
    }
}

#[test]
fn test_chmod_octal() {
    let tests = vec!{
        TestCase{args: vec!{"0700",  TEST_FILE}, before: 0o100000, after: 0o100700},
        TestCase{args: vec!{"0070",  TEST_FILE}, before: 0o100000, after: 0o100070},
        TestCase{args: vec!{"0007",  TEST_FILE}, before: 0o100000, after: 0o100007},
        TestCase{args: vec!{"-0700", TEST_FILE}, before: 0o100700, after: 0o100000},
        TestCase{args: vec!{"-0070", TEST_FILE}, before: 0o100060, after: 0o100000},
        TestCase{args: vec!{"-0007", TEST_FILE}, before: 0o100001, after: 0o100000},
        TestCase{args: vec!{"+0100", TEST_FILE}, before: 0o100600, after: 0o100700},
        TestCase{args: vec!{"+0020", TEST_FILE}, before: 0o100050, after: 0o100070},
        TestCase{args: vec!{"+0004", TEST_FILE}, before: 0o100003, after: 0o100007},
    };
    run_tests(tests);
}

#[test]
fn test_chmod_ugoa() {
    let _guard = UMASK_MUTEX.lock();

    let last = unsafe {
        umask(0)
    };
    let tests = vec!{
        TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o100000, after: 0o100700},
        TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o100000, after: 0o100070},
        TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o100000, after: 0o100007},
        TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o100000, after: 0o100777},
        TestCase{args: vec!{"-r", TEST_FILE}, before: 0o100777, after: 0o100333},
        TestCase{args: vec!{"-w", TEST_FILE}, before: 0o100777, after: 0o100555},
        TestCase{args: vec!{"-x", TEST_FILE}, before: 0o100777, after: 0o100666},
    };
    run_tests(tests);

    unsafe {
        umask(0o022);
    }
    let tests = vec!{
        TestCase{args: vec!{"u=rwx", TEST_FILE}, before: 0o100000, after: 0o100700},
        TestCase{args: vec!{"g=rwx", TEST_FILE}, before: 0o100000, after: 0o100070},
        TestCase{args: vec!{"o=rwx", TEST_FILE}, before: 0o100000, after: 0o100007},
        TestCase{args: vec!{"a=rwx", TEST_FILE}, before: 0o100000, after: 0o100777},
        TestCase{args: vec!{"+rw", TEST_FILE}, before: 0o100000, after: 0o100644},
        TestCase{args: vec!{"=rwx", TEST_FILE}, before: 0o100000, after: 0o100755},
        TestCase{args: vec!{"-w", TEST_FILE}, before: 0o100777, after: 0o100577},
        TestCase{args: vec!{"-x", TEST_FILE}, before: 0o100777, after: 0o100666},
    };
    run_tests(tests);
    unsafe {
        umask(last);
    }
}

#[test]
fn test_chmod_ugo_copy() {
    let tests = vec!{
        TestCase{args: vec!{"u=g", TEST_FILE}, before: 0o100070, after: 0o100770},
        TestCase{args: vec!{"g=o", TEST_FILE}, before: 0o100005, after: 0o100055},
        TestCase{args: vec!{"o=u", TEST_FILE}, before: 0o100200, after: 0o100202},
        TestCase{args: vec!{"u-g", TEST_FILE}, before: 0o100710, after: 0o100610},
        TestCase{args: vec!{"u+g", TEST_FILE}, before: 0o100250, after: 0o100750},
    };
    run_tests(tests);
}

#[test]
fn test_chmod_many_options() {
    let _guard = UMASK_MUTEX.lock();

    let original_umask = unsafe {
        umask(0)
    };
    let tests = vec!{
        TestCase{args: vec!{"-r,a+w", TEST_FILE}, before: 0o100444, after: 0o100222},
    };
    run_tests(tests);
    unsafe {
        umask(original_umask);
    }
}

#[test]
fn test_chmod_reference_file() {
    let tests = vec!{
        TestCase{args: vec!{"--reference", REFERENCE_FILE, TEST_FILE}, before: 0o100070, after: 0o100247},
        TestCase{args: vec!{"a-w", "--reference", REFERENCE_FILE, TEST_FILE}, before: 0o100070, after: 0o100247},
    };
    let (at, ucmd) = at_and_ucmd!();
    mkfile(&at.plus_as_string(REFERENCE_FILE), REFERENCE_PERMS);
    run_single_test(&tests[0], at, ucmd);
}
<|endoftext|>


<commit_before>use std::borrow::ToOwned;

use workdir::Workdir;

macro_rules! split_eq {
    ($wrk:expr, $path:expr, $expected:expr) => (
        // assert_eq!($wrk.path($path).into_os_string().into_string().unwrap(),
                   // $expected.to_owned());
        assert_eq!($wrk.from_str::<String>(&$wrk.path($path)),
                   $expected.to_owned());
    );
}

fn data(headers: bool) -> Vec<Vec<String>> {
    let mut rows = vec![
        svec!["a", "b"], svec!["c", "d"],
        svec!["e", "f"], svec!["g", "h"],
        svec!["i", "j"], svec!["k", "l"],
    ];
    if headers { rows.insert(0, svec!["h1", "h2"]); }
    rows
}

#[test]
fn split_zero() {
    let wrk = Workdir::new("split_zero");
    wrk.create("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "0"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.assert_err(&mut cmd);
}

#[test]
fn split() {
    let wrk = Workdir::new("split");
    wrk.create("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "2"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
c,d
");
    split_eq!(wrk, "2.csv", "\
h1,h2
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
k,l
");
}

#[test]
fn split_idx() {
    let wrk = Workdir::new("split_idx");
    wrk.create_indexed("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "2"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
c,d
");
    split_eq!(wrk, "2.csv", "\
h1,h2
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
k,l
");
}

#[test]
fn split_no_headers() {
    let wrk = Workdir::new("split_no_headers");
    wrk.create("in.csv", data(false));

    let mut cmd = wrk.command("split");
    cmd.args(&["--no-headers", "--size", "2"])
       .arg(&wrk.path("."))
       .arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
a,b
c,d
");
    split_eq!(wrk, "2.csv", "\
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
i,j
k,l
");
}

#[test]
fn split_no_headers_idx() {
    let wrk = Workdir::new("split_no_headers_idx");
    wrk.create_indexed("in.csv", data(false));

    let mut cmd = wrk.command("split");
    cmd.args(&["--no-headers", "--size", "2"])
       .arg(&wrk.path("."))
       .arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
a,b
c,d
");
    split_eq!(wrk, "2.csv", "\
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
i,j
k,l
");
}

#[test]
fn split_one() {
    let wrk = Workdir::new("split_one");
    wrk.create("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "1"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
");
    split_eq!(wrk, "1.csv", "\
h1,h2
c,d
");
    split_eq!(wrk, "2.csv", "\
h1,h2
e,f
");
    split_eq!(wrk, "3.csv", "\
h1,h2
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
");
    split_eq!(wrk, "5.csv", "\
h1,h2
k,l
");
}

#[test]
fn split_one_idx() {
    let wrk = Workdir::new("split_one_idx");
    wrk.create_indexed("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "1"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
");
    split_eq!(wrk, "1.csv", "\
h1,h2
c,d
");
    split_eq!(wrk, "2.csv", "\
h1,h2
e,f
");
    split_eq!(wrk, "3.csv", "\
h1,h2
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
");
    split_eq!(wrk, "5.csv", "\
h1,h2
k,l
");
}

#[test]
fn split_uneven() {
    let wrk = Workdir::new("split_uneven");
    wrk.create("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "4"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
c,d
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
k,l
");
}

#[test]
fn split_uneven_idx() {
    let wrk = Workdir::new("split_uneven_idx");
    wrk.create_indexed("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "4"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
c,d
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
k,l
");
}
<commit_msg>Assert that split doesn't produce extra empty files<commit_after>use std::borrow::ToOwned;

use workdir::Workdir;

macro_rules! split_eq {
    ($wrk:expr, $path:expr, $expected:expr) => (
        // assert_eq!($wrk.path($path).into_os_string().into_string().unwrap(),
                   // $expected.to_owned());
        assert_eq!($wrk.from_str::<String>(&$wrk.path($path)),
                   $expected.to_owned());
    );
}

fn data(headers: bool) -> Vec<Vec<String>> {
    let mut rows = vec![
        svec!["a", "b"], svec!["c", "d"],
        svec!["e", "f"], svec!["g", "h"],
        svec!["i", "j"], svec!["k", "l"],
    ];
    if headers { rows.insert(0, svec!["h1", "h2"]); }
    rows
}

#[test]
fn split_zero() {
    let wrk = Workdir::new("split_zero");
    wrk.create("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "0"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.assert_err(&mut cmd);
}

#[test]
fn split() {
    let wrk = Workdir::new("split");
    wrk.create("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "2"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
c,d
");
    split_eq!(wrk, "2.csv", "\
h1,h2
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
k,l
");
    assert!(!wrk.path("6.csv").exists());
}

#[test]
fn split_idx() {
    let wrk = Workdir::new("split_idx");
    wrk.create_indexed("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "2"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
c,d
");
    split_eq!(wrk, "2.csv", "\
h1,h2
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
k,l
");
    assert!(!wrk.path("6.csv").exists());
}

#[test]
fn split_no_headers() {
    let wrk = Workdir::new("split_no_headers");
    wrk.create("in.csv", data(false));

    let mut cmd = wrk.command("split");
    cmd.args(&["--no-headers", "--size", "2"])
       .arg(&wrk.path("."))
       .arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
a,b
c,d
");
    split_eq!(wrk, "2.csv", "\
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
i,j
k,l
");
}

#[test]
fn split_no_headers_idx() {
    let wrk = Workdir::new("split_no_headers_idx");
    wrk.create_indexed("in.csv", data(false));

    let mut cmd = wrk.command("split");
    cmd.args(&["--no-headers", "--size", "2"])
       .arg(&wrk.path("."))
       .arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
a,b
c,d
");
    split_eq!(wrk, "2.csv", "\
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
i,j
k,l
");
}

#[test]
fn split_one() {
    let wrk = Workdir::new("split_one");
    wrk.create("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "1"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
");
    split_eq!(wrk, "1.csv", "\
h1,h2
c,d
");
    split_eq!(wrk, "2.csv", "\
h1,h2
e,f
");
    split_eq!(wrk, "3.csv", "\
h1,h2
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
");
    split_eq!(wrk, "5.csv", "\
h1,h2
k,l
");
}

#[test]
fn split_one_idx() {
    let wrk = Workdir::new("split_one_idx");
    wrk.create_indexed("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "1"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
");
    split_eq!(wrk, "1.csv", "\
h1,h2
c,d
");
    split_eq!(wrk, "2.csv", "\
h1,h2
e,f
");
    split_eq!(wrk, "3.csv", "\
h1,h2
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
");
    split_eq!(wrk, "5.csv", "\
h1,h2
k,l
");
}

#[test]
fn split_uneven() {
    let wrk = Workdir::new("split_uneven");
    wrk.create("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "4"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
c,d
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
k,l
");
}

#[test]
fn split_uneven_idx() {
    let wrk = Workdir::new("split_uneven_idx");
    wrk.create_indexed("in.csv", data(true));

    let mut cmd = wrk.command("split");
    cmd.args(&["--size", "4"]).arg(&wrk.path(".")).arg("in.csv");
    wrk.run(&mut cmd);

    split_eq!(wrk, "0.csv", "\
h1,h2
a,b
c,d
e,f
g,h
");
    split_eq!(wrk, "4.csv", "\
h1,h2
i,j
k,l
");
}
<|endoftext|>