<commit_before>use ::Nav;
use ::traversal::Queue;
use ::util::{ChildIndex, SiblingIndex};

use std::borrow::{Borrow, BorrowMut};
use std::clone::Clone;
use std::intrinsics;
use std::iter::Iterator;

/// Fixed-layout tree with good memory locality guarantees.
///
/// This tree structure does not provide methods for arbitrarily modifying its
/// topology, but it does provide good memory locality guarantees. Internally,
/// tree data is kept in a single heap-allocated region. Records of tree edges
/// are also kept in contiguous regions of memory, so tree navigation should be
/// fast.
///
/// If the tree is extended with additional children, it may reallocate its
/// entire structure.
pub struct Tree<T> {
    data: Vec<T>, offsets: Vec<usize>, children: Vec<usize>,
}

impl<T> Tree<T> {
    /// Constructs a tree based on the ordering imposed by a traversal.
    ///
    /// In the resulting tree, node data will be laid out in memory in the same
    /// order in which they are visited by the traversal imposed by `queue`.
    pub fn from_traversal<Q, I>(mut queue: Q, data: T, children: I) -> Self
        where Q: Queue<(usize, usize, T, I)>, I: Iterator<Item=(T, I)> {
            let mut tree = Tree { data: Vec::new(), offsets: Vec::new(), children: Vec::new(), };
            tree.data.push(data);
            tree.offsets.push(0);
            {
                let mut child_index = 0usize;
                for (data, children) in children {
                    queue.unshift((0, child_index, data, children));
                    child_index += 1;
                    tree.children.push(0);
                }
            }
            loop {
                match queue.shift() {
                    None => return tree,
                    Some((parent_index, index, data, children)) => {
                        tree.data.push(data);
                        tree.offsets.push(tree.children.len());
                        tree.children[tree.offsets[parent_index] + index] = index;
                        let mut child_index = 0usize;
                        for (data, children) in children {
                            queue.unshift((index, child_index, data, children));
                            child_index += 1;
                            tree.children.push(0);
                        }
                    }
                }
            }
        }

    /// Constructs a new tree with no children and the given data.
    pub fn leaf(data: T) -> Self {
        Tree { data: vec![data], offsets: vec![0], children: Vec::new(), }
    }

    /// Returns the number of nodes in this tree.
    pub fn size(&self) -> usize {
        self.data.len()
    }

    /// Returns a borrowed view of the nodes, in the order in which they are
    /// stored.
    pub fn nodes(&self) -> &[T] {
        &self.data
    }

    /// Returns a borrowed mutable view of the nodes, in the order in which they
    /// are stored.
    pub fn nodes_mut(&mut self) -> &mut [T] {
        &mut self.data
    }

    fn child_count(&self, index: usize) -> usize {
        match index.checked_add(1) {
            None =>
                panic!["numerical overflow in computing child count"],
            Some(x) if x > self.size() =>
                panic!["no such child {} (only {} nodes in tree)", index, self.size()],
            Some(x) if x == self.size() =>
                self.size() - self.offsets[index],
            Some(x) =>
                self.offsets[x] - self.offsets[index],
        }
    }

    fn child_of(&self, parent: usize, index: usize) -> usize {
        assert![parent < self.size()];
        match self.offsets[parent].checked_add(index) {
            Some(x) => self.children[x],
            None => panic!["numerical overflow in computing child offset"],
        }
    }
}

#[derive(Clone, Copy)]
enum TreePosition {
    Root,
    Nonroot(TreePositionData),
}

#[derive(Clone, Copy)]
struct TreePositionData {
    // Index into tree array.
    tree_index: usize,
    // Index in sequence of children under parent.
    parent_index: usize,
}

pub struct TreeView<'a, T: 'a> {
    tree: &'a Tree<T>, path: Vec<TreePosition>,
}

impl<'a, T: 'a> TreeView<'a, T> {
    fn here(&self) -> TreePosition {
        match self.path.last() {
            None => unsafe { intrinsics::unreachable() },
            Some(x) => *x,
        }
    }
}

impl<'a, T: 'a> Clone for TreeView<'a, T> {
    fn clone(&self) -> Self {
        TreeView { tree: self.tree, path: self.path.clone(), }
    }
}

impl<'a, T: 'a> Borrow<T> for TreeView<'a, T> {
    fn borrow(&self) -> &T {
        match self.here() {
            TreePosition::Root => &self.tree.data[0],
            TreePosition::Nonroot(data) => &self.tree.data[data.tree_index],
        }
    }
}

impl<'a, T: 'a> Nav for TreeView<'a, T> {
    fn seek_sibling(&mut self, offset: isize) {
        let new_index = match self.path.pop() {
            None => unsafe { intrinsics::unreachable() },
            Some(TreePosition::Root) => SiblingIndex::Root,
            Some(TreePosition::Nonroot(data)) => match self.here() {
                TreePosition::Root =>
                    SiblingIndex::compute(self.tree.child_count(0), 0, offset),
                TreePosition::Nonroot(parent_data) =>
                    SiblingIndex::compute(self.tree.child_count(parent_data.tree_index),
                                          data.parent_index,
                                          offset),
            },
        }.unwrap();
        let tree_index = match self.here() {
            TreePosition::Root =>
                self.tree.child_of(0, new_index),
            TreePosition::Nonroot(data) =>
                self.tree.child_of(data.tree_index, new_index),
        };
        self.path.push(TreePosition::Nonroot(
            TreePositionData { tree_index: tree_index, parent_index: new_index, }));
    }

    fn seek_child(&mut self, index: usize) {
        let new_index =
            ChildIndex::compute(self.child_count(), index).unwrap();
        let tree_index = match self.here() {
            TreePosition::Root => self.tree.child_of(0, new_index),
            TreePosition::Nonroot(data) => self.tree.child_of(data.tree_index, new_index),
        };
        self.path.push(TreePosition::Nonroot(
            TreePositionData { tree_index: tree_index, parent_index: new_index, }));
    }

    fn child_count(&self) -> usize {
        match self.here() {
            TreePosition::Root => self.tree.child_count(0),
            TreePosition::Nonroot(data) => self.tree.child_count(data.tree_index),
        }
    }

    fn at_root(&self) -> bool {
        self.path.len() == 1
    }

    fn to_parent(&mut self) {
        assert![self.path.len() <= 1, "Already at root"];
        self.path.pop();
    }

    fn to_root(&mut self) {
        self.path.clear();
        self.path.push(TreePosition::Root);
    }
}

pub struct TreeViewMut<'a, T: 'a> {
    tree: &'a mut Tree<T>,
    path: Vec<TreePosition>,
}

impl<'a, T> TreeViewMut<'a, T> {
    fn here(&self) -> TreePosition {
        *self.path.last().unwrap()
    }
}

impl<'a, T: 'a> Borrow<T> for TreeViewMut<'a, T> {
    fn borrow(&self) -> &T {
        match self.here() {
            TreePosition::Root => &self.tree.data[0],
            TreePosition::Nonroot(data) => &self.tree.data[data.tree_index],
        }
    }
}

impl<'a, T: 'a> BorrowMut<T> for TreeViewMut<'a, T> {
    fn borrow_mut(&mut self) -> &mut T {
        match self.here() {
            TreePosition::Root => &mut self.tree.data[0],
            TreePosition::Nonroot(data) => &mut self.tree.data[data.tree_index],
        }
    }
}

impl<'a, T: 'a> Nav for TreeViewMut<'a, T> {
    fn seek_sibling(&mut self, offset: isize) {
        let new_index = match self.path.pop() {
            None => unsafe { intrinsics::unreachable() },
            Some(TreePosition::Root) => SiblingIndex::Root,
            Some(TreePosition::Nonroot(data)) => match self.here() {
                TreePosition::Root =>
                    SiblingIndex::compute(self.tree.child_count(0), 0, offset),
                TreePosition::Nonroot(parent_data) =>
                    SiblingIndex::compute(self.tree.child_count(parent_data.tree_index),
                                          data.parent_index,
                                          offset),
            },
        }.unwrap();
        let tree_index = match self.here() {
            TreePosition::Root =>
                self.tree.child_of(0, new_index),
            TreePosition::Nonroot(data) =>
                self.tree.child_of(data.tree_index, new_index),
        };
        self.path.push(TreePosition::Nonroot(
            TreePositionData { tree_index: tree_index, parent_index: new_index, }));
    }

    fn seek_child(&mut self, index: usize) {
        let new_index =
            ChildIndex::compute(self.child_count(), index).unwrap();
        let tree_index = match self.here() {
            TreePosition::Root => self.tree.child_of(0, new_index),
            TreePosition::Nonroot(data) => self.tree.child_of(data.tree_index, new_index),
        };
        self.path.push(TreePosition::Nonroot(
            TreePositionData { tree_index: tree_index, parent_index: new_index, }));
    }

    fn child_count(&self) -> usize {
        match self.here() {
            TreePosition::Root => self.tree.child_count(0),
            TreePosition::Nonroot(data) => self.tree.child_count(data.tree_index),
        }
    }

    fn at_root(&self) -> bool {
        self.path.len() == 1
    }

    fn to_parent(&mut self) {
        assert![self.path.len() <= 1, "already at root"];
        self.path.pop();
    }

    fn to_root(&mut self) {
        self.path.clear();
        self.path.push(TreePosition::Root);
    }
}
<commit_msg>Switch from intrinsics::unreachable() to unreachable!().<commit_after>use ::Nav;
use ::traversal::Queue;
use ::util::{ChildIndex, SiblingIndex};

use std::borrow::{Borrow, BorrowMut};
use std::clone::Clone;
use std::iter::Iterator;

/// Fixed-layout tree with good memory locality guarantees.
///
/// This tree structure does not provide methods for arbitrarily modifying its
/// topology, but it does provide good memory locality guarantees. Internally,
/// tree data is kept in a single heap-allocated region. Records of tree edges
/// are also kept in contiguous regions of memory, so tree navigation should be
/// fast.
///
/// If the tree is extended with additional children, it may reallocate its
/// entire structure.
pub struct Tree<T> {
    data: Vec<T>, offsets: Vec<usize>, children: Vec<usize>,
}

impl<T> Tree<T> {
    /// Constructs a tree based on the ordering imposed by a traversal.
    ///
    /// In the resulting tree, node data will be laid out in memory in the same
    /// order in which they are visited by the traversal imposed by `queue`.
    pub fn from_traversal<Q, I>(mut queue: Q, data: T, children: I) -> Self
        where Q: Queue<(usize, usize, T, I)>, I: Iterator<Item=(T, I)> {
            let mut tree = Tree { data: Vec::new(), offsets: Vec::new(), children: Vec::new(), };
            tree.data.push(data);
            tree.offsets.push(0);
            {
                let mut child_index = 0usize;
                for (data, children) in children {
                    queue.unshift((0, child_index, data, children));
                    child_index += 1;
                    tree.children.push(0);
                }
            }
            loop {
                match queue.shift() {
                    None => return tree,
                    Some((parent_index, index, data, children)) => {
                        tree.data.push(data);
                        tree.offsets.push(tree.children.len());
                        tree.children[tree.offsets[parent_index] + index] = index;
                        let mut child_index = 0usize;
                        for (data, children) in children {
                            queue.unshift((index, child_index, data, children));
                            child_index += 1;
                            tree.children.push(0);
                        }
                    }
                }
            }
        }

    /// Constructs a new tree with no children and the given data.
    pub fn leaf(data: T) -> Self {
        Tree { data: vec![data], offsets: vec![0], children: Vec::new(), }
    }

    /// Returns the number of nodes in this tree.
    pub fn size(&self) -> usize {
        self.data.len()
    }

    /// Returns a borrowed view of the nodes, in the order in which they are
    /// stored.
    pub fn nodes(&self) -> &[T] {
        &self.data
    }

    /// Returns a borrowed mutable view of the nodes, in the order in which they
    /// are stored.
    pub fn nodes_mut(&mut self) -> &mut [T] {
        &mut self.data
    }

    fn child_count(&self, index: usize) -> usize {
        match index.checked_add(1) {
            None =>
                panic!["numerical overflow in computing child count"],
            Some(x) if x > self.size() =>
                panic!["no such child {} (only {} nodes in tree)", index, self.size()],
            Some(x) if x == self.size() =>
                self.size() - self.offsets[index],
            Some(x) =>
                self.offsets[x] - self.offsets[index],
        }
    }

    fn child_of(&self, parent: usize, index: usize) -> usize {
        assert![parent < self.size()];
        match self.offsets[parent].checked_add(index) {
            Some(x) => self.children[x],
            None => panic!["numerical overflow in computing child offset"],
        }
    }
}

#[derive(Clone, Copy)]
enum TreePosition {
    Root,
    Nonroot(TreePositionData),
}

#[derive(Clone, Copy)]
struct TreePositionData {
    // Index into tree array.
    tree_index: usize,
    // Index in sequence of children under parent.
    parent_index: usize,
}

pub struct TreeView<'a, T: 'a> {
    tree: &'a Tree<T>, path: Vec<TreePosition>,
}

impl<'a, T: 'a> TreeView<'a, T> {
    fn here(&self) -> TreePosition {
        *self.path.last().unwrap()
    }
}

impl<'a, T: 'a> Clone for TreeView<'a, T> {
    fn clone(&self) -> Self {
        TreeView { tree: self.tree, path: self.path.clone(), }
    }
}

impl<'a, T: 'a> Borrow<T> for TreeView<'a, T> {
    fn borrow(&self) -> &T {
        match self.here() {
            TreePosition::Root => &self.tree.data[0],
            TreePosition::Nonroot(data) => &self.tree.data[data.tree_index],
        }
    }
}

impl<'a, T: 'a> Nav for TreeView<'a, T> {
    fn seek_sibling(&mut self, offset: isize) {
        let new_index = match self.path.pop() {
            None => unreachable!(),
            Some(TreePosition::Root) => SiblingIndex::Root,
            Some(TreePosition::Nonroot(data)) => match self.here() {
                TreePosition::Root =>
                    SiblingIndex::compute(self.tree.child_count(0), 0, offset),
                TreePosition::Nonroot(parent_data) =>
                    SiblingIndex::compute(self.tree.child_count(parent_data.tree_index),
                                          data.parent_index,
                                          offset),
            },
        }.unwrap();
        let tree_index = match self.here() {
            TreePosition::Root =>
                self.tree.child_of(0, new_index),
            TreePosition::Nonroot(data) =>
                self.tree.child_of(data.tree_index, new_index),
        };
        self.path.push(TreePosition::Nonroot(
            TreePositionData { tree_index: tree_index, parent_index: new_index, }));
    }

    fn seek_child(&mut self, index: usize) {
        let new_index =
            ChildIndex::compute(self.child_count(), index).unwrap();
        let tree_index = match self.here() {
            TreePosition::Root => self.tree.child_of(0, new_index),
            TreePosition::Nonroot(data) => self.tree.child_of(data.tree_index, new_index),
        };
        self.path.push(TreePosition::Nonroot(
            TreePositionData { tree_index: tree_index, parent_index: new_index, }));
    }

    fn child_count(&self) -> usize {
        match self.here() {
            TreePosition::Root => self.tree.child_count(0),
            TreePosition::Nonroot(data) => self.tree.child_count(data.tree_index),
        }
    }

    fn at_root(&self) -> bool {
        self.path.len() == 1
    }

    fn to_parent(&mut self) {
        assert![self.path.len() <= 1, "Already at root"];
        self.path.pop();
    }

    fn to_root(&mut self) {
        self.path.clear();
        self.path.push(TreePosition::Root);
    }
}

pub struct TreeViewMut<'a, T: 'a> {
    tree: &'a mut Tree<T>,
    path: Vec<TreePosition>,
}

impl<'a, T> TreeViewMut<'a, T> {
    fn here(&self) -> TreePosition {
        *self.path.last().unwrap()
    }
}

impl<'a, T: 'a> Borrow<T> for TreeViewMut<'a, T> {
    fn borrow(&self) -> &T {
        match self.here() {
            TreePosition::Root => &self.tree.data[0],
            TreePosition::Nonroot(data) => &self.tree.data[data.tree_index],
        }
    }
}

impl<'a, T: 'a> BorrowMut<T> for TreeViewMut<'a, T> {
    fn borrow_mut(&mut self) -> &mut T {
        match self.here() {
            TreePosition::Root => &mut self.tree.data[0],
            TreePosition::Nonroot(data) => &mut self.tree.data[data.tree_index],
        }
    }
}

impl<'a, T: 'a> Nav for TreeViewMut<'a, T> {
    fn seek_sibling(&mut self, offset: isize) {
        let new_index = match self.path.pop() {
            None => unreachable!(),
            Some(TreePosition::Root) => SiblingIndex::Root,
            Some(TreePosition::Nonroot(data)) => match self.here() {
                TreePosition::Root =>
                    SiblingIndex::compute(self.tree.child_count(0), 0, offset),
                TreePosition::Nonroot(parent_data) =>
                    SiblingIndex::compute(self.tree.child_count(parent_data.tree_index),
                                          data.parent_index,
                                          offset),
            },
        }.unwrap();
        let tree_index = match self.here() {
            TreePosition::Root =>
                self.tree.child_of(0, new_index),
            TreePosition::Nonroot(data) =>
                self.tree.child_of(data.tree_index, new_index),
        };
        self.path.push(TreePosition::Nonroot(
            TreePositionData { tree_index: tree_index, parent_index: new_index, }));
    }

    fn seek_child(&mut self, index: usize) {
        let new_index =
            ChildIndex::compute(self.child_count(), index).unwrap();
        let tree_index = match self.here() {
            TreePosition::Root => self.tree.child_of(0, new_index),
            TreePosition::Nonroot(data) => self.tree.child_of(data.tree_index, new_index),
        };
        self.path.push(TreePosition::Nonroot(
            TreePositionData { tree_index: tree_index, parent_index: new_index, }));
    }

    fn child_count(&self) -> usize {
        match self.here() {
            TreePosition::Root => self.tree.child_count(0),
            TreePosition::Nonroot(data) => self.tree.child_count(data.tree_index),
        }
    }

    fn at_root(&self) -> bool {
        self.path.len() == 1
    }

    fn to_parent(&mut self) {
        assert![self.path.len() <= 1, "already at root"];
        self.path.pop();
    }

    fn to_root(&mut self) {
        self.path.clear();
        self.path.push(TreePosition::Root);
    }
}

#[cfg(test)]
mod tests {
    use ::fixed::Tree;

    #[test]
    fn basic() {
        Tree { data: vec![0], offsets: vec![0], children: vec![], };
    }
}
<|endoftext|>


<commit_before>use clap::{App, Arg, AppSettings, Format, ArgMatches};
use std::io::{self, Write};
use std::process::exit;
use std::fs;

/// Prints an error on stderr and exit the program
pub fn print_error(s: &str) -> ! {
    writeln!(&mut io::stderr(), "{} {}", Format::Error("error:"), s).unwrap();
    exit(0);
}

/// create a book file with the command line arguments
/// and exit the process at the end
pub fn create_book(matches: &ArgMatches) -> ! {
    if let Some(values) = matches.values_of("files") {
        let numbering = match matches.value_of("numbering") {
            Some("false") => false,
            _ => true,
        };

        let s = matches.value_of("BOOK").unwrap();
        if fs::metadata(s).is_ok() {
            print_error(&format!("Could not create file {}: it already exists!", s));
        }
        let mut f = fs::File::create(s).unwrap();
        f.write_all(b"author: Your name\n").unwrap();
        f.write_all(b"title: Your title\n").unwrap();
        f.write_all(b"lang: en\n\n").unwrap();
        f.write_all(b"# Uncomment and fill to generate files\n").unwrap();
        f.write_all(b"# output.html: some_file.html\n").unwrap();
        f.write_all(b"# output.epub: some_file.epub\n").unwrap();
        f.write_all(b"# output.pdf: some_file.pdf\n\n").unwrap();
        f.write_all(b"# List of chapters\n").unwrap();
        for file in values {
            f.write_all(&format!("{} {}\n", if numbering {"+"} else {"-"}, file).as_bytes()).unwrap();
        }
        println!("Created {}, now you'll have to complete it!", s);
        exit(0);
    } else {
        print_error("--create must be used with a list of additonal files");
    }
}

pub fn create_matches<'a>() -> ArgMatches<'a> {
    let app = App::new("crowbook")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::UnifiedHelpMessage)
        //        .usage("crowbook [FLAGS] [OPTIONS] <BOOK> [FILE]")
        .version(env!("CARGO_PKG_VERSION"))
        .about("Render a markdown book in Epub, PDF or HTML.")
        .after_help("Command line options allow to override options defined in <BOOK> configuration file.
E.g., even if this file specifies 'verbose: false', calling 'crowbook --verbose <BOOK>'
will activate verbose mode.

Note that Crowbook generates output files relatively to the directory where <BOOK> is:
$ crowbook foo/bar.book --to pdf --output baz.pdf
will thus generate baz.pdf in directory foo and not in current directory.")
        .arg_from_usage("-v, --verbose 'Activate verbose mode'")
        .arg(Arg::with_name("files")
             .value_name("FILES")
             .help("Files to put in book when using --create")
             .takes_value(true)
             .multiple(true)
             .index(2))
        .arg(Arg::with_name("create")
             .long("--create")
             .help("Creates a new book file with existing markdown files"))
        .arg(Arg::with_name("output")
             .long("--output")
             .short("-o")
             .value_name("FILE")
             .requires("to")
             .help("Specify output file"))
        .arg(Arg::with_name("autoclean")
             .long("--autoclean")
             .value_name("BOOL")
             .takes_value(true)
             .help("Try to clean input markdown")
             .possible_values(&["true", "false"]))
        .arg(Arg::with_name("numbering")
             .long("--numbering")
             .value_name("BOOL")
             .takes_value(true)
             .help("Number chapters or not")
             .possible_values(&["true", "false"]))
        .arg(Arg::with_name("to")
             .long("--to")
             .short("t")
             .takes_value(true)
             .possible_values(&["epub", "pdf", "html", "tex", "odt"])
             .value_name("FORMAT")
             .help("Generate specific format"))
        .arg(Arg::with_name("BOOK")
             .index(1)
             .required(true)
             .help("A file containing the book configuration"));

    let matches = app.get_matches();

    pre_check(&matches);

    matches
}

/// Pre-check the matches to see if there isn't illegal options not detected by clap
fn pre_check(matches: &ArgMatches) {
    if matches.is_present("files") && !matches.is_present("create") {
        print_error("A list of additional files is only valid with the --create option.");
    }

}
<commit_msg>binary: added cover to default book generated<commit_after>use clap::{App, Arg, AppSettings, Format, ArgMatches};
use std::io::{self, Write};
use std::process::exit;
use std::fs;

/// Prints an error on stderr and exit the program
pub fn print_error(s: &str) -> ! {
    writeln!(&mut io::stderr(), "{} {}", Format::Error("error:"), s).unwrap();
    exit(0);
}

/// create a book file with the command line arguments
/// and exit the process at the end
pub fn create_book(matches: &ArgMatches) -> ! {
    if let Some(values) = matches.values_of("files") {
        let numbering = match matches.value_of("numbering") {
            Some("false") => false,
            _ => true,
        };

        let s = matches.value_of("BOOK").unwrap();
        if fs::metadata(s).is_ok() {
            print_error(&format!("Could not create file {}: it already exists!", s));
        }
        let mut f = fs::File::create(s).unwrap();
        f.write_all(b"author: Your name\n").unwrap();
        f.write_all(b"title: Your title\n").unwrap();
        f.write_all(b"lang: en\n\n").unwrap();
        f.write_all(b"# Uncomment and fill to generate files\n").unwrap();
        f.write_all(b"# output.html: some_file.html\n").unwrap();
        f.write_all(b"# output.epub: some_file.epub\n").unwrap();
        f.write_all(b"# output.pdf: some_file.pdf\n\n").unwrap();
        f.write_all(b"# Uncomment and fill to set cover image (for Epub)\n").unwrap();
        f.write_all(b"# cover: some_cover.png\n\n").unwrap();
        f.write_all(b"# List of chapters\n").unwrap();
        for file in values {
            f.write_all(&format!("{} {}\n", if numbering {"+"} else {"-"}, file).as_bytes()).unwrap();
        }
        println!("Created {}, now you'll have to complete it!", s);
        exit(0);
    } else {
        print_error("--create must be used with a list of additonal files");
    }
}

pub fn create_matches<'a>() -> ArgMatches<'a> {
    let app = App::new("crowbook")
        .setting(AppSettings::ArgRequiredElseHelp)
        .setting(AppSettings::UnifiedHelpMessage)
        //        .usage("crowbook [FLAGS] [OPTIONS] <BOOK> [FILE]")
        .version(env!("CARGO_PKG_VERSION"))
        .about("Render a markdown book in Epub, PDF or HTML.")
        .after_help("Command line options allow to override options defined in <BOOK> configuration file.
E.g., even if this file specifies 'verbose: false', calling 'crowbook --verbose <BOOK>'
will activate verbose mode.

Note that Crowbook generates output files relatively to the directory where <BOOK> is:
$ crowbook foo/bar.book --to pdf --output baz.pdf
will thus generate baz.pdf in directory foo and not in current directory.")
        .arg_from_usage("-v, --verbose 'Activate verbose mode'")
        .arg(Arg::with_name("files")
             .value_name("FILES")
             .help("Files to put in book when using --create")
             .takes_value(true)
             .multiple(true)
             .index(2))
        .arg(Arg::with_name("create")
             .long("--create")
             .help("Creates a new book file with existing markdown files"))
        .arg(Arg::with_name("output")
             .long("--output")
             .short("-o")
             .value_name("FILE")
             .requires("to")
             .help("Specify output file"))
        .arg(Arg::with_name("autoclean")
             .long("--autoclean")
             .value_name("BOOL")
             .takes_value(true)
             .help("Try to clean input markdown")
             .possible_values(&["true", "false"]))
        .arg(Arg::with_name("numbering")
             .long("--numbering")
             .value_name("BOOL")
             .takes_value(true)
             .help("Number chapters or not")
             .possible_values(&["true", "false"]))
        .arg(Arg::with_name("to")
             .long("--to")
             .short("t")
             .takes_value(true)
             .possible_values(&["epub", "pdf", "html", "tex", "odt"])
             .value_name("FORMAT")
             .help("Generate specific format"))
        .arg(Arg::with_name("BOOK")
             .index(1)
             .required(true)
             .help("A file containing the book configuration"));

    let matches = app.get_matches();

    pre_check(&matches);

    matches
}

/// Pre-check the matches to see if there isn't illegal options not detected by clap
fn pre_check(matches: &ArgMatches) {
    if matches.is_present("files") && !matches.is_present("create") {
        print_error("A list of additional files is only valid with the --create option.");
    }

}
<|endoftext|>


<commit_before>use {HashSet, HashMap};
use std::collections::{RingBuf, Deque};

// call this Unigraph instead?
pub trait Graph<T> {
    /// Insert a new node, returning its index
    fn add_node(&mut self, val: T) -> NodeIndex;

    /// Insert a new edge, returning an error if one of the indices is invalid
    /// and a result otherwise
    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool>;

    /// Return an iterator over the out-neighbors for a given node
    fn adj(&self, i: NodeIndex) -> NodeIndices;

    /// Return the number of nodes in the graph
    fn num_nodes(&self) -> uint;

    fn node_indices(&self) -> NodeIndices;
}

struct GraphError {
    error_type: GraphErrorType,
}

impl GraphError {
    fn invalid_index(ind: NodeIndex) -> GraphError {
        GraphError { error_type: InvalidNodeIndex(ind) }
    }
}

type GraphResult<T> = Result<T, GraphError>;

enum GraphErrorType {
    InvalidNodeIndex(NodeIndex),
}

pub type NodeIndex = uint;
type NodeIndexSet = HashSet<NodeIndex>;

#[deriving(Show, Clone)]
struct Node<T> {
    data: T,
    index: NodeIndex,
}

/// Undirected graph. Allows loops.
#[deriving(Show)]
pub struct Ungraph<T> {
    nodes: HashMap<NodeIndex, Node<T>>,
    adj: HashMap<NodeIndex, NodeIndexSet>,
    num_nodes: uint,
}

/// Directed graph. Allows loops.
#[deriving(Show)]
pub struct Digraph<T> {
    nodes: HashMap<NodeIndex, Node<T>>,
    in_adj: HashMap<NodeIndex, NodeIndexSet>,
    out_adj: HashMap<NodeIndex, NodeIndexSet>,
    num_nodes: uint,
}

impl<T> Ungraph<T> {
    pub fn new() -> Ungraph<T> {
        Ungraph { nodes: HashMap::new(), adj: HashMap::new(), num_nodes: 0 }
    }

    pub fn degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if !self.adj.contains_key(&ind) {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok( self.get_adj(ind).len() )
        }
    }

    pub fn get_node<'a>(&'a self, i: NodeIndex) -> &'a Node<T> {
        self.nodes.find(&i).unwrap()
    }

    pub fn get_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.adj.find(&i).unwrap()
    }
}
impl<T: Clone> Ungraph<T> {
    /// Returns a new graph induced by a set of node indices
    pub fn induced_subgraph(&self, nodes: &NodeIndexSet) -> Ungraph<T> {
        let mut new = Ungraph::new();
        let mut ind_map = HashMap::new();

        for (i, ind) in nodes.iter().enumerate() {
            ind_map.insert(ind, i);
            new.add_node(self.get_node(*ind).data.clone());
        }

        // Here we're assuming that NodeIndex = uint. Not sure how to easily do otherwise
        for i in range(0, self.num_nodes) {
            for j in self.get_adj(i).iter() {
                new.add_edge(i, *j);
            }
        }

        new
    }
}

impl<T> Graph<T> for Ungraph<T> {
    fn add_node(&mut self, val: T) -> NodeIndex {
        let ind = self.num_nodes;
        self.nodes.insert(ind, Node { data: val, index: ind });
        self.adj.insert(ind, HashSet::new());
        self.num_nodes += 1;
        ind
    }

    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool> {
        if !self.nodes.contains_key(&i) {
            Err(GraphError::invalid_index(i))
        } else if !self.nodes.contains_key(&j) {
            Err(GraphError::invalid_index(j))
        } else {
            if self.get_adj(i).contains(&j) {
                Ok(false)
            } else {
                self.adj.find_mut(&i).unwrap().insert(j);
                self.adj.find_mut(&j).unwrap().insert(i);
                Ok(true)
            }
        }
    }

    fn adj(&self, i: NodeIndex) -> NodeIndices {
        FromIterator::from_iter(self.get_adj(i).iter().map(|&x| x))
    }

    fn num_nodes(&self) -> uint {
        self.num_nodes
    }

    fn node_indices(&self) -> NodeIndices {
        FromIterator::from_iter(self.nodes.keys().map(|&x| x))
    }
}

impl<T> Digraph<T> {
    pub fn new() -> Digraph<T> {
        Digraph { nodes: HashMap::new(),
                  in_adj: HashMap::new(),
                  out_adj: HashMap::new(),
                  num_nodes: 0 }
    }

    pub fn out_degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if !self.nodes.contains_key(&ind) {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok(self.get_out_adj(ind).len())
        }
    }

    pub fn in_degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if ind >= self.num_nodes {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok(self.get_in_adj(ind).len())
        }
    }

    pub fn get_node<'a>(&'a self, i: NodeIndex) -> &'a Node<T> {
        self.nodes.find(&i).unwrap()
    }

    pub fn get_in_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.in_adj.find(&i).unwrap()
    }

    pub fn get_out_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.out_adj.find(&i).unwrap()
    }
}

impl<T: Clone> Digraph<T> {
    /// Returns a new graph induced by a set of node indices
    pub fn induced_subgraph(&self, nodes: &NodeIndexSet) -> Digraph<T> {
        let mut new = Digraph::new();
        let mut ind_map = HashMap::new();

        for (i, ind) in nodes.iter().enumerate() {
            ind_map.insert(ind, i);
            new.add_node(self.get_node(*ind).data.clone());
        }

        // Here we're assuming that NodeIndex = uint. Not sure how to easily do otherwise
        for i in range(0, self.num_nodes) {
            for j in self.get_in_adj(i).iter() {
                new.add_edge(*j, i);
            }

            for j in self.get_out_adj(i).iter() {
                new.add_edge(i, *j);
            }
        }

        new
    }
}

impl<T> Graph<T> for Digraph<T> {
    fn add_node(&mut self, val: T) -> NodeIndex {
        let ind = self.num_nodes;
        self.nodes.insert(ind, Node { data: val, index: ind });
        self.in_adj.insert(ind, HashSet::new());
        self.out_adj.insert(ind, HashSet::new());
        self.num_nodes += 1;
        ind
    }

    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool> {
        if !self.nodes.contains_key(&i) {
            Err(GraphError::invalid_index(i))
        } else if !self.nodes.contains_key(&j) {
            Err(GraphError::invalid_index(j))
        } else {
            if self.get_out_adj(i).contains(&j) {
                Ok(false)
            } else {
                self.out_adj.find_mut(&i).unwrap().insert(j);
                self.in_adj.find_mut(&j).unwrap().insert(i);
                Ok(true)
            }
        }
    }

    fn adj(&self, i: NodeIndex) -> NodeIndices {
        FromIterator::from_iter(self.get_out_adj(i).iter().map(|&x| x))
    }

    fn num_nodes(&self) -> uint {
        self.num_nodes
    }

    fn node_indices(&self) -> NodeIndices {
        FromIterator::from_iter(self.nodes.keys().map(|&x| x))
    }
}

struct NodeIndices {
    indices: Vec<NodeIndex>,
    curr: uint,
}

impl Iterator<NodeIndex> for NodeIndices {
    fn next(&mut self) -> Option<NodeIndex> {
        if self.curr < self.indices.len() {
            self.curr += 1;
            Some(self.indices[self.curr - 1])
        } else {
            None
        }
    }
}

impl FromIterator<NodeIndex> for NodeIndices {
    fn from_iter<T: Iterator<NodeIndex>>(mut it: T) -> NodeIndices {
        let mut vec = vec!();
        for i in it {
            vec.push(i);
        }
        NodeIndices { indices: vec, curr: 0 }
    }

}
<commit_msg>Maybe fix induced_subgraph<commit_after>use {HashSet, HashMap};
use std::collections::{RingBuf, Deque};

// call this Unigraph instead?
pub trait Graph<T> {
    /// Insert a new node, returning its index
    fn add_node(&mut self, val: T) -> NodeIndex;

    /// Insert a new edge, returning an error if one of the indices is invalid
    /// and a result otherwise
    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool>;

    /// Return an iterator over the out-neighbors for a given node
    fn adj(&self, i: NodeIndex) -> NodeIndices;

    /// Return the number of nodes in the graph
    fn num_nodes(&self) -> uint;

    fn node_indices(&self) -> NodeIndices;
}

struct GraphError {
    error_type: GraphErrorType,
}

impl GraphError {
    fn invalid_index(ind: NodeIndex) -> GraphError {
        GraphError { error_type: InvalidNodeIndex(ind) }
    }
}

type GraphResult<T> = Result<T, GraphError>;

enum GraphErrorType {
    InvalidNodeIndex(NodeIndex),
}

pub type NodeIndex = uint;
type NodeIndexSet = HashSet<NodeIndex>;

#[deriving(Show, Clone)]
struct Node<T> {
    data: T,
    index: NodeIndex,
}

/// Undirected graph. Allows loops.
#[deriving(Show)]
pub struct Ungraph<T> {
    nodes: HashMap<NodeIndex, Node<T>>,
    adj: HashMap<NodeIndex, NodeIndexSet>,
    num_nodes: uint,
}

/// Directed graph. Allows loops.
#[deriving(Show)]
pub struct Digraph<T> {
    nodes: HashMap<NodeIndex, Node<T>>,
    in_adj: HashMap<NodeIndex, NodeIndexSet>,
    out_adj: HashMap<NodeIndex, NodeIndexSet>,
    num_nodes: uint,
}

impl<T> Ungraph<T> {
    pub fn new() -> Ungraph<T> {
        Ungraph { nodes: HashMap::new(), adj: HashMap::new(), num_nodes: 0 }
    }

    pub fn degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if !self.adj.contains_key(&ind) {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok( self.get_adj(ind).len() )
        }
    }

    pub fn get_node<'a>(&'a self, i: NodeIndex) -> &'a Node<T> {
        self.nodes.find(&i).unwrap()
    }

    pub fn get_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.adj.find(&i).unwrap()
    }
}
impl<T: Clone> Ungraph<T> {
    /// Returns a new graph induced by a set of node indices
    pub fn induced_subgraph(&self, nodes: &NodeIndexSet) -> Ungraph<T> {
        let mut new = Ungraph::new();
        let mut ind_map = HashMap::new(); // maps old indices to new

        for (i, &ind) in nodes.iter().enumerate() {
            ind_map.insert(ind, i);
            new.add_node(self.get_node(ind).data.clone());
        }

        for &i in nodes.iter() {
            for j in self.get_adj(i).iter() {
                if nodes.contains(j) {
                    new.add_edge(i, *ind_map.find(j).unwrap());
                }
            }
        }

        new
    }
}

impl<T> Graph<T> for Ungraph<T> {
    fn add_node(&mut self, val: T) -> NodeIndex {
        let ind = self.num_nodes;
        self.nodes.insert(ind, Node { data: val, index: ind });
        self.adj.insert(ind, HashSet::new());
        self.num_nodes += 1;
        ind
    }

    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool> {
        if !self.nodes.contains_key(&i) {
            Err(GraphError::invalid_index(i))
        } else if !self.nodes.contains_key(&j) {
            Err(GraphError::invalid_index(j))
        } else {
            if self.get_adj(i).contains(&j) {
                Ok(false)
            } else {
                self.adj.find_mut(&i).unwrap().insert(j);
                self.adj.find_mut(&j).unwrap().insert(i);
                Ok(true)
            }
        }
    }

    fn adj(&self, i: NodeIndex) -> NodeIndices {
        FromIterator::from_iter(self.get_adj(i).iter().map(|&x| x))
    }

    fn num_nodes(&self) -> uint {
        self.num_nodes
    }

    fn node_indices(&self) -> NodeIndices {
        FromIterator::from_iter(self.nodes.keys().map(|&x| x))
    }
}

impl<T> Digraph<T> {
    pub fn new() -> Digraph<T> {
        Digraph { nodes: HashMap::new(),
                  in_adj: HashMap::new(),
                  out_adj: HashMap::new(),
                  num_nodes: 0 }
    }

    pub fn out_degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if !self.nodes.contains_key(&ind) {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok(self.get_out_adj(ind).len())
        }
    }

    pub fn in_degree(&mut self, ind: NodeIndex) -> Result<uint, GraphError> {
        if ind >= self.num_nodes {
            Err(GraphError::invalid_index(ind))
        } else {
            Ok(self.get_in_adj(ind).len())
        }
    }

    pub fn get_node<'a>(&'a self, i: NodeIndex) -> &'a Node<T> {
        self.nodes.find(&i).unwrap()
    }

    pub fn get_in_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.in_adj.find(&i).unwrap()
    }

    pub fn get_out_adj<'a>(&'a self, i: NodeIndex) -> &'a NodeIndexSet {
        self.out_adj.find(&i).unwrap()
    }
}

impl<T: Clone> Digraph<T> {
    /// Returns a new graph induced by a set of node indices
    pub fn induced_subgraph(&self, nodes: &NodeIndexSet) -> Digraph<T> {
        let mut new = Digraph::new();
        let mut ind_map = HashMap::new(); // maps old indices to new

        for (i, &ind) in nodes.iter().enumerate() {
            ind_map.insert(ind, i);
            new.add_node(self.get_node(ind).data.clone());
        }

        for &i in nodes.iter() {
            for j in self.get_in_adj(i).iter() {
                if nodes.contains(j) {
                    new.add_edge(i, *ind_map.find(j).unwrap());
                }
            }

            for j in self.get_out_adj(i).iter() {
                if nodes.contains(j) {
                    new.add_edge(i, *ind_map.find(j).unwrap());
                }
            }
        }

        new
    }
}

impl<T> Graph<T> for Digraph<T> {
    fn add_node(&mut self, val: T) -> NodeIndex {
        let ind = self.num_nodes;
        self.nodes.insert(ind, Node { data: val, index: ind });
        self.in_adj.insert(ind, HashSet::new());
        self.out_adj.insert(ind, HashSet::new());
        self.num_nodes += 1;
        ind
    }

    fn add_edge(&mut self, i: NodeIndex, j: NodeIndex) -> GraphResult<bool> {
        if !self.nodes.contains_key(&i) {
            Err(GraphError::invalid_index(i))
        } else if !self.nodes.contains_key(&j) {
            Err(GraphError::invalid_index(j))
        } else {
            if self.get_out_adj(i).contains(&j) {
                Ok(false)
            } else {
                self.out_adj.find_mut(&i).unwrap().insert(j);
                self.in_adj.find_mut(&j).unwrap().insert(i);
                Ok(true)
            }
        }
    }

    fn adj(&self, i: NodeIndex) -> NodeIndices {
        FromIterator::from_iter(self.get_out_adj(i).iter().map(|&x| x))
    }

    fn num_nodes(&self) -> uint {
        self.num_nodes
    }

    fn node_indices(&self) -> NodeIndices {
        FromIterator::from_iter(self.nodes.keys().map(|&x| x))
    }
}

struct NodeIndices {
    indices: Vec<NodeIndex>,
    curr: uint,
}

impl Iterator<NodeIndex> for NodeIndices {
    fn next(&mut self) -> Option<NodeIndex> {
        if self.curr < self.indices.len() {
            self.curr += 1;
            Some(self.indices[self.curr - 1])
        } else {
            None
        }
    }
}

impl FromIterator<NodeIndex> for NodeIndices {
    fn from_iter<T: Iterator<NodeIndex>>(mut it: T) -> NodeIndices {
        let mut vec = vec!();
        for i in it {
            vec.push(i);
        }
        NodeIndices { indices: vec, curr: 0 }
    }

}
<|endoftext|>


<commit_before>use std::collections::hash_map::{HashMap, RandomState};
use std::error;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use {Command, Commands, Error, Record, Stack};

/// A group of either stacks or records.
pub struct Group<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: HashMap<K, V, S>,
    active: Option<K>,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Group<'a, K, V, S> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<'a, K, V, RandomState> {
        Default::default()
    }

    /// Returns a builder for a group.
    #[inline]
    pub fn builder() -> GroupBuilder<'a, K, V, S> {
        GroupBuilder {
            map: PhantomData,
            capacity: 0,
            signals: None,
        }
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.map.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Gets a reference to the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active.as_ref().and_then(|active| self.map.get(active))
    }

    /// Gets a mutable reference to the current active item in the group.
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut V> {
        let map = &mut self.map;
        self.active.as_mut().and_then(move |active| map.get_mut(active))
    }

    /// Sets the current active item in the group.
    ///
    /// Returns `None` if the item was successfully set, otherwise `k` is returned.
    #[inline]
    pub fn set(&mut self, k: K) -> Option<K> {
        if self.map.contains_key(&k) {
            if self.active.as_ref().map_or(false, |a| a != &k) {
                if let Some(ref mut f) = self.signals {
                    f(Some(&k))
                }
            }
            self.active = Some(k);
            None
        } else {
            Some(k)
        }
    }

    /// Unsets the current active item in the group.
    #[inline]
    pub fn unset(&mut self) {
        if self.active.is_some() {
            if let Some(ref mut f) = self.signals {
                f(None);
            }
        }
        self.active = None;
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Stack<R>, S> {
    /// Calls the [`push`] method on the active stack.
    ///
    /// [`push`]: stack/struct.Stack.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<(), Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |stack| stack.push(cmd))
    }

    /// Calls the [`pop`] method on the active stack.
    ///
    /// [`pop`]: stack/struct.Stack.html#method.pop
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        self.get_mut().and_then(|stack| stack.pop())
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Record<'a, R>, S> {
    /// Calls the [`set_saved`] method on the active record.
    ///
    /// [`set_saved`]: record/struct.Record.html#method.set_saved
    #[inline]
    pub fn set_saved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_saved())
    }

    /// Calls the [`set_unsaved`] method on the active record.
    ///
    /// [`set_unsaved`]: record/struct.Record.html#method.set_unsaved
    #[inline]
    pub fn set_unsaved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_unsaved())
    }

    /// Calls the [`is_saved`] method on the active record.
    ///
    /// [`is_saved`]: record/struct.Record.html#method.is_saved
    #[inline]
    pub fn is_saved(&self) -> Option<bool> {
        self.get().map(|stack| stack.is_saved())
    }

    /// Calls the [`push`] method on the active record.
    ///
    /// [`push`]: record/struct.Record.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<Commands<R>, Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |record| record.push(cmd))
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.redo())
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.undo())
    }
}

impl<'a, K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for Group<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Group")
            .field("map", &self.map)
            .field("active", &self.active)
            .finish()
    }
}

impl<'a, K: Hash + Eq + Display, V: Display> Display for Group<'a, K, V> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for (key, item) in &self.map {
            if self.active.as_ref().map_or(false, |a| a == key) {
                writeln!(f, " -> {}:\n    {}", key, item)?;
            } else {
                writeln!(f, "    {}:\n    {}", key, item)?;
            }
        }
        Ok(())
    }
}

impl<'a, K: Hash + Eq, V> Default for Group<'a, K, V, RandomState> {
    #[inline]
    fn default() -> Group<'a, K, V, RandomState> {
        Group {
            map: HashMap::new(),
            active: None,
            signals: None,
        }
    }
}

/// Builder for a group.
pub struct GroupBuilder<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: PhantomData<(K, V, S)>,
    capacity: usize,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V> GroupBuilder<'a, K, V, RandomState> {
    /// Creates the group.
    #[inline]
    pub fn build(self) -> Group<'a, K, V, RandomState> {
        self.build_with_hasher(Default::default())
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> GroupBuilder<'a, K, V, S> {
    /// Sets the specified [capacity] for the group.
    ///
    /// [capacity]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
    #[inline]
    pub fn capacity(mut self, capacity: usize) -> GroupBuilder<'a, K, V, S> {
        self.capacity = capacity;
        self
    }

    /// Decides what should happen when the active stack changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::*;
    /// # let _: Group<u8, u8> =
    /// Group::builder()
    ///     .signals(|k| match k {
    ///         Some(k) => println!("The new active stack is {}.", k),
    ///         None => println!("No active stack."),
    ///     })
    ///     .build();
    /// ```
    #[inline]
    pub fn signals<F>(mut self, f: F) -> GroupBuilder<'a, K, V, S>
    where
        F: FnMut(Option<&K>) + Send + Sync + 'a
    {
        self.signals = Some(Box::new(f));
        self
    }

    /// Creates the group with the given hasher.
    #[inline]
    pub fn build_with_hasher(self, hasher: S) -> Group<'a, K, V, S> {
        Group {
            map: HashMap::with_capacity_and_hasher(self.capacity, hasher),
            active: None,
            signals: self.signals,
        }
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Debug for GroupBuilder<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("GroupBuilder")
            .field("map", &self.map)
            .field("capacity", &self.capacity)
            .finish()
    }
}
<commit_msg>Add to_undo_string and to_redo_string to group<commit_after>use std::collections::hash_map::{HashMap, RandomState};
use std::error;
use std::fmt::{self, Debug, Display, Formatter};
use std::hash::{BuildHasher, Hash};
use std::marker::PhantomData;
use {Command, Commands, Error, Record, Stack};

/// A group of either stacks or records.
pub struct Group<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: HashMap<K, V, S>,
    active: Option<K>,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Group<'a, K, V, S> {
    /// Returns a new group.
    #[inline]
    pub fn new() -> Group<'a, K, V, RandomState> {
        Default::default()
    }

    /// Returns a builder for a group.
    #[inline]
    pub fn builder() -> GroupBuilder<'a, K, V, S> {
        GroupBuilder {
            map: PhantomData,
            capacity: 0,
            signals: None,
        }
    }

    /// Returns the capacity of the group.
    #[inline]
    pub fn capacity(&self) -> usize {
        self.map.capacity()
    }

    /// Returns the number of items in the group.
    #[inline]
    pub fn len(&self) -> usize {
        self.map.len()
    }

    /// Returns `true` if the group is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.map.is_empty()
    }

    /// Inserts an item into the group.
    #[inline]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        self.map.insert(k, v)
    }

    /// Removes an item from the group.
    #[inline]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Gets a reference to the current active item in the group.
    #[inline]
    pub fn get(&self) -> Option<&V> {
        self.active.as_ref().and_then(|active| self.map.get(active))
    }

    /// Gets a mutable reference to the current active item in the group.
    #[inline]
    pub fn get_mut(&mut self) -> Option<&mut V> {
        let map = &mut self.map;
        self.active.as_mut().and_then(move |active| map.get_mut(active))
    }

    /// Sets the current active item in the group.
    ///
    /// Returns `None` if the item was successfully set, otherwise `k` is returned.
    #[inline]
    pub fn set(&mut self, k: K) -> Option<K> {
        if self.map.contains_key(&k) {
            if self.active.as_ref().map_or(false, |a| a != &k) {
                if let Some(ref mut f) = self.signals {
                    f(Some(&k))
                }
            }
            self.active = Some(k);
            None
        } else {
            Some(k)
        }
    }

    /// Unsets the current active item in the group.
    #[inline]
    pub fn unset(&mut self) {
        if self.active.is_some() {
            if let Some(ref mut f) = self.signals {
                f(None);
            }
        }
        self.active = None;
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Stack<R>, S> {
    /// Calls the [`push`] method on the active stack.
    ///
    /// [`push`]: stack/struct.Stack.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<(), Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |stack| stack.push(cmd))
    }

    /// Calls the [`pop`] method on the active stack.
    ///
    /// [`pop`]: stack/struct.Stack.html#method.pop
    #[inline]
    pub fn pop(&mut self) -> Option<Result<Box<Command<R>>, Error<R>>> {
        self.get_mut().and_then(|stack| stack.pop())
    }
}

impl<'a, K: Hash + Eq, R, S: BuildHasher> Group<'a, K, Record<'a, R>, S> {
    /// Calls the [`set_saved`] method on the active record.
    ///
    /// [`set_saved`]: record/struct.Record.html#method.set_saved
    #[inline]
    pub fn set_saved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_saved())
    }

    /// Calls the [`set_unsaved`] method on the active record.
    ///
    /// [`set_unsaved`]: record/struct.Record.html#method.set_unsaved
    #[inline]
    pub fn set_unsaved(&mut self) -> Option<()> {
        self.get_mut().map(|stack| stack.set_unsaved())
    }

    /// Calls the [`is_saved`] method on the active record.
    ///
    /// [`is_saved`]: record/struct.Record.html#method.is_saved
    #[inline]
    pub fn is_saved(&self) -> Option<bool> {
        self.get().map(|stack| stack.is_saved())
    }

    /// Calls the [`push`] method on the active record.
    ///
    /// [`push`]: record/struct.Record.html#method.push
    #[inline]
    pub fn push<C>(&mut self, cmd: C) -> Option<Result<Commands<R>, Error<R>>>
        where
            C: Command<R> + 'static,
            R: 'static,
    {
        self.get_mut().map(move |record| record.push(cmd))
    }

    /// Calls the [`redo`] method on the active record.
    ///
    /// [`redo`]: record/struct.Record.html#method.redo
    #[inline]
    pub fn redo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.redo())
    }

    /// Calls the [`undo`] method on the active record.
    ///
    /// [`undo`]: record/struct.Record.html#method.undo
    #[inline]
    pub fn undo(&mut self) -> Option<Result<(), Box<error::Error>>> {
        self.get_mut().and_then(|record| record.undo())
    }

    /// Calls the [`to_undo_string`] method on the active record.
    ///
    /// [`to_undo_string`]: record/struct.Record.html#method.to_undo_string
    #[inline]
    pub fn to_undo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_undo_string())
    }

    /// Calls the [`to_redo_string`] method on the active record.
    ///
    /// [`to_redo_string`]: record/struct.Record.html#method.to_redo_string
    #[inline]
    pub fn to_redo_string(&self) -> Option<String> {
        self.get().and_then(|record| record.to_redo_string())
    }
}

impl<'a, K: Hash + Eq + Debug, V: Debug, S: BuildHasher> Debug for Group<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("Group")
            .field("map", &self.map)
            .field("active", &self.active)
            .finish()
    }
}

impl<'a, K: Hash + Eq + Display, V: Display> Display for Group<'a, K, V> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        for (key, item) in &self.map {
            if self.active.as_ref().map_or(false, |a| a == key) {
                writeln!(f, " -> {}:\n    {}", key, item)?;
            } else {
                writeln!(f, "    {}:\n    {}", key, item)?;
            }
        }
        Ok(())
    }
}

impl<'a, K: Hash + Eq, V> Default for Group<'a, K, V, RandomState> {
    #[inline]
    fn default() -> Group<'a, K, V, RandomState> {
        Group {
            map: HashMap::new(),
            active: None,
            signals: None,
        }
    }
}

/// Builder for a group.
pub struct GroupBuilder<'a, K: Hash + Eq, V, S = RandomState> where S: BuildHasher {
    map: PhantomData<(K, V, S)>,
    capacity: usize,
    signals: Option<Box<FnMut(Option<&K>) + Send + Sync + 'a>>,
}

impl<'a, K: Hash + Eq, V> GroupBuilder<'a, K, V, RandomState> {
    /// Creates the group.
    #[inline]
    pub fn build(self) -> Group<'a, K, V, RandomState> {
        self.build_with_hasher(Default::default())
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> GroupBuilder<'a, K, V, S> {
    /// Sets the specified [capacity] for the group.
    ///
    /// [capacity]: https://doc.rust-lang.org/std/vec/struct.Vec.html#capacity-and-reallocation
    #[inline]
    pub fn capacity(mut self, capacity: usize) -> GroupBuilder<'a, K, V, S> {
        self.capacity = capacity;
        self
    }

    /// Decides what should happen when the active stack changes.
    ///
    /// # Examples
    /// ```
    /// # use undo::*;
    /// # let _: Group<u8, u8> =
    /// Group::builder()
    ///     .signals(|k| match k {
    ///         Some(k) => println!("The new active stack is {}.", k),
    ///         None => println!("No active stack."),
    ///     })
    ///     .build();
    /// ```
    #[inline]
    pub fn signals<F>(mut self, f: F) -> GroupBuilder<'a, K, V, S>
    where
        F: FnMut(Option<&K>) + Send + Sync + 'a
    {
        self.signals = Some(Box::new(f));
        self
    }

    /// Creates the group with the given hasher.
    #[inline]
    pub fn build_with_hasher(self, hasher: S) -> Group<'a, K, V, S> {
        Group {
            map: HashMap::with_capacity_and_hasher(self.capacity, hasher),
            active: None,
            signals: self.signals,
        }
    }
}

impl<'a, K: Hash + Eq, V, S: BuildHasher> Debug for GroupBuilder<'a, K, V, S> {
    #[inline]
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        f.debug_struct("GroupBuilder")
            .field("map", &self.map)
            .field("capacity", &self.capacity)
            .finish()
    }
}
<|endoftext|>


<commit_before>// This file is part of rgtk.
//
// rgtk 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 3 of the License, or
// (at your option) any later version.
//
// rgtk 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 a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

use std::fmt::{Show, Error};
use cairo::ffi;

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Copy)]
pub enum Status {
    StatusSuccess = 0,

    StatusNoMemory,
    StatusInvalidRestore,
    StatusInvalidPopGroup,
    StatusNoCurrentPoint,
    StatusInvalidMatrix,
    StatusInvalidStatus,
    StatusNullPointer,
    StatusInvalidString,
    StatusInvalidPathData,
    StatusReadError,
    StatusWriteError,
    StatusSurfaceFinished,
    StatusSurfaceTypeMismatch,
    StatusPatternTypeMismatch,
    StatusInvalidContent,
    StatusInvalidFormat,
    StatusInvalidVisual,
    StatusFileNotFound,
    StatusInvalidDash,
    StatusInvalidDscComment,
    StatusInvalidIndex,
    StatusClipNotRepresentable,
    StatusTempFileError,
    StatusInvalidStride,
    StatusFontTypeMismatch,
    StatusUserFontImmutable,
    StatusUserFontError,
    StatusNegativeCount,
    StatusInvalidClusters,
    StatusInvalidSlant,
    StatusInvalidWeight,
    StatusInvalidSize,
    StatusUserFontNotImplemented,
    StatusDeviceTypeMismatch,
    StatusDeviceError,
    StatusInvalidMeshConstruction,
    StatusDeviceFinished,

    StatusLastStatus
}

impl Show for Status {
    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), Error> {
        unsafe {
            let char_ptr = ffi::cairo_status_to_string(*self);
            let tmp = String::from_utf8_lossy(::std::ffi::c_str_to_bytes(&char_ptr)).to_string();

            tmp.fmt(formatter)
        }
    }
}

impl Status {
    pub fn ensure_valid(&self) {
        if *self != Status::StatusSuccess {
            panic!("Cairo error {:?}", *self)
        }
    }
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Antialias {
    AntialiasDefault,

    /* method */
    AntialiasNone,
    AntialiasGray,
    AntialiasSubpixel,

    /* hints */
    AntialiasFast,
    AntialiasGood,
    AntialiasBest
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum FillRule {
    FillRuleWinding,
    FillRuleEvenOdd
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum LineCap {
    LineCapButt,
    LineCapRound,
    LineCapSquare
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum LineJoin {
    LineJoinMiter,
    LineJoinRound,
    LineJoinBevel
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Operator {
    OperatorClear,

    OperatorSource,
    OperatorOver,
    OperatorIn,
    OperatorOut,
    OperatorAtop,

    OperatorDest,
    OperatorDestOver,
    OperatorDestIn,
    OperatorDestOut,
    OperatorDestAtop,

    OperatorXor,
    OperatorAdd,
    OperatorSaturate,

    OperatorMultiply,
    OperatorScreen,
    OperatorOverlay,
    OperatorDarken,
    OperatorLighten,
    OperatorColorDodge,
    OperatorColorBurn,
    OperatorHardLight,
    OperatorSoftLight,
    OperatorDifference,
    OperatorExclusion,
    OperatorHslHue,
    OperatorHslSaturation,
    OperatorHslColor,
    OperatorHslLuminosity
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum PathDataType {
    PathMoveTo,
    PathLineTo,
    PathCurveTo,
    PathClosePath
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Content {
    ContentColor      = 0x1000,
    ContentAlpha      = 0x2000,
    ContentColorAlpha = 0x3000
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Extend {
    ExtendNone,
    ExtendRepeat,
    ExtendReflect,
    ExtendPad
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Filter {
    FilterFast,
    FilterGood,
    FilterBest,
    FilterNearest,
    FilterBilinear,
    FilterGaussian
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum PatternType {
    PatternTypeSolid,
    PatternTypeSurface,
    PatternTypeLinearGradient,
    PatternTypeRadialGradient,
    PatternTypeMesh,
    PatternTypeRasterSource
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum FontSlant {
    FontSlantNormal,
    FontSlantItalic,
    FontSlantOblique
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum FontWeight {
    FontWeightNormal,
    FontWeightBold
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum TextClusterFlags {
    TextClusterFlagNone     = 0x00000000,
    TextClusterFlagBackward = 0x00000001
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum FontType {
    FontTypeToy,
    FontTypeFt,
    FontTypeWin32,
    FontTypeQuartz,
    FontTypeUser
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum SubpixelOrder {
    SubpixelOrderDefault,
    SubpixelOrderRgb,
    SubpixelOrderBgr,
    SubpixelOrderVrgb,
    SubpixelOrderVbgr
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum HintStyle {
    HintStyleDefault,
    HintStyleNone,
    HintStyleSlight,
    HintStyleMedium,
    HintStyleFull
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum HintMetrics {
    HintMetricsDefault,
    HintMetricsOff,
    HintMetricsOn
}
<commit_msg>Fix build error<commit_after>// This file is part of rgtk.
//
// rgtk 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 3 of the License, or
// (at your option) any later version.
//
// rgtk 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 a copy of the GNU Lesser General Public License
// along with rgtk.  If not, see <http://www.gnu.org/licenses/>.

use std::fmt::{Error, Debug};
use cairo::ffi;

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Copy)]
pub enum Status {
    StatusSuccess = 0,

    StatusNoMemory,
    StatusInvalidRestore,
    StatusInvalidPopGroup,
    StatusNoCurrentPoint,
    StatusInvalidMatrix,
    StatusInvalidStatus,
    StatusNullPointer,
    StatusInvalidString,
    StatusInvalidPathData,
    StatusReadError,
    StatusWriteError,
    StatusSurfaceFinished,
    StatusSurfaceTypeMismatch,
    StatusPatternTypeMismatch,
    StatusInvalidContent,
    StatusInvalidFormat,
    StatusInvalidVisual,
    StatusFileNotFound,
    StatusInvalidDash,
    StatusInvalidDscComment,
    StatusInvalidIndex,
    StatusClipNotRepresentable,
    StatusTempFileError,
    StatusInvalidStride,
    StatusFontTypeMismatch,
    StatusUserFontImmutable,
    StatusUserFontError,
    StatusNegativeCount,
    StatusInvalidClusters,
    StatusInvalidSlant,
    StatusInvalidWeight,
    StatusInvalidSize,
    StatusUserFontNotImplemented,
    StatusDeviceTypeMismatch,
    StatusDeviceError,
    StatusInvalidMeshConstruction,
    StatusDeviceFinished,

    StatusLastStatus
}

impl Debug for Status {
    fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), Error> {
        unsafe {
            let char_ptr = ffi::cairo_status_to_string(*self);
            let tmp = String::from_utf8_lossy(::std::ffi::c_str_to_bytes(&char_ptr)).to_string();

            tmp.fmt(formatter)
        }
    }
}

impl Status {
    pub fn ensure_valid(&self) {
        if *self != Status::StatusSuccess {
            panic!("Cairo error {:?}", *self)
        }
    }
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Antialias {
    AntialiasDefault,

    /* method */
    AntialiasNone,
    AntialiasGray,
    AntialiasSubpixel,

    /* hints */
    AntialiasFast,
    AntialiasGood,
    AntialiasBest
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum FillRule {
    FillRuleWinding,
    FillRuleEvenOdd
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum LineCap {
    LineCapButt,
    LineCapRound,
    LineCapSquare
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum LineJoin {
    LineJoinMiter,
    LineJoinRound,
    LineJoinBevel
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Operator {
    OperatorClear,

    OperatorSource,
    OperatorOver,
    OperatorIn,
    OperatorOut,
    OperatorAtop,

    OperatorDest,
    OperatorDestOver,
    OperatorDestIn,
    OperatorDestOut,
    OperatorDestAtop,

    OperatorXor,
    OperatorAdd,
    OperatorSaturate,

    OperatorMultiply,
    OperatorScreen,
    OperatorOverlay,
    OperatorDarken,
    OperatorLighten,
    OperatorColorDodge,
    OperatorColorBurn,
    OperatorHardLight,
    OperatorSoftLight,
    OperatorDifference,
    OperatorExclusion,
    OperatorHslHue,
    OperatorHslSaturation,
    OperatorHslColor,
    OperatorHslLuminosity
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum PathDataType {
    PathMoveTo,
    PathLineTo,
    PathCurveTo,
    PathClosePath
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Content {
    ContentColor      = 0x1000,
    ContentAlpha      = 0x2000,
    ContentColorAlpha = 0x3000
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Extend {
    ExtendNone,
    ExtendRepeat,
    ExtendReflect,
    ExtendPad
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum Filter {
    FilterFast,
    FilterGood,
    FilterBest,
    FilterNearest,
    FilterBilinear,
    FilterGaussian
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum PatternType {
    PatternTypeSolid,
    PatternTypeSurface,
    PatternTypeLinearGradient,
    PatternTypeRadialGradient,
    PatternTypeMesh,
    PatternTypeRasterSource
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum FontSlant {
    FontSlantNormal,
    FontSlantItalic,
    FontSlantOblique
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum FontWeight {
    FontWeightNormal,
    FontWeightBold
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum TextClusterFlags {
    TextClusterFlagNone     = 0x00000000,
    TextClusterFlagBackward = 0x00000001
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum FontType {
    FontTypeToy,
    FontTypeFt,
    FontTypeWin32,
    FontTypeQuartz,
    FontTypeUser
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum SubpixelOrder {
    SubpixelOrderDefault,
    SubpixelOrderRgb,
    SubpixelOrderBgr,
    SubpixelOrderVrgb,
    SubpixelOrderVbgr
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum HintStyle {
    HintStyleDefault,
    HintStyleNone,
    HintStyleSlight,
    HintStyleMedium,
    HintStyleFull
}

#[repr(C)]
#[derive(Clone, PartialEq, PartialOrd, Show, Copy)]
pub enum HintMetrics {
    HintMetricsDefault,
    HintMetricsOff,
    HintMetricsOn
}
<|endoftext|>


<commit_before>use std::f32;
use image::{GenericImage, ImageBuffer, Luma};
use image::imageops::blur;
use gradients::{vertical_sobel, horizontal_sobel};
use definitions::{HasWhite, HasBlack};

/// Runs the canny edge detection algorithm on the provided `ImageBuffer`.
///
/// # Params
///
/// - low_threshold: Low threshold for the hysteresis procedure.
/// Edges with a strength higher than the low threshold will appear
/// in the output image, if there are strong edges nearby.
/// - high_threshold: High threshold for the hysteresis procedure.
/// Edges with a strength higher than the high threshold will always
/// appear as edges in the output image.
///
/// Returns a binary image, where edge pixels have a value of 255 and non-edge pixels a value of 0.
pub fn canny<I>(image: &I,
                low_threshold: f32,
                high_threshold: f32)
                -> ImageBuffer<Luma<u8>, Vec<u8>>
    where I: GenericImage<Pixel = Luma<u8>> + 'static
{
    assert!(high_threshold >= low_threshold);
    // Heavily based on the implementation proposed by wikipedia.
    // 1. Gaussian blur.
    const SIGMA: f32 = 1.4;
    let blurred = blur(image, SIGMA);

    // 2. Intensity of gradients.
    let gx = horizontal_sobel(&blurred);
    let gy = vertical_sobel(&blurred);
    let mut g = ImageBuffer::from_fn(image.width(), image.height(), |x, y| {
        let g = (gx[(x, y)][0] as f32).hypot(gy[(x, y)][0] as f32);
        Luma { data: [g] }
    });

    // 3. Non-maximum-suppression (Make edges thinner)
    non_maximum_suppression(&mut g, &gx, &gy);

    // 4. Hysteresis to filter out edges based on thresholds.
    hysteresis(&g, low_threshold, high_threshold)
}

/// Finds local maxima to make the edges thinner.
fn non_maximum_suppression(g: &mut ImageBuffer<Luma<f32>, Vec<f32>>,
                           gx: &ImageBuffer<Luma<i16>, Vec<i16>>,
                           gy: &ImageBuffer<Luma<i16>, Vec<i16>>) {
    const RADIANS_TO_DEGREES: f32 = 180f32 / f32::consts::PI;
    for x in 1..g.width() - 1 {
        for y in 1..g.height() - 1 {
            let mut angle = (((gy[(x, y)][0] as f32).atan2(gx[(x, y)][0] as f32) *
                              RADIANS_TO_DEGREES) as i16) as f32;
            if angle < 0.0 {
                angle += 180.0
            }
            // Clamp angle.
            let clamped_angle = if angle >= 157.5 || angle < 22.5 {
                0
            } else if angle >= 22.5 && angle < 67.5 {
                45
            } else if angle >= 67.5 && angle < 112.5 {
                90
            } else if angle >= 112.5 && angle < 157.5 {
                135
            } else {
                unreachable!()
            };

            // Get the two perpendicular neighbors.
            let (cmp1, cmp2) = unsafe {
                match clamped_angle {
                    0 => (g.unsafe_get_pixel(x, y - 1), g.unsafe_get_pixel(x, y + 1)),
                    45 => (g.unsafe_get_pixel(x + 1, y + 1),
                           g.unsafe_get_pixel(x - 1, y - 1)),
                    90 => (g.unsafe_get_pixel(x + 1, y), g.unsafe_get_pixel(x - 1, y)),
                    135 => (g.unsafe_get_pixel(x - 1, y + 1),
                            g.unsafe_get_pixel(x + 1, y - 1)),
                    _ => unreachable!(),
                }
            };
            let pixel = *g.get_pixel(x, y);
            // If the pixel is not a local maximum, suppress it.
            if pixel[0] < cmp1[0] || pixel[0] < cmp2[0] {
                g.put_pixel(x, y, Luma { data: [0.0] });
            }
        }
    }
}

// Filter out edges with the thresholds.
fn hysteresis(g: &ImageBuffer<Luma<f32>, Vec<f32>>,
              low_thresh: f32,
              high_thresh: f32)
              -> ImageBuffer<Luma<u8>, Vec<u8>> {
    let max_brightness = Luma::white();
    let min_brightness = Luma::black();
    // Init output image as all black.
    let mut out = ImageBuffer::from_pixel(g.width(), g.height(), min_brightness);
    for x in 1..g.width() - 1 {
        for y in 1..g.height() - 1 {
            let inp_pix = g.get_pixel(x, y);
            // Higher than high_thresh -> its definitely an edge.
            if inp_pix[0] >= high_thresh {
                out.put_pixel(x, y, max_brightness);
            } else if inp_pix[0] >= low_thresh && inp_pix[0] < high_thresh {
                // First, check if any neighbors from the input image are edges.
                let in_neighbors = unsafe {
                    [g.unsafe_get_pixel(x + 1, y),
                     g.unsafe_get_pixel(x + 1, y + 1),
                     g.unsafe_get_pixel(x, y + 1),
                     g.unsafe_get_pixel(x - 1, y - 1),
                     g.unsafe_get_pixel(x - 1, y),
                     g.unsafe_get_pixel(x - 1, y + 1)]
                };
                let mut edge_detected = false;
                for neighbor in &in_neighbors {
                    if neighbor[0] >= high_thresh {
                        out.put_pixel(x, y, max_brightness);
                        edge_detected = true;
                        break;
                    }
                }
                // Still not sure? check if any neighbors from the output image are edges.
                if !edge_detected {
                    let out_neighbors = unsafe {
                        [out.unsafe_get_pixel(x + 1, y),
                         out.unsafe_get_pixel(x + 1, y + 1),
                         out.unsafe_get_pixel(x, y + 1),
                         out.unsafe_get_pixel(x - 1, y - 1),
                         out.unsafe_get_pixel(x - 1, y),
                         out.unsafe_get_pixel(x - 1, y + 1)]
                    };
                    for neighbor in &out_neighbors {
                        if neighbor[0] == max_brightness[0] {
                            out.put_pixel(x, y, max_brightness);
                            break;
                        }
                    }
                }
            }
        }
    }
    out
}

#[cfg(test)]
mod test {
    use super::canny;
    use utils::edge_detect_bench_image;
    use test;

    #[bench]
    fn bench_canny(b: &mut test::Bencher) {
        let image = edge_detect_bench_image(250, 250);
        b.iter(|| {
            let output = canny(&image, 250.0, 300.0);
            test::black_box(output);
        });
    }
}
<commit_msg>Add doc comment to edges.rs<commit_after>//! Functions for detecting edges in images.

use std::f32;
use image::{GenericImage, ImageBuffer, Luma};
use image::imageops::blur;
use gradients::{vertical_sobel, horizontal_sobel};
use definitions::{HasWhite, HasBlack};

/// Runs the canny edge detection algorithm on the provided `ImageBuffer`.
///
/// # Params
///
/// - low_threshold: Low threshold for the hysteresis procedure.
/// Edges with a strength higher than the low threshold will appear
/// in the output image, if there are strong edges nearby.
/// - high_threshold: High threshold for the hysteresis procedure.
/// Edges with a strength higher than the high threshold will always
/// appear as edges in the output image.
///
/// Returns a binary image, where edge pixels have a value of 255 and non-edge pixels a value of 0.
pub fn canny<I>(image: &I,
                low_threshold: f32,
                high_threshold: f32)
                -> ImageBuffer<Luma<u8>, Vec<u8>>
    where I: GenericImage<Pixel = Luma<u8>> + 'static
{
    assert!(high_threshold >= low_threshold);
    // Heavily based on the implementation proposed by wikipedia.
    // 1. Gaussian blur.
    const SIGMA: f32 = 1.4;
    let blurred = blur(image, SIGMA);

    // 2. Intensity of gradients.
    let gx = horizontal_sobel(&blurred);
    let gy = vertical_sobel(&blurred);
    let mut g = ImageBuffer::from_fn(image.width(), image.height(), |x, y| {
        let g = (gx[(x, y)][0] as f32).hypot(gy[(x, y)][0] as f32);
        Luma { data: [g] }
    });

    // 3. Non-maximum-suppression (Make edges thinner)
    non_maximum_suppression(&mut g, &gx, &gy);

    // 4. Hysteresis to filter out edges based on thresholds.
    hysteresis(&g, low_threshold, high_threshold)
}

/// Finds local maxima to make the edges thinner.
fn non_maximum_suppression(g: &mut ImageBuffer<Luma<f32>, Vec<f32>>,
                           gx: &ImageBuffer<Luma<i16>, Vec<i16>>,
                           gy: &ImageBuffer<Luma<i16>, Vec<i16>>) {
    const RADIANS_TO_DEGREES: f32 = 180f32 / f32::consts::PI;
    for x in 1..g.width() - 1 {
        for y in 1..g.height() - 1 {
            let mut angle = (((gy[(x, y)][0] as f32).atan2(gx[(x, y)][0] as f32) *
                              RADIANS_TO_DEGREES) as i16) as f32;
            if angle < 0.0 {
                angle += 180.0
            }
            // Clamp angle.
            let clamped_angle = if angle >= 157.5 || angle < 22.5 {
                0
            } else if angle >= 22.5 && angle < 67.5 {
                45
            } else if angle >= 67.5 && angle < 112.5 {
                90
            } else if angle >= 112.5 && angle < 157.5 {
                135
            } else {
                unreachable!()
            };

            // Get the two perpendicular neighbors.
            let (cmp1, cmp2) = unsafe {
                match clamped_angle {
                    0 => (g.unsafe_get_pixel(x, y - 1), g.unsafe_get_pixel(x, y + 1)),
                    45 => (g.unsafe_get_pixel(x + 1, y + 1),
                           g.unsafe_get_pixel(x - 1, y - 1)),
                    90 => (g.unsafe_get_pixel(x + 1, y), g.unsafe_get_pixel(x - 1, y)),
                    135 => (g.unsafe_get_pixel(x - 1, y + 1),
                            g.unsafe_get_pixel(x + 1, y - 1)),
                    _ => unreachable!(),
                }
            };
            let pixel = *g.get_pixel(x, y);
            // If the pixel is not a local maximum, suppress it.
            if pixel[0] < cmp1[0] || pixel[0] < cmp2[0] {
                g.put_pixel(x, y, Luma { data: [0.0] });
            }
        }
    }
}

// Filter out edges with the thresholds.
fn hysteresis(g: &ImageBuffer<Luma<f32>, Vec<f32>>,
              low_thresh: f32,
              high_thresh: f32)
              -> ImageBuffer<Luma<u8>, Vec<u8>> {
    let max_brightness = Luma::white();
    let min_brightness = Luma::black();
    // Init output image as all black.
    let mut out = ImageBuffer::from_pixel(g.width(), g.height(), min_brightness);
    for x in 1..g.width() - 1 {
        for y in 1..g.height() - 1 {
            let inp_pix = g.get_pixel(x, y);
            // Higher than high_thresh -> its definitely an edge.
            if inp_pix[0] >= high_thresh {
                out.put_pixel(x, y, max_brightness);
            } else if inp_pix[0] >= low_thresh && inp_pix[0] < high_thresh {
                // First, check if any neighbors from the input image are edges.
                let in_neighbors = unsafe {
                    [g.unsafe_get_pixel(x + 1, y),
                     g.unsafe_get_pixel(x + 1, y + 1),
                     g.unsafe_get_pixel(x, y + 1),
                     g.unsafe_get_pixel(x - 1, y - 1),
                     g.unsafe_get_pixel(x - 1, y),
                     g.unsafe_get_pixel(x - 1, y + 1)]
                };
                let mut edge_detected = false;
                for neighbor in &in_neighbors {
                    if neighbor[0] >= high_thresh {
                        out.put_pixel(x, y, max_brightness);
                        edge_detected = true;
                        break;
                    }
                }
                // Still not sure? check if any neighbors from the output image are edges.
                if !edge_detected {
                    let out_neighbors = unsafe {
                        [out.unsafe_get_pixel(x + 1, y),
                         out.unsafe_get_pixel(x + 1, y + 1),
                         out.unsafe_get_pixel(x, y + 1),
                         out.unsafe_get_pixel(x - 1, y - 1),
                         out.unsafe_get_pixel(x - 1, y),
                         out.unsafe_get_pixel(x - 1, y + 1)]
                    };
                    for neighbor in &out_neighbors {
                        if neighbor[0] == max_brightness[0] {
                            out.put_pixel(x, y, max_brightness);
                            break;
                        }
                    }
                }
            }
        }
    }
    out
}

#[cfg(test)]
mod test {
    use super::canny;
    use utils::edge_detect_bench_image;
    use test;

    #[bench]
    fn bench_canny(b: &mut test::Bencher) {
        let image = edge_detect_bench_image(250, 250);
        b.iter(|| {
            let output = canny(&image, 250.0, 300.0);
            test::black_box(output);
        });
    }
}
<|endoftext|>