<commit_before>//! indicatif is a library for Rust that helps you build command line
//! interfaces that report progress to users.  It comes with various
//! tools and utilities for formatting anything that indicates progress.
//!
//! Platform support:
//!
//! * Linux
//! * OS X
//! * Windows (colors require Windows 10)
//!
//! Best paired with other libraries in the family:
//!
//! * [console](https://docs.rs/console)
//! * [dialoguer](https://docs.rs/dialoguer)
//!
//! # Crate Contents
//!
//! * **Progress bars**
//!   * [`ProgressBar`](struct.ProgressBar.html) for bars and spinners
//!   * [`MultiProgress`](struct.MultiProgress.html) for multiple bars
//! * **Data Formatting**
//!   * [`HumanBytes`](struct.HumanBytes.html) for formatting bytes
//!   * [`DecimalBytes`](struct.DecimalBytes.html) for formatting bytes using SI prefixes
//!   * [`BinaryBytes`](struct.BinaryBytes.html) for formatting bytes using ISO/IEC prefixes
//!   * [`HumanDuration`](struct.HumanDuration.html) for formatting durations
//!
//! # Progress Bars and Spinners
//!
//! indicatif comes with a `ProgressBar` type that supports both bounded
//! progress bar uses as well as unbounded "spinner" type progress reports.
//! Progress bars are `Sync` and `Send` objects which means that they are
//! internally locked and can be passed from thread to thread.
//!
//! Additionally a `MultiProgress` utility is provided that can manage
//! rendering multiple progress bars at once (eg: from multiple threads).
//!
//! To whet your appetite, this is what this can look like:
//!
//!
//!
//! Progress bars are manually advanced and by default draw to stderr.
//! When you are done, the progress bar can be finished either visibly
//! (eg: the progress bar stays on the screen) or cleared (the progress
//! bar will be removed).
//!
//! ```rust
//! use indicatif::ProgressBar;
//!
//! let bar = ProgressBar::new(1000);
//! for _ in 0..1000 {
//!     bar.inc(1);
//!     // ...
//! }
//! bar.finish();
//! ```
//!
//! General progress bar behaviors:
//!
//! * if a non terminal is detected the progress bar will be completely
//!   hidden.  This makes piping programs to logfiles make sense out of
//!   the box.
//! * progress bars should be explicitly finished to reset the rendering
//!   for others.  Either by also clearing them or by replacing them with
//!   a new message / retaining the current message.
//! * the default template renders neither message nor prefix.
//!
//! # Iterators
//!
//! Similar to [tqdm](https://github.com/tqdm/tqdm), progress bars can be
//! associated with an iterator. For example:
//!
//! ```rust
//! use indicatif::ProgressIterator;
//!
//! for _ in (0..1000).progress() {
//!     // ...
//! }
//! ```
//!
//! See the [`ProgressIterator`](trait.ProgressIterator.html) trait for more
//! methods to configure the number of elements in the iterator or change
//! the progress bar style. Indicatif also has optional support for parallel
//! iterators with [Rayon](https://github.com/rayon-rs/rayon). In your
//! `cargo.toml`, use the "with_rayon" feature:
//!
//! ```toml
//! [dependencies]
//! indicatif = {version = "*", features = ["with_rayon"]}
//! ```
//!
//! And then use it like this:
//!
//! ```rust
//! use indicatif::ParallelProgressIterator;
//! use rayon::iter::{ParallelIterator, IntoParallelRefIterator};
//!
//! let v: Vec<_> = (0..100000).collect();
//! let v2: Vec<_> = v.par_iter().progress().map(|i| i + 1).collect();
//! assert_eq!(v2[0], 1);
//! ```
//!
//! # Templates
//!
//! Progress bars can be styled with simple format strings similar to the
//! ones in Rust itself.  The format for a placeholder is `{key:options}`
//! where the `options` part is optional.  If provided the format is this:
//!
//! ```text
//! [<^>]           for an optional alignment specification
//! WIDTH           an optional width as positive integer
//! !               an optional exclamation mark to enable truncation
//! .STYLE          an optional dot separated style string
//! /STYLE          an optional dot separated alternative style string
//! ```
//!
//! For the style component see `Styled::from_dotted_str` for more
//! information.
//!
//! Some examples for templates:
//!
//! ```text
//! [{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}
//! ```
//!
//! This sets a progress bar that is 40 characters wide and has cyan
//! as primary style color and blue as alternative style color.
//! Alternative styles are currently only used for progress bars.
//!
//! Example configuration:
//!
//! ```ignore
//! bar.set_style(ProgressStyle::default_bar()
//!     .template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
//!     .progress_chars("##-"));
//! ```
//!
//! The following keys exist:
//!
//! * `bar`: renders a progress bar. By default 20 characters wide.  The
//!   style string is used to color the elapsed part, the alternative
//!   style is used for the bar that is yet to render.
//! * `wide_bar`: like `bar` but always fills the remaining space.
//! * `spinner`: renders the spinner (current tick char)
//! * `prefix`: renders the prefix set on the progress bar.
//! * `msg`: renders the currently set message on the progress bar.
//! * `wide_msg`: like `msg` but always fills the remaining space and truncates.
//! * `pos`: renders the current position of the bar as integer
//! * `len`: renders the total length of the bar as integer
//! * `bytes`: renders the current position of the bar as bytes.
//! * `percent`: renders the current position of the bar as a percentage of the total length.
//! * `total_bytes`: renders the total length of the bar as bytes.
//! * `elapsed_precise`: renders the elapsed time as `HH:MM:SS`.
//! * `elapsed`: renders the elapsed time as `42s`, `1m` etc.
//! * `eta_precise`: the remaining time (like `elapsed_precise`).
//! * `eta`: the remaining time (like `elapsed`).
//!
//! The design of the progress bar can be altered with the integrated
//! template functionality.  The template can be set by changing a
//! `ProgressStyle` and attaching it to the progress bar.
//!
//! # Human Readable Formatting
//!
//! There are some formatting wrappers for showing elapsed time and
//! file sizes for human users:
//!
//! ```ignore
//! use std::time::Instant;
//! use indicatif::{HumanDuration, HumanBytes};
//!
//! let started = Instant::now();
//! println!("The file is {} large", HumanBytes(file.size));
//! println!("The script took {}", HumanDuration(started.elapsed()));
//! ```
extern crate parking_lot;
extern crate regex;
#[macro_use]
extern crate lazy_static;
extern crate console;
extern crate number_prefix;

#[cfg(feature = "with_rayon")]
extern crate rayon;

mod format;
mod progress;
mod utils;
mod iter;

pub use format::{BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanDuration};
pub use progress::{
    MultiProgress, ProgressBar, ProgressBarRead, ProgressDrawTarget, ProgressStyle,
    MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle,
};
pub use iter::{ProgressIterator, ProgressBarIter};

#[cfg(feature = "with_rayon")]
pub use iter::rayon::{ParProgressBarIter, ParallelProgressIterator};
<commit_msg>Fix rayon test<commit_after>//! indicatif is a library for Rust that helps you build command line
//! interfaces that report progress to users.  It comes with various
//! tools and utilities for formatting anything that indicates progress.
//!
//! Platform support:
//!
//! * Linux
//! * OS X
//! * Windows (colors require Windows 10)
//!
//! Best paired with other libraries in the family:
//!
//! * [console](https://docs.rs/console)
//! * [dialoguer](https://docs.rs/dialoguer)
//!
//! # Crate Contents
//!
//! * **Progress bars**
//!   * [`ProgressBar`](struct.ProgressBar.html) for bars and spinners
//!   * [`MultiProgress`](struct.MultiProgress.html) for multiple bars
//! * **Data Formatting**
//!   * [`HumanBytes`](struct.HumanBytes.html) for formatting bytes
//!   * [`DecimalBytes`](struct.DecimalBytes.html) for formatting bytes using SI prefixes
//!   * [`BinaryBytes`](struct.BinaryBytes.html) for formatting bytes using ISO/IEC prefixes
//!   * [`HumanDuration`](struct.HumanDuration.html) for formatting durations
//!
//! # Progress Bars and Spinners
//!
//! indicatif comes with a `ProgressBar` type that supports both bounded
//! progress bar uses as well as unbounded "spinner" type progress reports.
//! Progress bars are `Sync` and `Send` objects which means that they are
//! internally locked and can be passed from thread to thread.
//!
//! Additionally a `MultiProgress` utility is provided that can manage
//! rendering multiple progress bars at once (eg: from multiple threads).
//!
//! To whet your appetite, this is what this can look like:
//!
//!
//!
//! Progress bars are manually advanced and by default draw to stderr.
//! When you are done, the progress bar can be finished either visibly
//! (eg: the progress bar stays on the screen) or cleared (the progress
//! bar will be removed).
//!
//! ```rust
//! use indicatif::ProgressBar;
//!
//! let bar = ProgressBar::new(1000);
//! for _ in 0..1000 {
//!     bar.inc(1);
//!     // ...
//! }
//! bar.finish();
//! ```
//!
//! General progress bar behaviors:
//!
//! * if a non terminal is detected the progress bar will be completely
//!   hidden.  This makes piping programs to logfiles make sense out of
//!   the box.
//! * progress bars should be explicitly finished to reset the rendering
//!   for others.  Either by also clearing them or by replacing them with
//!   a new message / retaining the current message.
//! * the default template renders neither message nor prefix.
//!
//! # Iterators
//!
//! Similar to [tqdm](https://github.com/tqdm/tqdm), progress bars can be
//! associated with an iterator. For example:
//!
//! ```rust
//! use indicatif::ProgressIterator;
//!
//! for _ in (0..1000).progress() {
//!     // ...
//! }
//! ```
//!
//! See the [`ProgressIterator`](trait.ProgressIterator.html) trait for more
//! methods to configure the number of elements in the iterator or change
//! the progress bar style. Indicatif also has optional support for parallel
//! iterators with [Rayon](https://github.com/rayon-rs/rayon). In your
//! `cargo.toml`, use the "with_rayon" feature:
//!
//! ```toml
//! [dependencies]
//! indicatif = {version = "*", features = ["with_rayon"]}
//! ```
//!
//! And then use it like this:
//!
//! ```rust,ignore
//! # extern crate rayon;
//! use indicatif::ParallelProgressIterator;
//! use rayon::iter::{ParallelIterator, IntoParallelRefIterator};
//!
//! let v: Vec<_> = (0..100000).collect();
//! let v2: Vec<_> = v.par_iter().progress().map(|i| i + 1).collect();
//! assert_eq!(v2[0], 1);
//! ```
//!
//! # Templates
//!
//! Progress bars can be styled with simple format strings similar to the
//! ones in Rust itself.  The format for a placeholder is `{key:options}`
//! where the `options` part is optional.  If provided the format is this:
//!
//! ```text
//! [<^>]           for an optional alignment specification
//! WIDTH           an optional width as positive integer
//! !               an optional exclamation mark to enable truncation
//! .STYLE          an optional dot separated style string
//! /STYLE          an optional dot separated alternative style string
//! ```
//!
//! For the style component see `Styled::from_dotted_str` for more
//! information.
//!
//! Some examples for templates:
//!
//! ```text
//! [{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}
//! ```
//!
//! This sets a progress bar that is 40 characters wide and has cyan
//! as primary style color and blue as alternative style color.
//! Alternative styles are currently only used for progress bars.
//!
//! Example configuration:
//!
//! ```ignore
//! bar.set_style(ProgressStyle::default_bar()
//!     .template("[{elapsed_precise}] {bar:40.cyan/blue} {pos:>7}/{len:7} {msg}")
//!     .progress_chars("##-"));
//! ```
//!
//! The following keys exist:
//!
//! * `bar`: renders a progress bar. By default 20 characters wide.  The
//!   style string is used to color the elapsed part, the alternative
//!   style is used for the bar that is yet to render.
//! * `wide_bar`: like `bar` but always fills the remaining space.
//! * `spinner`: renders the spinner (current tick char)
//! * `prefix`: renders the prefix set on the progress bar.
//! * `msg`: renders the currently set message on the progress bar.
//! * `wide_msg`: like `msg` but always fills the remaining space and truncates.
//! * `pos`: renders the current position of the bar as integer
//! * `len`: renders the total length of the bar as integer
//! * `bytes`: renders the current position of the bar as bytes.
//! * `percent`: renders the current position of the bar as a percentage of the total length.
//! * `total_bytes`: renders the total length of the bar as bytes.
//! * `elapsed_precise`: renders the elapsed time as `HH:MM:SS`.
//! * `elapsed`: renders the elapsed time as `42s`, `1m` etc.
//! * `eta_precise`: the remaining time (like `elapsed_precise`).
//! * `eta`: the remaining time (like `elapsed`).
//!
//! The design of the progress bar can be altered with the integrated
//! template functionality.  The template can be set by changing a
//! `ProgressStyle` and attaching it to the progress bar.
//!
//! # Human Readable Formatting
//!
//! There are some formatting wrappers for showing elapsed time and
//! file sizes for human users:
//!
//! ```ignore
//! use std::time::Instant;
//! use indicatif::{HumanDuration, HumanBytes};
//!
//! let started = Instant::now();
//! println!("The file is {} large", HumanBytes(file.size));
//! println!("The script took {}", HumanDuration(started.elapsed()));
//! ```
extern crate parking_lot;
extern crate regex;
#[macro_use]
extern crate lazy_static;
extern crate console;
extern crate number_prefix;

#[cfg(feature = "with_rayon")]
extern crate rayon;

mod format;
mod iter;
mod progress;
mod utils;

pub use format::{BinaryBytes, DecimalBytes, FormattedDuration, HumanBytes, HumanDuration};
pub use iter::{ProgressBarIter, ProgressIterator};
pub use progress::{
    MultiProgress, ProgressBar, ProgressBarRead, ProgressDrawTarget, ProgressStyle,
};

#[cfg(feature = "with_rayon")]
pub use iter::rayon::{ParProgressBarIter, ParallelProgressIterator};
<|endoftext|>


<commit_before>extern crate nalgebra as na;
extern crate num;

use na::{Norm, FloatPnt, FloatVec};
use num::Zero;
use std::cmp;

/// Wraps a square distance.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct SqDist(pub f32);

impl SqDist {
    pub fn from_dist(d: f32) -> SqDist {
        SqDist(d.powi(2))
    }
}

/// What to do when a node `connects` with an attrator.
#[derive(Debug, Copy, Clone)]
pub enum ConnectAction {
    KillAttractor,
    DisableFor {
        iterations: u32,
    },
}

#[derive(Debug, Copy, Clone)]
pub struct Attractor<P, I: Copy> {
    /// The square distance within which it can influence a Node.
    attract_dist: SqDist,

    /// If there is a node closer than the square root of
    /// this distance, the information is exchanged with the
    /// node and the ```connect_action``` is performed.
    /// This can be for example: kill the attractor,
    /// or disable it for a while.
    connect_dist: SqDist,

    /// The strenght with which it influences a Node.
    strength: f32,

    /// The position of the attractor.
    position: P,

    /// The attractor carries a bit of information.
    /// When a node comes closer than ```connect_radius```
    /// this bit of information is exchanged.
    information: I,

    /// Action performed when a node comes closer
    /// than ```connect_radius```.
    connect_action: ConnectAction,
}

#[derive(Debug, Copy, Clone)]
struct NodeIdx(u32, u32);

struct Node<P, F, I: Copy> {
    /// Index of the direct parent.
    parent: NodeIdx,

    /// Index of the root node this node is associated with.
    root: NodeIdx,

    /// Number of nodes between this node and the root node.
    length: usize,

    /// Number of branches this node has. This count
    /// is increased whenever another node refers this node
    /// as parent.
    branches: usize,

    /// The node's coordinate position.
    position: P,

    growth: F,
    growth_count: u32,

    assigned_information: Option<I>,
}

impl<P, F, I: Copy> Node<P, F, I> {
    fn transmit_information(&mut self, information: I) {
        self.assigned_information = Some(information);
    }

    fn is_leaf(&self) -> bool {
        self.branches == 0
    }

    fn is_root(&self) -> bool {
        // also self.root == self.parent
        self.length == 0
    }

    fn is_active(&self) -> bool {
        true
    }

    fn is_active2(&self, max_length: usize, max_branches: usize) -> bool {
        self.length < max_length && self.branches < max_branches
    }
}

pub struct SpaceColonization<P, F, I>
    where P: FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy,
          I: Copy + Default
{
    nodes: Vec<Node<P, F, I>>,
    attractors: Vec<Attractor<P, I>>,
    default_attract_dist: SqDist,
    default_connect_dist: SqDist,
}

impl<P, F, I> SpaceColonization<P, F, I>
    where P: FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy,
          I: Copy + Default
{
    pub fn new(default_attract_dist: SqDist,
               default_connect_dist: SqDist)
               -> SpaceColonization<P, F, I> {
        SpaceColonization {
            nodes: Vec::new(),
            attractors: Vec::new(),
            default_attract_dist: default_attract_dist,
            default_connect_dist: default_connect_dist,
        }
    }

    pub fn add_attractor(&mut self, position: P) {
        self.attractors.push(Attractor {
            attract_dist: self.default_attract_dist,
            connect_dist: self.default_connect_dist,
            strength: 1.0,
            position: position,
            information: I::default(),
            connect_action: ConnectAction::KillAttractor,
        });
    }

    pub fn add_root_node(&mut self, position: P) {
        // A root node has it's own index as parent and root.
        let len = self.nodes.len();
        self.nodes.push(Node {
            parent: NodeIdx(len as u32, 0),
            root: NodeIdx(len as u32, 0),
            length: 0,
            branches: 0,
            position: position,
            growth: Zero::zero(),
            growth_count: 0,
            assigned_information: None,
        });
    }

    fn get_node(&self, node_idx: NodeIdx) -> Option<&Node<P, F, I>> {
        self.nodes.get(node_idx.0 as usize)
    }

    fn get_node_mut(&mut self, node_idx: NodeIdx) -> Option<&mut Node<P, F, I>> {
        self.nodes.get_mut(node_idx.0 as usize)
    }

    fn add_leaf_node(&mut self, position: P, parent: NodeIdx) {
        let (root, length) = {
            let parent_node = self.get_node_mut(parent).unwrap();
            parent_node.branches += 1;
            (parent_node.root, parent_node.length + 1)
        };

        self.nodes.push(Node {
            parent: parent,
            root: root,
            length: length,
            branches: 0,
            position: position,
            growth: Zero::zero(),
            growth_count: 0,
            assigned_information: None,
        });
    }

    pub fn visit_node_segments<V>(&self, visitor: &mut V)
        where V: FnMut(&P, &P)
    {
        for node in self.nodes.iter() {
            if !node.is_root() {
                visitor(&node.position,
                        &self.get_node(node.parent).unwrap().position);
            }
        }
    }

    pub fn visit_attractor_points<V>(&self, visitor: &mut V)
        where V: FnMut(&P)
    {
        for attractor in self.attractors.iter() {
            visitor(&attractor.position)
        }
    }

    pub fn iterate(&mut self, move_distance: f32, use_last_n_nodes: Option<usize>) -> usize {
        let num_nodes = self.nodes.len();
        let use_last_nodes: usize = cmp::min(num_nodes, use_last_n_nodes.unwrap_or(num_nodes));
        let start_index = num_nodes - use_last_nodes;

        {
            let nodes = &mut self.nodes[start_index..];

            // for each attraction_point, find the nearest node that it influences
            let mut ap_idx = 0;
            'outer: while ap_idx < self.attractors.len() {
                let ap = self.attractors[ap_idx];

                // find the node nearest to the `ap` attraction point
                let mut nearest_node: Option<&mut Node<_, _, _>> = None;
                let mut nearest_distance = ap.attract_dist;
                let mut connect_node: Option<&mut Node<_, _, _>> = None;
                for node in nodes.iter_mut() {
                    if !node.is_active() {
                        // The node has become inactive
                        continue;
                    }

                    let dist = SqDist(node.position.sqdist(&ap.position));

                    if dist < ap.connect_dist {
                        // This node is within the connect radius of a node.
                        // XXX: There might be a closer node, but we use
                        // the first we find.
                        connect_node = Some(node);
                        // outside the node loop, we perform some action
                        break;
                    } else if dist < nearest_distance {
                        // ```node``` is within the influence of the attraction point,
                        // and it's closer than the currently closest node.
                        nearest_distance = dist;
                        nearest_node = Some(node);
                    }
                }

                if let Some(node) = connect_node {
                    node.transmit_information(ap.information);
                    match ap.connect_action {
                        ConnectAction::KillAttractor => {
                            // remove attraction point
                            self.attractors.swap_remove(ap_idx);
                            // and continue with "next" (without increasing ap_idx)
                            continue 'outer;
                        }
                        ConnectAction::DisableFor {iterations: _} => {
                            unimplemented!();
                        }
                    }
                } else if let Some(node) = nearest_node {
                    // update the force with the normalized vector towards the attraction point
                    let v = (ap.position - node.position).normalize() * ap.strength;
                    node.growth = node.growth + v;
                    node.growth_count += 1;
                }

                // go to next attractor point
                ap_idx += 1;
            }
        }

        // now create new nodes
        for i in start_index..num_nodes {
            let growth_count = self.nodes[i].growth_count;
            if growth_count > 0 {
                let growth_factor = 1.0; //((growth_count + 1) as f32).ln();
                let d = self.nodes[i].growth.normalize() * move_distance * growth_factor;
                let new_position = self.nodes[i].position + d;
                self.add_leaf_node(new_position, NodeIdx(i as u32, 0));

                // and reset growth attraction forces
                self.nodes[i].growth = Zero::zero();
                self.nodes[i].growth_count = 0;
            }
        }

        // Note that nodes can oscillate, between two attraction points, so
        // it's better to stop after a certain number of iterations
        return self.nodes.len() - num_nodes;
    }
}
<commit_msg>Move &mut reference to nodes inside loop and unindent<commit_after>extern crate nalgebra as na;
extern crate num;

use na::{Norm, FloatPnt, FloatVec};
use num::Zero;
use std::cmp;

/// Wraps a square distance.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct SqDist(pub f32);

impl SqDist {
    pub fn from_dist(d: f32) -> SqDist {
        SqDist(d.powi(2))
    }
}

/// What to do when a node `connects` with an attrator.
#[derive(Debug, Copy, Clone)]
pub enum ConnectAction {
    KillAttractor,
    DisableFor {
        iterations: u32,
    },
}

#[derive(Debug, Copy, Clone)]
pub struct Attractor<P, I: Copy> {
    /// The square distance within which it can influence a Node.
    attract_dist: SqDist,

    /// If there is a node closer than the square root of
    /// this distance, the information is exchanged with the
    /// node and the ```connect_action``` is performed.
    /// This can be for example: kill the attractor,
    /// or disable it for a while.
    connect_dist: SqDist,

    /// The strenght with which it influences a Node.
    strength: f32,

    /// The position of the attractor.
    position: P,

    /// The attractor carries a bit of information.
    /// When a node comes closer than ```connect_radius```
    /// this bit of information is exchanged.
    information: I,

    /// Action performed when a node comes closer
    /// than ```connect_radius```.
    connect_action: ConnectAction,
}

#[derive(Debug, Copy, Clone)]
struct NodeIdx(u32, u32);

struct Node<P, F, I: Copy> {
    /// Index of the direct parent.
    parent: NodeIdx,

    /// Index of the root node this node is associated with.
    root: NodeIdx,

    /// Number of nodes between this node and the root node.
    length: usize,

    /// Number of branches this node has. This count
    /// is increased whenever another node refers this node
    /// as parent.
    branches: usize,

    /// The node's coordinate position.
    position: P,

    growth: F,
    growth_count: u32,

    assigned_information: Option<I>,
}

impl<P, F, I: Copy> Node<P, F, I> {
    fn transmit_information(&mut self, information: I) {
        self.assigned_information = Some(information);
    }

    fn is_leaf(&self) -> bool {
        self.branches == 0
    }

    fn is_root(&self) -> bool {
        // also self.root == self.parent
        self.length == 0
    }

    fn is_active(&self) -> bool {
        true
    }

    fn is_active2(&self, max_length: usize, max_branches: usize) -> bool {
        self.length < max_length && self.branches < max_branches
    }
}

pub struct SpaceColonization<P, F, I>
    where P: FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy,
          I: Copy + Default
{
    nodes: Vec<Node<P, F, I>>,
    attractors: Vec<Attractor<P, I>>,
    default_attract_dist: SqDist,
    default_connect_dist: SqDist,
}

impl<P, F, I> SpaceColonization<P, F, I>
    where P: FloatPnt<f32, F>,
          F: FloatVec<f32> + Zero + Copy,
          I: Copy + Default
{
    pub fn new(default_attract_dist: SqDist,
               default_connect_dist: SqDist)
               -> SpaceColonization<P, F, I> {
        SpaceColonization {
            nodes: Vec::new(),
            attractors: Vec::new(),
            default_attract_dist: default_attract_dist,
            default_connect_dist: default_connect_dist,
        }
    }

    pub fn add_attractor(&mut self, position: P) {
        self.attractors.push(Attractor {
            attract_dist: self.default_attract_dist,
            connect_dist: self.default_connect_dist,
            strength: 1.0,
            position: position,
            information: I::default(),
            connect_action: ConnectAction::KillAttractor,
        });
    }

    pub fn add_root_node(&mut self, position: P) {
        // A root node has it's own index as parent and root.
        let len = self.nodes.len();
        self.nodes.push(Node {
            parent: NodeIdx(len as u32, 0),
            root: NodeIdx(len as u32, 0),
            length: 0,
            branches: 0,
            position: position,
            growth: Zero::zero(),
            growth_count: 0,
            assigned_information: None,
        });
    }

    fn get_node(&self, node_idx: NodeIdx) -> Option<&Node<P, F, I>> {
        self.nodes.get(node_idx.0 as usize)
    }

    fn get_node_mut(&mut self, node_idx: NodeIdx) -> Option<&mut Node<P, F, I>> {
        self.nodes.get_mut(node_idx.0 as usize)
    }

    fn add_leaf_node(&mut self, position: P, parent: NodeIdx) {
        let (root, length) = {
            let parent_node = self.get_node_mut(parent).unwrap();
            parent_node.branches += 1;
            (parent_node.root, parent_node.length + 1)
        };

        self.nodes.push(Node {
            parent: parent,
            root: root,
            length: length,
            branches: 0,
            position: position,
            growth: Zero::zero(),
            growth_count: 0,
            assigned_information: None,
        });
    }

    pub fn visit_node_segments<V>(&self, visitor: &mut V)
        where V: FnMut(&P, &P)
    {
        for node in self.nodes.iter() {
            if !node.is_root() {
                visitor(&node.position,
                        &self.get_node(node.parent).unwrap().position);
            }
        }
    }

    pub fn visit_attractor_points<V>(&self, visitor: &mut V)
        where V: FnMut(&P)
    {
        for attractor in self.attractors.iter() {
            visitor(&attractor.position)
        }
    }

    pub fn iterate(&mut self, move_distance: f32, use_last_n_nodes: Option<usize>) -> usize {
        let num_nodes = self.nodes.len();
        let use_last_nodes: usize = cmp::min(num_nodes, use_last_n_nodes.unwrap_or(num_nodes));
        let start_index = num_nodes - use_last_nodes;

        // for each attraction_point, find the nearest node that it influences
        let mut ap_idx = 0;
        'outer: while ap_idx < self.attractors.len() {
            let ap = self.attractors[ap_idx];

            let nodes = &mut self.nodes[start_index..];

            // find the node nearest to the `ap` attraction point
            let mut nearest_node: Option<&mut Node<_, _, _>> = None;
            let mut nearest_distance = ap.attract_dist;
            let mut connect_node: Option<&mut Node<_, _, _>> = None;
            for node in nodes.iter_mut() {
                if !node.is_active() {
                    // The node has become inactive
                    continue;
                }

                let dist = SqDist(node.position.sqdist(&ap.position));

                if dist < ap.connect_dist {
                    // This node is within the connect radius of a node.
                    // XXX: There might be a closer node, but we use
                    // the first we find.
                    connect_node = Some(node);
                    // outside the node loop, we perform some action
                    break;
                } else if dist < nearest_distance {
                    // ```node``` is within the influence of the attraction point,
                    // and it's closer than the currently closest node.
                    nearest_distance = dist;
                    nearest_node = Some(node);
                }
            }

            if let Some(node) = connect_node {
                node.transmit_information(ap.information);
                match ap.connect_action {
                    ConnectAction::KillAttractor => {
                        // remove attraction point
                        self.attractors.swap_remove(ap_idx);
                        // and continue with "next" (without increasing ap_idx)
                        continue 'outer;
                    }
                    ConnectAction::DisableFor {iterations: _} => {
                        unimplemented!();
                    }
                }
            } else if let Some(node) = nearest_node {
                // update the force with the normalized vector towards the attraction point
                let v = (ap.position - node.position).normalize() * ap.strength;
                node.growth = node.growth + v;
                node.growth_count += 1;
            }

            // go to next attractor point
            ap_idx += 1;
        }

        // now create new nodes
        for i in start_index..num_nodes {
            let growth_count = self.nodes[i].growth_count;
            if growth_count > 0 {
                let growth_factor = 1.0; //((growth_count + 1) as f32).ln();
                let d = self.nodes[i].growth.normalize() * move_distance * growth_factor;
                let new_position = self.nodes[i].position + d;
                self.add_leaf_node(new_position, NodeIdx(i as u32, 0));

                // and reset growth attraction forces
                self.nodes[i].growth = Zero::zero();
                self.nodes[i].growth_count = 0;
            }
        }

        // Note that nodes can oscillate, between two attraction points, so
        // it's better to stop after a certain number of iterations
        return self.nodes.len() - num_nodes;
    }
}
<|endoftext|>


<commit_before>//! This crate allows to communicate with usbmuxd (USB multiplexer daemon) which is used to
//! communicate with iOS devices.

extern crate unix_socket;
extern crate byteorder;
extern crate plist;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;

use std::io;
use std::fmt;
use std::error;
use std::time::Duration;
use unix_socket::UnixStream;
use plist::Plist;

pub mod requests;

/// Represents connection to usbmuxd.
pub struct Stream {
    inner: UnixStream,
}

impl Stream {
    /// Tries to connect to usbmuxd.
    pub fn connect() -> io::Result<Self> {
        Ok(Stream {
            inner: try!(UnixStream::connect("/var/run/usbmuxd")),
        })
    }

    /// Sets the send timeout for the stream.
    ///
    /// If the provided value is `None`, then `send` calls will block indefinitely.
    /// It is an error to pass the zero `Duration` to this method.
    pub fn set_send_tymeout(&mut self, timeout: Option<Duration>) -> Result<()> {
        Ok(try!(self.inner.set_write_timeout(timeout)))
    }

    /// Sets the receive timeout for the stream.
    ///
    /// If the provided value is `None`, then `receive` calls will block indefinitely.
    /// It is an error to pass the zero `Duration` to this method.
    pub fn set_receive_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
        Ok(try!(self.inner.set_read_timeout(timeout)))
    }

    /// Tries to send `plist` data to usbmuxd.
    ///
    /// After this call you should call `receive` method to get a response from usbmuxd.
    pub fn send(&mut self, plist: Plist) -> Result<()> {
        send(&mut self.inner, plist)
    }

    /// Tries to receive `plist` data from usbmuxd.
    ///
    /// Typically this method should be called after `send` method.
    pub fn receive(&mut self) -> Result<Plist> {
        receive(&mut self.inner)
    }
}

/// A Result type alias.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An Error type.
#[derive(Debug)]
pub enum Error {
    /// Denotes I/O error.
    Io(io::Error),
    /// Denotes error that produces plist crate.
    Plist(plist::Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref e) => e.description(),
            Error::Plist(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref e) => Some(e),
            Error::Plist(ref e) => Some(e),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => e.fmt(f),
            Error::Plist(ref e) => e.fmt(f),
        }
    }
}

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

impl From<plist::Error> for Error {
    fn from(e: plist::Error) -> Self {
        Error::Plist(e)
    }
}

fn send<W>(stream: &mut W, plist: Plist) -> Result<()> where W: io::Write {
    let data = prepare_request_data(&plist_to_data(plist));
    Ok(try!(stream.write_all(&data)))
}

fn receive<R>(stream: &mut R) -> Result<Plist> where R: io::Read {
    use byteorder::{LittleEndian, ByteOrder};

    // Read header and get length of the data.
    // Don't bother to check version and message type. Deserialization
    // from plist will fail anyway if message will have wrong format.
    let mut header = [0; 16];
    try!(stream.read_exact(&mut header));
    let length = LittleEndian::read_u32(&header) as usize - header.len();

    let mut data = vec![0; length];
    try!(stream.read_exact(&mut data));

    Ok(try!(Plist::read(io::Cursor::new(data))))
}

/// Converts the `plist` to the raw xml data.
fn plist_to_data(plist: Plist) -> Vec<u8> {
    use plist::xml::EventWriter;
    let mut buffer = Vec::new();
    {
        let mut writer = EventWriter::new(&mut buffer);
        for event in plist.into_events() {
            writer.write(&event).unwrap();
        }
    }
    buffer
}

/// Prepares request data for usbmuxd by adding a header info.
fn prepare_request_data(data: &[u8]) -> Vec<u8> {
    use byteorder::{WriteBytesExt, LittleEndian};
    use std::io::{Write, Cursor};

    let mut cursor = Cursor::new(Vec::new());
    cursor.write_u32::<LittleEndian>(data.len() as u32 + 16).unwrap(); // total length
    cursor.write_u32::<LittleEndian>(1).unwrap(); // version
    cursor.write_u32::<LittleEndian>(8).unwrap(); // message type (plist)
    cursor.write_u32::<LittleEndian>(1).unwrap(); // tag
    cursor.write_all(data).unwrap();
    cursor.into_inner()
}

#[cfg(test)]
mod tests {
    use super::prepare_request_data;
    use std::io;
    use expectest::prelude::*;

    #[test]
    fn test_prepare_data() {
        expect!(prepare_request_data(&[1, 2, 3, 4]).iter()).to(have_count(20));
    }

    #[test]
    fn test_send_receive_message() {
        let message = super::requests::listen();
        let mut buffer = Vec::new();
        expect!(super::send(&mut buffer, message.clone())).to(be_ok());
        let mut cursor = io::Cursor::new(buffer);
        expect!(super::receive(&mut cursor)).to(be_ok().value(message));
    }
}
<commit_msg>Return library Result instead of io::Result from connect method.<commit_after>//! This crate allows to communicate with usbmuxd (USB multiplexer daemon) which is used to
//! communicate with iOS devices.

extern crate unix_socket;
extern crate byteorder;
extern crate plist;
#[cfg(test)]
#[macro_use(expect)]
extern crate expectest;

use std::io;
use std::fmt;
use std::error;
use std::time::Duration;
use unix_socket::UnixStream;
use plist::Plist;

pub mod requests;

/// Represents connection to usbmuxd.
pub struct Stream {
    inner: UnixStream,
}

impl Stream {
    /// Tries to connect to usbmuxd.
    pub fn connect() -> Result<Self> {
        Ok(Stream {
            inner: try!(UnixStream::connect("/var/run/usbmuxd")),
        })
    }

    /// Sets the send timeout for the stream.
    ///
    /// If the provided value is `None`, then `send` calls will block indefinitely.
    /// It is an error to pass the zero `Duration` to this method.
    pub fn set_send_tymeout(&mut self, timeout: Option<Duration>) -> Result<()> {
        Ok(try!(self.inner.set_write_timeout(timeout)))
    }

    /// Sets the receive timeout for the stream.
    ///
    /// If the provided value is `None`, then `receive` calls will block indefinitely.
    /// It is an error to pass the zero `Duration` to this method.
    pub fn set_receive_timeout(&mut self, timeout: Option<Duration>) -> Result<()> {
        Ok(try!(self.inner.set_read_timeout(timeout)))
    }

    /// Tries to send `plist` data to usbmuxd.
    ///
    /// After this call you should call `receive` method to get a response from usbmuxd.
    pub fn send(&mut self, plist: Plist) -> Result<()> {
        send(&mut self.inner, plist)
    }

    /// Tries to receive `plist` data from usbmuxd.
    ///
    /// Typically this method should be called after `send` method.
    pub fn receive(&mut self) -> Result<Plist> {
        receive(&mut self.inner)
    }
}

/// A Result type alias.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An Error type.
#[derive(Debug)]
pub enum Error {
    /// Denotes I/O error.
    Io(io::Error),
    /// Denotes error that produces plist crate.
    Plist(plist::Error),
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::Io(ref e) => e.description(),
            Error::Plist(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Io(ref e) => Some(e),
            Error::Plist(ref e) => Some(e),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Io(ref e) => e.fmt(f),
            Error::Plist(ref e) => e.fmt(f),
        }
    }
}

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

impl From<plist::Error> for Error {
    fn from(e: plist::Error) -> Self {
        Error::Plist(e)
    }
}

fn send<W>(stream: &mut W, plist: Plist) -> Result<()> where W: io::Write {
    let data = prepare_request_data(&plist_to_data(plist));
    Ok(try!(stream.write_all(&data)))
}

fn receive<R>(stream: &mut R) -> Result<Plist> where R: io::Read {
    use byteorder::{LittleEndian, ByteOrder};

    // Read header and get length of the data.
    // Don't bother to check version and message type. Deserialization
    // from plist will fail anyway if message will have wrong format.
    let mut header = [0; 16];
    try!(stream.read_exact(&mut header));
    let length = LittleEndian::read_u32(&header) as usize - header.len();

    let mut data = vec![0; length];
    try!(stream.read_exact(&mut data));

    Ok(try!(Plist::read(io::Cursor::new(data))))
}

/// Converts the `plist` to the raw xml data.
fn plist_to_data(plist: Plist) -> Vec<u8> {
    use plist::xml::EventWriter;
    let mut buffer = Vec::new();
    {
        let mut writer = EventWriter::new(&mut buffer);
        for event in plist.into_events() {
            writer.write(&event).unwrap();
        }
    }
    buffer
}

/// Prepares request data for usbmuxd by adding a header info.
fn prepare_request_data(data: &[u8]) -> Vec<u8> {
    use byteorder::{WriteBytesExt, LittleEndian};
    use std::io::{Write, Cursor};

    let mut cursor = Cursor::new(Vec::new());
    cursor.write_u32::<LittleEndian>(data.len() as u32 + 16).unwrap(); // total length
    cursor.write_u32::<LittleEndian>(1).unwrap(); // version
    cursor.write_u32::<LittleEndian>(8).unwrap(); // message type (plist)
    cursor.write_u32::<LittleEndian>(1).unwrap(); // tag
    cursor.write_all(data).unwrap();
    cursor.into_inner()
}

#[cfg(test)]
mod tests {
    use super::prepare_request_data;
    use std::io;
    use expectest::prelude::*;

    #[test]
    fn test_prepare_data() {
        expect!(prepare_request_data(&[1, 2, 3, 4]).iter()).to(have_count(20));
    }

    #[test]
    fn test_send_receive_message() {
        let message = super::requests::listen();
        let mut buffer = Vec::new();
        expect!(super::send(&mut buffer, message.clone())).to(be_ok());
        let mut cursor = io::Cursor::new(buffer);
        expect!(super::receive(&mut cursor)).to(be_ok().value(message));
    }
}
<|endoftext|>


<commit_before>extern crate heatmap;
extern crate hsl;
extern crate lodepng;
extern crate rusttype;

use std::path::Path;

use heatmap::Heatmap;
use hsl::HSL;
use lodepng::encode_file;
use rusttype::{FontCollection, PixelsXY, point, PositionedGlyph};

#[allow(dead_code)]
pub struct Waterfall {
    config: Config,
}

pub struct Config { }

impl Default for Config {
    fn default() -> Config {
        Config {}
    }
}

impl Config {
    pub fn new() -> Config {
        Default::default()
    }

    pub fn build(self) -> Waterfall {
        Waterfall::configured(self)
    }
}

struct Label {
    value: u64,
    text: String,
}

impl Default for Waterfall {
    fn default() -> Waterfall {
        Waterfall::configured(Config::default())
    }
}

impl Waterfall {
    pub fn new() -> Waterfall {
        Default::default()
    }

    pub fn configure() -> Config {
        Config::default()
    }

    fn configured(config: Config) -> Waterfall {
        Waterfall { config: config }
    }

    pub fn render_png(&mut self, heatmap: &Heatmap, file: String) {
        let height = heatmap.num_slices() as usize;
        let width = heatmap.histogram_buckets() as usize;

        // build buffer from data
        let mut buffer = ImageBuffer::<ColorRgb>::new(width, height);
        let max = find_max(heatmap);
        let mut x;
        let mut y = 0;

        // loop to color the pixels
        for slice in heatmap {
            x = 0;
            for bucket in &slice.histogram() {
                let value = bucket.count() as f64;
                let pixel = color_from_value(value, max);
                buffer.set_pixel(x, y, pixel);
                x += 1;
            }
            y += 1;
        }

        // latency annotations
        let labels: Vec<Label> = vec!(
			Label{ value: 200, text: "200nS".to_string() },
			Label{ value: 500, text: "500nS".to_string() },
			Label{ value: 1000, text: "1uS".to_string() },
			Label{ value: 2000, text: "2uS".to_string() },
			Label{ value: 5000, text: "5uS".to_string() },
			Label{ value: 10000, text: "10uS".to_string() },
			Label{ value: 20000, text: "20uS".to_string() },
			Label{ value: 50000, text: "50uS".to_string() },
			Label{ value: 100000, text: "100uS".to_string() },
			Label{ value: 200000, text: "200uS".to_string() },
			Label{ value: 500000, text: "500uS".to_string() },
			Label{ value: 1000000, text: "1mS".to_string() },
			Label{ value: 2000000, text: "2mS".to_string() },
			Label{ value: 5000000, text: "5mS".to_string() },
			Label{ value: 10000000, text: "10mS".to_string() },
			Label{ value: 20000000, text: "20mS".to_string() },
			Label{ value: 50000000, text: "50mS".to_string() },
			Label{ value: 100000000, text: "100mS".to_string() },
			Label{ value: 200000000, text: "200mS".to_string() },
			Label{ value: 500000000, text: "500mS".to_string() },
			);

        let mut l = 0;
        y = 0;

        for slice in heatmap {
            x = 0;
            for bucket in &slice.histogram() {
                if (y % 60) == 0 {
                    if x == 0 {
                        let hour = y / 3600;
                        let minute = y / 60;
                        let time = format!("{:02}:{:02}", hour, minute);
                        let overlay = string_buffer(time.to_string(), 25.0);
                        buffer.overlay(&overlay, x, y);
                        buffer.horizontal_line(y, ColorRgb { r: 0, g: 0, b: 0 });
                    }
                    let v = bucket.value();
                    if (l < labels.len()) && (v >= labels[l].value) {
                        let overlay = string_buffer(labels[l].text.clone(), 25.0);
                        buffer.overlay(&overlay, x, y);
                        buffer.vertical_line(x, ColorRgb { r: 0, g: 0, b: 0 });
                        l += 1;
                    }
                }
                x += 1;
            }
            y += 1;
        }

        let _ = buffer.write_png(file.clone());
    }
}

fn find_max(heatmap: &Heatmap) -> f64 {
    let mut max = 0.0;

    for slice in heatmap {
        for bucket in &slice.histogram() {
            let value = bucket.count() as f64;
            if value > max {
                max = value;
            }
        }
    }
    max
}

fn string_buffer(string: String, size: f32) -> ImageBuffer<ColorRgb> {
    // load font
    let font_data = include_bytes!("../assets/ubuntumono/UbuntuMono-Regular.ttf");
    let collection = FontCollection::from_bytes(font_data as &[u8]);
    let font = collection.into_font().unwrap();

    // size and scaling
    let height: f32 = size;
    let pixel_height = height.ceil() as usize;
    let scale = PixelsXY(height * 1.0, height);

    let v_metrics = font.v_metrics(scale);
    let offset = point(0.0, v_metrics.ascent);

    let glyphs: Vec<PositionedGlyph> = font.layout(&string, scale, offset).collect();

    let width = glyphs.iter()
        .map(|g| g.h_metrics().advance_width)
        .fold(0.0, |x, y| x + y)
        .ceil() as usize;

    let mut overlay = ImageBuffer::<ColorRgb>::new(width, pixel_height);

    for g in glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            g.draw(|x, y, v| {
                let x = (x as i32 + bb.min.x) as usize;
                let y = (y as i32 + bb.min.y) as usize;
                if v > 0.25 {
                    overlay.set_pixel(x,
                                      y,
                                      ColorRgb {
                                          r: 255,
                                          g: 255,
                                          b: 255,
                                      });
                }
            })
        }
    }

    overlay
}

fn color_from_value(value: f64, max: f64) -> ColorRgb {
    let value = value / max;

    let knee = 0.10_f64;

    let hsl = if value < knee {
        let l = 0.25_f64 + 0.25_f64 * value / knee;
        HSL {
            h: 236_f64,
            s: 1_f64,
            l: l,
        }
    } else {
        let h_per_deg: f64 = 236_f64 / (1.0_f64 - knee);
        let deg = (value - knee) * h_per_deg;

        HSL {
            h: (236_f64 - deg),
            s: 1_f64,
            l: 0.50_f64,
        }
    };

    let (r, g, b) = hsl.to_rgb();

    ColorRgb { r: r, g: g, b: b }
}

#[derive(Clone, Copy, Debug, PartialEq)]
struct ColorRgb {
    r: u8,
    g: u8,
    b: u8,
}

struct ImageBuffer<T> {
    buffer: Vec<Vec<T>>,
    height: usize,
    width: usize,
}

impl ImageBuffer<ColorRgb> {
    pub fn new(width: usize, height: usize) -> ImageBuffer<ColorRgb> {
        let background = ColorRgb { r: 0, g: 0, b: 0 };
        let mut row = Vec::<ColorRgb>::with_capacity(width);
        for _ in 0..width {
            row.push(background);
        }
        let mut buffer = Vec::<Vec<ColorRgb>>::with_capacity(height);
        for _ in 0..height {
            buffer.push(row.clone());
        }
        ImageBuffer {
            buffer: buffer,
            height: height,
            width: width,
        }
    }

    pub fn write_png(self, file: String) -> Result<(), lodepng::ffi::Error> {
        let mut buffer = Vec::<u8>::with_capacity((self.height * self.width));
        for row in 0..self.height {
            for col in 0..self.width {
                let pixel = self.buffer[row][col];
                buffer.push(pixel.r);
                buffer.push(pixel.g);
                buffer.push(pixel.b);
            }
        }
        let path = &Path::new(&file);
        encode_file(path, &buffer, self.width, self.height, lodepng::LCT_RGB, 8)
    }

    pub fn set_pixel(&mut self, x: usize, y: usize, value: ColorRgb) {
        if x < self.width && y < self.height {
            self.buffer[y][x] = value;
        }
    }

    pub fn overlay(&mut self, other: &ImageBuffer<ColorRgb>, x: usize, y: usize) {
        let ignore = ColorRgb { r: 0, g: 0, b: 0 };
        for sx in 0..other.width {
            for sy in 0..other.height {
                if (other.buffer[sy][sx] != ignore) &&
                   (((sy + y) < self.height) && ((sx + x) < self.width)) {
                    self.buffer[(sy + y)][(sx + x)] = other.buffer[sy][sx];
                }
            }
        }
    }

    pub fn horizontal_line(&mut self, y: usize, color: ColorRgb) {
        for x in 0..self.width {
            self.buffer[y][x] = color;
        }
    }

    pub fn vertical_line(&mut self, x: usize, color: ColorRgb) {
        for y in 0..self.height {
            self.buffer[y][x] = color;
        }
    }
}
<commit_msg>revert to use width corrected values (#11)<commit_after>extern crate heatmap;
extern crate hsl;
extern crate lodepng;
extern crate rusttype;

use std::path::Path;

use heatmap::Heatmap;
use hsl::HSL;
use lodepng::encode_file;
use rusttype::{FontCollection, PixelsXY, point, PositionedGlyph};

#[allow(dead_code)]
pub struct Waterfall {
    config: Config,
}

pub struct Config { }

impl Default for Config {
    fn default() -> Config {
        Config {}
    }
}

impl Config {
    pub fn new() -> Config {
        Default::default()
    }

    pub fn build(self) -> Waterfall {
        Waterfall::configured(self)
    }
}

struct Label {
    value: u64,
    text: String,
}

impl Default for Waterfall {
    fn default() -> Waterfall {
        Waterfall::configured(Config::default())
    }
}

impl Waterfall {
    pub fn new() -> Waterfall {
        Default::default()
    }

    pub fn configure() -> Config {
        Config::default()
    }

    fn configured(config: Config) -> Waterfall {
        Waterfall { config: config }
    }

    pub fn render_png(&mut self, heatmap: &Heatmap, file: String) {
        let height = heatmap.num_slices() as usize;
        let width = heatmap.histogram_buckets() as usize;

        // build buffer from data
        let mut buffer = ImageBuffer::<ColorRgb>::new(width, height);
        let max = find_max(heatmap);
        let mut x;
        let mut y = 0;

        // loop to color the pixels
        for slice in heatmap {
            x = 0;
            for bucket in &slice.histogram() {
                let value = (bucket.count() as f64) / (bucket.width() as f64);
                let pixel = color_from_value(value, max);
                buffer.set_pixel(x, y, pixel);
                x += 1;
            }
            y += 1;
        }

        // latency annotations
        let labels: Vec<Label> = vec!(
			Label{ value: 200, text: "200nS".to_string() },
			Label{ value: 500, text: "500nS".to_string() },
			Label{ value: 1000, text: "1uS".to_string() },
			Label{ value: 2000, text: "2uS".to_string() },
			Label{ value: 5000, text: "5uS".to_string() },
			Label{ value: 10000, text: "10uS".to_string() },
			Label{ value: 20000, text: "20uS".to_string() },
			Label{ value: 50000, text: "50uS".to_string() },
			Label{ value: 100000, text: "100uS".to_string() },
			Label{ value: 200000, text: "200uS".to_string() },
			Label{ value: 500000, text: "500uS".to_string() },
			Label{ value: 1000000, text: "1mS".to_string() },
			Label{ value: 2000000, text: "2mS".to_string() },
			Label{ value: 5000000, text: "5mS".to_string() },
			Label{ value: 10000000, text: "10mS".to_string() },
			Label{ value: 20000000, text: "20mS".to_string() },
			Label{ value: 50000000, text: "50mS".to_string() },
			Label{ value: 100000000, text: "100mS".to_string() },
			Label{ value: 200000000, text: "200mS".to_string() },
			Label{ value: 500000000, text: "500mS".to_string() },
			);

        let mut l = 0;
        y = 0;

        for slice in heatmap {
            x = 0;
            for bucket in &slice.histogram() {
                if (y % 60) == 0 {
                    if x == 0 {
                        let hour = y / 3600;
                        let minute = y / 60;
                        let time = format!("{:02}:{:02}", hour, minute);
                        let overlay = string_buffer(time.to_string(), 25.0);
                        buffer.overlay(&overlay, x, y);
                        buffer.horizontal_line(y, ColorRgb { r: 0, g: 0, b: 0 });
                    }
                    let v = bucket.value();
                    if (l < labels.len()) && (v >= labels[l].value) {
                        let overlay = string_buffer(labels[l].text.clone(), 25.0);
                        buffer.overlay(&overlay, x, y);
                        buffer.vertical_line(x, ColorRgb { r: 0, g: 0, b: 0 });
                        l += 1;
                    }
                }
                x += 1;
            }
            y += 1;
        }

        let _ = buffer.write_png(file.clone());
    }
}

fn find_max(heatmap: &Heatmap) -> f64 {
    let mut max = 0.0;

    for slice in heatmap {
        for bucket in &slice.histogram() {
            let value = (bucket.count() as f64) / (bucket.width() as f64);
            if value > max {
                max = value;
            }
        }
    }
    max
}

fn string_buffer(string: String, size: f32) -> ImageBuffer<ColorRgb> {
    // load font
    let font_data = include_bytes!("../assets/ubuntumono/UbuntuMono-Regular.ttf");
    let collection = FontCollection::from_bytes(font_data as &[u8]);
    let font = collection.into_font().unwrap();

    // size and scaling
    let height: f32 = size;
    let pixel_height = height.ceil() as usize;
    let scale = PixelsXY(height * 1.0, height);

    let v_metrics = font.v_metrics(scale);
    let offset = point(0.0, v_metrics.ascent);

    let glyphs: Vec<PositionedGlyph> = font.layout(&string, scale, offset).collect();

    let width = glyphs.iter()
        .map(|g| g.h_metrics().advance_width)
        .fold(0.0, |x, y| x + y)
        .ceil() as usize;

    let mut overlay = ImageBuffer::<ColorRgb>::new(width, pixel_height);

    for g in glyphs {
        if let Some(bb) = g.pixel_bounding_box() {
            g.draw(|x, y, v| {
                let x = (x as i32 + bb.min.x) as usize;
                let y = (y as i32 + bb.min.y) as usize;
                if v > 0.25 {
                    overlay.set_pixel(x,
                                      y,
                                      ColorRgb {
                                          r: 255,
                                          g: 255,
                                          b: 255,
                                      });
                }
            })
        }
    }

    overlay
}

fn color_from_value(value: f64, max: f64) -> ColorRgb {
    let value = value / max;

    let knee = 0.10_f64;

    let hsl = if value < knee {
        let l = 0.25_f64 + 0.25_f64 * value / knee;
        HSL {
            h: 236_f64,
            s: 1_f64,
            l: l,
        }
    } else {
        let h_per_deg: f64 = 236_f64 / (1.0_f64 - knee);
        let deg = (value - knee) * h_per_deg;

        HSL {
            h: (236_f64 - deg),
            s: 1_f64,
            l: 0.50_f64,
        }
    };

    let (r, g, b) = hsl.to_rgb();

    ColorRgb { r: r, g: g, b: b }
}

#[derive(Clone, Copy, Debug, PartialEq)]
struct ColorRgb {
    r: u8,
    g: u8,
    b: u8,
}

struct ImageBuffer<T> {
    buffer: Vec<Vec<T>>,
    height: usize,
    width: usize,
}

impl ImageBuffer<ColorRgb> {
    pub fn new(width: usize, height: usize) -> ImageBuffer<ColorRgb> {
        let background = ColorRgb { r: 0, g: 0, b: 0 };
        let mut row = Vec::<ColorRgb>::with_capacity(width);
        for _ in 0..width {
            row.push(background);
        }
        let mut buffer = Vec::<Vec<ColorRgb>>::with_capacity(height);
        for _ in 0..height {
            buffer.push(row.clone());
        }
        ImageBuffer {
            buffer: buffer,
            height: height,
            width: width,
        }
    }

    pub fn write_png(self, file: String) -> Result<(), lodepng::ffi::Error> {
        let mut buffer = Vec::<u8>::with_capacity((self.height * self.width));
        for row in 0..self.height {
            for col in 0..self.width {
                let pixel = self.buffer[row][col];
                buffer.push(pixel.r);
                buffer.push(pixel.g);
                buffer.push(pixel.b);
            }
        }
        let path = &Path::new(&file);
        encode_file(path, &buffer, self.width, self.height, lodepng::LCT_RGB, 8)
    }

    pub fn set_pixel(&mut self, x: usize, y: usize, value: ColorRgb) {
        if x < self.width && y < self.height {
            self.buffer[y][x] = value;
        }
    }

    pub fn overlay(&mut self, other: &ImageBuffer<ColorRgb>, x: usize, y: usize) {
        let ignore = ColorRgb { r: 0, g: 0, b: 0 };
        for sx in 0..other.width {
            for sy in 0..other.height {
                if (other.buffer[sy][sx] != ignore) &&
                   (((sy + y) < self.height) && ((sx + x) < self.width)) {
                    self.buffer[(sy + y)][(sx + x)] = other.buffer[sy][sx];
                }
            }
        }
    }

    pub fn horizontal_line(&mut self, y: usize, color: ColorRgb) {
        for x in 0..self.width {
            self.buffer[y][x] = color;
        }
    }

    pub fn vertical_line(&mut self, x: usize, color: ColorRgb) {
        for y in 0..self.height {
            self.buffer[y][x] = color;
        }
    }
}
<|endoftext|>


<commit_before>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.
//!
//! To implement your own back-end, use the BackEnd trait.
//!
//! ## Usage
//!
//! If you are using [Rust-Empty](https://github.com/bvssvni/rust-empty) or Cargo, put the compiled library in the "target/cpu-vendor-platform/lib/" directory, then add the following to your source:
//!
//! ```Rust
//! #![feature(globs)] // Allow global imports
//!
//! extern crate graphics; // Link to 'graphics' library
//!
//! use graphics::*; // Use the graphics types in the module
//! ```
//!
//! To draw to the back-end, you need a context.
//! The context contains the information necessary to perform the drawing.
//! Unlike other graphics libraries, this library is not bound to the back-end.
//! You do not have to specify which back-end to use before doing the actual drawing.
//!
//! For example, assuming we have a back-end called `back_end`:
//!
//! ```
//! Context::new().rect(x, y, w, h).rgba(r, g, b, a).fill(&mut back_end);
//! ```
//!
//! ## Important!
//!
//! Because the context is built using borrowed pointers,
//! it is not possible to do two or more steps at a time and assign it to a variable:
//!
//! ```
//! // ERROR: Borrowed value does not live long enough
//! let rect = Context::new().rect(x, y, w, h);
//! ```
//!
//! This is because the lifetime of the first step only lives inside the expression.
//! To solve this problem, break the statement into two parts, one for each step:
//!
//! ```
//! let c = Context::new();
//! let rect = c.rect(x, y, w, h);
//! ```
//!
//! This is only the case when you are assigning the context to a variable.

#[cfg(gl)]
extern crate gl;
#[cfg(gl)]
extern crate libc;
extern crate image;
extern crate core;
extern crate std;

#[cfg(gl)]
pub use Gl = gl_back_end::Gl;
#[cfg(gl)]
pub use Texture = texture::Texture;

pub use AddBevel = add_bevel::AddBevel;
pub use AddBevelBorder = add_bevel_border::AddBevelBorder;
pub use AddBorder = add_border::AddBorder;
pub use AddColor = add_color::AddColor;
pub use AddEllipse = add_ellipse::AddEllipse;
pub use AddImage = add_image::AddImage;
pub use AddLine = add_line::AddLine;
pub use AddPolygon = add_polygon::AddPolygon;
pub use AddPolygons = add_polygons::AddPolygons;
pub use AddRectangle = add_rectangle::AddRectangle;
pub use AddRound = add_round::AddRound;
pub use AddRoundBorder = add_round_border::AddRoundBorder;
pub use AddSquareBorder = add_square_border::AddSquareBorder;
pub use AddTween = add_tween::AddTween;
pub use BackEnd = back_end::BackEnd;
pub use BevelBorderLineColorContext = bevel_border_line_color_context::BevelBorderLineColorContext;
pub use BevelBorderLineContext = bevel_border_line_context::BevelBorderLineContext;
pub use BevelRectangleBorderColorContext = bevel_rectangle_border_color_context::BevelRectangleBorderColorContext;
pub use BevelRectangleBorderContext = bevel_rectangle_border_context::BevelRectangleBorderContext;
pub use BevelRectangleColorContext = bevel_rectangle_color_context::BevelRectangleColorContext;
pub use BevelRectangleContext = bevel_rectangle_context::BevelRectangleContext;
pub use Clear = clear::Clear;
pub use ColorContext = color_context::ColorContext;
pub use Context = context::Context;
pub use Draw = draw::Draw;
pub use EllipseContext = ellipse_context::EllipseContext;
pub use EllipseBorderContext = ellipse_border_context::EllipseBorderContext;
pub use EllipseColorContext = ellipse_color_context::EllipseColorContext;
pub use EllipseBorderColorContext = ellipse_border_color_context::EllipseBorderColorContext;
pub use Fill = fill::Fill;
pub use ImageSize = image_size::ImageSize;
pub use ImageContext = image_context::ImageContext;
pub use ImageColorContext = image_color_context::ImageColorContext;
pub use ImageRectangleContext = image_rectangle_context::ImageRectangleContext;
pub use ImageRectangleColorContext = image_rectangle_color_context::ImageRectangleColorContext;
pub use LerpTweenContext = lerp_tween_context::LerpTweenContext;
pub use LerpTweenColorContext = lerp_tween_color_context::LerpTweenColorContext;
pub use LerpTweenPolygonsContext = lerp_tween_polygons_context::LerpTweenPolygonsContext;
pub use LerpTweenPolygonsColorContext = lerp_tween_polygons_color_context::LerpTweenPolygonsColorContext;
pub use LineContext = line_context::LineContext;
pub use LineColorContext = line_color_context::LineColorContext;
pub use PolygonContext = polygon_context::PolygonContext;
pub use PolygonColorContext = polygon_color_context::PolygonColorContext;
pub use RectangleBorderContext = rectangle_border_context::RectangleBorderContext;
pub use RectangleBorderColorContext = rectangle_border_color_context::RectangleBorderColorContext;
pub use RectangleContext = rectangle_context::RectangleContext;
pub use RectangleColorContext = rectangle_color_context::RectangleColorContext;
pub use RelativeColor = relative_color::RelativeColor;
pub use RelativeRectangle = relative_rectangle::RelativeRectangle;
pub use RelativeSourceRectangle = relative_source_rectangle::RelativeSourceRectangle;
pub use RelativeTransform2d = relative_transform2d::RelativeTransform2d;
pub use RoundBorderLineContext = round_border_line_context::RoundBorderLineContext;
pub use RoundBorderLineColorContext = round_border_line_color_context::RoundBorderLineColorContext;
pub use RoundRectangleBorderColorContext = round_rectangle_border_color_context::RoundRectangleBorderColorContext;
pub use RoundRectangleBorderContext = round_rectangle_border_context::RoundRectangleBorderContext;
pub use RoundRectangleColorContext = round_rectangle_color_context::RoundRectangleColorContext;
pub use RoundRectangleContext = round_rectangle_context::RoundRectangleContext;
pub use Stroke = stroke::Stroke;
pub use SquareBorderLineColorContext = square_border_line_color_context::SquareBorderLineColorContext;
pub use SquareBorderLineContext = square_border_line_context::SquareBorderLineContext;
pub use View = view::View;

#[cfg(gl)]
mod gl_back_end;
#[cfg(gl)]
mod texture;
#[cfg(gl)]
pub mod shader_utils;

mod add_bevel;
mod add_bevel_border;
mod add_border;
mod add_color;
mod add_ellipse;
mod add_image;
mod add_line;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_round_border;
mod add_square_border;
mod add_tween;
mod back_end;
mod bevel_border_line_color_context;
mod bevel_border_line_context;
mod bevel_rectangle_border_color_context;
mod bevel_rectangle_border_context;
mod bevel_rectangle_color_context;
mod bevel_rectangle_context;
mod clear;
mod color_context;
mod context;
mod draw;
mod ellipse_border_context;
mod ellipse_border_color_context;
mod ellipse_color_context;
mod ellipse_context;
mod fill;
mod image_size;
mod image_context;
mod image_color_context;
mod image_rectangle_color_context;
mod image_rectangle_context;
mod line_color_context;
mod line_context;
mod polygon_color_context;
mod polygon_context;
mod rectangle_border_context;
mod rectangle_border_color_context;
mod rectangle_color_context;
mod rectangle_context;
mod relative_color;
mod relative_rectangle;
mod relative_source_rectangle;
mod relative_transform2d;
mod round_border_line_color_context;
mod round_border_line_context;
mod round_rectangle_border_color_context;
mod round_rectangle_border_context;
mod round_rectangle_color_context;
mod round_rectangle_context;
mod square_border_line_color_context;
mod square_border_line_context;
mod stroke;
mod lerp_tween_color_context;
mod lerp_tween_context;
mod lerp_tween_polygons_color_context;
mod lerp_tween_polygons_context;
mod view;

pub mod internal;
pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

<commit_msg>Made rust-image compile under gl flag<commit_after>#![crate_id = "graphics"]
#![deny(missing_doc)]

//! A library for 2D graphics that works with multiple back-ends.
//!
//! To implement your own back-end, use the BackEnd trait.
//!
//! ## Usage
//!
//! If you are using [Rust-Empty](https://github.com/bvssvni/rust-empty) or Cargo, put the compiled library in the "target/cpu-vendor-platform/lib/" directory, then add the following to your source:
//!
//! ```Rust
//! #![feature(globs)] // Allow global imports
//!
//! extern crate graphics; // Link to 'graphics' library
//!
//! use graphics::*; // Use the graphics types in the module
//! ```
//!
//! To draw to the back-end, you need a context.
//! The context contains the information necessary to perform the drawing.
//! Unlike other graphics libraries, this library is not bound to the back-end.
//! You do not have to specify which back-end to use before doing the actual drawing.
//!
//! For example, assuming we have a back-end called `back_end`:
//!
//! ```
//! Context::new().rect(x, y, w, h).rgba(r, g, b, a).fill(&mut back_end);
//! ```
//!
//! ## Important!
//!
//! Because the context is built using borrowed pointers,
//! it is not possible to do two or more steps at a time and assign it to a variable:
//!
//! ```
//! // ERROR: Borrowed value does not live long enough
//! let rect = Context::new().rect(x, y, w, h);
//! ```
//!
//! This is because the lifetime of the first step only lives inside the expression.
//! To solve this problem, break the statement into two parts, one for each step:
//!
//! ```
//! let c = Context::new();
//! let rect = c.rect(x, y, w, h);
//! ```
//!
//! This is only the case when you are assigning the context to a variable.

#[cfg(gl)]
extern crate gl;
#[cfg(gl)]
extern crate libc;
#[cfg(gl)]
extern crate image;
extern crate core;
extern crate std;

#[cfg(gl)]
pub use Gl = gl_back_end::Gl;
#[cfg(gl)]
pub use Texture = texture::Texture;

pub use AddBevel = add_bevel::AddBevel;
pub use AddBevelBorder = add_bevel_border::AddBevelBorder;
pub use AddBorder = add_border::AddBorder;
pub use AddColor = add_color::AddColor;
pub use AddEllipse = add_ellipse::AddEllipse;
pub use AddImage = add_image::AddImage;
pub use AddLine = add_line::AddLine;
pub use AddPolygon = add_polygon::AddPolygon;
pub use AddPolygons = add_polygons::AddPolygons;
pub use AddRectangle = add_rectangle::AddRectangle;
pub use AddRound = add_round::AddRound;
pub use AddRoundBorder = add_round_border::AddRoundBorder;
pub use AddSquareBorder = add_square_border::AddSquareBorder;
pub use AddTween = add_tween::AddTween;
pub use BackEnd = back_end::BackEnd;
pub use BevelBorderLineColorContext = bevel_border_line_color_context::BevelBorderLineColorContext;
pub use BevelBorderLineContext = bevel_border_line_context::BevelBorderLineContext;
pub use BevelRectangleBorderColorContext = bevel_rectangle_border_color_context::BevelRectangleBorderColorContext;
pub use BevelRectangleBorderContext = bevel_rectangle_border_context::BevelRectangleBorderContext;
pub use BevelRectangleColorContext = bevel_rectangle_color_context::BevelRectangleColorContext;
pub use BevelRectangleContext = bevel_rectangle_context::BevelRectangleContext;
pub use Clear = clear::Clear;
pub use ColorContext = color_context::ColorContext;
pub use Context = context::Context;
pub use Draw = draw::Draw;
pub use EllipseContext = ellipse_context::EllipseContext;
pub use EllipseBorderContext = ellipse_border_context::EllipseBorderContext;
pub use EllipseColorContext = ellipse_color_context::EllipseColorContext;
pub use EllipseBorderColorContext = ellipse_border_color_context::EllipseBorderColorContext;
pub use Fill = fill::Fill;
pub use ImageSize = image_size::ImageSize;
pub use ImageContext = image_context::ImageContext;
pub use ImageColorContext = image_color_context::ImageColorContext;
pub use ImageRectangleContext = image_rectangle_context::ImageRectangleContext;
pub use ImageRectangleColorContext = image_rectangle_color_context::ImageRectangleColorContext;
pub use LerpTweenContext = lerp_tween_context::LerpTweenContext;
pub use LerpTweenColorContext = lerp_tween_color_context::LerpTweenColorContext;
pub use LerpTweenPolygonsContext = lerp_tween_polygons_context::LerpTweenPolygonsContext;
pub use LerpTweenPolygonsColorContext = lerp_tween_polygons_color_context::LerpTweenPolygonsColorContext;
pub use LineContext = line_context::LineContext;
pub use LineColorContext = line_color_context::LineColorContext;
pub use PolygonContext = polygon_context::PolygonContext;
pub use PolygonColorContext = polygon_color_context::PolygonColorContext;
pub use RectangleBorderContext = rectangle_border_context::RectangleBorderContext;
pub use RectangleBorderColorContext = rectangle_border_color_context::RectangleBorderColorContext;
pub use RectangleContext = rectangle_context::RectangleContext;
pub use RectangleColorContext = rectangle_color_context::RectangleColorContext;
pub use RelativeColor = relative_color::RelativeColor;
pub use RelativeRectangle = relative_rectangle::RelativeRectangle;
pub use RelativeSourceRectangle = relative_source_rectangle::RelativeSourceRectangle;
pub use RelativeTransform2d = relative_transform2d::RelativeTransform2d;
pub use RoundBorderLineContext = round_border_line_context::RoundBorderLineContext;
pub use RoundBorderLineColorContext = round_border_line_color_context::RoundBorderLineColorContext;
pub use RoundRectangleBorderColorContext = round_rectangle_border_color_context::RoundRectangleBorderColorContext;
pub use RoundRectangleBorderContext = round_rectangle_border_context::RoundRectangleBorderContext;
pub use RoundRectangleColorContext = round_rectangle_color_context::RoundRectangleColorContext;
pub use RoundRectangleContext = round_rectangle_context::RoundRectangleContext;
pub use Stroke = stroke::Stroke;
pub use SquareBorderLineColorContext = square_border_line_color_context::SquareBorderLineColorContext;
pub use SquareBorderLineContext = square_border_line_context::SquareBorderLineContext;
pub use View = view::View;

#[cfg(gl)]
mod gl_back_end;
#[cfg(gl)]
mod texture;
#[cfg(gl)]
pub mod shader_utils;

mod add_bevel;
mod add_bevel_border;
mod add_border;
mod add_color;
mod add_ellipse;
mod add_image;
mod add_line;
mod add_polygon;
mod add_polygons;
mod add_rectangle;
mod add_round;
mod add_round_border;
mod add_square_border;
mod add_tween;
mod back_end;
mod bevel_border_line_color_context;
mod bevel_border_line_context;
mod bevel_rectangle_border_color_context;
mod bevel_rectangle_border_context;
mod bevel_rectangle_color_context;
mod bevel_rectangle_context;
mod clear;
mod color_context;
mod context;
mod draw;
mod ellipse_border_context;
mod ellipse_border_color_context;
mod ellipse_color_context;
mod ellipse_context;
mod fill;
mod image_size;
mod image_context;
mod image_color_context;
mod image_rectangle_color_context;
mod image_rectangle_context;
mod line_color_context;
mod line_context;
mod polygon_color_context;
mod polygon_context;
mod rectangle_border_context;
mod rectangle_border_color_context;
mod rectangle_color_context;
mod rectangle_context;
mod relative_color;
mod relative_rectangle;
mod relative_source_rectangle;
mod relative_transform2d;
mod round_border_line_color_context;
mod round_border_line_context;
mod round_rectangle_border_color_context;
mod round_rectangle_border_context;
mod round_rectangle_color_context;
mod round_rectangle_context;
mod square_border_line_color_context;
mod square_border_line_context;
mod stroke;
mod lerp_tween_color_context;
mod lerp_tween_context;
mod lerp_tween_polygons_color_context;
mod lerp_tween_polygons_context;
mod view;

pub mod internal;
pub mod interpolation;
pub mod modular_index;
pub mod triangulation;
pub mod vecmath;

/// A structure that might contain a value or a borrowed value.
/// This is to used as building block to create data structure
/// that is partially based on an existing structure.
pub enum Field<'a, T> {
    /// Contains a value.
    Value(T),
    /// Contains a borrowed pointer.
    Borrowed(&'a T),
}

impl<'a, T> Field<'a, T> {
    /// Gets a read only value.
    #[inline(always)]
    pub fn get(&'a self) -> &'a T {
        match *self {
            Value(ref val) => val,
            Borrowed(rval) => rval,
        }
    }
}

<|endoftext|>


<commit_before>use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

#[derive(Clone, Debug)]
pub struct Expression {
    // TODO: Make these private.
    pub inner: ExpressionInner,
    pub ioargs: IoArgs,
}

// TODO: Make this private.
#[derive(Clone, Debug)]
pub enum ExpressionInner {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression>, Box<Expression>),
    Then(Box<Expression>, Box<Expression>),
}

impl Expression {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };
    // TODO: Use a scoped thread here, to avoid this stupid clone.
    let left_expression_clone = left.clone();
    let thread = std::thread::spawn(move || left_expression_clone.exec(left_context));
    let right_status = try!(right.exec(right_context));
    let left_status = try!(thread.join().unwrap());
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

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

impl From<std::str::Utf8Error> for Error {
    fn from(err: std::str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
// TODO: Make this private.
#[derive(Clone, Debug)]
pub struct IoArgs {
    stdin: InputArg,
    stdout: OutputArg,
    stderr: OutputArg,
}

impl IoArgs {
    fn new() -> IoArgs {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        let (stdin, maybe_stdin_thread) = try!(self.stdin.update_handle(parent_context.stdin));
        let stdout = try!(self.stdout.update_handle(parent_context.stdout));
        let stderr = try!(self.stderr.update_handle(parent_context.stderr));
        let child_context = IoContext {
            stdin: stdin,
            stdout: stdout,
            stderr: stderr,
        };

        let result = try!(inner(child_context));

        if let Some(thread) = maybe_stdin_thread {
            try!(thread.join().unwrap());
        }

        Ok(result)
    }
}

#[derive(Clone, Debug)]
enum InputArg {
    Inherit,
    Null,
    Path(PathBuf),
    Bytes(Vec<u8>),
}

impl InputArg {
    fn update_handle(&self,
                     parent_handle: pipe::Handle)
                     -> io::Result<(pipe::Handle, Option<JoinHandle<io::Result<()>>>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open(&p))),
            &InputArg::Bytes(ref v) => {
                // TODO: figure out a way to get rid of this clone
                let (handle, thread) = pipe_with_writer_thread(v.clone());
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

#[derive(  Clone, Debug)]
enum OutputArg {
    Inherit,
    Null,
    Path(PathBuf), // TODO: stdout/stderr swaps
}

impl OutputArg {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            &OutputArg::Inherit => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create(&p))),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

fn pipe_with_writer_thread(input: Vec<u8>) -> (pipe::Handle, JoinHandle<io::Result<()>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    use super::{cmd, sh, pipe, then, InputArg, OutputArg};
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.ioargs.stdin = InputArg::Bytes(b"foo".to_vec());
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.ioargs.stdin = InputArg::Null;
        expr.ioargs.stdout = OutputArg::Null;
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let input_path = Path::new("/tmp/duct_file_input");
        let output_path = Path::new("/tmp/duct_file_output");
        File::create(&input_path).unwrap().write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.ioargs.stdin = InputArg::Path(input_path.to_owned());
        expr.ioargs.stdout = OutputArg::Path(output_path.to_owned());
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        File::open(&output_path).unwrap().read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }
}
<commit_msg>use sh("mktemp") instead of a hardcoded temp path<commit_after>use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::PathBuf;
use std::process::{Command, Output, ExitStatus};
use std::thread::JoinHandle;

mod pipe;

pub fn cmd<T: AsRef<OsStr>>(argv: &[T]) -> Expression {
    let argv_vec = argv.iter().map(|arg| arg.as_ref().to_owned()).collect();
    Expression {
        inner: ExpressionInner::ArgvCommand(argv_vec),
        ioargs: IoArgs::new(),
    }
}

pub fn sh<T: AsRef<OsStr>>(command: T) -> Expression {
    Expression {
        inner: ExpressionInner::ShCommand(command.as_ref().to_owned()),
        ioargs: IoArgs::new(),
    }
}

pub fn pipe(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Pipe(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

pub fn then(left: Expression, right: Expression) -> Expression {
    Expression {
        inner: ExpressionInner::Then(Box::new(left), Box::new(right)),
        ioargs: IoArgs::new(),
    }
}

#[derive(Clone, Debug)]
pub struct Expression {
    // TODO: Make these private.
    pub inner: ExpressionInner,
    pub ioargs: IoArgs,
}

// TODO: Make this private.
#[derive(Clone, Debug)]
pub enum ExpressionInner {
    ArgvCommand(Vec<OsString>),
    ShCommand(OsString),
    Pipe(Box<Expression>, Box<Expression>),
    Then(Box<Expression>, Box<Expression>),
}

impl Expression {
    pub fn run(&self) -> Result<Output, Error> {
        unreachable!();
    }

    pub fn read(&self) -> Result<String, Error> {
        let (handle, reader) = pipe_with_reader_thread();
        let mut context = IoContext::new();
        context.stdout = handle;
        let status = try!(self.exec(context));
        let stdout_vec = try!(reader.join().unwrap());
        if !status.success() {
            return Err(Error::Status(Output {
                status: status,
                stdout: stdout_vec,
                stderr: Vec::new(),
            }));
        }
        let stdout_string = try!(std::str::from_utf8(&stdout_vec))
                                .trim_right_matches('\n')
                                .to_owned();
        Ok(stdout_string)
    }

    fn exec(&self, parent_context: IoContext) -> io::Result<ExitStatus> {
        self.ioargs.with_child_context(parent_context, |context| {
            match self.inner {
                ExpressionInner::ArgvCommand(ref argv) => exec_argv(argv, context),
                ExpressionInner::ShCommand(ref command) => exec_sh(command, context),
                ExpressionInner::Pipe(ref left, ref right) => exec_pipe(left, right, context),
                ExpressionInner::Then(ref left, ref right) => exec_then(left, right, context),
            }
        })
    }
}

fn exec_argv(argv: &Vec<OsString>, context: IoContext) -> io::Result<ExitStatus> {
    let mut command = Command::new(&argv[0]);
    command.args(&argv[1..]);
    command.stdin(context.stdin.to_stdio());
    command.stdout(context.stdout.to_stdio());
    command.stderr(context.stderr.to_stdio());
    command.status()
}

fn exec_sh(command: &OsStr, context: IoContext) -> io::Result<ExitStatus> {
    // TODO: What shell should we be using here, really?
    // TODO: Figure out how cmd.exe works on Windows.
    let mut argv = Vec::new();
    argv.push("bash".into());
    argv.push("-c".into());
    argv.push(command.to_owned());
    exec_argv(&argv, context)
}

fn exec_pipe(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let left_context = IoContext {
        stdin: context.stdin,
        stdout: write_pipe,
        stderr: context.stderr.clone(),
    };
    let right_context = IoContext {
        stdin: read_pipe,
        stdout: context.stdout,
        stderr: context.stderr,
    };
    // TODO: Use a scoped thread here, to avoid this stupid clone.
    let left_expression_clone = left.clone();
    let thread = std::thread::spawn(move || left_expression_clone.exec(left_context));
    let right_status = try!(right.exec(right_context));
    let left_status = try!(thread.join().unwrap());
    if !right_status.success() {
        Ok(right_status)
    } else {
        Ok(left_status)
    }
}

fn exec_then(left: &Expression, right: &Expression, context: IoContext) -> io::Result<ExitStatus> {
    let status = try!(left.exec(context.clone()));
    if !status.success() {
        Ok(status)
    } else {
        right.exec(context)
    }
}

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Utf8(std::str::Utf8Error),
    Status(Output),
}

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

impl From<std::str::Utf8Error> for Error {
    fn from(err: std::str::Utf8Error) -> Error {
        Error::Utf8(err)
    }
}

// IoArgs store the redirections and other settings associated with an expression. At execution
// time, IoArgs are used to modify an IoContext, which contains the actual pipes that child process
// TODO: Make this private.
#[derive(Clone, Debug)]
pub struct IoArgs {
    stdin: InputArg,
    stdout: OutputArg,
    stderr: OutputArg,
}

impl IoArgs {
    fn new() -> IoArgs {
        IoArgs {
            stdin: InputArg::Inherit,
            stdout: OutputArg::Inherit,
            stderr: OutputArg::Inherit,
        }
    }

    fn with_child_context<F, T>(&self, parent_context: IoContext, inner: F) -> io::Result<T>
        where F: FnOnce(IoContext) -> io::Result<T>
    {
        let (stdin, maybe_stdin_thread) = try!(self.stdin.update_handle(parent_context.stdin));
        let stdout = try!(self.stdout.update_handle(parent_context.stdout));
        let stderr = try!(self.stderr.update_handle(parent_context.stderr));
        let child_context = IoContext {
            stdin: stdin,
            stdout: stdout,
            stderr: stderr,
        };

        let result = try!(inner(child_context));

        if let Some(thread) = maybe_stdin_thread {
            try!(thread.join().unwrap());
        }

        Ok(result)
    }
}

#[derive(Clone, Debug)]
enum InputArg {
    Inherit,
    Null,
    Path(PathBuf),
    Bytes(Vec<u8>),
}

impl InputArg {
    fn update_handle(&self,
                     parent_handle: pipe::Handle)
                     -> io::Result<(pipe::Handle, Option<JoinHandle<io::Result<()>>>)> {
        let mut maybe_thread = None;
        let handle = match self {
            &InputArg::Inherit => parent_handle,
            &InputArg::Null => pipe::Handle::from_file(try!(File::open("/dev/null"))),  // TODO: Windows
            &InputArg::Path(ref p) => pipe::Handle::from_file(try!(File::open(&p))),
            &InputArg::Bytes(ref v) => {
                // TODO: figure out a way to get rid of this clone
                let (handle, thread) = pipe_with_writer_thread(v.clone());
                maybe_thread = Some(thread);
                handle
            }
        };
        Ok((handle, maybe_thread))
    }
}

#[derive(  Clone, Debug)]
enum OutputArg {
    Inherit,
    Null,
    Path(PathBuf), // TODO: stdout/stderr swaps
}

impl OutputArg {
    fn update_handle(&self, parent_handle: pipe::Handle) -> io::Result<pipe::Handle> {
        let handle = match self {
            &OutputArg::Inherit => parent_handle,
            &OutputArg::Null => pipe::Handle::from_file(try!(File::create("/dev/null"))),  // TODO: Windows
            &OutputArg::Path(ref p) => pipe::Handle::from_file(try!(File::create(&p))),
        };
        Ok(handle)
    }
}

// An IoContext represents the file descriptors child processes are talking to at execution time.
// It's initialized in run(), with dups of the stdin/stdout/stderr pipes, and then passed down to
// sub-expressions. Compound expressions will clone() it, and pipes/redirections will modify it
// according to their IoArgs.
#[derive(Clone, Debug)]
pub struct IoContext {
    stdin: pipe::Handle,
    stdout: pipe::Handle,
    stderr: pipe::Handle,
}

impl IoContext {
    fn new() -> IoContext {
        IoContext {
            stdin: pipe::Handle::stdin(),
            stdout: pipe::Handle::stdout(),
            stderr: pipe::Handle::stderr(),
        }
    }
}

fn pipe_with_reader_thread() -> (pipe::Handle, JoinHandle<io::Result<Vec<u8>>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut read_file = read_pipe.to_file();
        let mut output = Vec::new();
        try!(read_file.read_to_end(&mut output));
        Ok(output)
    });
    (write_pipe, thread)
}

fn pipe_with_writer_thread(input: Vec<u8>) -> (pipe::Handle, JoinHandle<io::Result<()>>) {
    let (read_pipe, write_pipe) = pipe::open_pipe();
    let thread = std::thread::spawn(move || {
        let mut write_file = write_pipe.to_file();
        try!(write_file.write_all(&input));
        Ok(())
    });
    (read_pipe, thread)
}

#[cfg(test)]
mod test {
    use super::{cmd, sh, pipe, then, InputArg, OutputArg};
    use std::fs::File;
    use std::io::prelude::*;
    use std::path::Path;

    #[test]
    fn test_cmd() {
        let output = cmd(&["echo", "hi"]).read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_sh() {
        let output = sh("echo hi").read().unwrap();
        assert_eq!("hi", output);
    }

    #[test]
    fn test_pipe() {
        let output = pipe(sh("echo hi"), sh("sed s/i/o/")).read().unwrap();
        assert_eq!("ho", output);
    }

    #[test]
    fn test_then() {
        let output = then(sh("echo -n hi"), sh("echo lo")).read().unwrap();
        assert_eq!("hilo", output);
    }

    #[test]
    fn test_input() {
        let mut expr = sh("sed s/f/g/");
        expr.ioargs.stdin = InputArg::Bytes(b"foo".to_vec());
        let output = expr.read().unwrap();
        assert_eq!("goo", output);
    }

    #[test]
    fn test_null() {
        let mut expr = cmd(&["cat"]);
        expr.ioargs.stdin = InputArg::Null;
        expr.ioargs.stdout = OutputArg::Null;
        let output = expr.read().unwrap();
        assert_eq!("", output);
    }

    #[test]
    fn test_path() {
        let input_path = sh("mktemp").read().unwrap();
        let output_path = sh("mktemp").read().unwrap();
        println!("Here are the paths: {:?} {:?}", &input_path, &output_path);
        File::create(&input_path).unwrap().write_all(b"foo").unwrap();
        let mut expr = sh("sed s/o/a/g");
        expr.ioargs.stdin = InputArg::Path(input_path.into());
        expr.ioargs.stdout = OutputArg::Path(output_path.clone().into());
        let output = expr.read().unwrap();
        assert_eq!("", output);
        let mut file_output = String::new();
        File::open(&output_path).unwrap().read_to_string(&mut file_output).unwrap();
        assert_eq!("faa", file_output);
    }
}
<|endoftext|>