<commit_before>//! Main module to handle the layout.
//! This is where the i3-specific code is.

use std::sync::{Mutex, MutexGuard, TryLockError};
use std::ptr;

use super::container::{Container, Handle, ContainerType};
use super::node::{Node};
use super::super::rustwlc::{WlcView, WlcOutput, Geometry, Point, ResizeEdge};

pub type TreeErr = TryLockError<MutexGuard<'static, Tree>>;
pub type TreeResult = Result<MutexGuard<'static, Tree>, TreeErr>;

const ERR_BAD_TREE: &'static str = "Layout tree was in an invalid configuration";

lazy_static! {
    static ref TREE: Mutex<Tree> = {
        Mutex::new(Tree{
            root: Node::new(Container::new_root()),
            active_container: ptr::null_mut(),
        })
    };
}

pub struct Tree {
    root: Node,
    active_container: *mut Node,
}

unsafe impl Send for Tree {}

impl Tree {

    /// Moves the current active container to a new workspace
    pub fn move_container_to_workspace(&mut self, name: &str) {
        let container: Option<Node> = None;
        if let Some(sub_container) = self.get_active_container() {
            // NOTE Assumes workspace exists, fix this
            // NOTE Should not do this, because floating windows
            // Should do an if let
            let container = Some(sub_container.remove_from_parent()
                .expect("Could not remove container, was not part of tree"));
        }
        if let Some(container) = container {
            if let Some(workspace) = self.get_workspace_by_name(name) {
                // Assume workspace has a container
                let output = &mut workspace.get_children_mut()[0];
                output.new_child(container.get_val().clone());
            }
        }
    }

    /// Switch to the workspace with the give name
    pub fn switch_workspace(&mut self, name: &str ) {
        trace!("Switching to workspace {}", name);
        if let Some(old_workspace) = self.get_active_workspace() {
            old_workspace.set_visibility(false);
        }
        let current_workspace: *mut Node;
        {
            if let Some(_) = self.get_workspace_by_name(name) {
                trace!("Found workspace {}", name);
            } else {
                trace!("Adding workspace {}", name);
                self.add_workspace(name.to_string());
            }
            let new_current_workspace = self.get_workspace_by_name_mut(name).expect(ERR_BAD_TREE);
            new_current_workspace.set_visibility(true);
            // Set the first view to be focused, so the screen refreshes itself
            if new_current_workspace.get_children()[0].get_children().len() > 0 {
                trace!("Focusing view");
                match new_current_workspace.get_children_mut()[0].get_children_mut()[0]
                    .get_val().get_handle().expect(ERR_BAD_TREE) {
                    Handle::View(view) => view.focus(),
                    _ => {},
                }
            } else {
                WlcView::root().focus();
            }
            // Update the tree's pointer to the currently focused container
            current_workspace = &mut new_current_workspace.get_children_mut()[0] as *mut Node;
        }
        self.active_container = current_workspace;
    }

    /// Returns the currently viewed container.
    /// If multiple views are selected, the parent container they share is returned
    pub fn get_active_container(&self) -> Option<&mut Node> {
        if self.active_container.is_null() {
            None
        } else {
            unsafe {
                Some(&mut *self.active_container)
            }
        }
    }

    /// Get the monitor (output) that the active container is located on
    pub fn get_active_output(&self) -> Option<&mut Node> {
        if let Some(node) = self.get_active_container() {
            node.get_ancestor_of_type(ContainerType::Output)
        } else {
            None
        }
    }

    /// Get the workspace that the active container is located on
    pub fn get_active_workspace(&self) -> Option<&mut Node> {
        if let Some(container) = self.get_active_container() {
            if let Some(workspace) = container.get_ancestor_of_type(ContainerType::Workspace) {
                return Some(workspace)
            }
        }
        return None
    }

    /// Find the workspace node that has the given name
    pub fn get_workspace_by_name(&mut self, name: &str) -> Option<&mut Node> {
        for child in self.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    /// Find the workspace node that has the given name, with a mutable reference
    pub fn get_workspace_by_name_mut(&mut self, name: &str) -> Option<&mut Node> {
        for child in self.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    /// Make a new output container with the given WlcOutput.
    /// This is done when a new monitor is added
    pub fn add_output(&mut self, wlc_output: WlcOutput) {
        match self.root.new_child(Container::new_output(wlc_output)) {
            Ok(_) => {},
            Err(e) => error!("Could not add output: {:?}", e),
        }
    }

    /// Make a new workspace container with the given name.
    pub fn add_workspace(&mut self, name: String) {
        if let Some(output) = self.get_active_output() {
            let size = output.get_val().get_geometry()
                .expect("Output did not have a geometry").size;
            let workspace = Container::new_workspace(name.to_string(),
                                                     size.clone());
            match output.new_child(workspace) {
                Ok(workspace) => {
                    trace!("Added workspace {:?}", workspace);
                    let geometry = Geometry {
                        size: size,
                        origin: Point { x: 0, y: 0}
                    };
                    if let Err(e) = workspace.new_child(Container::new_container(geometry)) {
                        error!("Could not add container to workspace: {:?}",e );
                    }
                },
                Err(e) => error!("Could not add workspace: {:?}", e),
            }
        }
    }

    /// Make a new view container with the given WlcView, and adds it to
    /// the active workspace.
    pub fn add_view(&mut self, wlc_view: WlcView) {
        let mut maybe_new_view: *const Node = ptr::null();
        if let Some(current_workspace) = self.get_active_workspace() {
            trace!("Adding view {:?} to {:?}", wlc_view, current_workspace);
            if current_workspace.get_children().len() == 0 {
                let output = self.get_active_output()
                    .expect("Could not get active output");
                let output_size = output.get_val().get_geometry()
                    .expect("Could not get geometry from output").size;
                let mut geometry = wlc_view.get_geometry()
                    .expect("Could not get geometry from wlc view").clone();
                // Ensure that it starts within the bounds
                // Width
                if geometry.origin.x > output_size.w as i32 {
                    geometry.origin.x = output_size.w as i32 ;
                } else if geometry.origin.x < 0 {
                    geometry.origin.x = 0;
                }
                // Height
                if geometry.origin.y > output_size.h as i32 {
                    geometry.origin.y = output_size.h as i32;
                } else if geometry.origin.y < 0 {
                    geometry.origin.y = 0;
                }
                wlc_view.set_geometry(ResizeEdge::empty(), &geometry);
                match current_workspace.new_child(Container::new_container(geometry)) {
                    Ok(_) => {},
                    Err(e) => {
                        error!("Could not add workspace: {:?}", e);
                        return;
                    }
                }
            }
            let container = &mut current_workspace.get_children_mut()[0];
            match container.new_child(Container::new_view(wlc_view)) {
                Ok(view_node) => maybe_new_view = view_node as *const Node,
                Err(e) => {
                    error!("Could not add view to current workspace: {:?}", e);
                    return;
                }
            }
        };
        if ! maybe_new_view.is_null() {
            self.active_container = maybe_new_view as *mut Node;
        }
    }

    /// Remove the view container with the given view
    pub fn remove_view(&self, wlc_view: &WlcView) {
        if let Some(view) = self.root.find_view_by_handle(&wlc_view) {
            let parent = view.get_parent().expect(ERR_BAD_TREE);
            parent.remove_child(view);
        }
    }
}

pub fn try_lock_tree() -> TreeResult {
    trace!("Locking the tree!");
    TREE.try_lock()
}
<commit_msg>Fixed build, disabled most features.<commit_after>//! Main module to handle the layout.
//! This is where the i3-specific code is.

use std::sync::{Mutex, MutexGuard, TryLockError};
use std::ptr;

use super::container::{Container, Handle, ContainerType};
use super::node::{Node};
use super::super::rustwlc::{WlcView, WlcOutput, Geometry, Point, ResizeEdge};

pub type TreeErr = TryLockError<MutexGuard<'static, Tree>>;
pub type TreeResult = Result<MutexGuard<'static, Tree>, TreeErr>;

const ERR_BAD_TREE: &'static str = "Layout tree was in an invalid configuration";

lazy_static! {
    static ref TREE: Mutex<Tree> = {
        Mutex::new(Tree{
            root: Node::new(Container::new_root()),
            active_container: ptr::null_mut(),
        })
    };
}

pub struct Tree {
    root: Node,
    active_container: *mut Node,
}

unsafe impl Send for Tree {}

impl Tree {

    /// Moves the current active container to a new workspace
    pub fn move_container_to_workspace(&mut self, name: &str) {
        let container: Option<Node> = None;
        if let Some(sub_container) = self.get_active_container() {
            // NOTE Assumes workspace exists, fix this
            // NOTE Should not do this, because floating windows
            // Should do an if let
            let container = Some(sub_container.remove_from_parent()
                .expect("Could not remove container, was not part of tree"));
        }
        if let Some(container) = container {
            if let Some(workspace) = self.get_workspace_by_name(name) {
                // Assume workspace has a container
                let output = &mut workspace.get_children_mut()[0];
                output.new_child(container.get_val().clone());
            }
        }
    }

    /// Switch to the workspace with the give name
    pub fn switch_workspace(&mut self, name: &str ) {
        trace!("Switching to workspace {}", name);
        if let Some(old_workspace) = self.get_active_workspace() {
            old_workspace.set_visibility(false);
        }
        if self.active_container.is_null() {
            warn!("Not current active container, cannot switch workspace");
            return;
        }
        let current_workspace: *mut Node;
        {
            if let Some(_) = self.get_workspace_by_name(name) {
                trace!("Found workspace {}", name);
            } else {
                trace!("Adding workspace {}", name);
                self.add_workspace(name.to_string());
            }
            let new_current_workspace = self.get_workspace_by_name_mut(name).expect(ERR_BAD_TREE);
            new_current_workspace.set_visibility(true);
            // Set the first view to be focused, so the screen refreshes itself
            if new_current_workspace.get_children()[0].get_children().len() > 0 {
                trace!("Focusing view");
                match new_current_workspace.get_children_mut()[0].get_children_mut()[0]
                    .get_val().get_handle().expect(ERR_BAD_TREE) {
                    Handle::View(view) => view.focus(),
                    _ => {},
                }
            } else {
                WlcView::root().focus();
            }
            // Update the tree's pointer to the currently focused container
            current_workspace = &mut new_current_workspace.get_children_mut()[0] as *mut Node;
        }
        self.active_container = current_workspace;
    }

    /// Returns the currently viewed container.
    /// If multiple views are selected, the parent container they share is returned
    pub fn get_active_container(&self) -> Option<&mut Node> {
        if self.active_container.is_null() {
            None
        } else {
            unsafe {
                Some(&mut *self.active_container)
            }
        }
    }

    /// Get the monitor (output) that the active container is located on
    pub fn get_active_output(&self) -> Option<&mut Node> {
        if let Some(node) = self.get_active_container() {
            node.get_ancestor_of_type(ContainerType::Output)
        } else {
            None
        }
    }

    /// Get the workspace that the active container is located on
    pub fn get_active_workspace(&self) -> Option<&mut Node> {
        if let Some(container) = self.get_active_container() {
            if let Some(workspace) = container.get_ancestor_of_type(ContainerType::Workspace) {
                return Some(workspace)
            }
        }
        return None
    }

    /// Find the workspace node that has the given name
    pub fn get_workspace_by_name(&mut self, name: &str) -> Option<&mut Node> {
        for child in self.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    /// Find the workspace node that has the given name, with a mutable reference
    pub fn get_workspace_by_name_mut(&mut self, name: &str) -> Option<&mut Node> {
        for child in self.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    /// Make a new output container with the given WlcOutput.
    /// This is done when a new monitor is added
    pub fn add_output(&mut self, wlc_output: WlcOutput) {
        match self.root.new_child(Container::new_output(wlc_output)) {
            Ok(_) => {},
            Err(e) => error!("Could not add output: {:?}", e),
        }
    }

    /// Make a new workspace container with the given name.
    pub fn add_workspace(&mut self, name: String) {
        if let Some(output) = self.get_active_output() {
            let size = output.get_val().get_geometry()
                .expect("Output did not have a geometry").size;
            let workspace = Container::new_workspace(name.to_string(),
                                                     size.clone());
            match output.new_child(workspace) {
                Ok(workspace) => {
                    trace!("Added workspace {:?}", workspace);
                    let geometry = Geometry {
                        size: size,
                        origin: Point { x: 0, y: 0}
                    };
                    if let Err(e) = workspace.new_child(Container::new_container(geometry)) {
                        error!("Could not add container to workspace: {:?}",e );
                    }
                },
                Err(e) => error!("Could not add workspace: {:?}", e),
            }
        }
    }

    /// Make a new view container with the given WlcView, and adds it to
    /// the active workspace.
    pub fn add_view(&mut self, wlc_view: WlcView) {
        let mut maybe_new_view: *const Node = ptr::null();
        if let Some(current_workspace) = self.get_active_workspace() {
            trace!("Adding view {:?} to {:?}", wlc_view, current_workspace);
            if current_workspace.get_children().len() == 0 {
                let output = self.get_active_output()
                    .expect("Could not get active output");
                let output_size = output.get_val().get_geometry()
                    .expect("Could not get geometry from output").size;
                let mut geometry = wlc_view.get_geometry()
                    .expect("Could not get geometry from wlc view").clone();
                // Ensure that it starts within the bounds
                // Width
                if geometry.origin.x > output_size.w as i32 {
                    geometry.origin.x = output_size.w as i32 ;
                } else if geometry.origin.x < 0 {
                    geometry.origin.x = 0;
                }
                // Height
                if geometry.origin.y > output_size.h as i32 {
                    geometry.origin.y = output_size.h as i32;
                } else if geometry.origin.y < 0 {
                    geometry.origin.y = 0;
                }
                wlc_view.set_geometry(ResizeEdge::empty(), &geometry);
                match current_workspace.new_child(Container::new_container(geometry)) {
                    Ok(_) => {},
                    Err(e) => {
                        error!("Could not add workspace: {:?}", e);
                        return;
                    }
                }
            }
            let container = &mut current_workspace.get_children_mut()[0];
            match container.new_child(Container::new_view(wlc_view)) {
                Ok(view_node) => maybe_new_view = view_node as *const Node,
                Err(e) => {
                    error!("Could not add view to current workspace: {:?}", e);
                    return;
                }
            }
        };
        if ! maybe_new_view.is_null() {
            self.active_container = maybe_new_view as *mut Node;
        }
    }

    /// Remove the view container with the given view
    pub fn remove_view(&self, wlc_view: &WlcView) {
        if let Some(view) = self.root.find_view_by_handle(&wlc_view) {
            let parent = view.get_parent().expect(ERR_BAD_TREE);
            parent.remove_child(view);
        }
    }
}

pub fn try_lock_tree() -> TreeResult {
    trace!("Locking the tree!");
    TREE.try_lock()
}
<|endoftext|>


<commit_before>/*!
A macro for declaring lazily evaluated statics.

Using this macro, it is possible to have `static`s that require code to be
executed at runtime in order to be initialized.
This includes anything requiring heap allocations, like vectors or hash maps,
as well as anything that requires function calls to be computed.

# Syntax

```ignore
lazy_static! {
    [pub] static ref NAME_1: TYPE_1 = EXPR_1;
    [pub] static ref NAME_2: TYPE_2 = EXPR_2;
    ...
    [pub] static ref NAME_N: TYPE_N = EXPR_N;
}
```

# Semantic

For a given `static ref NAME: TYPE = EXPR;`, the macro generates a
unique type that implements `Deref<TYPE>` and stores it in a static with name `NAME`.

On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs
can return a reference to the same object.

Like regular `static mut`s, this macro only works for types that fulfill the `Sync`
trait.

# Example

Using the macro:

```rust
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
    static ref NUMBER: u32 = times_two(21);
}

fn times_two(n: u32) -> u32 { n * 2 }

fn main() {
    println!("The map has {} entries.", *COUNT);
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
    println!("A expensive calculation on a static results in: {}.", *NUMBER);
}
```

# Implementation details

The `Deref` implementation uses a hidden `static mut` that is guarded by a atomic check
using the `sync::Once` abstraction. All lazily evaluated values are currently
put in a heap allocated box, due to the Rust language currently not providing any way to
define uninitialized `static mut` values.

*/

#![crate_type = "dylib"]

#[macro_export]
macro_rules! lazy_static {
    (static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PRIV static ref $N : $T = $e; $($t)*);
    };
    (pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PUB static ref $N : $T = $e; $($t)*);
    };
    ($VIS:ident static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(MAKE TY $VIS $N);
        impl ::std::ops::Deref for $N {
            type Target = $T;
            fn deref<'a>(&'a self) -> &'a $T {
                use std::sync::{Once, ONCE_INIT};
                use std::mem::transmute;

                #[inline(always)]
                fn require_sync<T: Sync>(_: &T) { }

                unsafe {
                    static mut __static: *const $T = 0 as *const $T;
                    static mut __ONCE: Once = ONCE_INIT;
                    __ONCE.call_once(|| {
                        __static = transmute::<Box<$T>, *const $T>(Box::new(($e)));
                    });
                    let static_ref = &*__static;
                    require_sync(static_ref);
                    static_ref
                }
            }
        }
        lazy_static!($($t)*);
    };
    (MAKE TY PUB $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        pub struct $N {__private_field: ()}
        #[allow(dead_code)]
        pub static $N: $N = $N {__private_field: ()};
    };
    (MAKE TY PRIV $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        struct $N {__private_field: ()}
        #[allow(dead_code)]
        static $N: $N = $N {__private_field: ()};
    };
    () => ()
}
<commit_msg>Revert "We need an additional dead_code disable, since Rust has gotten better about warnings recently"<commit_after>/*!
A macro for declaring lazily evaluated statics.

Using this macro, it is possible to have `static`s that require code to be
executed at runtime in order to be initialized.
This includes anything requiring heap allocations, like vectors or hash maps,
as well as anything that requires function calls to be computed.

# Syntax

```ignore
lazy_static! {
    [pub] static ref NAME_1: TYPE_1 = EXPR_1;
    [pub] static ref NAME_2: TYPE_2 = EXPR_2;
    ...
    [pub] static ref NAME_N: TYPE_N = EXPR_N;
}
```

# Semantic

For a given `static ref NAME: TYPE = EXPR;`, the macro generates a
unique type that implements `Deref<TYPE>` and stores it in a static with name `NAME`.

On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs
can return a reference to the same object.

Like regular `static mut`s, this macro only works for types that fulfill the `Sync`
trait.

# Example

Using the macro:

```rust
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
    static ref NUMBER: u32 = times_two(21);
}

fn times_two(n: u32) -> u32 { n * 2 }

fn main() {
    println!("The map has {} entries.", *COUNT);
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
    println!("A expensive calculation on a static results in: {}.", *NUMBER);
}
```

# Implementation details

The `Deref` implementation uses a hidden `static mut` that is guarded by a atomic check
using the `sync::Once` abstraction. All lazily evaluated values are currently
put in a heap allocated box, due to the Rust language currently not providing any way to
define uninitialized `static mut` values.

*/

#![crate_type = "dylib"]

#[macro_export]
macro_rules! lazy_static {
    (static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PRIV static ref $N : $T = $e; $($t)*);
    };
    (pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(PUB static ref $N : $T = $e; $($t)*);
    };
    ($VIS:ident static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        lazy_static!(MAKE TY $VIS $N);
        impl ::std::ops::Deref for $N {
            type Target = $T;
            fn deref<'a>(&'a self) -> &'a $T {
                use std::sync::{Once, ONCE_INIT};
                use std::mem::transmute;

                #[inline(always)]
                fn require_sync<T: Sync>(_: &T) { }

                unsafe {
                    static mut __static: *const $T = 0 as *const $T;
                    static mut __ONCE: Once = ONCE_INIT;
                    __ONCE.call_once(|| {
                        __static = transmute::<Box<$T>, *const $T>(Box::new(($e)));
                    });
                    let static_ref = &*__static;
                    require_sync(static_ref);
                    static_ref
                }
            }
        }
        lazy_static!($($t)*);
    };
    (MAKE TY PUB $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        pub struct $N {__private_field: ()}
        pub static $N: $N = $N {__private_field: ()};
    };
    (MAKE TY PRIV $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        struct $N {__private_field: ()}
        static $N: $N = $N {__private_field: ()};
    };
    () => ()
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;

use core::str::FromStr;
use rust_decimal::Decimal;

macro_rules! bench_decimal_op {
    ($name:ident, $op:tt, $y:expr) => {
        #[bench]
        fn $name(b: &mut ::test::Bencher) {
            let x = Decimal::from_str("2.01").unwrap();
            let y = Decimal::from_str($y).unwrap();
            b.iter(|| {
                let result = x $op y;
                ::test::black_box(result);
            });
        }
    }
}

macro_rules! bench_fold_op {
    ($name:ident, $op:tt, $init:expr, $count:expr) => {
        #[bench]
        fn $name(b: &mut ::test::Bencher) {
            fn fold(values: &[Decimal]) -> Decimal {
                let mut acc: Decimal = $init.into();
                for value in values {
                    acc = acc $op value;
                }
                acc
            }

            let values: Vec<Decimal> = test::black_box((1..$count).map(|i| i.into()).collect());
            b.iter(|| {
                let result = fold(&values);
                ::test::black_box(result);
            });
        }
    }
}

/* Add */
bench_decimal_op!(add_one, +, "1");
bench_decimal_op!(add_two, +, "2");
bench_decimal_op!(add_one_hundred, +, "100");
bench_decimal_op!(add_point_zero_one, +, "0.01");
bench_decimal_op!(add_negative_point_five, +, "-0.5");
bench_decimal_op!(add_pi, +, "3.1415926535897932384626433832");
bench_decimal_op!(add_negative_pi, +, "-3.1415926535897932384626433832");

bench_fold_op!(add_10k, +, 0, 10_000);

/* Sub */
bench_decimal_op!(sub_one, -, "1");
bench_decimal_op!(sub_two, -, "2");
bench_decimal_op!(sub_one_hundred, -, "100");
bench_decimal_op!(sub_point_zero_one, -, "0.01");
bench_decimal_op!(sub_negative_point_five, -, "-0.5");
bench_decimal_op!(sub_pi, -, "3.1415926535897932384626433832");
bench_decimal_op!(sub_negative_pi, -, "-3.1415926535897932384626433832");

bench_fold_op!(sub_10k, -, 5_000_000, 10_000);

/* Mul */
bench_decimal_op!(mul_one, *, "1");
bench_decimal_op!(mul_two, *, "2");
bench_decimal_op!(mul_one_hundred, *, "100");
bench_decimal_op!(mul_point_zero_one, *, "0.01");
bench_decimal_op!(mul_negative_point_five, *, "-0.5");
bench_decimal_op!(mul_pi, *, "3.1415926535897932384626433832");
bench_decimal_op!(mul_negative_pi, *, "-3.1415926535897932384626433832");

/* Div */
bench_decimal_op!(div_one, /, "1");
bench_decimal_op!(div_two, /, "2");
bench_decimal_op!(div_one_hundred, /, "100");
bench_decimal_op!(div_point_zero_one, /, "0.01");
bench_decimal_op!(div_negative_point_five, /, "-0.5");
bench_decimal_op!(div_pi, /, "3.1415926535897932384626433832");
bench_decimal_op!(div_negative_pi, /, "-3.1415926535897932384626433832");

bench_fold_op!(div_10k, /, Decimal::max_value(), 10_000);

/* Iteration */
struct DecimalIterator {
    count: usize,
}

impl DecimalIterator {
    fn new() -> DecimalIterator {
        DecimalIterator { count: 0 }
    }
}

impl Iterator for DecimalIterator {
    type Item = Decimal;

    fn next(&mut self) -> Option<Decimal> {
        self.count += 1;
        if self.count < 6 {
            Some(Decimal::new(314, 2))
        } else {
            None
        }
    }
}

#[bench]
fn iterator_individual(b: &mut ::test::Bencher) {
    b.iter(|| {
        let mut result = Decimal::new(0, 0);
        let iterator = DecimalIterator::new();
        for i in iterator {
            result += i;
        }
        ::test::black_box(result);
    });
}

#[bench]
fn iterator_sum(b: &mut ::test::Bencher) {
    b.iter(|| {
        let result: Decimal = DecimalIterator::new().sum();
        ::test::black_box(result);
    });
}

#[bench]
fn decimal_from_str(b: &mut test::Bencher) {
    let samples_strs = &[
        "3950.123456",
        "3950",
        "0.1",
        "0.01",
        "0.001",
        "0.0001",
        "0.00001",
        "0.000001",
        "1",
        "-100",
        "-123.456",
        "119996.25",
        "1000000",
        "9999999.99999",
        "12340.56789",
    ];

    b.iter(|| {
        for s in samples_strs {
            let result = Decimal::from_str(s).unwrap();
            test::black_box(result);
        }
    })
}

#[cfg(feature = "postgres")]
#[bench]
fn to_from_sql(b: &mut ::test::Bencher) {
    use postgres::types::{FromSql, Kind, ToSql, Type};

    let samples_strs = &[
        "3950.123456",
        "3950",
        "0.1",
        "0.01",
        "0.001",
        "0.0001",
        "0.00001",
        "0.000001",
        "1",
        "-100",
        "-123.456",
        "119996.25",
        "1000000",
        "9999999.99999",
        "12340.56789",
    ];

    let samples: Vec<Decimal> = test::black_box(samples_strs.iter().map(|x| Decimal::from_str(x).unwrap()).collect());
    let t = Type::new("".into(), 0, Kind::Simple, "".into());
    let mut bytes: BytesMut = BytesMut::with_capacity(100).into();

    b.iter(|| {
        for _ in 0..100 {
            for sample in &samples {
                bytes.clear();
                sample.to_sql(&t, &mut bytes).unwrap();
                let result = Decimal::from_sql(&t, &bytes).unwrap();
                ::test::black_box(result);
            }
        }
    });
}

#[bench]
fn powi(b: &mut ::test::Bencher) {
    // These exponents have to be fairly small because multiplcation overflows easily
    let samples = &[
        (Decimal::from_str("36.7").unwrap(), 5),
        (Decimal::from_str("0.00000007").unwrap(), 5),
        (Decimal::from(2), 64),
        (Decimal::from_str("8819287.19276555").unwrap(), 3),
        (Decimal::from_str("-8819287.19276555").unwrap(), 3),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.0.powi(sample.1);
            ::test::black_box(result);
        }
    });
}

#[bench]
fn sqrt(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("36.7").unwrap(),
        Decimal::from_str("0.00000007").unwrap(),
        Decimal::from(2),
        Decimal::from_str("8819287.19276555").unwrap(),
        Decimal::from_str("-8819287.19276555").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.sqrt();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn exp(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("3.7").unwrap(),
        Decimal::from_str("0.07").unwrap(),
        Decimal::from(2),
        Decimal::from_str("8.19").unwrap(),
        Decimal::from_str("-8.19").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.exp();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn norm_cdf(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("3.7").unwrap(),
        Decimal::from_str("0.007").unwrap(),
        Decimal::from(2),
        Decimal::from_str("1.19").unwrap(),
        Decimal::from_str("-1.19").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.norm_cdf();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn norm_pdf(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("3.7").unwrap(),
        Decimal::from_str("0.007").unwrap(),
        Decimal::from(2),
        Decimal::from_str("1.19").unwrap(),
        Decimal::from_str("-1.19").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.norm_pdf();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn ln(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("36.7").unwrap(),
        Decimal::from_str("0.00000007").unwrap(),
        Decimal::from(2),
        Decimal::from_str("8819287.19").unwrap(),
        Decimal::from_str("-8819287.19").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.ln();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn erf(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from(0),
        Decimal::from(1),
        Decimal::from_str("-0.98717").unwrap(),
        Decimal::from_str("0.07").unwrap(),
        Decimal::from_str("0.1111").unwrap(),
        Decimal::from_str("0.4").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.erf();
            ::test::black_box(result);
        }
    });
}
<commit_msg>Add serde benches & to_string bench<commit_after>#![feature(test)]

extern crate test;

use core::str::FromStr;
use rust_decimal::Decimal;
use bincode::Options as _;

macro_rules! bench_decimal_op {
    ($name:ident, $op:tt, $y:expr) => {
        #[bench]
        fn $name(b: &mut ::test::Bencher) {
            let x = Decimal::from_str("2.01").unwrap();
            let y = Decimal::from_str($y).unwrap();
            b.iter(|| {
                let result = x $op y;
                ::test::black_box(result);
            });
        }
    }
}

macro_rules! bench_fold_op {
    ($name:ident, $op:tt, $init:expr, $count:expr) => {
        #[bench]
        fn $name(b: &mut ::test::Bencher) {
            fn fold(values: &[Decimal]) -> Decimal {
                let mut acc: Decimal = $init.into();
                for value in values {
                    acc = acc $op value;
                }
                acc
            }

            let values: Vec<Decimal> = test::black_box((1..$count).map(|i| i.into()).collect());
            b.iter(|| {
                let result = fold(&values);
                ::test::black_box(result);
            });
        }
    }
}

/* Add */
bench_decimal_op!(add_one, +, "1");
bench_decimal_op!(add_two, +, "2");
bench_decimal_op!(add_one_hundred, +, "100");
bench_decimal_op!(add_point_zero_one, +, "0.01");
bench_decimal_op!(add_negative_point_five, +, "-0.5");
bench_decimal_op!(add_pi, +, "3.1415926535897932384626433832");
bench_decimal_op!(add_negative_pi, +, "-3.1415926535897932384626433832");

bench_fold_op!(add_10k, +, 0, 10_000);

/* Sub */
bench_decimal_op!(sub_one, -, "1");
bench_decimal_op!(sub_two, -, "2");
bench_decimal_op!(sub_one_hundred, -, "100");
bench_decimal_op!(sub_point_zero_one, -, "0.01");
bench_decimal_op!(sub_negative_point_five, -, "-0.5");
bench_decimal_op!(sub_pi, -, "3.1415926535897932384626433832");
bench_decimal_op!(sub_negative_pi, -, "-3.1415926535897932384626433832");

bench_fold_op!(sub_10k, -, 5_000_000, 10_000);

/* Mul */
bench_decimal_op!(mul_one, *, "1");
bench_decimal_op!(mul_two, *, "2");
bench_decimal_op!(mul_one_hundred, *, "100");
bench_decimal_op!(mul_point_zero_one, *, "0.01");
bench_decimal_op!(mul_negative_point_five, *, "-0.5");
bench_decimal_op!(mul_pi, *, "3.1415926535897932384626433832");
bench_decimal_op!(mul_negative_pi, *, "-3.1415926535897932384626433832");

/* Div */
bench_decimal_op!(div_one, /, "1");
bench_decimal_op!(div_two, /, "2");
bench_decimal_op!(div_one_hundred, /, "100");
bench_decimal_op!(div_point_zero_one, /, "0.01");
bench_decimal_op!(div_negative_point_five, /, "-0.5");
bench_decimal_op!(div_pi, /, "3.1415926535897932384626433832");
bench_decimal_op!(div_negative_pi, /, "-3.1415926535897932384626433832");

bench_fold_op!(div_10k, /, Decimal::max_value(), 10_000);

/* Iteration */
struct DecimalIterator {
    count: usize,
}

impl DecimalIterator {
    fn new() -> DecimalIterator {
        DecimalIterator { count: 0 }
    }
}

impl Iterator for DecimalIterator {
    type Item = Decimal;

    fn next(&mut self) -> Option<Decimal> {
        self.count += 1;
        if self.count < 6 {
            Some(Decimal::new(314, 2))
        } else {
            None
        }
    }
}

#[bench]
fn iterator_individual(b: &mut ::test::Bencher) {
    b.iter(|| {
        let mut result = Decimal::new(0, 0);
        let iterator = DecimalIterator::new();
        for i in iterator {
            result += i;
        }
        ::test::black_box(result);
    });
}

#[bench]
fn iterator_sum(b: &mut ::test::Bencher) {
    b.iter(|| {
        let result: Decimal = DecimalIterator::new().sum();
        ::test::black_box(result);
    });
}

const SAMPLE_STRS: &[&str] = &[
    "3950.123456",
    "3950",
    "0.1",
    "0.01",
    "0.001",
    "0.0001",
    "0.00001",
    "0.000001",
    "1",
    "-100",
    "-123.456",
    "119996.25",
    "1000000",
    "9999999.99999",
    "12340.56789",
];

#[bench]
fn serialize_bincode(b: &mut test::Bencher) {
    let decimals: Vec<Decimal> = SAMPLE_STRS.iter().map(|s| Decimal::from_str(s).unwrap()).collect();

    b.iter(|| {
        for d in &decimals {
            let bytes = bincode::options().serialize(d).unwrap();
            test::black_box(bytes);
        }
    })
}

#[cfg(feature = "serde-str")]
#[bench]
fn deserialize_bincode(b: &mut test::Bencher) {
    let payloads: Vec<Vec<u8>> = SAMPLE_STRS
        .iter()
        .map(|s| bincode::options().serialize(&Decimal::from_str(s).unwrap()).unwrap())
        .collect();

    b.iter(|| {
        for payload in &payloads {
            let decimal: Decimal = bincode::options().deserialize(payload).unwrap();
            test::black_box(decimal);
        }
    })
}

#[bench]
fn decimal_from_str(b: &mut test::Bencher) {
    b.iter(|| {
        for s in SAMPLE_STRS {
            let result = Decimal::from_str(s).unwrap();
            test::black_box(result);
        }
    })
}

#[bench]
fn decimal_to_string(b: &mut test::Bencher) {
    let decimals: Vec<Decimal> = SAMPLE_STRS.iter().map(|s| Decimal::from_str(s).unwrap()).collect();

    b.iter(|| {
        for s in decimals.iter() {
            let string = s.to_string();
            test::black_box(string);
        }
    })
}

#[cfg(feature = "postgres")]
#[bench]
fn to_from_sql(b: &mut ::test::Bencher) {
    use postgres::types::{FromSql, Kind, ToSql, Type};

    let samples: Vec<Decimal> = test::black_box(SAMPLE_STRS.iter().map(|x| Decimal::from_str(x).unwrap()).collect());
    let t = Type::new("".into(), 0, Kind::Simple, "".into());
    let mut bytes: BytesMut = BytesMut::with_capacity(100).into();

    b.iter(|| {
        for _ in 0..100 {
            for sample in &samples {
                bytes.clear();
                sample.to_sql(&t, &mut bytes).unwrap();
                let result = Decimal::from_sql(&t, &bytes).unwrap();
                ::test::black_box(result);
            }
        }
    });
}

#[bench]
fn powi(b: &mut ::test::Bencher) {
    // These exponents have to be fairly small because multiplcation overflows easily
    let samples = &[
        (Decimal::from_str("36.7").unwrap(), 5),
        (Decimal::from_str("0.00000007").unwrap(), 5),
        (Decimal::from(2), 64),
        (Decimal::from_str("8819287.19276555").unwrap(), 3),
        (Decimal::from_str("-8819287.19276555").unwrap(), 3),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.0.powi(sample.1);
            ::test::black_box(result);
        }
    });
}

#[bench]
fn sqrt(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("36.7").unwrap(),
        Decimal::from_str("0.00000007").unwrap(),
        Decimal::from(2),
        Decimal::from_str("8819287.19276555").unwrap(),
        Decimal::from_str("-8819287.19276555").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.sqrt();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn exp(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("3.7").unwrap(),
        Decimal::from_str("0.07").unwrap(),
        Decimal::from(2),
        Decimal::from_str("8.19").unwrap(),
        Decimal::from_str("-8.19").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.exp();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn norm_cdf(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("3.7").unwrap(),
        Decimal::from_str("0.007").unwrap(),
        Decimal::from(2),
        Decimal::from_str("1.19").unwrap(),
        Decimal::from_str("-1.19").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.norm_cdf();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn norm_pdf(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("3.7").unwrap(),
        Decimal::from_str("0.007").unwrap(),
        Decimal::from(2),
        Decimal::from_str("1.19").unwrap(),
        Decimal::from_str("-1.19").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.norm_pdf();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn ln(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from_str("36.7").unwrap(),
        Decimal::from_str("0.00000007").unwrap(),
        Decimal::from(2),
        Decimal::from_str("8819287.19").unwrap(),
        Decimal::from_str("-8819287.19").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.ln();
            ::test::black_box(result);
        }
    });
}

#[bench]
fn erf(b: &mut ::test::Bencher) {
    let samples = &[
        Decimal::from(0),
        Decimal::from(1),
        Decimal::from_str("-0.98717").unwrap(),
        Decimal::from_str("0.07").unwrap(),
        Decimal::from_str("0.1111").unwrap(),
        Decimal::from_str("0.4").unwrap(),
    ];
    b.iter(|| {
        for sample in samples.iter() {
            let result = sample.erf();
            ::test::black_box(result);
        }
    });
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -C debug-assertions

// Check that we do *not* overflow on a number of edge cases.
// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)

// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }

fn main() {
    test_left_shift();
    test_right_shift();
}

fn test_left_shift() {
    // negative rhs can panic, but values in [0,N-1] are okay for iN

    macro_rules! tests {
        ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
            let x = 1 as $iN << id(0);
            assert_eq!(x, 1);
            let x = 1 as $uN << id(0);
            assert_eq!(x, 1);
            let x = 1 as $iN << id($max_rhs);
            assert_eq!(x, $expect_i);
            let x = 1 as $uN << id($max_rhs);
            assert_eq!(x, $expect_u);
            // high-order bits on LHS are silently discarded without panic.
            let x = 3 as $iN << id($max_rhs);
            assert_eq!(x, $expect_i);
            let x = 3 as $uN << id($max_rhs);
            assert_eq!(x, $expect_u);
        } }
    }

    let x = 1_i8 << id(0);
    assert_eq!(x, 1);
    let x = 1_u8 << id(0);
    assert_eq!(x, 1);
    let x = 1_i8 << id(7);
    assert_eq!(x, std::i8::MIN);
    let x = 1_u8 << id(7);
    assert_eq!(x, 0x80);
    // high-order bits on LHS are silently discarded without panic.
    let x = 3_i8 << id(7);
    assert_eq!(x, std::i8::MIN);
    let x = 3_u8 << id(7);
    assert_eq!(x, 0x80);

    // above is (approximately) expanded from:
    tests!(i8, u8, 7, std::i8::MIN, 0x80_u8);

    tests!(i16, u16, 15, std::i16::MIN, 0x8000_u16);
    tests!(i32, u32, 31, std::i32::MIN, 0x8000_0000_u32);
    tests!(i64, u64, 63, std::i64::MIN, 0x8000_0000_0000_0000_u64);
}

fn test_right_shift() {
    // negative rhs can panic, but values in [0,N-1] are okay for iN

    macro_rules! tests {
        ($iN:ty, $uN:ty, $max_rhs:expr,
         $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
        { {
            let x = 1 as $iN >> id(0);
            assert_eq!(x, 1);
            let x = 1 as $uN >> id(0);
            assert_eq!(x, 1);
            let x = $highbit_i >> id($max_rhs-1);
            assert_eq!(x, 1);
            let x = $highbit_u >> id($max_rhs);
            assert_eq!(x, 1);
            // sign-bit is carried by arithmetic right shift
            let x = $signbit_i >> id($max_rhs);
            assert_eq!(x, -1);
            // low-order bits on LHS are silently discarded without panic.
            let x = $highbit_i + 1 >> id($max_rhs-1);
            assert_eq!(x, 1);
            let x = $highbit_u + 1 >> id($max_rhs);
            assert_eq!(x, 1);
            let x = $signbit_i + 1 >> id($max_rhs);
            assert_eq!(x, -1);
        } }
    }

    tests!(i8, u8, 7, std::i8::MIN, 0x40_i8, 0x80_u8);
    tests!(i16, u16, 15, std::i16::MIN, 0x4000_u16, 0x8000_u16);
    tests!(i32, u32, 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32);
    tests!(i64, u64, 63, std::i64::MIN,
           0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64);
}
<commit_msg>workaround bugs in pretty-printer so that we can pass check-stage2-pretty-rpass.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -C debug-assertions

// Check that we do *not* overflow on a number of edge cases.
// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)

// (Work around constant-evaluation)
fn id<T>(x: T) -> T { x }

fn main() {
    test_left_shift();
    test_right_shift();
}

fn test_left_shift() {
    // negative rhs can panic, but values in [0,N-1] are okay for iN

    macro_rules! tests {
        ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
            let x = (1 as $iN) << id(0);
            assert_eq!(x, 1);
            let x = (1 as $uN) << id(0);
            assert_eq!(x, 1);
            let x = (1 as $iN) << id($max_rhs);
            assert_eq!(x, $expect_i);
            let x = (1 as $uN) << id($max_rhs);
            assert_eq!(x, $expect_u);
            // high-order bits on LHS are silently discarded without panic.
            let x = (3 as $iN) << id($max_rhs);
            assert_eq!(x, $expect_i);
            let x = (3 as $uN) << id($max_rhs);
            assert_eq!(x, $expect_u);
        } }
    }

    let x = 1_i8 << id(0);
    assert_eq!(x, 1);
    let x = 1_u8 << id(0);
    assert_eq!(x, 1);
    let x = 1_i8 << id(7);
    assert_eq!(x, std::i8::MIN);
    let x = 1_u8 << id(7);
    assert_eq!(x, 0x80);
    // high-order bits on LHS are silently discarded without panic.
    let x = 3_i8 << id(7);
    assert_eq!(x, std::i8::MIN);
    let x = 3_u8 << id(7);
    assert_eq!(x, 0x80);

    // above is (approximately) expanded from:
    tests!(i8, u8, 7, std::i8::MIN, 0x80_u8);

    tests!(i16, u16, 15, std::i16::MIN, 0x8000_u16);
    tests!(i32, u32, 31, std::i32::MIN, 0x8000_0000_u32);
    tests!(i64, u64, 63, std::i64::MIN, 0x8000_0000_0000_0000_u64);
}

fn test_right_shift() {
    // negative rhs can panic, but values in [0,N-1] are okay for iN

    macro_rules! tests {
        ($iN:ty, $uN:ty, $max_rhs:expr,
         $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
        { {
            let x = (1 as $iN) >> id(0);
            assert_eq!(x, 1);
            let x = (1 as $uN) >> id(0);
            assert_eq!(x, 1);
            let x = ($highbit_i) >> id($max_rhs-1);
            assert_eq!(x, 1);
            let x = ($highbit_u) >> id($max_rhs);
            assert_eq!(x, 1);
            // sign-bit is carried by arithmetic right shift
            let x = ($signbit_i) >> id($max_rhs);
            assert_eq!(x, -1);
            // low-order bits on LHS are silently discarded without panic.
            let x = ($highbit_i + 1) >> id($max_rhs-1);
            assert_eq!(x, 1);
            let x = ($highbit_u + 1) >> id($max_rhs);
            assert_eq!(x, 1);
            let x = ($signbit_i + 1) >> id($max_rhs);
            assert_eq!(x, -1);
        } }
    }

    tests!(i8, u8, 7, std::i8::MIN, 0x40_i8, 0x80_u8);
    tests!(i16, u16, 15, std::i16::MIN, 0x4000_u16, 0x8000_u16);
    tests!(i32, u32, 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32);
    tests!(i64, u64, 63, std::i64::MIN,
           0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64);
}
<|endoftext|>


<commit_before>pub mod bitbucket;
pub mod gist;
pub mod hastebin;
pub mod pastebin;
pub mod pastie;
pub mod sprunge;

use bins::error::*;
use bins::network::download::Downloader;
use bins::network::upload::Uploader;
use bins::network;
use bins::{self, Bins, PasteFile};
use hyper::Url;
use linked_hash_map::LinkedHashMap;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Write;
use std::iter::repeat;
use std::path::{Path, PathBuf};

pub struct Index {
  pub files: LinkedHashMap<String, Url>
}

impl Index {
  fn repeat_str(string: &str, count: usize) -> String {
    repeat(string).take(count).collect()
  }

  pub fn to_string(&self) -> String {
    let header = format!("{} files", self.files.len());
    let separator = Self::repeat_str("-", header.len());
    let mut body = String::from("");
    for (i, (name, url)) in self.files.iter().enumerate() {
      let number = i + 1;
      body.push_str(&format!("{number}. {name}: {url}\n",
                             number = number,
                             name = name,
                             url = url));
    }
    format!("{}\n{}\n\n{}", header, separator, body)
  }

  pub fn parse<S: Into<String>>(string: S) -> Result<Index> {
    let string = string.into();
    let lines: Vec<&str> = string.split('\n').collect();
    if lines.len() < 4 {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let mut split = lines.iter().skip(3).filter(|s| !s.trim().is_empty()).map(|s| s.split(": ")).collect::<Vec<_>>();
    let names: Vec<String> = some_or_err!(split.iter_mut()
                                            .map(|s| {
                                              s.nth(0)
                                                .map(|n| n.split(' ').skip(1).collect::<Vec<&str>>().join(" "))
                                            })
                                            .collect(),
                                          ErrorKind::InvalidIndexError.into());
    let url_strings: Vec<String> = some_or_err!(split.iter_mut().map(|s| s.nth(0).map(|s| s.to_owned())).collect(),
                                                ErrorKind::InvalidIndexError.into());
    if url_strings.is_empty() {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let urls: Result<Vec<Url>> = url_strings.into_iter().map(network::parse_url).collect();
    let urls: Vec<Url> = try!(urls.chain_err(|| ErrorKind::InvalidIndexError));
    let urls: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: urls })
  }
}

#[derive(Debug)]
pub struct RemotePasteFile {
  pub name: String,
  pub url: Url,
  pub contents: Option<String>
}

/// Produce information about HTML content from URLs to HTML content.
pub trait ProduceInfo {
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceInfo for T
  where T: GenerateIndex + ConvertUrlsToRawUrls + Downloader
{
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let raw_url = try!(self.convert_url_to_raw_url(bins, url));
    let mut res = try!(self.download(&bins, &raw_url));
    let content = try!(network::read_response(&mut res));
    let index = Index::parse(content.clone());
    let mut urls: Vec<RemotePasteFile> = Vec::new();
    match index {
      Ok(ref i) => {
        for (name, url) in i.files.clone().into_iter() {
          urls.push(RemotePasteFile {
            name: name.clone(),
            url: url.clone(),
            contents: None
          });
        }
      }
      Err(ref e) => {
        if let ErrorKind::InvalidIndexError = *e.kind() {} else {
          return Err(e.to_string().into());
        }
        let url = url.clone();
        let name = some_or_err!(url.path_segments().and_then(|s| s.last()),
                                "paste url was a root url".into());
        urls.push(RemotePasteFile {
          name: name.to_owned(),
          url: url.clone(),
          contents: Some(content)
        });
      }
    }
    Ok(urls)
  }
}

/// Produce information about raw content from URLs to HTML content.
pub trait ProduceRawInfo {
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_raw_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_raw_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceRawInfo for T
  where T: ConvertUrlsToRawUrls + Downloader + UsesIndices + ProduceInfo
{
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let info = try!(self.produce_info(bins, url));
    info.into_iter()
      .map(|r| {
        let raw_url = try!(self.convert_url_to_raw_url(bins, &r.url));
        Ok(RemotePasteFile { url: raw_url, ..r })
      })
      .collect()
  }
}

pub trait ConvertUrlsToRawUrls {
  fn convert_url_to_raw_url(&self, bins: &Bins, url: &Url) -> Result<Url>;

  fn convert_urls_to_raw_urls(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<Url>> {
    urls.iter().map(|u| self.convert_url_to_raw_url(bins, u)).collect()
  }
}

/// Produce raw content from a URL to HTML content.
pub trait ProduceRawContent: ProduceRawInfo + ProduceInfo + Downloader {
  fn produce_raw_contents(&self, bins: &Bins, url: &Url) -> Result<String> {
    let raw_info = if bins.arguments.urls {
      try!(self.produce_info(bins, url))
    } else {
      try!(self.produce_raw_info(bins, url))
    };
    let raw_info: Vec<RemotePasteFile> = if raw_info.len() > 1 {
      if !bins.arguments.files.is_empty() {
        let mut map: HashMap<String, RemotePasteFile> =
          raw_info.into_iter().map(|r| (r.name.to_lowercase(), r)).collect();
        try!(bins.arguments
          .files
          .iter()
          .map(|s| map.remove(&s.to_lowercase()).ok_or(format!("file {} not found", s)))
          .collect())
      } else if let Some(ref range) = bins.arguments.range {
        let mut numbered_info: HashMap<usize, RemotePasteFile> = raw_info.into_iter()
          .enumerate()
          .collect();
        try!(range.clone()
          .into_iter()
          .map(|n| numbered_info.remove(&n).ok_or(format!("file {} not found", n)))
          .collect())
      } else if bins.arguments.all {
        raw_info
      } else {
        let names = raw_info.into_iter().map(|r| String::from("  ") + &r.name).collect::<Vec<_>>().join("\n");
        return Err(format!("paste had multiple files, but no behavior was specified on the command \
                            line\n\navailable files:\n{}",
                           names)
          .into());
      }
    } else {
      raw_info
    };
    if bins.arguments.raw_urls || bins.arguments.urls {
      return Ok(raw_info.into_iter().map(|r| r.url.as_str().to_owned()).collect::<Vec<_>>().join("\n"));
    }
    let names: Vec<String> = raw_info.iter().map(|p| p.name.clone()).collect();
    let all_contents: Vec<String> = try!(raw_info.iter()
      .map(|p| {
        match p.contents.clone() {
          Some(contents) => Ok(contents),
          None => self.download(&bins, &p.url).and_then(|mut r| network::read_response(&mut r)),
        }
      })
      .collect());
    let files: LinkedHashMap<String, String> = names.into_iter().zip(all_contents.into_iter()).collect();
    let paste_files = files.into_iter()
      .map(|(name, content)| {
        PasteFile {
          name: name.clone(),
          data: if bins.arguments.number_lines {
            number_lines(content.clone())
          } else {
            content.clone()
          }
        }
      })
      .collect::<Vec<PasteFile>>();
    if bins.arguments.write {
      let mut bins_output = String::new();
      let output = match bins.arguments.output {
        Some(ref s) => PathBuf::from(s),
        None => try!(env::current_dir()),
      };
      if !output.exists() {
        return Err("output dir did not exist".into());
      }
      if !output.is_dir() || output.is_file() {
        return Err("output dir was not a directory".into());
      }
      for p in &paste_files {
        let sanitized = try!(Bins::sanitize_path(Path::new(&p.name)));
        let original_path = output.join(sanitized);
        let mut path = original_path.clone();
        let mut num = 0;
        while path.exists() {
          num = num + 1;
          path = Bins::add_number_to_path(&original_path, num);
        }
        let mut file = try!(File::create(&path));
        try!(file.write_all(p.data.as_bytes()));
        bins_output.push_str(format!("Wrote {} -> {}\n", p.name, path.to_string_lossy()).as_str());
      }
      return Ok(bins_output);
    }
    Ok(paste_files.join())
  }
}

fn number_lines(string: String) -> String {
  let lines: Vec<&str> = string.split('\n').collect();
  let num_lines = lines.len();
  let zeroes: String = repeat(" ").take(num_lines.to_string().len()).collect();
  lines.into_iter()
    .enumerate()
    .map(|(i, l)| {
      let i = i + 1;
      format!("{}{}  {}",
              &zeroes[0..zeroes.len() - i.to_string().len()],
              i,
              l)
    })
    .collect::<Vec<_>>()
    .join("\n")
}

/// Produce a URL to HTML content from raw content.
pub trait UploadContent: Uploader {
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url>;
}

impl<T> UploadContent for T
  where T: UploadUrl + Uploader
{
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url> {
    let url = try!(network::parse_url(self.get_upload_url()));
    let mut response = try!(self.upload(&url, bins, &content));
    network::parse_url(try!(network::read_response(&mut response)))
  }
}

/// Produce a URL to HTML content from a batch of raw content.
pub trait UploadBatchContent: UploadContent {
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url>;
}

impl<T> UploadBatchContent for T
  where T: GenerateIndex + UploadContent
{
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url> {
    let index = try!(self.generate_index(bins, content));
    self.upload_paste(bins,
                      PasteFile {
                        name: "index.md".to_owned(),
                        data: index.to_string()
                      })
  }
}

pub trait UsesIndices {}

/// Generate an index for multiple files.
pub trait GenerateIndex {
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index>;
}

impl<T> GenerateIndex for T
  where T: UploadContent + UsesIndices
{
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index> {
    let names: Vec<String> = (&content).into_iter().map(|p| p.name.clone()).collect();
    let urls: Vec<Url> = try!(content.into_iter().map(|p| self.upload_paste(bins, p)).collect());
    let uploads: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: uploads })
  }
}

pub trait UploadUrl {
  fn get_upload_url(&self) -> &str;
}

pub trait VerifyUrl {
  fn segments(&self, url: &Url) -> Vec<String> {
    let segments = match url.path_segments() {
      Some(s) => s,
      None => return Vec::new(),
    };
    segments.filter(|s| !s.is_empty()).map(|s| s.to_owned()).collect::<Vec<_>>()
  }

  fn verify_url(&self, url: &Url) -> bool;
}

/// A bin, which can upload content in raw form and download content in raw and HTML form.
pub trait Bin: Sync + ProduceInfo + ProduceRawContent + UploadBatchContent + VerifyUrl {
  fn get_name(&self) -> &str;

  fn get_domain(&self) -> &str;
}

trait Join {
  fn join(&self) -> String;
}

impl Join for Vec<PasteFile> {
  fn join(&self) -> String {
    if self.len() == 1 {
      self.get(0).expect("len() == 1, but no first element").data.clone()
    } else {
      self.into_iter().map(|p| format!("==> {} <==\n{}", p.name, p.data)).collect::<Vec<String>>().join("\n")
    }
  }
}

lazy_static! {
  pub static ref BINS: Vec<Box<Bin>> = {
      vec![
        Box::new(bins::Gist::new()),
        Box::new(bins::Bitbucket::new()),
        Box::new(bins::Sprunge::new()),
        Box::new(bins::Hastebin::new()),
        Box::new(bins::Pastebin::new()),
        Box::new(bins::Pastie::new())
      ]
  };
}

pub fn get_bin_names<'a>() -> Vec<&'a str> {
  BINS.iter().map(|e| e.get_name()).collect()
}

pub fn get_bin_by_name(name: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_name().to_lowercase() == name.to_lowercase())
}

pub fn get_bin_by_domain(domain: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_domain().to_lowercase() == domain.to_lowercase())
}
<commit_msg>fix(write): remove extraneous newline from output<commit_after>pub mod bitbucket;
pub mod gist;
pub mod hastebin;
pub mod pastebin;
pub mod pastie;
pub mod sprunge;

use bins::error::*;
use bins::network::download::Downloader;
use bins::network::upload::Uploader;
use bins::network;
use bins::{self, Bins, PasteFile};
use hyper::Url;
use linked_hash_map::LinkedHashMap;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Write;
use std::iter::repeat;
use std::path::{Path, PathBuf};

pub struct Index {
  pub files: LinkedHashMap<String, Url>
}

impl Index {
  fn repeat_str(string: &str, count: usize) -> String {
    repeat(string).take(count).collect()
  }

  pub fn to_string(&self) -> String {
    let header = format!("{} files", self.files.len());
    let separator = Self::repeat_str("-", header.len());
    let mut body = String::from("");
    for (i, (name, url)) in self.files.iter().enumerate() {
      let number = i + 1;
      body.push_str(&format!("{number}. {name}: {url}\n",
                             number = number,
                             name = name,
                             url = url));
    }
    format!("{}\n{}\n\n{}", header, separator, body)
  }

  pub fn parse<S: Into<String>>(string: S) -> Result<Index> {
    let string = string.into();
    let lines: Vec<&str> = string.split('\n').collect();
    if lines.len() < 4 {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let mut split = lines.iter().skip(3).filter(|s| !s.trim().is_empty()).map(|s| s.split(": ")).collect::<Vec<_>>();
    let names: Vec<String> = some_or_err!(split.iter_mut()
                                            .map(|s| {
                                              s.nth(0)
                                                .map(|n| n.split(' ').skip(1).collect::<Vec<&str>>().join(" "))
                                            })
                                            .collect(),
                                          ErrorKind::InvalidIndexError.into());
    let url_strings: Vec<String> = some_or_err!(split.iter_mut().map(|s| s.nth(0).map(|s| s.to_owned())).collect(),
                                                ErrorKind::InvalidIndexError.into());
    if url_strings.is_empty() {
      return Err(ErrorKind::InvalidIndexError.into());
    }
    let urls: Result<Vec<Url>> = url_strings.into_iter().map(network::parse_url).collect();
    let urls: Vec<Url> = try!(urls.chain_err(|| ErrorKind::InvalidIndexError));
    let urls: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: urls })
  }
}

#[derive(Debug)]
pub struct RemotePasteFile {
  pub name: String,
  pub url: Url,
  pub contents: Option<String>
}

/// Produce information about HTML content from URLs to HTML content.
pub trait ProduceInfo {
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceInfo for T
  where T: GenerateIndex + ConvertUrlsToRawUrls + Downloader
{
  fn produce_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let raw_url = try!(self.convert_url_to_raw_url(bins, url));
    let mut res = try!(self.download(&bins, &raw_url));
    let content = try!(network::read_response(&mut res));
    let index = Index::parse(content.clone());
    let mut urls: Vec<RemotePasteFile> = Vec::new();
    match index {
      Ok(ref i) => {
        for (name, url) in i.files.clone().into_iter() {
          urls.push(RemotePasteFile {
            name: name.clone(),
            url: url.clone(),
            contents: None
          });
        }
      }
      Err(ref e) => {
        if let ErrorKind::InvalidIndexError = *e.kind() {} else {
          return Err(e.to_string().into());
        }
        let url = url.clone();
        let name = some_or_err!(url.path_segments().and_then(|s| s.last()),
                                "paste url was a root url".into());
        urls.push(RemotePasteFile {
          name: name.to_owned(),
          url: url.clone(),
          contents: Some(content)
        });
      }
    }
    Ok(urls)
  }
}

/// Produce information about raw content from URLs to HTML content.
pub trait ProduceRawInfo {
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>>;

  fn produce_raw_info_all(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<RemotePasteFile>> {
    let info: Vec<Vec<RemotePasteFile>> = try!(urls.iter().map(|u| self.produce_raw_info(bins, u)).collect());
    Ok(info.into_iter().flat_map(|v| v).collect())
  }
}

impl<T> ProduceRawInfo for T
  where T: ConvertUrlsToRawUrls + Downloader + UsesIndices + ProduceInfo
{
  fn produce_raw_info(&self, bins: &Bins, url: &Url) -> Result<Vec<RemotePasteFile>> {
    let info = try!(self.produce_info(bins, url));
    info.into_iter()
      .map(|r| {
        let raw_url = try!(self.convert_url_to_raw_url(bins, &r.url));
        Ok(RemotePasteFile { url: raw_url, ..r })
      })
      .collect()
  }
}

pub trait ConvertUrlsToRawUrls {
  fn convert_url_to_raw_url(&self, bins: &Bins, url: &Url) -> Result<Url>;

  fn convert_urls_to_raw_urls(&self, bins: &Bins, urls: Vec<&Url>) -> Result<Vec<Url>> {
    urls.iter().map(|u| self.convert_url_to_raw_url(bins, u)).collect()
  }
}

/// Produce raw content from a URL to HTML content.
pub trait ProduceRawContent: ProduceRawInfo + ProduceInfo + Downloader {
  fn produce_raw_contents(&self, bins: &Bins, url: &Url) -> Result<String> {
    let raw_info = if bins.arguments.urls {
      try!(self.produce_info(bins, url))
    } else {
      try!(self.produce_raw_info(bins, url))
    };
    let raw_info: Vec<RemotePasteFile> = if raw_info.len() > 1 {
      if !bins.arguments.files.is_empty() {
        let mut map: HashMap<String, RemotePasteFile> =
          raw_info.into_iter().map(|r| (r.name.to_lowercase(), r)).collect();
        try!(bins.arguments
          .files
          .iter()
          .map(|s| map.remove(&s.to_lowercase()).ok_or(format!("file {} not found", s)))
          .collect())
      } else if let Some(ref range) = bins.arguments.range {
        let mut numbered_info: HashMap<usize, RemotePasteFile> = raw_info.into_iter()
          .enumerate()
          .collect();
        try!(range.clone()
          .into_iter()
          .map(|n| numbered_info.remove(&n).ok_or(format!("file {} not found", n)))
          .collect())
      } else if bins.arguments.all {
        raw_info
      } else {
        let names = raw_info.into_iter().map(|r| String::from("  ") + &r.name).collect::<Vec<_>>().join("\n");
        return Err(format!("paste had multiple files, but no behavior was specified on the command \
                            line\n\navailable files:\n{}",
                           names)
          .into());
      }
    } else {
      raw_info
    };
    if bins.arguments.raw_urls || bins.arguments.urls {
      return Ok(raw_info.into_iter().map(|r| r.url.as_str().to_owned()).collect::<Vec<_>>().join("\n"));
    }
    let names: Vec<String> = raw_info.iter().map(|p| p.name.clone()).collect();
    let all_contents: Vec<String> = try!(raw_info.iter()
      .map(|p| {
        match p.contents.clone() {
          Some(contents) => Ok(contents),
          None => self.download(&bins, &p.url).and_then(|mut r| network::read_response(&mut r)),
        }
      })
      .collect());
    let files: LinkedHashMap<String, String> = names.into_iter().zip(all_contents.into_iter()).collect();
    let paste_files = files.into_iter()
      .map(|(name, content)| {
        PasteFile {
          name: name.clone(),
          data: if bins.arguments.number_lines {
            number_lines(content.clone())
          } else {
            content.clone()
          }
        }
      })
      .collect::<Vec<PasteFile>>();
    if bins.arguments.write {
      let mut bins_output = String::new();
      let output = match bins.arguments.output {
        Some(ref s) => PathBuf::from(s),
        None => try!(env::current_dir()),
      };
      if !output.exists() {
        return Err("output dir did not exist".into());
      }
      if !output.is_dir() || output.is_file() {
        return Err("output dir was not a directory".into());
      }
      for p in &paste_files {
        let sanitized = try!(Bins::sanitize_path(Path::new(&p.name)));
        let original_path = output.join(sanitized);
        let mut path = original_path.clone();
        let mut num = 0;
        while path.exists() {
          num = num + 1;
          path = Bins::add_number_to_path(&original_path, num);
        }
        let mut file = try!(File::create(&path));
        try!(file.write_all(p.data.as_bytes()));
        bins_output.push_str(format!("Wrote {} -> {}\n", p.name, path.to_string_lossy()).as_str());
      }
      return Ok(bins_output[0..bins_output.len() - 1].to_owned());
    }
    Ok(paste_files.join())
  }
}

fn number_lines(string: String) -> String {
  let lines: Vec<&str> = string.split('\n').collect();
  let num_lines = lines.len();
  let zeroes: String = repeat(" ").take(num_lines.to_string().len()).collect();
  lines.into_iter()
    .enumerate()
    .map(|(i, l)| {
      let i = i + 1;
      format!("{}{}  {}",
              &zeroes[0..zeroes.len() - i.to_string().len()],
              i,
              l)
    })
    .collect::<Vec<_>>()
    .join("\n")
}

/// Produce a URL to HTML content from raw content.
pub trait UploadContent: Uploader {
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url>;
}

impl<T> UploadContent for T
  where T: UploadUrl + Uploader
{
  fn upload_paste(&self, bins: &Bins, content: PasteFile) -> Result<Url> {
    let url = try!(network::parse_url(self.get_upload_url()));
    let mut response = try!(self.upload(&url, bins, &content));
    network::parse_url(try!(network::read_response(&mut response)))
  }
}

/// Produce a URL to HTML content from a batch of raw content.
pub trait UploadBatchContent: UploadContent {
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url>;
}

impl<T> UploadBatchContent for T
  where T: GenerateIndex + UploadContent
{
  fn upload_all(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Url> {
    let index = try!(self.generate_index(bins, content));
    self.upload_paste(bins,
                      PasteFile {
                        name: "index.md".to_owned(),
                        data: index.to_string()
                      })
  }
}

pub trait UsesIndices {}

/// Generate an index for multiple files.
pub trait GenerateIndex {
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index>;
}

impl<T> GenerateIndex for T
  where T: UploadContent + UsesIndices
{
  fn generate_index(&self, bins: &Bins, content: Vec<PasteFile>) -> Result<Index> {
    let names: Vec<String> = (&content).into_iter().map(|p| p.name.clone()).collect();
    let urls: Vec<Url> = try!(content.into_iter().map(|p| self.upload_paste(bins, p)).collect());
    let uploads: LinkedHashMap<String, Url> = names.into_iter().zip(urls.into_iter()).collect();
    Ok(Index { files: uploads })
  }
}

pub trait UploadUrl {
  fn get_upload_url(&self) -> &str;
}

pub trait VerifyUrl {
  fn segments(&self, url: &Url) -> Vec<String> {
    let segments = match url.path_segments() {
      Some(s) => s,
      None => return Vec::new(),
    };
    segments.filter(|s| !s.is_empty()).map(|s| s.to_owned()).collect::<Vec<_>>()
  }

  fn verify_url(&self, url: &Url) -> bool;
}

/// A bin, which can upload content in raw form and download content in raw and HTML form.
pub trait Bin: Sync + ProduceInfo + ProduceRawContent + UploadBatchContent + VerifyUrl {
  fn get_name(&self) -> &str;

  fn get_domain(&self) -> &str;
}

trait Join {
  fn join(&self) -> String;
}

impl Join for Vec<PasteFile> {
  fn join(&self) -> String {
    if self.len() == 1 {
      self.get(0).expect("len() == 1, but no first element").data.clone()
    } else {
      self.into_iter().map(|p| format!("==> {} <==\n{}", p.name, p.data)).collect::<Vec<String>>().join("\n")
    }
  }
}

lazy_static! {
  pub static ref BINS: Vec<Box<Bin>> = {
      vec![
        Box::new(bins::Gist::new()),
        Box::new(bins::Bitbucket::new()),
        Box::new(bins::Sprunge::new()),
        Box::new(bins::Hastebin::new()),
        Box::new(bins::Pastebin::new()),
        Box::new(bins::Pastie::new())
      ]
  };
}

pub fn get_bin_names<'a>() -> Vec<&'a str> {
  BINS.iter().map(|e| e.get_name()).collect()
}

pub fn get_bin_by_name(name: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_name().to_lowercase() == name.to_lowercase())
}

pub fn get_bin_by_domain(domain: &str) -> Option<&Box<Bin>> {
  BINS.iter().find(|e| e.get_domain().to_lowercase() == domain.to_lowercase())
}
<|endoftext|>


<commit_before>use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::fs::OpenOptions;
use std::io;
use std::io::prelude::*;
use std::path::{Path, PathBuf, Component};

use util::{human, internal, CargoResult, ChainError};

pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
    env::join_paths(paths.iter()).or_else(|e| {
        let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
        internal(format!("failed to join path array: {:?}", paths)).chain_error(|| {
            human(format!("failed to join search paths together: {}\n\
                           Does ${} have an unterminated quote character?",
                          e, env))
        })
    })
}

pub fn dylib_path_envvar() -> &'static str {
    if cfg!(windows) {"PATH"}
    else if cfg!(target_os = "macos") {"DYLD_LIBRARY_PATH"}
    else {"LD_LIBRARY_PATH"}
}

pub fn dylib_path() -> Vec<PathBuf> {
    match env::var_os(dylib_path_envvar()) {
        Some(var) => env::split_paths(&var).collect(),
        None => Vec::new(),
    }
}

pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek()
                                                                     .cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => { ret.push(component.as_os_str()); }
            Component::CurDir => {}
            Component::ParentDir => { ret.pop(); }
            Component::Normal(c) => { ret.push(c); }
        }
    }
    ret
}

pub fn without_prefix<'a>(a: &'a Path, b: &'a Path) -> Option<&'a Path> {
    let mut a = a.components();
    let mut b = b.components();
    loop {
        match b.next() {
            Some(y) => match a.next() {
                Some(x) if x == y => continue,
                _ => return None,
            },
            None => return Some(a.as_path()),
        }
    }
}

pub fn file(p: &Path, contents: &[u8]) -> io::Result<()> {
    try!(File::create(p)).write_all(contents)
}

pub fn read(path: &Path) -> CargoResult<String> {
    (|| -> CargoResult<_> {
        let mut ret = String::new();
        let mut f = File::open(path)?;
        f.read_to_string(&mut ret)?;
        Ok(ret)
    })().map_err(human).chain_error(|| {
        human(format!("failed to read `{}`", path.display()))
    })
}

pub fn read_bytes(path: &Path) -> CargoResult<Vec<u8>> {
    (|| -> CargoResult<_> {
        let mut ret = Vec::new();
        let mut f = File::open(path)?;
        f.read_to_end(&mut ret)?;
        Ok(ret)
    })().map_err(human).chain_error(|| {
        human(format!("failed to read `{}`", path.display()))
    })
}

pub fn write(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = File::create(path)?;
        f.write_all(contents)?;
        Ok(())
    })().map_err(human).chain_error(|| {
        human(format!("failed to write `{}`", path.display()))
    })
}

pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = OpenOptions::new()
                                 .write(true)
                                 .append(true)
                                 .create(true)
                                 .open(path)?;

        f.write_all(contents)?;
        Ok(())
    }).chain_error(|| {
        internal(format!("failed to write `{}`", path.display()))
    })
}

#[cfg(unix)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    use std::os::unix::prelude::*;
    Ok(path.as_os_str().as_bytes())
}
#[cfg(windows)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    match path.as_os_str().to_str() {
        Some(s) => Ok(s.as_bytes()),
        None => Err(human(format!("invalid non-unicode path: {}",
                                  path.display())))
    }
}

#[cfg(unix)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::os::unix::prelude::*;
    use std::ffi::OsStr;
    Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(windows)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::str;
    match str::from_utf8(bytes) {
        Ok(s) => Ok(PathBuf::from(s)),
        Err(..) => Err(human("invalid non-unicode path")),
    }
}
<commit_msg>Remove unused 'file' function.<commit_after>use std::env;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::fs::OpenOptions;
use std::io::prelude::*;
use std::path::{Path, PathBuf, Component};

use util::{human, internal, CargoResult, ChainError};

pub fn join_paths<T: AsRef<OsStr>>(paths: &[T], env: &str) -> CargoResult<OsString> {
    env::join_paths(paths.iter()).or_else(|e| {
        let paths = paths.iter().map(Path::new).collect::<Vec<_>>();
        internal(format!("failed to join path array: {:?}", paths)).chain_error(|| {
            human(format!("failed to join search paths together: {}\n\
                           Does ${} have an unterminated quote character?",
                          e, env))
        })
    })
}

pub fn dylib_path_envvar() -> &'static str {
    if cfg!(windows) {"PATH"}
    else if cfg!(target_os = "macos") {"DYLD_LIBRARY_PATH"}
    else {"LD_LIBRARY_PATH"}
}

pub fn dylib_path() -> Vec<PathBuf> {
    match env::var_os(dylib_path_envvar()) {
        Some(var) => env::split_paths(&var).collect(),
        None => Vec::new(),
    }
}

pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek()
                                                                     .cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => { ret.push(component.as_os_str()); }
            Component::CurDir => {}
            Component::ParentDir => { ret.pop(); }
            Component::Normal(c) => { ret.push(c); }
        }
    }
    ret
}

pub fn without_prefix<'a>(a: &'a Path, b: &'a Path) -> Option<&'a Path> {
    let mut a = a.components();
    let mut b = b.components();
    loop {
        match b.next() {
            Some(y) => match a.next() {
                Some(x) if x == y => continue,
                _ => return None,
            },
            None => return Some(a.as_path()),
        }
    }
}

pub fn read(path: &Path) -> CargoResult<String> {
    (|| -> CargoResult<_> {
        let mut ret = String::new();
        let mut f = File::open(path)?;
        f.read_to_string(&mut ret)?;
        Ok(ret)
    })().map_err(human).chain_error(|| {
        human(format!("failed to read `{}`", path.display()))
    })
}

pub fn read_bytes(path: &Path) -> CargoResult<Vec<u8>> {
    (|| -> CargoResult<_> {
        let mut ret = Vec::new();
        let mut f = File::open(path)?;
        f.read_to_end(&mut ret)?;
        Ok(ret)
    })().map_err(human).chain_error(|| {
        human(format!("failed to read `{}`", path.display()))
    })
}

pub fn write(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = File::create(path)?;
        f.write_all(contents)?;
        Ok(())
    })().map_err(human).chain_error(|| {
        human(format!("failed to write `{}`", path.display()))
    })
}

pub fn append(path: &Path, contents: &[u8]) -> CargoResult<()> {
    (|| -> CargoResult<()> {
        let mut f = OpenOptions::new()
                                 .write(true)
                                 .append(true)
                                 .create(true)
                                 .open(path)?;

        f.write_all(contents)?;
        Ok(())
    }).chain_error(|| {
        internal(format!("failed to write `{}`", path.display()))
    })
}

#[cfg(unix)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    use std::os::unix::prelude::*;
    Ok(path.as_os_str().as_bytes())
}
#[cfg(windows)]
pub fn path2bytes(path: &Path) -> CargoResult<&[u8]> {
    match path.as_os_str().to_str() {
        Some(s) => Ok(s.as_bytes()),
        None => Err(human(format!("invalid non-unicode path: {}",
                                  path.display())))
    }
}

#[cfg(unix)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::os::unix::prelude::*;
    use std::ffi::OsStr;
    Ok(PathBuf::from(OsStr::from_bytes(bytes)))
}
#[cfg(windows)]
pub fn bytes2path(bytes: &[u8]) -> CargoResult<PathBuf> {
    use std::str;
    match str::from_utf8(bytes) {
        Ok(s) => Ok(PathBuf::from(s)),
        Err(..) => Err(human("invalid non-unicode path")),
    }
}
<|endoftext|>