<commit_before>//! Handle colors and themes in the UI.
//!
//! # Colors
//!
//! Characters can be printed in the terminal with a specific color.
//! The [`Color`] enum represents the ways this can be set.
//!
//! [`Color`]: enum.Color.html
//!
//! # Palette
//!
//! To achieve a customizable, yet unified look, Cursive uses a configurable
//! palette of colors to be used through the entire application.
//!
//! The [`PaletteColor`] enum defines possible entries in this palette.
//!
//! [`PaletteColor`]: enum.PaletteColor.html
//!
//! These entries are:
//!
//! * **`Background`**: used to color the application background
//!   (around views).
//!   Defaults to **blue**.
//! * **`Shadow`**: used to color shadow around views.
//!   Defaults to **black**.
//! * **`View`**: used to color the background for views.
//!   Defaults to **white**.
//! * **`Primary`**: used to print primary text.
//!   Defaults to **black**.
//! * **`Secondary`**: used to print secondary text.
//!   Defaults to **blue**.
//! * **`Tertiary`**: used to print tertiary text.
//!   Defaults to **white**.
//! * **`TitlePrimary`**: used to print primary titles.
//!   Defaults to **red**.
//! * **`TitleSecondary`**: used to print secondary titles.
//!   Defaults to **yellow**.
//! * **`Highlight`**: used to highlight selected items.
//!   Defaults to **red**.
//! * **`HighlightInactive`**: used to highlight selected but inactive items.
//!   Defaults to **blue**.
//!
//! A [`Palette`] then maps each of these to an actual [`Color`].
//!
//! [`Palette`]: struct.Palette.html
//! [`Color`]: enum.Color.html
//!
//! # Color Types
//!
//! When drawing views, color can be picked in two way:
//!
//! * An exact [`Color`] can be given directly
//! * A [`PaletteColor`] entry can be given, which will fetch whatever color
//!   is currently defined for this.
//!
//! The [`ColorType`] enum abstract over these two choices.
//!
//! [`ColorType`]: enum.ColorType.html
//!
//! # Color Styles
//!
//! To actually print anything, two colors must be picked: one for the
//! foreground, and one for the background.
//!
//! As such, a [`ColorStyle`] is made of a pair of `ColorType`.
//!
//! Since some pairs are frequently used, `ColorStyle` defines some methods to
//! create these usual values:
//!
//! * **`ColorStyle::background()`**: style used to print the application background.
//!     * Its *background* color is `Background`.
//!     * Its *foreground* color is unimportant as no characters are ever
//!       printed in the background.
//! * **`ColorStyle::shadow()`**: style used to print shadows behind views.
//!     * Its *background* color is `Shadow`.
//!     * Here again, the *foreground* color is unimportant.
//! * **`ColorStyle::primary()`**: style used to print primary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Primary`.
//! * **`ColorStyle::secondary()`**: style used to print secondary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Secondary`.
//! * **`ColorStyle::tertiary()`**: style used to print tertiary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Tertiary`.
//! * **`ColorStyle::title_primary()`**: style used to print titles.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `TitlePrimary`.
//! * **`ColorStyle::title_secondary()`**: style used to print secondary titles.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `TitleSecondary`.
//! * **`ColorStyle::highlight()`**: style used to print selected items.
//!     * Its *background* color is `Highlight`.
//!     * Its *foreground* color is `View`.
//! * **`ColorStyle::highlight_inactive()`**: style used to print selected,
//!   but inactive items.
//!     * Its *background* color is `HighlightInactive`.
//!     * Its *foreground* color is `View`.
//!
//! Using one of these pairs when styling your application helps give it a
//! coherent look.
//!
//! [`ColorStyle`]: struct.ColorStyle.html
//!
//! # Effects
//!
//! On top of a color style, some effects can be applied on cells: `Reverse`,
//! for instance, swaps the foreground and background colors of a cell.
//!
//!
//! # Style
//!
//! Finally, a style combine a [`ColorType`] and a set of [`Effect`]s, to
//! represent any way text should be printed on screen.
//!
//! [`Effect`]: enum.Effect.html
//!
//! # Themes
//!
//! A theme defines the color palette an application will use, as well as
//! various options to style views.
//!
//! Themes are described in toml configuration files. All fields are optional.
//!
//! Here are the possible entries:
//!
//! ```toml
//! # Every field in a theme file is optional.
//!
//! # First come some various options
//! shadow = false  # Don't draw shadows around stacked views
//! borders = "simple"  # Alternatives are "none" and "outset"
//!
//! # Here we define the color palette.
//! [colors]
//! 	background = "black"
//! 	# If the value is an array, the first valid color will be used.
//! 	# If the terminal doesn't support custom color,
//! 	# non-base colors will be skipped.
//! 	shadow     = ["#000000", "black"]
//! 	view       = "#d3d7cf"
//!
//! 	# Array and simple values have the same effect.
//! 	primary   = ["#111111"]
//! 	secondary = "#EEEEEE"
//! 	tertiary  = "#444444"
//!
//! 	# Hex values can use lower or uppercase.
//! 	# (base color MUST be lowercase)
//! 	title_primary   = "#ff5555"
//! 	title_secondary = "#ffff55"
//!
//! 	# Lower precision values can use only 3 digits.
//! 	highlight          = "#F00"
//! 	highlight_inactive = "#5555FF"
//! ```
mod style;
mod effect;
mod color;
mod color_pair;
mod color_style;
mod border_style;
mod palette;

pub use self::border_style::BorderStyle;
pub use self::color::{BaseColor, Color};
pub use self::color_pair::ColorPair;
pub use self::color_style::{ColorStyle, ColorType};
pub use self::effect::Effect;
pub use self::palette::{Palette, PaletteColor, default_palette};
pub use self::style::Style;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use toml;

/// Represents the style a Cursive application will use.
#[derive(Clone, Debug)]
pub struct Theme {
    /// Whether views in a StackView should have shadows.
    pub shadow: bool,
    /// How view borders should be drawn.
    pub borders: BorderStyle,
    /// What colors should be used through the application?
    pub palette: Palette,
}

impl Default for Theme {
    fn default() -> Self {
        Theme {
            shadow: true,
            borders: BorderStyle::Simple,
            palette: default_palette(),
        }
    }
}

impl Theme {
    fn load(&mut self, table: &toml::value::Table) {
        if let Some(&toml::Value::Boolean(shadow)) = table.get("shadow") {
            self.shadow = shadow;
        }

        if let Some(&toml::Value::String(ref borders)) = table.get("borders") {
            self.borders = BorderStyle::from(borders);
        }

        if let Some(&toml::Value::Table(ref table)) = table.get("colors") {
            palette::load_table(&mut self.palette, table);
        }
    }
}

/// Possible error returned when loading a theme.
#[derive(Debug)]
pub enum Error {
    /// An error occured when reading the file.
    Io(io::Error),
    /// An error occured when parsing the toml content.
    Parse(toml::de::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}

impl From<toml::de::Error> for Error {
    fn from(err: toml::de::Error) -> Self {
        Error::Parse(err)
    }
}

/// Loads a theme from file and sets it as active.
pub fn load_theme_file<P: AsRef<Path>>(filename: P) -> Result<Theme, Error> {
    let content = {
        let mut content = String::new();
        let mut file = try!(File::open(filename));
        try!(file.read_to_string(&mut content));
        content
    };

    load_theme(&content)
}

/// Loads a theme string and sets it as active.
pub fn load_theme(content: &str) -> Result<Theme, Error> {
    let table = toml::de::from_str(content)?;

    let mut theme = Theme::default();
    theme.load(&table);

    Ok(theme)
}

/// Loads the default theme, and returns its representation.
pub fn load_default() -> Theme {
    Theme::default()
}
<commit_msg>Fix doc link<commit_after>//! Handle colors and themes in the UI.
//!
//! # Colors
//!
//! Characters can be printed in the terminal with a specific color.
//! The [`Color`] enum represents the ways this can be set.
//!
//! [`Color`]: enum.Color.html
//!
//! # Palette
//!
//! To achieve a customizable, yet unified look, Cursive uses a configurable
//! palette of colors to be used through the entire application.
//!
//! The [`PaletteColor`] enum defines possible entries in this palette.
//!
//! [`PaletteColor`]: enum.PaletteColor.html
//!
//! These entries are:
//!
//! * **`Background`**: used to color the application background
//!   (around views).
//!   Defaults to **blue**.
//! * **`Shadow`**: used to color shadow around views.
//!   Defaults to **black**.
//! * **`View`**: used to color the background for views.
//!   Defaults to **white**.
//! * **`Primary`**: used to print primary text.
//!   Defaults to **black**.
//! * **`Secondary`**: used to print secondary text.
//!   Defaults to **blue**.
//! * **`Tertiary`**: used to print tertiary text.
//!   Defaults to **white**.
//! * **`TitlePrimary`**: used to print primary titles.
//!   Defaults to **red**.
//! * **`TitleSecondary`**: used to print secondary titles.
//!   Defaults to **yellow**.
//! * **`Highlight`**: used to highlight selected items.
//!   Defaults to **red**.
//! * **`HighlightInactive`**: used to highlight selected but inactive items.
//!   Defaults to **blue**.
//!
//! A [`Palette`] then maps each of these to an actual [`Color`].
//!
//! [`Palette`]: type.Palette.html
//! [`Color`]: enum.Color.html
//!
//! # Color Types
//!
//! When drawing views, color can be picked in two way:
//!
//! * An exact [`Color`] can be given directly
//! * A [`PaletteColor`] entry can be given, which will fetch whatever color
//!   is currently defined for this.
//!
//! The [`ColorType`] enum abstract over these two choices.
//!
//! [`ColorType`]: enum.ColorType.html
//!
//! # Color Styles
//!
//! To actually print anything, two colors must be picked: one for the
//! foreground, and one for the background.
//!
//! As such, a [`ColorStyle`] is made of a pair of `ColorType`.
//!
//! Since some pairs are frequently used, `ColorStyle` defines some methods to
//! create these usual values:
//!
//! * **`ColorStyle::background()`**: style used to print the application background.
//!     * Its *background* color is `Background`.
//!     * Its *foreground* color is unimportant as no characters are ever
//!       printed in the background.
//! * **`ColorStyle::shadow()`**: style used to print shadows behind views.
//!     * Its *background* color is `Shadow`.
//!     * Here again, the *foreground* color is unimportant.
//! * **`ColorStyle::primary()`**: style used to print primary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Primary`.
//! * **`ColorStyle::secondary()`**: style used to print secondary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Secondary`.
//! * **`ColorStyle::tertiary()`**: style used to print tertiary text.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `Tertiary`.
//! * **`ColorStyle::title_primary()`**: style used to print titles.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `TitlePrimary`.
//! * **`ColorStyle::title_secondary()`**: style used to print secondary titles.
//!     * Its *background* color is `View`.
//!     * Its *foreground* color is `TitleSecondary`.
//! * **`ColorStyle::highlight()`**: style used to print selected items.
//!     * Its *background* color is `Highlight`.
//!     * Its *foreground* color is `View`.
//! * **`ColorStyle::highlight_inactive()`**: style used to print selected,
//!   but inactive items.
//!     * Its *background* color is `HighlightInactive`.
//!     * Its *foreground* color is `View`.
//!
//! Using one of these pairs when styling your application helps give it a
//! coherent look.
//!
//! [`ColorStyle`]: struct.ColorStyle.html
//!
//! # Effects
//!
//! On top of a color style, some effects can be applied on cells: `Reverse`,
//! for instance, swaps the foreground and background colors of a cell.
//!
//!
//! # Style
//!
//! Finally, a style combine a [`ColorType`] and a set of [`Effect`]s, to
//! represent any way text should be printed on screen.
//!
//! [`Effect`]: enum.Effect.html
//!
//! # Themes
//!
//! A theme defines the color palette an application will use, as well as
//! various options to style views.
//!
//! Themes are described in toml configuration files. All fields are optional.
//!
//! Here are the possible entries:
//!
//! ```toml
//! # Every field in a theme file is optional.
//!
//! # First come some various options
//! shadow = false  # Don't draw shadows around stacked views
//! borders = "simple"  # Alternatives are "none" and "outset"
//!
//! # Here we define the color palette.
//! [colors]
//! 	background = "black"
//! 	# If the value is an array, the first valid color will be used.
//! 	# If the terminal doesn't support custom color,
//! 	# non-base colors will be skipped.
//! 	shadow     = ["#000000", "black"]
//! 	view       = "#d3d7cf"
//!
//! 	# Array and simple values have the same effect.
//! 	primary   = ["#111111"]
//! 	secondary = "#EEEEEE"
//! 	tertiary  = "#444444"
//!
//! 	# Hex values can use lower or uppercase.
//! 	# (base color MUST be lowercase)
//! 	title_primary   = "#ff5555"
//! 	title_secondary = "#ffff55"
//!
//! 	# Lower precision values can use only 3 digits.
//! 	highlight          = "#F00"
//! 	highlight_inactive = "#5555FF"
//! ```
mod style;
mod effect;
mod color;
mod color_pair;
mod color_style;
mod border_style;
mod palette;

pub use self::border_style::BorderStyle;
pub use self::color::{BaseColor, Color};
pub use self::color_pair::ColorPair;
pub use self::color_style::{ColorStyle, ColorType};
pub use self::effect::Effect;
pub use self::palette::{Palette, PaletteColor, default_palette};
pub use self::style::Style;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use toml;

/// Represents the style a Cursive application will use.
#[derive(Clone, Debug)]
pub struct Theme {
    /// Whether views in a StackView should have shadows.
    pub shadow: bool,
    /// How view borders should be drawn.
    pub borders: BorderStyle,
    /// What colors should be used through the application?
    pub palette: Palette,
}

impl Default for Theme {
    fn default() -> Self {
        Theme {
            shadow: true,
            borders: BorderStyle::Simple,
            palette: default_palette(),
        }
    }
}

impl Theme {
    fn load(&mut self, table: &toml::value::Table) {
        if let Some(&toml::Value::Boolean(shadow)) = table.get("shadow") {
            self.shadow = shadow;
        }

        if let Some(&toml::Value::String(ref borders)) = table.get("borders") {
            self.borders = BorderStyle::from(borders);
        }

        if let Some(&toml::Value::Table(ref table)) = table.get("colors") {
            palette::load_table(&mut self.palette, table);
        }
    }
}

/// Possible error returned when loading a theme.
#[derive(Debug)]
pub enum Error {
    /// An error occured when reading the file.
    Io(io::Error),
    /// An error occured when parsing the toml content.
    Parse(toml::de::Error),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}

impl From<toml::de::Error> for Error {
    fn from(err: toml::de::Error) -> Self {
        Error::Parse(err)
    }
}

/// Loads a theme from file and sets it as active.
pub fn load_theme_file<P: AsRef<Path>>(filename: P) -> Result<Theme, Error> {
    let content = {
        let mut content = String::new();
        let mut file = try!(File::open(filename));
        try!(file.read_to_string(&mut content));
        content
    };

    load_theme(&content)
}

/// Loads a theme string and sets it as active.
pub fn load_theme(content: &str) -> Result<Theme, Error> {
    let table = toml::de::from_str(content)?;

    let mut theme = Theme::default();
    theme.load(&table);

    Ok(theme)
}

/// Loads the default theme, and returns its representation.
pub fn load_default() -> Theme {
    Theme::default()
}
<|endoftext|>


<commit_before>use ::Nav;
use std::collections::VecDeque;
use std::marker::PhantomData;

/// Persistent queue that imposes an ordering on data.
///
/// This trait is characterized by the ordering it imposes on a stream of
/// data. Based on the semantics of `shift` and `unshift`, which consume a
/// stream of data items one at a time,
///
/// This is used in tree traversals to determine the order in which tree nodes
/// are visited:
///
/// * Depth-first traversal is done when `shift` and `unshift` have push/pop
/// (last in, first out) semantics, so that unshifting each child of a tree node
/// and recurring results in a traversal in which the first grandchild is
/// visited prior to the last child.
/// * Breadth-first traversal is done when `shift` and `unshift` have
/// enqueue/dequeue semantics (first in, first out), so that unshifting each
/// child of a tree node and recurring results in a traversal in which the last
/// child is visited before the first grandchild.
/// * Other traversal orders can be generated by more exotic queue
/// implementations.
pub trait Queue<T> {
    /// Returns the number of elements in the queue.
    fn len(&self) -> usize;

    /// Returns `true` iff the queue has no elements.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Peeks at the next item to be returned by `shift.
    ///
    /// Returns `None` if the queue is empty.
    fn first(&self) -> Option<&T>;

    /// Adds an item to the queue.
    fn unshift(&mut self, t: T);

    /// Pulls the next available item from the queue.
    ///
    /// Returns `None` if the queue is empty.
    fn shift(&mut self) -> Option<T>;
}

/// `std::Vec`-backed queue with last in, first out ordering. Used for
/// depth-first search.
///
/// Note that the search which this queue powers visits a node's immediate
/// children in reverse order.
pub struct DepthQueue<T> {
    v: Vec<T>,
}

impl<T> DepthQueue<T> {
    pub fn new() -> Self { DepthQueue { v: Vec::new(), } }
}

impl<T> Queue<T> for DepthQueue<T> {
    fn len(&self) -> usize { self.v.len() }
    fn first(&self) -> Option<&T> { self.v.first() }
    fn unshift(&mut self, t: T) { self.v.push(t); }
    fn shift(&mut self) -> Option<T> { self.v.pop() }
}

/// `std::collections::VecDeque`-backed queue with first in, first out
/// ordering. Used for breadth-first search.
pub struct BreadthQueue<T> {
    v: VecDeque<T>,
}

impl<T> BreadthQueue<T> {
    pub fn new() -> Self { BreadthQueue { v: VecDeque::new(), } }
}

impl<T> Queue<T> for BreadthQueue<T> {
    fn len(&self) -> usize { self.v.len() }
    fn first(&self) -> Option<&T> { self.v.front() }
    fn unshift(&mut self, t: T) { self.v.push_back(t) }
    fn shift(&mut self) -> Option<T> { self.v.pop_front() }
}

/// Traverses a tree with a visitor function that is called at each node.
///
/// The traversal starts at the tree location `v` and proceeds through it and
/// all nodes below it in the order defined by `queue`. At each node,
/// `predicate` is called with a pointer to the current tree node.
pub fn traverse<T, N, Q, F>(n: N, mut queue: Q, predicate: F)
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) {
        queue.unshift(n);
        loop {
            match queue.shift() {
                None => return,
                Some(next) => {
                    predicate(next.clone());
                    if ! next.at_leaf() {
                        for i in 0..next.child_count() {
                            let mut child = next.clone();
                            child.seek_child(i);
                            queue.unshift(child);
                        }
                    }
                }
            }
        }
    }

/// Finds the first node in a tree matching a predicate.
///
/// The search starts at the tree location `n` and proceeds through it and all
/// nodes below it in the order defined by `queue`. At each node, `predicate` is
/// called with a pointer to the current tree node. If `predicate` returns
/// `true`, a pointer to the current tree location is returned. If `predicate`
/// never returns `true`, `None` is returned.
pub fn find_first<N, Q, F>(n: N, mut queue: Q, predicate: F) -> Option<N>
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) -> bool {
        queue.unshift(n);
        loop {
            match queue.shift() {
                None => return None,
                Some(next) => {
                    if predicate(next.clone()) {
                        return Some(next);
                    }
                    if ! next.at_leaf() {
                        for i in 0..next.child_count() {
                            let mut child = next.clone();
                            child.seek_child(i);
                            queue.unshift(child);
                        }
                    }
                },
            }
        }
    }

/// Iterator closing over a tree search environment.
pub struct FindIter<N, Q, F>
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) -> bool {
        phantom: PhantomData<N>,
        predicate: F,
        queue: Q,
    }

impl<N, Q, F> Iterator for FindIter<N, Q, F>
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) -> bool {
        type Item = N;
        fn next(&mut self) -> Option<N> {
            loop {
                match self.queue.shift() {
                    None => return None,
                    Some(next) => {
                        if ! next.at_leaf() {
                            for i in 0..next.child_count() {
                                let mut child = next.clone();
                                child.seek_child(i);
                                self.queue.unshift(child);
                            }
                        }
                        let f = &self.predicate;
                        if f(next.clone()) {
                            return Some(next);
                        }
                    },
                }
            }
        }
    }

/// Finds all nodes in a tree matching a predicate.
///
/// The search starts at the tree location `n` and proceeds through it and all
/// nodes below it in the order defined by `queue`. At each node, `predicate` is
/// called with a pointer to the current tree node. The iterator yields only
/// nodes for which `predicate` returned `true`.
pub fn find_all<N, Q, F>(n: N, mut queue: Q, predicate: F) -> FindIter<N, Q, F>
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) -> bool {
        queue.unshift(n);
        FindIter { phantom: PhantomData, predicate: predicate, queue: queue, }
    }

// #[cfg(test)]
// mod test {
//     fn iter_eq<T, I, J>(i: I, j: J) -> bool
//         where T: PartialEq, I: Iterator<Item=T>, J: Iterator<Item=T> {
//             loop {
//                 match (i.next(), j.next()) {
//                     (Some(x), Some(y)) if x == y => continue,
//                     (None, None) => return true,
//                     _ => return false,
//                 }
//             }
//         }
// }
<commit_msg>Prospective simpler bfs and dfs routines that don't grow queues.<commit_after>use ::Nav;
use std::collections::VecDeque;
use std::marker::PhantomData;

/// Persistent queue that imposes an ordering on data.
///
/// This trait is characterized by the ordering it imposes on a stream of
/// data. Based on the semantics of `shift` and `unshift`, which consume a
/// stream of data items one at a time,
///
/// This is used in tree traversals to determine the order in which tree nodes
/// are visited:
///
/// * Depth-first traversal is done when `shift` and `unshift` have push/pop
/// (last in, first out) semantics, so that unshifting each child of a tree node
/// and recurring results in a traversal in which the first grandchild is
/// visited prior to the last child.
/// * Breadth-first traversal is done when `shift` and `unshift` have
/// enqueue/dequeue semantics (first in, first out), so that unshifting each
/// child of a tree node and recurring results in a traversal in which the last
/// child is visited before the first grandchild.
/// * Other traversal orders can be generated by more exotic queue
/// implementations.
pub trait Queue<T> {
    /// Returns the number of elements in the queue.
    fn len(&self) -> usize;

    /// Returns `true` iff the queue has no elements.
    fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Peeks at the next item to be returned by `shift.
    ///
    /// Returns `None` if the queue is empty.
    fn first(&self) -> Option<&T>;

    /// Adds an item to the queue.
    fn unshift(&mut self, t: T);

    /// Pulls the next available item from the queue.
    ///
    /// Returns `None` if the queue is empty.
    fn shift(&mut self) -> Option<T>;
}

/// `std::Vec`-backed queue with last in, first out ordering. Used for
/// depth-first search.
///
/// Note that the search which this queue powers visits a node's immediate
/// children in reverse order.
pub struct DepthQueue<T> {
    v: Vec<T>,
}

impl<T> DepthQueue<T> {
    pub fn new() -> Self { DepthQueue { v: Vec::new(), } }
}

impl<T> Queue<T> for DepthQueue<T> {
    fn len(&self) -> usize { self.v.len() }
    fn first(&self) -> Option<&T> { self.v.first() }
    fn unshift(&mut self, t: T) { self.v.push(t); }
    fn shift(&mut self) -> Option<T> { self.v.pop() }
}

/// `std::collections::VecDeque`-backed queue with first in, first out
/// ordering. Used for breadth-first search.
pub struct BreadthQueue<T> {
    v: VecDeque<T>,
}

impl<T> BreadthQueue<T> {
    pub fn new() -> Self { BreadthQueue { v: VecDeque::new(), } }
}

impl<T> Queue<T> for BreadthQueue<T> {
    fn len(&self) -> usize { self.v.len() }
    fn first(&self) -> Option<&T> { self.v.front() }
    fn unshift(&mut self, t: T) { self.v.push_back(t) }
    fn shift(&mut self) -> Option<T> { self.v.pop_front() }
}

/// Traverses a tree with a visitor function that is called at each node.
///
/// The traversal starts at the tree location `v` and proceeds through it and
/// all nodes below it in the order defined by `queue`. At each node,
/// `predicate` is called with a pointer to the current tree node.
pub fn traverse<T, N, Q, F>(n: N, mut queue: Q, predicate: F)
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) {
        queue.unshift(n);
        loop {
            match queue.shift() {
                None => return,
                Some(next) => {
                    predicate(next.clone());
                    if ! next.at_leaf() {
                        for i in 0..next.child_count() {
                            let mut child = next.clone();
                            child.seek_child(i);
                            queue.unshift(child);
                        }
                    }
                }
            }
        }
    }

pub fn bfs<N, F>(mut n: N, predicate: F) -> Option<N>
    where N: Nav, F: Fn(&N) -> bool {
        enum Breadcrumb {
            Unvisited,
            Visited,
            Exhausted,
        }
        let mut state = Breadcrumb::Unvisited;
        loop {
            state = match state {
                Breadcrumb::Unvisited =>
                    if predicate(&n) {
                        return Some(n)
                    } else if n.seek_sibling(1) {
                        Breadcrumb::Unvisited
                    } else {
                        n.seek_first_sibling();
                        Breadcrumb::Visited
                    },
                Breadcrumb::Visited =>
                    if n.seek_child(0) {
                        Breadcrumb::Unvisited
                    } else {
                        Breadcrumb::Exhausted
                    },
                Breadcrumb::Exhausted =>
                    if n.seek_sibling(1) {
                        Breadcrumb::Unvisited
                    } else if n.to_parent() {
                        Breadcrumb::Exhausted
                    } else {
                        return None
                    },
            }
        }
    }

pub fn dfs<N, F>(mut n: N, predicate: F) -> Option<N>
    where N: Nav, F: Fn(&N) -> bool {
        enum Breadcrumb {
            Unvisited,
            Exhausted,
        }
        let mut state = Breadcrumb::Unvisited;
        loop {
            state = match state {
                Breadcrumb::Unvisited =>
                    if predicate(&n) {
                        return Some(n)
                    } else if n.seek_child(0) {
                        Breadcrumb::Unvisited
                    } else if n.seek_sibling(1) {
                        Breadcrumb::Unvisited
                    } else if n.to_parent() {
                        Breadcrumb::Exhausted
                    } else {
                        return None
                    },
                Breadcrumb::Exhausted =>
                    if n.seek_sibling(1) {
                        Breadcrumb::Unvisited
                    } else if n.to_parent() {
                        Breadcrumb::Exhausted
                    } else {
                        return None
                    },
            }
        }
    }

/// Finds the first node in a tree matching a predicate.
///
/// The search starts at the tree location `n` and proceeds through it and all
/// nodes below it in the order defined by `queue`. At each node, `predicate` is
/// called with a pointer to the current tree node. If `predicate` returns
/// `true`, a pointer to the current tree location is returned. If `predicate`
/// never returns `true`, `None` is returned.
pub fn find_first<N, Q, F>(n: N, mut queue: Q, predicate: F) -> Option<N>
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) -> bool {
        queue.unshift(n);
        loop {
            match queue.shift() {
                None => return None,
                Some(next) => {
                    if predicate(next.clone()) {
                        return Some(next);
                    }
                    if ! next.at_leaf() {
                        for i in 0..next.child_count() {
                            let mut child = next.clone();
                            child.seek_child(i);
                            queue.unshift(child);
                        }
                    }
                },
            }
        }
    }

/// Iterator closing over a tree search environment.
pub struct FindIter<N, Q, F>
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) -> bool {
        phantom: PhantomData<N>,
        predicate: F,
        queue: Q,
    }

impl<N, Q, F> Iterator for FindIter<N, Q, F>
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) -> bool {
        type Item = N;
        fn next(&mut self) -> Option<N> {
            loop {
                match self.queue.shift() {
                    None => return None,
                    Some(next) => {
                        if ! next.at_leaf() {
                            for i in 0..next.child_count() {
                                let mut child = next.clone();
                                child.seek_child(i);
                                self.queue.unshift(child);
                            }
                        }
                        let f = &self.predicate;
                        if f(next.clone()) {
                            return Some(next);
                        }
                    },
                }
            }
        }
    }

/// Finds all nodes in a tree matching a predicate.
///
/// The search starts at the tree location `n` and proceeds through it and all
/// nodes below it in the order defined by `queue`. At each node, `predicate` is
/// called with a pointer to the current tree node. The iterator yields only
/// nodes for which `predicate` returned `true`.
pub fn find_all<N, Q, F>(n: N, mut queue: Q, predicate: F) -> FindIter<N, Q, F>
    where N: Nav + Clone, Q: Queue<N>, F: Fn(N) -> bool {
        queue.unshift(n);
        FindIter { phantom: PhantomData, predicate: predicate, queue: queue, }
    }

// #[cfg(test)]
// mod test {
//     fn iter_eq<T, I, J>(i: I, j: J) -> bool
//         where T: PartialEq, I: Iterator<Item=T>, J: Iterator<Item=T> {
//             loop {
//                 match (i.next(), j.next()) {
//                     (Some(x), Some(y)) if x == y => continue,
//                     (None, None) => return true,
//                     _ => return false,
//                 }
//             }
//         }
// }
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::net::IpAddr;
use uuid::Uuid;

use types::{AsRustType, CBytes, AsRust};
use frame::frame_result::{ColTypeOption, ColTypeOptionValue, ColType};
use types::data_serialization_types::*;
use types::list::List;
use types::udt::UDT;
use types::tuple::Tuple;
use error::{Error, Result};

#[derive(Debug)]
pub struct Map {
    metadata: ColTypeOption,
    data: Vec<(CBytes, CBytes)>,
}

impl Map {
    /// Creates new `Map` using the provided data and key and value types.
    pub fn new(data: Vec<(CBytes, CBytes)>, meta: ColTypeOption) -> Map {
        Map {
            metadata: meta,
            data: data,
        }
    }
}

impl AsRust for Map {}

// Generate `AsRust` implementations for all kinds of map types.
// The macro `map_as_rust!` takes the types as lists of token trees,
// which means that for example the type definition of `Vec<u8>` is split into
// four tokens `Vec`, `<`, `u8` and `>`. Since `map_as_rust!` takes two lists
// of token trees in a row, they have to be separated by a prefix.
// So every token of the key type has to prefixed with a `K` and the value tokens with a `V`.

map_as_rust!(K Vec K < K u8 K >, V Vec V < V u8 V >);
map_as_rust!(K Vec K < K u8 K >, V String);
map_as_rust!(K Vec K < K u8 K >, V bool);
map_as_rust!(K Vec K < K u8 K >, V i64);
map_as_rust!(K Vec K < K u8 K >, V i32);
map_as_rust!(K Vec K < K u8 K >, V i16);
map_as_rust!(K Vec K < K u8 K >, V i8);
map_as_rust!(K Vec K < K u8 K >, V f64);
map_as_rust!(K Vec K < K u8 K >, V f32);
map_as_rust!(K Vec K < K u8 K >, V IpAddr);
map_as_rust!(K Vec K < K u8 K >, V Uuid);
map_as_rust!(K Vec K < K u8 K >, V List);
map_as_rust!(K Vec K < K u8 K >, V Map);
map_as_rust!(K Vec K < K u8 K >, V UDT);
map_as_rust!(K Vec K < K u8 K >, V Tuple);

map_as_rust!(K String, V Vec V < V u8 V >);
map_as_rust!(K String, V String);
map_as_rust!(K String, V bool);
map_as_rust!(K String, V i64);
map_as_rust!(K String, V i32);
map_as_rust!(K String, V i16);
map_as_rust!(K String, V i8);
map_as_rust!(K String, V f64);
map_as_rust!(K String, V f32);
map_as_rust!(K String, V IpAddr);
map_as_rust!(K String, V Uuid);
map_as_rust!(K String, V List);
map_as_rust!(K String, V Map);
map_as_rust!(K String, V UDT);
map_as_rust!(K String, V Tuple);

map_as_rust!(K bool, V Vec V < V u8 V >);
map_as_rust!(K bool, V String);
map_as_rust!(K bool, V bool);
map_as_rust!(K bool, V i64);
map_as_rust!(K bool, V i32);
map_as_rust!(K bool, V i16);
map_as_rust!(K bool, V i8);
map_as_rust!(K bool, V f64);
map_as_rust!(K bool, V f32);
map_as_rust!(K bool, V IpAddr);
map_as_rust!(K bool, V Uuid);
map_as_rust!(K bool, V List);
map_as_rust!(K bool, V Map);
map_as_rust!(K bool, V UDT);
map_as_rust!(K bool, V Tuple);

map_as_rust!(K i64, V Vec V < V u8 V >);
map_as_rust!(K i64, V String);
map_as_rust!(K i64, V bool);
map_as_rust!(K i64, V i64);
map_as_rust!(K i64, V i32);
map_as_rust!(K i64, V i16);
map_as_rust!(K i64, V i8);
map_as_rust!(K i64, V f64);
map_as_rust!(K i64, V f32);
map_as_rust!(K i64, V IpAddr);
map_as_rust!(K i64, V Uuid);
map_as_rust!(K i64, V List);
map_as_rust!(K i64, V Map);
map_as_rust!(K i64, V UDT);
map_as_rust!(K i64, V Tuple);

map_as_rust!(K i32, V Vec V < V u8 V >);
map_as_rust!(K i32, V String);
map_as_rust!(K i32, V bool);
map_as_rust!(K i32, V i64);
map_as_rust!(K i32, V i32);
map_as_rust!(K i32, V i16);
map_as_rust!(K i32, V i8);
map_as_rust!(K i32, V f64);
map_as_rust!(K i32, V f32);
map_as_rust!(K i32, V IpAddr);
map_as_rust!(K i32, V Uuid);
map_as_rust!(K i32, V List);
map_as_rust!(K i32, V Map);
map_as_rust!(K i32, V UDT);
map_as_rust!(K i32, V Tuple);

map_as_rust!(K i16, V Vec V < V u8 V >);
map_as_rust!(K i16, V String);
map_as_rust!(K i16, V bool);
map_as_rust!(K i16, V i64);
map_as_rust!(K i16, V i32);
map_as_rust!(K i16, V i16);
map_as_rust!(K i16, V i8);
map_as_rust!(K i16, V f64);
map_as_rust!(K i16, V f32);
map_as_rust!(K i16, V IpAddr);
map_as_rust!(K i16, V Uuid);
map_as_rust!(K i16, V List);
map_as_rust!(K i16, V Map);
map_as_rust!(K i16, V UDT);
map_as_rust!(K i16, V Tuple);

map_as_rust!(K i8, V Vec V < V u8 V >);
map_as_rust!(K i8, V String);
map_as_rust!(K i8, V bool);
map_as_rust!(K i8, V i64);
map_as_rust!(K i8, V i32);
map_as_rust!(K i8, V i16);
map_as_rust!(K i8, V i8);
map_as_rust!(K i8, V f64);
map_as_rust!(K i8, V f32);
map_as_rust!(K i8, V IpAddr);
map_as_rust!(K i8, V Uuid);
map_as_rust!(K i8, V List);
map_as_rust!(K i8, V Map);
map_as_rust!(K i8, V UDT);
map_as_rust!(K i8, V Tuple);

map_as_rust!(K IpAddr, V Vec V < V u8 V >);
map_as_rust!(K IpAddr, V String);
map_as_rust!(K IpAddr, V bool);
map_as_rust!(K IpAddr, V i64);
map_as_rust!(K IpAddr, V i32);
map_as_rust!(K IpAddr, V i16);
map_as_rust!(K IpAddr, V i8);
map_as_rust!(K IpAddr, V f64);
map_as_rust!(K IpAddr, V f32);
map_as_rust!(K IpAddr, V IpAddr);
map_as_rust!(K IpAddr, V Uuid);
map_as_rust!(K IpAddr, V List);
map_as_rust!(K IpAddr, V Map);
map_as_rust!(K IpAddr, V UDT);
map_as_rust!(K IpAddr, V Tuple);

map_as_rust!(K Uuid, V Vec V < V u8 V >);
map_as_rust!(K Uuid, V String);
map_as_rust!(K Uuid, V bool);
map_as_rust!(K Uuid, V i64);
map_as_rust!(K Uuid, V i32);
map_as_rust!(K Uuid, V i16);
map_as_rust!(K Uuid, V i8);
map_as_rust!(K Uuid, V f64);
map_as_rust!(K Uuid, V f32);
map_as_rust!(K Uuid, V IpAddr);
map_as_rust!(K Uuid, V Uuid);
map_as_rust!(K Uuid, V List);
map_as_rust!(K Uuid, V Map);
map_as_rust!(K Uuid, V UDT);
map_as_rust!(K Uuid, V Tuple);

map_as_rust!(K Tuple, V Vec V < V u8 V >);
map_as_rust!(K Tuple, V String);
map_as_rust!(K Tuple, V bool);
map_as_rust!(K Tuple, V i64);
map_as_rust!(K Tuple, V i32);
map_as_rust!(K Tuple, V i16);
map_as_rust!(K Tuple, V i8);
map_as_rust!(K Tuple, V f64);
map_as_rust!(K Tuple, V f32);
map_as_rust!(K Tuple, V IpAddr);
map_as_rust!(K Tuple, V Uuid);
map_as_rust!(K Tuple, V List);
map_as_rust!(K Tuple, V Map);
map_as_rust!(K Tuple, V UDT);
map_as_rust!(K Tuple, V Tuple);
<commit_msg>Add missing Timespec support for maps<commit_after>use std::collections::HashMap;
use std::net::IpAddr;
use uuid::Uuid;
use time::Timespec;

use types::{AsRustType, CBytes, AsRust};
use frame::frame_result::{ColTypeOption, ColTypeOptionValue, ColType};
use types::data_serialization_types::*;
use types::list::List;
use types::udt::UDT;
use types::tuple::Tuple;
use error::{Error, Result};

#[derive(Debug)]
pub struct Map {
    metadata: ColTypeOption,
    data: Vec<(CBytes, CBytes)>,
}

impl Map {
    /// Creates new `Map` using the provided data and key and value types.
    pub fn new(data: Vec<(CBytes, CBytes)>, meta: ColTypeOption) -> Map {
        Map {
            metadata: meta,
            data: data,
        }
    }
}

impl AsRust for Map {}

// Generate `AsRust` implementations for all kinds of map types.
// The macro `map_as_rust!` takes the types as lists of token trees,
// which means that for example the type definition of `Vec<u8>` is split into
// four tokens `Vec`, `<`, `u8` and `>`. Since `map_as_rust!` takes two lists
// of token trees in a row, they have to be separated by a prefix.
// So every token of the key type has to prefixed with a `K` and the value tokens with a `V`.

map_as_rust!(K Vec K < K u8 K >, V Vec V < V u8 V >);
map_as_rust!(K Vec K < K u8 K >, V String);
map_as_rust!(K Vec K < K u8 K >, V bool);
map_as_rust!(K Vec K < K u8 K >, V i64);
map_as_rust!(K Vec K < K u8 K >, V i32);
map_as_rust!(K Vec K < K u8 K >, V i16);
map_as_rust!(K Vec K < K u8 K >, V i8);
map_as_rust!(K Vec K < K u8 K >, V f64);
map_as_rust!(K Vec K < K u8 K >, V f32);
map_as_rust!(K Vec K < K u8 K >, V IpAddr);
map_as_rust!(K Vec K < K u8 K >, V Uuid);
map_as_rust!(K Vec K < K u8 K >, V Timespec);
map_as_rust!(K Vec K < K u8 K >, V List);
map_as_rust!(K Vec K < K u8 K >, V Map);
map_as_rust!(K Vec K < K u8 K >, V UDT);
map_as_rust!(K Vec K < K u8 K >, V Tuple);

map_as_rust!(K String, V Vec V < V u8 V >);
map_as_rust!(K String, V String);
map_as_rust!(K String, V bool);
map_as_rust!(K String, V i64);
map_as_rust!(K String, V i32);
map_as_rust!(K String, V i16);
map_as_rust!(K String, V i8);
map_as_rust!(K String, V f64);
map_as_rust!(K String, V f32);
map_as_rust!(K String, V IpAddr);
map_as_rust!(K String, V Uuid);
map_as_rust!(K String, V Timespec);
map_as_rust!(K String, V List);
map_as_rust!(K String, V Map);
map_as_rust!(K String, V UDT);
map_as_rust!(K String, V Tuple);

map_as_rust!(K bool, V Vec V < V u8 V >);
map_as_rust!(K bool, V String);
map_as_rust!(K bool, V bool);
map_as_rust!(K bool, V i64);
map_as_rust!(K bool, V i32);
map_as_rust!(K bool, V i16);
map_as_rust!(K bool, V i8);
map_as_rust!(K bool, V f64);
map_as_rust!(K bool, V f32);
map_as_rust!(K bool, V IpAddr);
map_as_rust!(K bool, V Uuid);
map_as_rust!(K bool, V Timespec);
map_as_rust!(K bool, V List);
map_as_rust!(K bool, V Map);
map_as_rust!(K bool, V UDT);
map_as_rust!(K bool, V Tuple);

map_as_rust!(K i64, V Vec V < V u8 V >);
map_as_rust!(K i64, V String);
map_as_rust!(K i64, V bool);
map_as_rust!(K i64, V i64);
map_as_rust!(K i64, V i32);
map_as_rust!(K i64, V i16);
map_as_rust!(K i64, V i8);
map_as_rust!(K i64, V f64);
map_as_rust!(K i64, V f32);
map_as_rust!(K i64, V IpAddr);
map_as_rust!(K i64, V Uuid);
map_as_rust!(K i64, V Timespec);
map_as_rust!(K i64, V List);
map_as_rust!(K i64, V Map);
map_as_rust!(K i64, V UDT);
map_as_rust!(K i64, V Tuple);

map_as_rust!(K i32, V Vec V < V u8 V >);
map_as_rust!(K i32, V String);
map_as_rust!(K i32, V bool);
map_as_rust!(K i32, V i64);
map_as_rust!(K i32, V i32);
map_as_rust!(K i32, V i16);
map_as_rust!(K i32, V i8);
map_as_rust!(K i32, V f64);
map_as_rust!(K i32, V f32);
map_as_rust!(K i32, V IpAddr);
map_as_rust!(K i32, V Uuid);
map_as_rust!(K i32, V Timespec);
map_as_rust!(K i32, V List);
map_as_rust!(K i32, V Map);
map_as_rust!(K i32, V UDT);
map_as_rust!(K i32, V Tuple);

map_as_rust!(K i16, V Vec V < V u8 V >);
map_as_rust!(K i16, V String);
map_as_rust!(K i16, V bool);
map_as_rust!(K i16, V i64);
map_as_rust!(K i16, V i32);
map_as_rust!(K i16, V i16);
map_as_rust!(K i16, V i8);
map_as_rust!(K i16, V f64);
map_as_rust!(K i16, V f32);
map_as_rust!(K i16, V IpAddr);
map_as_rust!(K i16, V Uuid);
map_as_rust!(K i16, V Timespec);
map_as_rust!(K i16, V List);
map_as_rust!(K i16, V Map);
map_as_rust!(K i16, V UDT);
map_as_rust!(K i16, V Tuple);

map_as_rust!(K i8, V Vec V < V u8 V >);
map_as_rust!(K i8, V String);
map_as_rust!(K i8, V bool);
map_as_rust!(K i8, V i64);
map_as_rust!(K i8, V i32);
map_as_rust!(K i8, V i16);
map_as_rust!(K i8, V i8);
map_as_rust!(K i8, V f64);
map_as_rust!(K i8, V f32);
map_as_rust!(K i8, V IpAddr);
map_as_rust!(K i8, V Uuid);
map_as_rust!(K i8, V Timespec);
map_as_rust!(K i8, V List);
map_as_rust!(K i8, V Map);
map_as_rust!(K i8, V UDT);
map_as_rust!(K i8, V Tuple);

map_as_rust!(K IpAddr, V Vec V < V u8 V >);
map_as_rust!(K IpAddr, V String);
map_as_rust!(K IpAddr, V bool);
map_as_rust!(K IpAddr, V i64);
map_as_rust!(K IpAddr, V i32);
map_as_rust!(K IpAddr, V i16);
map_as_rust!(K IpAddr, V i8);
map_as_rust!(K IpAddr, V f64);
map_as_rust!(K IpAddr, V f32);
map_as_rust!(K IpAddr, V IpAddr);
map_as_rust!(K IpAddr, V Uuid);
map_as_rust!(K IpAddr, V Timespec);
map_as_rust!(K IpAddr, V List);
map_as_rust!(K IpAddr, V Map);
map_as_rust!(K IpAddr, V UDT);
map_as_rust!(K IpAddr, V Tuple);

map_as_rust!(K Uuid, V Vec V < V u8 V >);
map_as_rust!(K Uuid, V String);
map_as_rust!(K Uuid, V bool);
map_as_rust!(K Uuid, V i64);
map_as_rust!(K Uuid, V i32);
map_as_rust!(K Uuid, V i16);
map_as_rust!(K Uuid, V i8);
map_as_rust!(K Uuid, V f64);
map_as_rust!(K Uuid, V f32);
map_as_rust!(K Uuid, V IpAddr);
map_as_rust!(K Uuid, V Uuid);
map_as_rust!(K Uuid, V Timespec);
map_as_rust!(K Uuid, V List);
map_as_rust!(K Uuid, V Map);
map_as_rust!(K Uuid, V UDT);
map_as_rust!(K Uuid, V Tuple);

map_as_rust!(K Timespec, V Vec V < V u8 V >);
map_as_rust!(K Timespec, V String);
map_as_rust!(K Timespec, V bool);
map_as_rust!(K Timespec, V i64);
map_as_rust!(K Timespec, V i32);
map_as_rust!(K Timespec, V i16);
map_as_rust!(K Timespec, V i8);
map_as_rust!(K Timespec, V f64);
map_as_rust!(K Timespec, V f32);
map_as_rust!(K Timespec, V IpAddr);
map_as_rust!(K Timespec, V Uuid);
map_as_rust!(K Timespec, V Timespec);
map_as_rust!(K Timespec, V List);
map_as_rust!(K Timespec, V Map);
map_as_rust!(K Timespec, V UDT);
map_as_rust!(K Timespec, V Tuple);

map_as_rust!(K Tuple, V Vec V < V u8 V >);
map_as_rust!(K Tuple, V String);
map_as_rust!(K Tuple, V bool);
map_as_rust!(K Tuple, V i64);
map_as_rust!(K Tuple, V i32);
map_as_rust!(K Tuple, V i16);
map_as_rust!(K Tuple, V i8);
map_as_rust!(K Tuple, V f64);
map_as_rust!(K Tuple, V f32);
map_as_rust!(K Tuple, V IpAddr);
map_as_rust!(K Tuple, V Uuid);
map_as_rust!(K Tuple, V Timespec);
map_as_rust!(K Tuple, V List);
map_as_rust!(K Tuple, V Map);
map_as_rust!(K Tuple, V UDT);
map_as_rust!(K Tuple, V Tuple);
<|endoftext|>


<commit_before>extern crate itertools;

use std::collections::{HashSet, HashMap};
use itertools::Itertools;

pub fn solve(puzzle: &str) -> Option<HashMap<char, u8>> {
    let puzzle_split = puzzle.split("==").map(|s| s.trim()).collect::<Vec<_>>();
    if puzzle_split.len() != 2 {
        return None;
    }
    let result = puzzle_split[1];
    let left_tkns = puzzle_split[0]
        .split('+')
        .map(|s| s.trim())
        .collect::<Vec<_>>();

    let all_chars = left_tkns
        .iter()
        .flat_map(|s| s.chars())
        .chain(puzzle_split[1].chars())
        .unique()
        .collect::<String>();

    let combinations = (0..10)
        .into_iter()
        .cartesian_product(all_chars.chars())
        .into_iter()
        .combinations(3)
        .filter(|v| {
                    v.iter().map(|&(d, c)| d).collect::<HashSet<_>>().len() == v.len() &&
                    v.iter().map(|&(d, c)| c).collect::<HashSet<_>>().len() == v.len()
                })
        .map(|v| v.iter().map(|&(x, y)| (y, x as u8)).collect::<Vec<_>>())
        .collect::<Vec<_>>();

    for combination in combinations {
        println!("{:?}", combination);
        if is_combination_alphametic(left_tkns.as_slice(), result, &combination) {
            return Some(combination
                            .iter()
                            .collect::<HashMap<_, _>>());
        }
    }
    None
}

fn is_combination_alphametic(left: &[&str], right: &str, combination: &[(char, u8)]) -> bool {
    let result = str_to_num(&right, &combination);

    let mut num = 0;
    for token in left {
        num += str_to_num(*token, combination);
    }

    if result == 100 {
        println!("result: {:?}", result);
    }

    if num == 100 {
        println!("num: {:?}", num);
    }

    result == num
}
fn str_to_num(val: &str, lnums_slice: &[(char, u8)]) -> u32 {
    // println!("val: {:?}", val);
    // println!("lnums_slice: {:?}", lnums_slice);
    let mut num = 1;
    let mut val_slice = val;
    for letter in val.chars() {
        let digit = *lnums_slice
                         .iter()
                         .collect::<HashMap<_, _>>()
                         .get(&letter)
                         .unwrap();
        // println!("digit: {:?}", digit);
        // println!("val_slice.len(): {:?}", val_slice.len());
        num += 10u32.pow(val_slice.len() as u32 - 1) * digit as u32;
        val_slice = &val_slice[1..];
    }
    // println!("num: {:?}", num);
    num

}<commit_msg>rust: Update to Alphametics code<commit_after>extern crate itertools;

use std::collections::{HashSet, HashMap};
use itertools::Itertools;

pub fn solve(puzzle: &str) -> Option<HashMap<char, u8>> {
    let puzzle_split = puzzle.split("==").map(|s| s.trim()).collect::<Vec<_>>();
    if puzzle_split.len() != 2 {
        return None;
    }
    let result = puzzle_split[1];
    let left_tkns = puzzle_split[0]
        .split('+')
        .map(|s| s.trim())
        .collect::<Vec<_>>();

    let all_chars = left_tkns
        .iter()
        .flat_map(|s| s.chars())
        .chain(puzzle_split[1].chars())
        .unique()
        .collect::<String>();

    let combinations = (0..10)
        .into_iter()
        .cartesian_product(all_chars.chars())
        .into_iter()
        .combinations(3)
        .filter(|v| {
                    v.iter().map(|&(d, _)| d).collect::<HashSet<_>>().len() == v.len() &&
                    v.iter().map(|&(_, c)| c).collect::<HashSet<_>>().len() == v.len()
                })
        .map(|v| v.iter().map(|&(x, y)| (y, x as u8)).collect::<Vec<_>>())
        .collect::<Vec<_>>();

    for combination in combinations {
        println!("{:?}", combination);
        if is_combination_alphametic(left_tkns.as_slice(), result, &combination) {
            return Some(combination
                            .iter()
                            .map(|&(x, y)| (x, y))
                            .collect::<HashMap<_, _>>());
        }
    }
    None
}

fn is_combination_alphametic(left: &[&str], right: &str, combination: &[(char, u8)]) -> bool {
    let result = str_to_num(right, combination);

    let mut num = 0;
    for token in left {
        num += str_to_num(*token, combination);
    }

    if result == 100 {
        println!("result: {:?}", result);
    }

    if num == 100 {
        println!("num: {:?}", num);
    }

    result == num
}
fn str_to_num(val: &str, lnums_slice: &[(char, u8)]) -> u32 {
    let mut num = 1;
    let mut val_slice = val;
    for letter in val.chars() {
        let digit = lnums_slice
                         .iter()
                         .map(|&(x, y)| (x, y))
                         .collect::<HashMap<_, _>>()[&letter];
        num += 10u32.pow(val_slice.len() as u32 - 1) * digit as u32;
        val_slice = &val_slice[1..];
    }

    num

}<|endoftext|>


<commit_before>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

/*===============================================================================================*/
/*------LERP TRAIT-------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The lerp trait.
pub trait Lerp {

    /// Linearly interpolates between two values.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::util::Lerp;
    /// println! ("{}", f32::lerp (&1.0, &7.5, 0.5));
    /// ```
    fn lerp (start: &Self, end: &Self, percentage: f32) -> Self;

    /// Linearly interpolates between two values without clamping.
    ///
    /// # Examples
    /// ```
    /// # use ion_math::util::Lerp;
    /// println! ("{}", f32::lerp (&1.0, &7.5, 0.5));
    /// ```
    fn lerp_unclamped (start: &Self, end: &Self, percentage: f32) -> Self;
}
<commit_msg>Removed Lerp example<commit_after>/*===============================================================================================*/
// Copyright 2016 Kyle Finlay
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*===============================================================================================*/

/*===============================================================================================*/
/*------LERP TRAIT-------------------------------------------------------------------------------*/
/*===============================================================================================*/

/// The lerp trait.
pub trait Lerp {

    /// Linearly interpolates between two values.
    fn lerp (start: &Self, end: &Self, percentage: f32) -> Self;
    /// Linearly interpolates between two values without clamping.
    fn lerp_unclamped (start: &Self, end: &Self, percentage: f32) -> Self;
}
<|endoftext|>


<commit_before>//! Toolbox to make text layout easier.

use unicode_width::UnicodeWidthStr;
use unicode_segmentation::UnicodeSegmentation;

mod lines_iterator;
mod reader;

pub use self::lines_iterator::{LinesIterator, Row};
pub use self::reader::ProgressReader;

/// Computes the length of a prefix that fits in the given `width`.
///
/// Takes non-breakable elements from `iter`, while keeping the
/// string width under `width` (and adding the length of `delimiter`
/// between each element).
///
/// Given `total_text = iter.collect().join(delimiter)`, the result
/// is the length of the longest prefix of `width` or less cells,
/// without breaking inside an element.
///
/// Example:
///
/// ```
/// # extern crate cursive;
/// extern crate unicode_segmentation;
/// use unicode_segmentation::UnicodeSegmentation;
///
/// # use cursive::utils::prefix_length;
/// # fn main() {
/// let my_text = "blah...";
/// // This returns the number of bytes for a prefix of `my_text` that
/// // fits within 5 cells.
/// prefix_length(my_text.graphemes(true), 5, "");
/// # }
/// ```
pub fn prefix_length<'a, I>(iter: I, width: usize, delimiter: &str) -> usize
    where I: Iterator<Item = &'s str>
{
    let delimiter_width = delimiter.width();
    let delimiter_len = delimiter.len();

    let sum = iter.scan(0, |w, token| {
            *w += token.width();
            if *w > width {
                None
            } else {
                // Add a space
                *w += delimiter_width;
                Some(token)
            }
        })
        .map(|token| token.len() + delimiter_len)
        .fold(0, |a, b| a + b);

    // We counted delimiter once too many times,
    // but only if the iterator was non empty.
    if sum == 0 {
        sum
    } else {
        sum - delimiter_len
    }
}

/// Computes the length of a suffix that fits in the given `width`.
///
/// Doesn't break inside elements returned by `iter`.
///
/// Returns the number of bytes of the longest
/// suffix from `text` that fits in `width`.
///
/// This is a shortcut for `prefix_length(iter.rev(), width, delimiter)`
pub fn suffix_length<'a, I>(iter: I, width: usize, delimiter: &str) -> usize
    where I: DoubleEndedIterator<Item = &'a str>
{
    prefix_length(iter.rev(), width, delimiter)
}

/// Computes the length of a suffix that fits in the given `width`.
///
/// Breaks between any two graphemes.
pub fn simple_suffix_length(text: &str, width: usize) -> usize {
    suffix_length(text.graphemes(true), width, "")
}
<commit_msg>Fix typo<commit_after>//! Toolbox to make text layout easier.

use unicode_width::UnicodeWidthStr;
use unicode_segmentation::UnicodeSegmentation;

mod lines_iterator;
mod reader;

pub use self::lines_iterator::{LinesIterator, Row};
pub use self::reader::ProgressReader;

/// Computes the length of a prefix that fits in the given `width`.
///
/// Takes non-breakable elements from `iter`, while keeping the
/// string width under `width` (and adding the length of `delimiter`
/// between each element).
///
/// Given `total_text = iter.collect().join(delimiter)`, the result
/// is the length of the longest prefix of `width` or less cells,
/// without breaking inside an element.
///
/// Example:
///
/// ```
/// # extern crate cursive;
/// extern crate unicode_segmentation;
/// use unicode_segmentation::UnicodeSegmentation;
///
/// # use cursive::utils::prefix_length;
/// # fn main() {
/// let my_text = "blah...";
/// // This returns the number of bytes for a prefix of `my_text` that
/// // fits within 5 cells.
/// prefix_length(my_text.graphemes(true), 5, "");
/// # }
/// ```
pub fn prefix_length<'a, I>(iter: I, width: usize, delimiter: &str) -> usize
    where I: Iterator<Item = &'a str>
{
    let delimiter_width = delimiter.width();
    let delimiter_len = delimiter.len();

    let sum = iter.scan(0, |w, token| {
            *w += token.width();
            if *w > width {
                None
            } else {
                // Add a space
                *w += delimiter_width;
                Some(token)
            }
        })
        .map(|token| token.len() + delimiter_len)
        .fold(0, |a, b| a + b);

    // We counted delimiter once too many times,
    // but only if the iterator was non empty.
    if sum == 0 {
        sum
    } else {
        sum - delimiter_len
    }
}

/// Computes the length of a suffix that fits in the given `width`.
///
/// Doesn't break inside elements returned by `iter`.
///
/// Returns the number of bytes of the longest
/// suffix from `text` that fits in `width`.
///
/// This is a shortcut for `prefix_length(iter.rev(), width, delimiter)`
pub fn suffix_length<'a, I>(iter: I, width: usize, delimiter: &str) -> usize
    where I: DoubleEndedIterator<Item = &'a str>
{
    prefix_length(iter.rev(), width, delimiter)
}

/// Computes the length of a suffix that fits in the given `width`.
///
/// Breaks between any two graphemes.
pub fn simple_suffix_length(text: &str, width: usize) -> usize {
    suffix_length(text.graphemes(true), width, "")
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Johan Sköld.
// License: http://opensource.org/licenses/ISC

extern crate gcc;

use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    let target = env::var("TARGET").unwrap();
    let profile = env::var("PROFILE").unwrap();
    let target_quad = target.split("-").collect::<Vec<_>>();
    let (arch, compiler) = (target_quad.first().unwrap(), target_quad.last().unwrap());
    let bitness = if *arch == "x86_64" { 64 } else { 32 };

    build_bgfx(bitness, compiler, &profile);
}

#[cfg(target_os = "windows")]
fn build_bgfx(bitness: u32, compiler: &str, profile: &str) {
    if compiler != "gnu" {
        panic!("Unsupported compiler");
    }

    Command::new("make.exe")
        .current_dir("bgfx")
        .arg(".build/projects/gmake-mingw-gcc")
        .output()
        .unwrap();

    let status = Command::new("make.exe")
                     .current_dir("bgfx")
                     .env("CPPFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(".build/projects/gmake-mingw-gcc")
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .unwrap_or_else(|e| panic!("Failed to build bgfx: {}", e));

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx.");
    }

    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("win{}_mingw-gcc", bitness));
    path.push("bin");

    println!("cargo:rustc-link-lib=bgfx{}",
             if profile == "debug" { "Debug" } else { "Release" });
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-lib=gdi32");
    println!("cargo:rustc-link-lib=opengl32");
    println!("cargo:rustc-link-lib=psapi");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());
}

#[cfg(target_os = "linux")]
fn build_bgfx(bitness: u32, compiler: &str, profile: &str) {
    if compiler != "gnu" {
        panic!("Unsupported compiler");
    }

    // Generate makefiles
    Command::new("make")
        .current_dir("bgfx")
        .arg(".build/projects/gmake-linux")
        .output()
        .unwrap();

    // Build bgfx
    let status = Command::new("make")
                     .current_dir("bgfx")
                     .env("CPPFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(".build/projects/gmake-linux")
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .unwrap_or_else(|e| panic!("Failed to build bgfx: {}", e));

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx.");
    }

    // Output linker config
    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("linux{}_gcc", bitness));
    path.push("bin");

    println!("cargo:rustc-link-lib=bgfx{}",
             if profile == "debug" { "Debug" } else { "Release" });
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-lib=GL");
    println!("cargo:rustc-link-lib=X11");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());
}
<commit_msg>Removing CPPFLAGS<commit_after>// Copyright (c) 2015, Johan Sköld.
// License: http://opensource.org/licenses/ISC

extern crate gcc;

use std::env;
use std::path::PathBuf;
use std::process::Command;

fn main() {
    let target = env::var("TARGET").unwrap();
    let profile = env::var("PROFILE").unwrap();
    let target_quad = target.split("-").collect::<Vec<_>>();
    let (arch, compiler) = (target_quad.first().unwrap(), target_quad.last().unwrap());
    let bitness = if *arch == "x86_64" { 64 } else { 32 };

    build_bgfx(bitness, compiler, &profile);
}

#[cfg(target_os = "windows")]
fn build_bgfx(bitness: u32, compiler: &str, profile: &str) {
    if compiler != "gnu" {
        panic!("Unsupported compiler");
    }

    Command::new("make.exe")
        .current_dir("bgfx")
        .arg(".build/projects/gmake-mingw-gcc")
        .output()
        .unwrap();

    let status = Command::new("make.exe")
                     .current_dir("bgfx")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(".build/projects/gmake-mingw-gcc")
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .unwrap_or_else(|e| panic!("Failed to build bgfx: {}", e));

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx.");
    }

    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("win{}_mingw-gcc", bitness));
    path.push("bin");

    println!("cargo:rustc-link-lib=bgfx{}",
             if profile == "debug" { "Debug" } else { "Release" });
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-lib=gdi32");
    println!("cargo:rustc-link-lib=opengl32");
    println!("cargo:rustc-link-lib=psapi");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());
}

#[cfg(target_os = "linux")]
fn build_bgfx(bitness: u32, compiler: &str, profile: &str) {
    if compiler != "gnu" {
        panic!("Unsupported compiler");
    }

    // Generate makefiles
    Command::new("make")
        .current_dir("bgfx")
        .arg(".build/projects/gmake-linux")
        .output()
        .unwrap();

    // Build bgfx
    let status = Command::new("make")
                     .current_dir("bgfx")
                     .env("CFLAGS", "-fPIC -DBGFX_CONFIG_MULTITHREADED=1")
                     .arg("-R")
                     .arg("-C")
                     .arg(".build/projects/gmake-linux")
                     .arg(format!("config={}{}", profile, bitness))
                     .arg("bgfx")
                     .status()
                     .unwrap_or_else(|e| panic!("Failed to build bgfx: {}", e));

    if status.code().unwrap() != 0 {
        panic!("Failed to build bgfx.");
    }

    // Output linker config
    let mut path = PathBuf::from(env::current_dir().unwrap());
    path.push("bgfx");
    path.push(".build");
    path.push(format!("linux{}_gcc", bitness));
    path.push("bin");

    println!("cargo:rustc-link-lib=bgfx{}",
             if profile == "debug" { "Debug" } else { "Release" });
    println!("cargo:rustc-link-lib=stdc++");
    println!("cargo:rustc-link-lib=GL");
    println!("cargo:rustc-link-lib=X11");
    println!("cargo:rustc-link-search=native={}", path.as_os_str().to_str().unwrap());
}
<|endoftext|>


<commit_before>extern crate ramp;
extern crate float;

use float::Float;
use std::i64;

struct AtPrecision {
    val: u32,
    prec: u32,
}

impl AtPrecision {
    fn new(p: u32) -> AtPrecision {
        assert!(p >= 1);
        AtPrecision {
            val: 1 << (p - 1),
            prec: p
        }
    }
}

impl Iterator for AtPrecision {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        if self.val >= (1 << self.prec) {
            None
        } else {
            let f = (self.val as f64) / (1 << (self.prec - 1)) as f64;
            self.val += 1;
            Some(f)
        }
    }
}

fn floats<F: FnMut(Float), E: Clone + Iterator<Item = i64>>(p: u32, region: Region, zero: bool, exps: E, mut f: F) {
    if zero {
        f(Float::zero(p))
    }
    for raw_x in AtPrecision::new(p) {
        for exp in exps.clone() {
            let x = Float::from(raw_x).with_precision(p).mul_exp2(exp);
            match region {
                Region::Neg => f(-x),
                Region::NegPos => { f(-x.clone()); f(x) }
                Region::Pos => f(x)
            }
        }
    }
}

#[derive(Copy, Clone, PartialEq)]
enum Region {
    Neg,
    NegPos,
    Pos
}
fn un_op<F, G, E>(p: u32, exps: E,
               region: Region, zero: bool,
               mut op: F, mut op_f64: G)
    where F: FnMut(Float) -> Float, G: FnMut(f64) -> f64, E: Clone + Iterator<Item = i64>
{
    floats(p, region, zero, exps, |x| {
        let est = op(x.clone());
        let x_f64 = x.into();
        let real = op_f64(x_f64);

        let real = Float::from(real).with_precision(p);
        assert!(est == real,
                "{} => {:?} != {:?}",
                x_f64, est, real);
    });
}

fn bin_op<F, G, E1, E2>(p: u32,
                        exps1: E1, region1: Region, zero1: bool,
                        exps2: E2, region2: Region, zero2: bool,
                        mut op: F, mut op_f64: G)
    where F: FnMut(Float, Float) -> Float, G: FnMut(f64, f64) -> f64,
          E1: Clone + Iterator<Item = i64>,
          E2: Clone + Iterator<Item = i64>
{
    floats(p, region1, zero1, exps1, |x| {
        floats(p, region2, zero2, exps2.clone(), |y| {
            let est = op(x.clone(), y.clone());
            let x_f64 = x.clone().into();
            let y_f64 = y.into();
            let real = op_f64(x_f64, y_f64);

            let real = Float::from(real).with_precision(p);
            assert!(est == real,
                    "{}, {} => {:?} != {:?}",
                    x_f64, y_f64, est, real);
        })
    })
}

fn bin_op_extreme<F, E1, E2>(p: u32,
                             exps1: E1, region1: Region, zero1: bool, mul1: i64,
                             exps2: E2, region2: Region, zero2: bool, mul2: i64,
                             unmul: i64,
                             mut op: F)
    where F: FnMut(Float, Float) -> Float,
          E1: Clone + Iterator<Item = i64>,
          E2: Clone + Iterator<Item = i64>
{
    floats(p, region1, zero1, exps1, |x| {
        floats(p, region2, zero2, exps2.clone(), |y| {
            let scaled = op(x.clone().mul_exp2(mul1),
                            y.clone().mul_exp2(mul2));
            let expected = scaled.mul_exp2(unmul);
            let est = op(x.clone(), y.clone());
            assert!(est == expected,
                    "{:?}, {:?} => {:?} != {:?}",
                    x, y, est, expected)
        })
    })
}

#[test]
fn sqrt() {
    un_op(10,
          -10..10 + 1, Region::Pos, true,
          |x| x.sqrt(),
          |y| y.sqrt())
}

#[test]
fn add() {
    bin_op(5,
           -10..10 + 1, Region::NegPos, true,
           -10..10 + 1, Region::NegPos, true,
           |x, y| x + y,
           |x, y| x + y)
}

#[test]
fn add_extreme_overflow() {
    bin_op_extreme(5,
                   i64::MAX - 6..i64::MAX, Region::NegPos, true, -i64::MAX,
                   i64::MAX - 6..i64::MAX, Region::NegPos, true, -i64::MAX,
                   i64::MAX,
                   |x, y| x + y)
}

#[test]
fn add_extreme_underflow() {
    bin_op_extreme(5,
                   i64::MIN..i64::MIN + 6, Region::NegPos, true, i64::MAX,
                   i64::MIN..i64::MIN + 6, Region::NegPos, true, i64::MAX,
                   -i64::MAX,
                   |x, y| x + y)
}

#[test]
fn sub() {
    bin_op(5,
           -10..10 + 1, Region::NegPos, true,
           -10..10 + 1, Region::NegPos, true,
           |x, y| x - y,
           |x, y| x - y)
}

#[test]
fn sub_extreme_overflow() {
    bin_op_extreme(5,
                   i64::MAX - 6..i64::MAX, Region::NegPos, true, -i64::MAX,
                   i64::MAX - 6..i64::MAX, Region::NegPos, true, -i64::MAX,
                   i64::MAX,
                   |x, y| x - y)
}

#[test]
fn sub_extreme_underflow() {
    bin_op_extreme(5,
                   i64::MIN..i64::MIN + 6, Region::NegPos, true, i64::MAX,
                   i64::MIN..i64::MIN + 6, Region::NegPos, true, i64::MAX,
                   -i64::MAX,
                   |x, y| x - y)
}

#[test]
fn mul() {
    bin_op(5,
           -10..10 + 1, Region::NegPos, true,
           -10..10 + 1, Region::NegPos, true,
           |x, y| x * y,
           |x, y| x * y)
}

const HALF_EXP: i64 = i64::MAX / 2;

#[test]
fn mul_extreme_overflow() {
    let exps = (i64::MAX - 4..i64::MAX).chain(HALF_EXP - 4..HALF_EXP + 5).chain(0..4);
    bin_op_extreme(5,
                   exps.clone(), Region::NegPos, true, -HALF_EXP,
                   exps, Region::NegPos, true, -HALF_EXP,
                   HALF_EXP * 2,
                   |x, y| x * y)
}

#[test]
fn mul_extreme_underflow() {
    let exps = (i64::MIN..i64::MIN + 4).chain(-HALF_EXP - 4..-HALF_EXP + 5).chain(-4..0);
    bin_op_extreme(5,
                   exps.clone(), Region::NegPos, false, HALF_EXP,
                   exps.clone(), Region::NegPos, false, HALF_EXP,
                   -HALF_EXP * 2,
                   |x, y| x * y)
}

#[test]
fn div() {
    bin_op(5,
           -10..10 + 1, Region::NegPos, true,
           -10..10 + 1, Region::NegPos, false,
           |x, y| x / y,
           |x, y| x / y)
}

#[test]
fn div_extreme_overflow() {
    let exp_numer = (i64::MAX - 4..i64::MAX).chain(HALF_EXP - 4..HALF_EXP + 5).chain(0..4);
    let exp_denom = (i64::MIN + 1.. i64::MIN + 5).chain(-HALF_EXP - 5..-HALF_EXP + 5).chain(-4..0);
    bin_op_extreme(5,
                   exp_numer, Region::NegPos, false, -HALF_EXP,
                   exp_denom, Region::NegPos, false, HALF_EXP,
                   HALF_EXP * 2,
                   |x, y| x / y)
}

#[test]
fn div_extreme_underflow() {
    let exp_numer = (i64::MIN + 1.. i64::MIN + 5).chain(-HALF_EXP - 5..-HALF_EXP + 5).chain(-4..0);
    let exp_denom = (i64::MAX - 4..i64::MAX).chain(HALF_EXP - 4..HALF_EXP + 5).chain(0..4);
    bin_op_extreme(5,
                   exp_numer, Region::NegPos, false, HALF_EXP,
                   exp_denom, Region::NegPos, false, -HALF_EXP,
                   -HALF_EXP * 2,
                   |x, y| x / y)
}
<commit_msg>Test all permutations of by-reference & by-value operators.<commit_after>extern crate ramp;
extern crate float;

use float::Float;
use std::i64;

struct AtPrecision {
    val: u32,
    prec: u32,
}

impl AtPrecision {
    fn new(p: u32) -> AtPrecision {
        assert!(p >= 1);
        AtPrecision {
            val: 1 << (p - 1),
            prec: p
        }
    }
}

impl Iterator for AtPrecision {
    type Item = f64;

    fn next(&mut self) -> Option<f64> {
        if self.val >= (1 << self.prec) {
            None
        } else {
            let f = (self.val as f64) / (1 << (self.prec - 1)) as f64;
            self.val += 1;
            Some(f)
        }
    }
}

fn floats<F: FnMut(Float), E: Clone + Iterator<Item = i64>>(p: u32, region: Region, zero: bool, exps: E, mut f: F) {
    if zero {
        f(Float::zero(p))
    }
    for raw_x in AtPrecision::new(p) {
        for exp in exps.clone() {
            let x = Float::from(raw_x).with_precision(p).mul_exp2(exp);
            match region {
                Region::Neg => f(-x),
                Region::NegPos => { f(-x.clone()); f(x) }
                Region::Pos => f(x)
            }
        }
    }
}

#[derive(Copy, Clone, PartialEq)]
enum Region {
    Neg,
    NegPos,
    Pos
}
fn un_op<F, G, E>(p: u32, exps: E,
               region: Region, zero: bool,
               mut op: F, mut op_f64: G)
    where F: FnMut(Float) -> Float, G: FnMut(f64) -> f64, E: Clone + Iterator<Item = i64>
{
    floats(p, region, zero, exps, |x| {
        let est = op(x.clone());
        let x_f64 = x.into();
        let real = op_f64(x_f64);

        let real = Float::from(real).with_precision(p);
        assert!(est == real,
                "{} => {:?} != {:?}",
                x_f64, est, real);
    });
}

fn bin_op<F, G, E1, E2>(p: u32,
                        exps1: E1, region1: Region, zero1: bool,
                        exps2: E2, region2: Region, zero2: bool,
                        mut op: F, mut op_f64: G)
    where F: FnMut(Float, Float) -> Float, G: FnMut(f64, f64) -> f64,
          E1: Clone + Iterator<Item = i64>,
          E2: Clone + Iterator<Item = i64>
{
    floats(p, region1, zero1, exps1, |x| {
        floats(p, region2, zero2, exps2.clone(), |y| {
            let est = op(x.clone(), y.clone());
            let x_f64 = x.clone().into();
            let y_f64 = y.clone().into();
            let real = op_f64(x_f64, y_f64);

            let real = Float::from(real).with_precision(p);
            assert!(est == real,
                    "{:?} ({}), {:?} ({}) => {:?} != {:?}",
                    x, x_f64, y, y_f64, est, real);
        })
    })
}

fn bin_op_extreme<F, E1, E2>(p: u32,
                             exps1: E1, region1: Region, zero1: bool, mul1: i64,
                             exps2: E2, region2: Region, zero2: bool, mul2: i64,
                             unmul: i64,
                             mut op: F)
    where F: FnMut(Float, Float) -> Float,
          E1: Clone + Iterator<Item = i64>,
          E2: Clone + Iterator<Item = i64>
{
    floats(p, region1, zero1, exps1, |x| {
        floats(p, region2, zero2, exps2.clone(), |y| {
            let scaled = op(x.clone().mul_exp2(mul1),
                            y.clone().mul_exp2(mul2));
            let expected = scaled.mul_exp2(unmul);
            let est = op(x.clone(), y.clone());
            assert!(est == expected,
                    "{:?}, {:?} => {:?} != {:?}",
                    x, y, est, expected)
        })
    })
}

#[test]
fn sqrt() {
    un_op(10,
          -10..10 + 1, Region::Pos, true,
          |x| x.sqrt(),
          |y| y.sqrt())
}

macro_rules! expr { ($e: expr) => { $e } }
macro_rules! by_val_by_ref {
    ($op: tt, $tester: ident) => {
        #[test] fn val_val() { expr!($tester(|x, y| x $op y)) }
        #[test] fn val_ref() { expr!($tester(|x, y| x $op &y)) }
        #[test] fn ref_val() { expr!($tester(|x, y| &x $op y)) }
        #[test] fn ref_ref() { expr!($tester(|x, y| &x $op &y)) }
    }
}
macro_rules! tests {
    ($($name: ident, $op: tt, $y_zero: expr,
       $extreme_x_exp: expr, $x_shift: expr,
       $extreme_y_exp: expr, $y_shift: expr,
       $unshift: expr;)*) => {
        $(mod $name {
            use {bin_op, Region};
            use float::Float;

            fn test<F: FnMut(Float, Float) -> Float>(f: F) {
                expr!(bin_op(5,
                             -5..5 + 1, Region::NegPos, true,
                             -5..5 + 1, Region::NegPos, $y_zero,
                             f,
                             |x, y| x $op y))
            }

            by_val_by_ref! { $op, test }

            #[allow(unused_imports)]
            mod overflow {
                use {bin_op_extreme, Region};
                use float::Float;
                use HALF_EXP;
                use std::i64;

                fn test<F: FnMut(Float, Float) -> Float>(f: F) {
                    expr!(bin_op_extreme(5,
                                         $extreme_x_exp, Region::NegPos, true, -$x_shift,
                                         $extreme_y_exp, Region::NegPos, $y_zero, -$y_shift,
                                         $unshift,
                                         f))
                }

                by_val_by_ref! { $op, test }
            }
            #[allow(unused_imports)]
            mod underflow {
                use {bin_op_extreme, Region};
                use float::Float;
                use HALF_EXP;
                use std::i64;
                use std::ops::Neg;

                fn test<F: FnMut(Float, Float) -> Float>(f: F) {
                    expr!(bin_op_extreme(5,
                                         $extreme_x_exp.map(Neg::neg as fn(i64) -> i64), Region::NegPos, true, $x_shift,
                                         $extreme_y_exp.map(Neg::neg as fn(i64) -> i64), Region::NegPos, $y_zero, $y_shift,
                                         -$unshift,
                                         f))
                }

                by_val_by_ref! { $op, test }
            }
        })*
    }
}

const HALF_EXP: i64 = i64::MAX / 2;
tests! {
    add, +, true, i64::MAX - 6..i64::MAX, i64::MAX, i64::MAX - 6..i64::MAX, i64::MAX, i64::MAX;
    sub, -, true, i64::MAX - 6..i64::MAX, i64::MAX, i64::MAX - 6..i64::MAX, i64::MAX, i64::MAX;
    mul, *, true,
    (i64::MAX - 4..i64::MAX).chain(HALF_EXP - 4..HALF_EXP + 5).chain(1..4), HALF_EXP,
    (i64::MAX - 4..i64::MAX).chain(HALF_EXP - 4..HALF_EXP + 5).chain(1..4), HALF_EXP,
    HALF_EXP * 2;
    div, /, false,
    (i64::MAX - 4..i64::MAX).chain(HALF_EXP - 4..HALF_EXP + 5).chain(0..4), HALF_EXP,
    (i64::MIN + 1.. i64::MIN + 5).chain(-HALF_EXP - 5..-HALF_EXP + 5).chain(-4..0), -HALF_EXP,
    HALF_EXP * 2;
}
<|endoftext|>