<commit_before>//! # liquery-file
//! A library to make queryable files for the liquery `Queryable`
//! trait.

extern crate liquery;
extern crate mime_guess;

use std::path::Path;
use std::fs::Metadata;

use liquery::Queryable;

pub struct QueryFile<'a> {
    metadata: Metadata,
    path: &'a Path,
}

impl <'a> QueryFile<'a> {
    pub fn new(path: &'a Path) -> std::io::Result<Self> {
        Ok(QueryFile {
            metadata: try!(path.metadata()),
            path: path,
        })
    }
}

impl <'a>  Queryable for QueryFile<'a> {
    fn query(&self, key: &str) -> Option<String> {
        match key {
            "size" => Some(format!("{}", self.metadata.len())),
            "filetype" => {
                let filetype = self.metadata.file_type();
                if filetype.is_symlink() {
                    Some("symlink".to_owned())
                } else if filetype.is_dir() {
                    Some("directory".to_owned())
                } else {
                    Some("file".to_owned())
                }
            },
            "extension" => match self.path.extension() {
                Some(ostr) => match ostr.to_str() {
                    Some(pstr) => Some(pstr.to_owned()),
                    None => None,
                },
                None => None,
            },
            "filename" => match self.path.file_name() {
                Some(ostr) => match ostr.to_str() {
                    Some(pstr) => Some(pstr.to_owned()),
                    None => None,
                },
                None => None,
            },
            "mimetype" => Some(format!("{}", mime_guess::guess_mime_type(self.path))),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate liquery;
    use super::*;
    use liquery::Queryable;
    use std::path::Path;

    macro_rules! query_test {
        ($name: ident, $field: expr, $out: expr) => {
            query_test!($name, $field, $out, "tests/file_1b.txt");
        };
        ($name: ident, $field: expr, $out: expr, $path: expr) => {
            #[test]
            fn $name() {
                let path = Path::new($path);
                let queryable = QueryFile::new(path).unwrap();

                assert_eq!($out, &queryable.query($field).unwrap());
            }
        };
    }

    macro_rules! query_test_no_result {
        ($name: ident, $field: expr) => {
            query_test_no_result!($name, $field, "tests/file_1b.txt");
        };
        ($name: ident, $field: expr, $path: expr) => {
            #[test]
            fn $name() {
                let path = Path::new($path);
                let queryable = QueryFile::new(path).unwrap();

                assert_eq!(None, queryable.query($field));
            }
        };
    }

    query_test!(size_of_file, "size", "1");

    query_test!(file_type_file, "filetype", "file");
    query_test!(file_type_dir, "filetype", "directory", "tests");

    query_test!(file_name, "filename", "file_1b.txt");
    query_test!(file_name_dir, "filename", "tests", "tests");

    query_test!(file_extension, "extension", "txt");
    query_test_no_result!(file_extension_dir, "extension", "tests");

    query_test!(file_mime, "mimetype", "text/plain");
    query_test!(file_mime_rust, "mimetype", "text/x-rust", "src/lib.rs");

    query_test_no_result!(unkown_feild, "unkown");
    query_test_no_result!(empty_feild, "");
}
<commit_msg>fix issues clippy brought up<commit_after>//! # liquery-file
//! A library to make queryable files for the liquery `Queryable`
//! trait.

extern crate liquery;
extern crate mime_guess;

use std::path::Path;
use std::fs::Metadata;

use liquery::Queryable;

pub struct QueryFile<'a> {
    metadata: Metadata,
    path: &'a Path,
}

impl <'a> QueryFile<'a> {
    pub fn new(path: &'a Path) -> std::io::Result<Self> {
        Ok(QueryFile {
            metadata: try!(path.metadata()),
            path: path,
        })
    }
}

impl <'a>  Queryable for QueryFile<'a> {
    fn query(&self, key: &str) -> Option<String> {
        match key {
            "size" => Some(format!("{}", self.metadata.len())),
            "filetype" => {
                let filetype = self.metadata.file_type();
                if filetype.is_symlink() {
                    Some("symlink".to_owned())
                } else if filetype.is_dir() {
                    Some("directory".to_owned())
                } else {
                    Some("file".to_owned())
                }
            },
            "extension" => match self.path.extension() {
                Some(os_str) => match os_str.to_str() {
                    Some(s) => Some(s.to_owned()),
                    None => None,
                },
                None => None,
            },
            "filename" => match self.path.file_name() {
                Some(os_str) => match os_str.to_str() {
                    Some(s) => Some(s.to_owned()),
                    None => None,
                },
                None => None,
            },
            "mimetype" => Some(format!("{}", mime_guess::guess_mime_type(self.path))),
            _ => None,
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate liquery;
    use super::*;
    use liquery::Queryable;
    use std::path::Path;

    macro_rules! query_test {
        ($name: ident, $field: expr, $out: expr) => {
            query_test!($name, $field, $out, "tests/file_1b.txt");
        };
        ($name: ident, $field: expr, $out: expr, $path: expr) => {
            #[test]
            fn $name() {
                let path = Path::new($path);
                let queryable = QueryFile::new(path).unwrap();

                assert_eq!($out, &queryable.query($field).unwrap());
            }
        };
    }

    macro_rules! query_test_no_result {
        ($name: ident, $field: expr) => {
            query_test_no_result!($name, $field, "tests/file_1b.txt");
        };
        ($name: ident, $field: expr, $path: expr) => {
            #[test]
            fn $name() {
                let path = Path::new($path);
                let queryable = QueryFile::new(path).unwrap();

                assert_eq!(None, queryable.query($field));
            }
        };
    }

    query_test!(size_of_file, "size", "1");

    query_test!(file_type_file, "filetype", "file");
    query_test!(file_type_dir, "filetype", "directory", "tests");
    query_test!(file_type_symlink, "filetype", "symlink", "tests/target");

    query_test!(file_name, "filename", "file_1b.txt");
    query_test!(file_name_dir, "filename", "tests", "tests");

    query_test!(file_extension, "extension", "txt");
    query_test_no_result!(file_extension_dir, "extension", "tests");

    query_test!(file_mime, "mimetype", "text/plain");
    query_test!(file_mime_rust, "mimetype", "text/x-rust", "src/lib.rs");

    query_test_no_result!(unkown_feild, "unkown");
    query_test_no_result!(empty_feild, "");
}
<|endoftext|>


<commit_before>#![warn(missing_docs)]

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`)
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(missing_docs)]
    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(missing_docs)]
    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    #[allow(missing_docs)]
    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[allow(missing_docs)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    #[allow(missing_docs)]
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    #[allow(missing_docs)]
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    #[allow(missing_docs)]
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    #[allow(missing_docs)]
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    #[allow(missing_docs)]
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    #[allow(missing_docs)]
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().map(|x| *x))
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        //input_rebind.keymap = self.keymap.btn_map.
        //input_rebind.keymap = self.keymap.btn_map.drain().map(|(k, v)| (v, k)).collect();
        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}

<commit_msg>Add crate documentation header<commit_after>#![warn(missing_docs)]

//! input-map
//! =========
//!
//! A library for binding input keys to actions, and manipulating mouse input

extern crate input;
extern crate piston_window;
extern crate rustc_serialize;
extern crate viewport;

mod builder;

use input::{Input, Button, Motion};
use piston_window::Size;
use std::collections::HashMap;
use std::default::Default;
use std::hash::Hash;
use viewport::Viewport;

pub use builder::InputTranslatorBuilder;

/// Represents a logical action to be bound to a particular button press, e.g.
/// jump, attack, or move forward
pub trait Action: Copy + PartialEq + Eq + Hash { }

/// A translated action.
#[derive(Debug, Copy, Clone)]
pub enum Translated<A: Action> {
    /// A keypress event which was bound to an action
    Press(A),

    /// A key release event which was bound to an action
    Release(A),

    /// A translated mouse motion. The logical origin of a translated MouseCursor event
    /// is in the top left corner of the window, and the logical scroll is non-natural.
    /// Relative events are unchanged for now.
    Move(Motion)
}

/// A three-element tuple of Option<Button>. Used as the key of an InputTranslator
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct ButtonTuple(pub Option<Button>, pub Option<Button>, pub Option<Button>);

impl ButtonTuple {
    /// Creates a new tuple with no buttons in it (equivalent to `Default::default()`)
    pub fn new() -> Self { Default::default() }

    /// Check if the button is in the tuple.
    pub fn contains(&self, button: Button) -> bool {
        let sbtn = Some(button);
        self.0 == sbtn || self.1 == sbtn || self.2 == sbtn
    }

    #[allow(missing_docs)]
    pub fn remove_inplace(&mut self, btn: Button) {
        let sbtn = Some(btn);
        if self.0 == sbtn {self.0 = None}
        if self.1 == sbtn {self.1 = None}
        if self.2 == sbtn {self.2 = None}
    }

    #[allow(missing_docs)]
    pub fn replace_inplace(&mut self, btn_idx: u32, btn: Button) -> bool {
        match btn_idx {
            0 => {self.0 = Some(btn); true},
            1 => {self.1 = Some(btn); true},
            2 => {self.2 = Some(btn); true},
            _ => false
        }
    }

    #[allow(missing_docs)]
    pub fn insert_inplace(&mut self, btn: Button) -> bool {
        match self {
            &mut ButtonTuple(a, b, c) if a.is_none() => {*self = ButtonTuple(Some(btn), b, c); true},
            &mut ButtonTuple(a, b, c) if b.is_none() => {*self = ButtonTuple(a, Some(btn), c); true},
            &mut ButtonTuple(a, b, c) if c.is_none() => {*self = ButtonTuple(a, b, Some(btn)); true}
            _ => false
        }
    }
}

impl Default for ButtonTuple {
    /// Creates a new tuple with no buttons in it
    fn default() -> Self { ButtonTuple(None, None, None) }
}

/// An object which translates piston::input::Input events into input_map::Translated<A> events
#[derive(Clone)]
pub struct InputTranslator<A: Action> {
    keymap: HashMap<Button, A>,
    mouse_translator: MouseTranslator
}

impl<A: Action> InputTranslator<A> {

    /// Creates an empty InputTranslator.
    pub fn new(size: Size) -> Self {
        InputTranslator {
            keymap: HashMap::new(),
            mouse_translator: MouseTranslator::new(size)
        }
    }

    /// Translate an Input into a Translated<A> event
    pub fn translate(&self, input: &Input) -> Option<Translated<A>> {
        macro_rules! translate_button(($but_state:ident, $but_var:ident) => (
            match self.keymap.get(&$but_var).map(|x| *x) {
                Some(act) => Some(Translated::$but_state(act)),
                None => None
            });
        );

        match input {
            &Input::Press(button) => translate_button!(Press, button),
            &Input::Release(button) => translate_button!(Release, button),
            &Input::Move(motion) =>
                Some(Translated::Move(self.mouse_translator.translate(motion))),
            _ => None
        }
    }

    /// Re-set the mouse bounds size used for calculating mouse events
    pub fn set_size(&mut self, size: Size) {
        self.mouse_translator.data.viewport_size = size
    }

    /// Re-set the mouse bounds size from a viewport
    pub fn set_size_from_viewport(&mut self, vp: Viewport) {
        self.set_size(Size::from(vp.draw_size));
    }
}

#[derive(Clone)]
struct MouseTranslationData {
    x_axis_motion_inverted: bool,
    y_axis_motion_inverted: bool,
    x_axis_scroll_inverted: bool,
    y_axis_scroll_inverted: bool,
    viewport_size: Size
}

impl MouseTranslationData {
    fn new(size: Size) -> Self {
        MouseTranslationData {
            x_axis_motion_inverted: false,
            y_axis_motion_inverted: false,
            x_axis_scroll_inverted: false,
            y_axis_scroll_inverted: false,
            viewport_size: size
        }
    }
}

#[derive(Clone)]
struct MouseTranslator {
    data: MouseTranslationData
}

impl MouseTranslator {
    fn new(size: Size) -> Self {
        MouseTranslator {
            data: MouseTranslationData::new(size)
        }
    }

    fn translate(&self, motion: Motion) -> Motion {
        match motion {
            Motion::MouseCursor(x, y) => {
                let (sw, sh) = {
                    let Size {width, height} = self.data.viewport_size;
                    (width as f64, height as f64)
                };

                let cx = if self.data.x_axis_motion_inverted { sw - x } else { x };
                let cy = if self.data.y_axis_motion_inverted { sh - y } else { y };

                Motion::MouseCursor(cx, cy)
            },
            Motion::MouseScroll(x, y) => {
                let mx = if self.data.x_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                let my = if self.data.y_axis_scroll_inverted { -1.0f64 } else { 1.0 };
                Motion::MouseScroll(x * mx, y * my)
            },
            relative => relative
        }
    }
}

#[allow(missing_docs)]
pub struct InputRebind<A: Action> {
    keymap: HashMap<A, ButtonTuple>,
    mouse_data: MouseTranslationData
}

impl<A: Action> InputRebind<A> {
    #[allow(missing_docs)]
    pub fn new(size: Size) -> Self {
        InputRebind {
            keymap: HashMap::new(),
            mouse_data: MouseTranslationData::new(size)
        }
    }

    #[allow(missing_docs)]
    pub fn insert_action(&mut self, action: A) -> Option<ButtonTuple> {
        self.keymap.insert(action, ButtonTuple::new())
    }

    #[allow(missing_docs)]
    pub fn insert_action_with_buttons(&mut self, action: A, buttons: ButtonTuple) -> Option<ButtonTuple> {
        self.keymap.insert(action, buttons)
    }

    #[allow(missing_docs)]
    pub fn get_bindings(&self, action: &A) -> Option<&ButtonTuple> {
        self.keymap.get(action)
    }

    #[allow(missing_docs)]
    pub fn get_bindings_mut(&mut self, action: &mut A) -> Option<&mut ButtonTuple> {
        self.keymap.get_mut(action)
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_scroll_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_scroll_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted(&self) -> &bool {
        &self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_x_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.x_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted(&self) -> &bool {
        &self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_y_motion_inverted_mut(&mut self) -> &mut bool {
        &mut self.mouse_data.y_axis_motion_inverted
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size(&self) -> &Size {
        &self.mouse_data.viewport_size
    }

    #[allow(missing_docs)]
    pub fn get_viewport_size_mut(&mut self) -> &mut Size {
        &mut self.mouse_data.viewport_size
    }
}

impl<A: Action> Default for InputRebind<A> {
    #[allow(missing_docs)]
    fn default() -> Self {
        InputRebind::new((800, 600).into())
    }
}

impl<A: Action> Into<InputTranslator<A>> for InputRebind<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputTranslator<A> {
        let mut input_translator = InputTranslator::new(self.mouse_data.viewport_size);
        input_translator.mouse_translator.data = self.mouse_data;
        input_translator.keymap = self.keymap.values()
                                             .flat_map(|&bt| bt.into_iter())
                                             .filter_map(|x| x)
                                             .zip(self.keymap.keys().map(|x| *x))
                                             .collect();

        input_translator
    }
}

impl<A: Action> Into<InputRebind<A>> for InputTranslator<A> {
    #[allow(missing_docs)]
    fn into(self) -> InputRebind<A> {
        let mut input_rebind = InputRebind::new(self.mouse_translator.data.viewport_size);
        input_rebind.mouse_data = self.mouse_translator.data;
        //input_rebind.keymap = self.keymap.btn_map.
        //input_rebind.keymap = self.keymap.btn_map.drain().map(|(k, v)| (v, k)).collect();
        input_rebind
    }
}

impl ButtonTuple {
    fn into_iter(self) -> ButtonTupleIterator {
        ButtonTupleIterator {
            button_tuple: self,
            i: 0
        }
    }
}

struct ButtonTupleIterator {
    button_tuple: ButtonTuple,
    i: usize
}

impl Iterator for ButtonTupleIterator {
    type Item = Option<Button>;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.i;
        self.i += 1;
        match i {
            0 => Some(self.button_tuple.0),
            1 => Some(self.button_tuple.1),
            2 => Some(self.button_tuple.2),
            _ => None
        }
    }
}

<|endoftext|>


<commit_before>#![feature(core)]

extern crate atom;

use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::mem;
use atom::Atom;

use std::boxed::FnBox;

pub use select::Select;
pub use barrier::Barrier;
mod select;
mod barrier;

/// Drop rules
/// This may be freed iff state is Pulsed | Dropped
/// and Waiting is Dropped
struct Inner {
    state: AtomicUsize,
    waiting: Atom<Waiting, Box<Waiting>>
}

// TODO 64bit sized, probably does not matter now
const PULSED: usize = 0x8000_0000;
const TX_DROP: usize = 0x4000_0000;
const TX_FLAGS: usize = PULSED | TX_DROP;
const REF_COUNT: usize = !TX_FLAGS;

struct Waiting {
    next: Option<Box<Waiting>>,
    wake: Wake
}

enum Wake {
    Thread(thread::Thread),
    Select(select::Handle),
    Barrier(barrier::Handle),
    Callback(Box<FnBox() + Send>)
}

impl Waiting {
    fn trigger(s: Box<Self>, id: usize) {
        let mut next = Some(s);
        while let Some(s) = next {
            let s = *s;
            let Waiting { next: n, wake } = s;
            next = n;
            match wake {
                Wake::Thread(thread) => thread.unpark(),
                Wake::Select(select) => {
                    let trigger = {
                        let mut guard = select.0.lock().unwrap();
                        guard.ready.push(id);
                        guard.trigger.take()
                    };
                    trigger.map(|x| x.pulse());
                }
                Wake::Barrier(barrier) => {
                    let count = barrier.0.count.fetch_sub(1, Ordering::Relaxed);
                    if count == 1 {
                        let mut guard = barrier.0.trigger.lock().unwrap();
                        if let Some(t) = guard.take() {
                            t.pulse();
                        }
                    }
                }
                Wake::Callback(cb) => cb()
            }
        }
    }

    fn thread() -> Box<Waiting> {
        Box::new(Waiting {
            next: None,
            wake: Wake::Thread(thread::current())
        })
    }

    fn select(handle: select::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Select(handle)
        })
    }

    fn barrier(handle: barrier::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Barrier(handle)
        })
    }

    fn callback(f: Box<FnBox() + Send>) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Callback(f)
        })
    }
}

unsafe impl Send for Trigger {}

pub struct Trigger {
    inner: *mut Inner,
    pulsed: bool
}

fn delete_inner(state: usize, inner: *mut Inner) {
    if state & REF_COUNT == 1 {
        let inner: Box<Inner> = unsafe {
            mem::transmute(inner)
        };
        drop(inner);
    }
}

impl Drop for Trigger {
    fn drop(&mut self) {
        if !self.pulsed {
            self.set(TX_DROP);
            self.wake();
        }
        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner)
    }
}

impl Trigger {
    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    fn set(&self, state: usize) -> usize {
        self.inner().state.fetch_or(state, Ordering::Relaxed)
    }

    fn wake(&self) {
        let id = unsafe { mem::transmute(self.inner) };
        match self.inner().waiting.take(Ordering::Acquire) {
            None => (),
            Some(v) => Waiting::trigger(v, id)
        }
    }

    /// Trigger an pulse, this can only occure once
    /// Returns true if this triggering triggered the pulse
    pub fn pulse(mut self) {
        self.pulsed = true;
        self.set(PULSED);
        self.wake();

        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner);
        unsafe { mem::forget(self) }
    }
}

unsafe impl Send for Pulse {}

pub struct Pulse(*mut Inner);

impl Clone for Pulse {
    fn clone(&self) -> Pulse {
        self.inner().state.fetch_add(1, Ordering::Relaxed);
        Pulse(self.0)
    }
}

impl Drop for Pulse {
    fn drop(&mut self) {
        let flag = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(flag, self.0);
    }
}

impl Pulse {
    pub fn new() -> (Pulse, Trigger) {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(2),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        (Pulse(inner),
         Trigger{
            inner: inner,
            pulsed: false
        })
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.0) }
    }

    // Read out the state of the Pulse
    fn state(&self) -> usize {
        self.inner().state.load(Ordering::Relaxed)
    }

    // Check to see if the pulse is pending or not
    pub fn is_pending(&self) -> bool {
        self.state() & TX_FLAGS == 0
    }

    // Check to see if the pulse is pending or not
    fn in_use(&self) -> bool {
        let state = self.state();
        (state & REF_COUNT) != 1 || (state & TX_FLAGS) == 0
    }

    /// Arm a pulse to wake
    fn arm(&self, waiter: Box<Waiting>) {
        let old = self.inner().waiting.swap(
            waiter,
            Ordering::AcqRel
        );

        // if armed fire now
        if !self.is_pending() {
            if let Some(t) = self.inner().waiting.take(Ordering::Acquire) {
                Waiting::trigger(t, self.id());
            }
        }

        if old.is_some() {
            panic!("Pulse cannot be waited on by multiple clients");
        }
    }

    /// Disarm a pulse
    fn disarm(&self) {
        self.inner().waiting.take(Ordering::Acquire);
    }

    /// Wait for an pulse to be triggered
    ///
    /// Panics if something else is waiting on this already
    pub fn wait(&self) -> Result<(), WaitError> {
        loop {
            if !self.is_pending() {
                let state = self.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(WaitError(state))
                };
            }

            self.arm(Waiting::thread());

            if self.is_pending() {
                // wait for wake
                thread::park();
            }
            self.disarm();
        }
    }

    pub fn id(&self) -> usize {
        unsafe { mem::transmute_copy(&self.0) }
    }

    pub fn recycle(&self) -> Option<Trigger> {
        if self.in_use() {
            None
        } else {
            self.inner().state.store(2, Ordering::Relaxed);
            Some(Trigger{
                inner: self.0,
                pulsed: false,
            })
        }
    }

    pub fn on_complete<F>(self, f: F) where F: FnOnce() + Send + 'static {
        self.arm(Waiting::callback(Box::new(f)));
    }
}

#[derive(Debug)]
pub struct WaitError(usize);<commit_msg>Added GetNextMut to Waiting<commit_after>#![feature(core)]

extern crate atom;

use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use std::mem;
use atom::{Atom, GetNextMut};

use std::boxed::FnBox;

pub use select::Select;
pub use barrier::Barrier;
mod select;
mod barrier;

/// Drop rules
/// This may be freed iff state is Pulsed | Dropped
/// and Waiting is Dropped
struct Inner {
    state: AtomicUsize,
    waiting: Atom<Waiting, Box<Waiting>>
}

// TODO 64bit sized, probably does not matter now
const PULSED: usize = 0x8000_0000;
const TX_DROP: usize = 0x4000_0000;
const TX_FLAGS: usize = PULSED | TX_DROP;
const REF_COUNT: usize = !TX_FLAGS;

struct Waiting {
    next: Option<Box<Waiting>>,
    wake: Wake
}

impl GetNextMut for Waiting {
    type NextPtr = Option<Box<Waiting>>;

    fn get_next(&mut self) -> &mut Option<Box<Waiting>> {
        &mut self.next
    }
}

enum Wake {
    Thread(thread::Thread),
    Select(select::Handle),
    Barrier(barrier::Handle),
    Callback(Box<FnBox() + Send>)
}

impl Waiting {
    fn trigger(s: Box<Self>, id: usize) {
        let mut next = Some(s);
        while let Some(s) = next {
            // There must be a better way to do this...
            let s = *s;
            let Waiting { next: n, wake } = s;
            next = n;
            match wake {
                Wake::Thread(thread) => thread.unpark(),
                Wake::Select(select) => {
                    let trigger = {
                        let mut guard = select.0.lock().unwrap();
                        guard.ready.push(id);
                        guard.trigger.take()
                    };
                    trigger.map(|x| x.pulse());
                }
                Wake::Barrier(barrier) => {
                    let count = barrier.0.count.fetch_sub(1, Ordering::Relaxed);
                    if count == 1 {
                        let mut guard = barrier.0.trigger.lock().unwrap();
                        if let Some(t) = guard.take() {
                            t.pulse();
                        }
                    }
                }
                Wake::Callback(cb) => cb()
            }
        }
    }

    fn thread() -> Box<Waiting> {
        Box::new(Waiting {
            next: None,
            wake: Wake::Thread(thread::current())
        })
    }

    fn select(handle: select::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Select(handle)
        })
    }

    fn barrier(handle: barrier::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Barrier(handle)
        })
    }

    fn callback(f: Box<FnBox() + Send>) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Callback(f)
        })
    }
}

unsafe impl Send for Trigger {}

pub struct Trigger {
    inner: *mut Inner,
    pulsed: bool
}

fn delete_inner(state: usize, inner: *mut Inner) {
    if state & REF_COUNT == 1 {
        let inner: Box<Inner> = unsafe {
            mem::transmute(inner)
        };
        drop(inner);
    }
}

impl Drop for Trigger {
    fn drop(&mut self) {
        if !self.pulsed {
            self.set(TX_DROP);
            self.wake();
        }
        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner)
    }
}

impl Trigger {
    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    fn set(&self, state: usize) -> usize {
        self.inner().state.fetch_or(state, Ordering::Relaxed)
    }

    fn wake(&self) {
        let id = unsafe { mem::transmute(self.inner) };
        match self.inner().waiting.take(Ordering::Acquire) {
            None => (),
            Some(v) => Waiting::trigger(v, id)
        }
    }

    /// Trigger an pulse, this can only occure once
    /// Returns true if this triggering triggered the pulse
    pub fn pulse(mut self) {
        self.pulsed = true;
        self.set(PULSED);
        self.wake();

        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner);
        unsafe { mem::forget(self) }
    }
}

unsafe impl Send for Pulse {}

pub struct Pulse(*mut Inner);

impl Clone for Pulse {
    fn clone(&self) -> Pulse {
        self.inner().state.fetch_add(1, Ordering::Relaxed);
        Pulse(self.0)
    }
}

impl Drop for Pulse {
    fn drop(&mut self) {
        let flag = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(flag, self.0);
    }
}

impl Pulse {
    pub fn new() -> (Pulse, Trigger) {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(2),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        (Pulse(inner),
         Trigger{
            inner: inner,
            pulsed: false
        })
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.0) }
    }

    // Read out the state of the Pulse
    fn state(&self) -> usize {
        self.inner().state.load(Ordering::Relaxed)
    }

    // Check to see if the pulse is pending or not
    pub fn is_pending(&self) -> bool {
        self.state() & TX_FLAGS == 0
    }

    // Check to see if the pulse is pending or not
    fn in_use(&self) -> bool {
        let state = self.state();
        (state & REF_COUNT) != 1 || (state & TX_FLAGS) == 0
    }

    /// Arm a pulse to wake
    fn arm(&self, waiter: Box<Waiting>) {
        let old = self.inner().waiting.swap(
            waiter,
            Ordering::AcqRel
        );

        // if armed fire now
        if !self.is_pending() {
            if let Some(t) = self.inner().waiting.take(Ordering::Acquire) {
                Waiting::trigger(t, self.id());
            }
        }

        if old.is_some() {
            panic!("Pulse cannot be waited on by multiple clients");
        }
    }

    /// Disarm a pulse
    fn disarm(&self) {
        self.inner().waiting.take(Ordering::Acquire);
    }

    /// Wait for an pulse to be triggered
    ///
    /// Panics if something else is waiting on this already
    pub fn wait(&self) -> Result<(), WaitError> {
        loop {
            if !self.is_pending() {
                let state = self.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(WaitError(state))
                };
            }

            self.arm(Waiting::thread());

            if self.is_pending() {
                // wait for wake
                thread::park();
            }
            self.disarm();
        }
    }

    pub fn id(&self) -> usize {
        unsafe { mem::transmute_copy(&self.0) }
    }

    pub fn recycle(&self) -> Option<Trigger> {
        if self.in_use() {
            None
        } else {
            self.inner().state.store(2, Ordering::Relaxed);
            Some(Trigger{
                inner: self.0,
                pulsed: false,
            })
        }
    }

    pub fn on_complete<F>(self, f: F) where F: FnOnce() + Send + 'static {
        self.arm(Waiting::callback(Box::new(f)));
    }
}

#[derive(Debug)]
pub struct WaitError(usize);<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::all)]
#![allow(improper_ctypes)]
//! This module exposes the raw [HTSlib](https://github.com/samtools/htslib) bindings for reading and writing
//! genomics file formats like SAM, BAM, CRAM, VCF, BCF and tabix.
//! Instead of using this crate directly, it is recommended to use [rust-htslib](https://docs.rs/rust-htslib)
//! instead, which has a more idiomatic and high-level API and builds on top of this crate.

#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "curl")]
extern crate curl_sys;
#[cfg(feature = "libdeflate")]
extern crate libdeflate_sys;
extern crate libz_sys;
#[cfg(feature = "lzma")]
extern crate lzma_sys;

// include on-the-fly generated bindings
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<commit_msg>refactor: fmt<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::all)]
#![allow(improper_ctypes)]
//! This module exposes the raw [HTSlib](https://github.com/samtools/htslib) bindings for reading and writing
//! genomics file formats like SAM, BAM, CRAM, VCF, BCF and tabix.
//! Instead of using this crate directly, it is recommended to use [rust-htslib](https://docs.rs/rust-htslib)
//! instead, which has a more idiomatic and high-level API and builds on top of this crate.

#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "curl")]
extern crate curl_sys;
#[cfg(feature = "libdeflate")]
extern crate libdeflate_sys;
extern crate libz_sys;
#[cfg(feature = "lzma")]
extern crate lzma_sys;

// include on-the-fly generated bindings
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<|endoftext|>


<commit_before>extern crate libc;
#[macro_use]
extern crate log;
extern crate openssl_sys;
extern crate rand;
extern crate rustc_serialize;

pub mod crypto;

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Add missing lib.rs changes<commit_after>#[macro_use]
extern crate hyper;
extern crate hyper_native_tls;
extern crate libc;
#[macro_use]
extern crate log;
extern crate openssl_sys;
extern crate rand;
extern crate rustc_serialize;

pub mod crypto;
pub mod subscription;

<|endoftext|>


<commit_before>#![deny(unused_mut)]
#![feature(io)]
#[macro_use]
extern crate hyper;
extern crate protobuf;
extern crate proto; // mesos protobuf messages, bad name?
extern crate zookeeper;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate rustc_serialize;

mod master_detector;
pub mod scheduler;
pub mod scheduler_driver;
mod executor;
mod executor_driver;
#[allow(non_upper_case_globals)]
mod http_api;
<commit_msg>Reexport proto create since usage of rust-mesos depends on it.<commit_after>#![deny(unused_mut)]
#![feature(io)]
#[macro_use]
extern crate hyper;
extern crate protobuf;

// mesos protobuf messages, bad name?
//
// We want to reexport the messages as part of this crate.
// Otherwise one cannot use the provided interfaces.
// `pub extern crate` does not work. See https://github.com/rust-lang/rust/issues/21757
// This is why import crate for a different name here such that we can use pub use below.
extern crate proto as proto_crate;

extern crate zookeeper;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate rustc_serialize;

pub use proto_crate as proto;

mod master_detector;
pub mod scheduler;
pub mod scheduler_driver;
mod executor;
mod executor_driver;
#[allow(non_upper_case_globals)]
mod http_api;
<|endoftext|>


<commit_before>extern crate nalgebra as na;

use std::io::{self, Write};
pub use bounds::Bounds;
pub use na::Vec2;

pub mod bounds;

pub type Position = na::Pnt2<f32>;

fn pmin(p1: Position, p2: Position) -> Position {
    Position::new(p1.x.min(p2.x), p1.y.min(p2.y))
}

fn pmax(p1: Position, p2: Position) -> Position {
    Position::new(p1.x.max(p2.x), p1.y.max(p2.y))
}

fn ptransform(p: Position, translation: Vec2<f32>, scale: Vec2<f32>) -> Position {
    let n = p + translation;
    Position::new(n.x * scale.x, n.y * scale.y)
}

pub trait Shape {
    fn bounds(&self) -> Bounds;
    fn write_eps(&self, wr: &mut Write) -> io::Result<()>;
    fn transform(&mut self, translation: Vec2<f32>, scale: Vec2<f32>);
}

pub struct SetRGB(pub f32, pub f32, pub f32);
pub struct Point(pub Position, pub f32);
pub struct Points(pub Vec<Position>, pub f32);
pub struct Line(pub Position, pub Position);
pub struct Lines(pub Vec<(Position, Position)>);
pub struct PolyLine(pub Vec<Position>);

impl Shape for SetRGB {
    fn bounds(&self) -> Bounds {
        Bounds::new()
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        writeln!(wr, "{:.2} {:.2} {:.2} setrgbcolor", self.0, self.1, self.2)
    }

    fn transform(&mut self, _translation: Vec2<f32>, _scale: Vec2<f32>) {}
}

impl Shape for Point {
    fn bounds(&self) -> Bounds {
        let mut b = Bounds::new();
        b.add_position(self.0);
        b
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        writeln!(wr,
                 "newpath {} {} {} 0 360 arc fill",
                 self.0.x,
                 self.0.y,
                 self.1)
    }

    fn transform(&mut self, translation: Vec2<f32>, scale: Vec2<f32>) {
        self.0 = ptransform(self.0, translation, scale);
    }
}

impl Shape for Points {
    fn bounds(&self) -> Bounds {
        let mut b = Bounds::new();
        for &pos in &self.0 {
            b.add_position(pos);
        }
        b
    }

    fn transform(&mut self, translation: Vec2<f32>, scale: Vec2<f32>) {
        for p in self.0.iter_mut() {
            *p = ptransform(*p, translation, scale);
        }
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        try!(writeln!(wr,
                      "/p {{
2 dict begin
/y exch def
/x exch def
gsave
newpath x y {} 0 360 \
                       arc fill
grestore
end
}} def",
                      self.1));
        for pos in &self.0 {
            try!(writeln!(wr, "{:.4} {:.4} p", pos.x, pos.y));
        }

        Ok(())
    }
}

impl Shape for Lines {
    fn bounds(&self) -> Bounds {
        let mut b = Bounds::new();
        for &(p1, p2) in &self.0 {
            b.add_position(p1);
            b.add_position(p2);
        }
        b
    }

    fn transform(&mut self, translation: Vec2<f32>, scale: Vec2<f32>) {
        for &mut (ref mut p1, ref mut p2) in self.0.iter_mut() {
            *p1 = ptransform(*p1, translation, scale);
            *p2 = ptransform(*p2, translation, scale);
        }
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        try!(writeln!(wr,
                      "/l {{
2 dict begin
/y2 exch def
/x2 exch def
/y1 exch def
/x1 exch def
\
                       gsave
newpath x1 y1 moveto x2 y2 lineto stroke
grestore
end
}} def"));
        for &(p1, p2) in &self.0 {
            try!(writeln!(wr, "{:.4} {:.4} {:.4} {:.4} l", p1.x, p1.y, p2.x, p2.y));
        }

        Ok(())
    }
}

impl Shape for Line {
    fn bounds(&self) -> Bounds {
        let mut b = Bounds::new();
        b.add_position(self.0);
        b.add_position(self.1);
        b
    }

    fn transform(&mut self, translation: Vec2<f32>, scale: Vec2<f32>) {
        self.0 = ptransform(self.0, translation, scale);
        self.1 = ptransform(self.1, translation, scale);
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        writeln!(wr,
                 "newpath {} {} moveto {} {} lineto stroke",
                 self.0.x,
                 self.0.y,
                 self.1.x,
                 self.1.y)
    }
}

impl Shape for PolyLine {
    fn bounds(&self) -> Bounds {
        let mut b = Bounds::new();
        for &p in &self.0 {
            b.add_position(p);
        }
        b
    }

    fn transform(&mut self, translation: Vec2<f32>, scale: Vec2<f32>) {
        for p in self.0.iter_mut() {
            *p = ptransform(*p, translation, scale);
        }
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        match self.0.split_first() {
            Some((first, tail)) if tail.len() > 0 => {
                try!(write!(wr, "newpath {:.4} {:.4} moveto ", first.x, first.y));
                for l in tail {
                    try!(write!(wr, "{:.4} {:.4} lineto ", l.x, l.y));
                }
                try!(writeln!(wr, "stroke"));
            }
            _ => {}
        }
        Ok(())
    }
}

pub struct EpsDocument {
    shapes: Vec<Box<Shape>>,
}

impl EpsDocument {
    pub fn new() -> EpsDocument {
        EpsDocument { shapes: Vec::new() }
    }

    pub fn add_shape(&mut self, shape: Box<Shape>) {
        self.shapes.push(shape);
    }

    pub fn get_bounds(&self) -> Bounds {
        // Determine extend of canvas
        let mut bounds = Bounds::new();

        for shape in &self.shapes {
            bounds.extend(shape.bounds());
        }

        bounds
    }

    pub fn transform(&mut self, translate: Vec2<f32>, scale: Vec2<f32>) {
        for shape in self.shapes.iter_mut() {
            shape.transform(translate, scale);
        }
    }

    /// Write as Embedded Postscript (EPS)
    pub fn write_eps(&self, wr: &mut Write, min_width: f32, min_height: f32) -> io::Result<()> {
        let bounds = self.get_bounds();

        let width = bounds.width().max(min_width);
        let height = bounds.height().max(min_height);
        let border_percent = 0.1;

        let scale = 1.0 + 2.0 * border_percent;

        try!(writeln!(wr,
                      r#"%%!PS-Adobe-3.0 EPSF-3.0
%%Creator: https://github.com/mneumann/eps-writer-rs
%%DocumentData: Clean7Bit
%%Origin: 0 0
%%BoundingBox: {} {} {} {}
%%HiResBoundingBox: {} {} {} {}
%%LanguageLevel: 2
%%Pages: 1
%%Page: 1 1
"#,
                      (bounds.min_x() - border_percent * width) as isize,
                      (bounds.min_y() - border_percent * height) as isize,
                      (bounds.max_x() + border_percent * width) as isize,
                      (bounds.max_y() + border_percent * height) as isize,

                      bounds.min_x() - border_percent * width,
                      bounds.min_y() - border_percent * height,
                      bounds.max_x() + border_percent * width,
                      bounds.max_y() + border_percent * height));

        // use a stroke width of 0.1% of the width or height of the canvas
        let stroke_width = scale * width.max(height) / 1000.0;
        try!(writeln!(wr, r#"{} setlinewidth"#, stroke_width));

        for shape in &self.shapes {
            try!(shape.write_eps(wr));
        }

        writeln!(wr, "%%EOF")
    }
}
<commit_msg>Introduce visit_pos and visit_pos_mut visitors.<commit_after>extern crate nalgebra as na;

use std::io::{self, Write};
pub use bounds::Bounds;
pub use na::Vec2;

pub mod bounds;

pub type Position = na::Pnt2<f32>;

fn pmin(p1: Position, p2: Position) -> Position {
    Position::new(p1.x.min(p2.x), p1.y.min(p2.y))
}

fn pmax(p1: Position, p2: Position) -> Position {
    Position::new(p1.x.max(p2.x), p1.y.max(p2.y))
}

fn ptransform(p: Position, translation: Vec2<f32>, scale: Vec2<f32>) -> Position {
    let n = p + translation;
    Position::new(n.x * scale.x, n.y * scale.y)
}

pub trait Shape {
    fn visit_pos(&self, cb: &mut FnMut(&Position));
    fn visit_pos_mut(&mut self, cb: &mut FnMut(&mut Position));

    fn bounds(&self) -> Bounds {
        let mut b = Bounds::new();
        self.visit_pos(&mut |p| b.add_position(*p));
        b
    }

    fn transform(&mut self, translation: Vec2<f32>, scale: Vec2<f32>) {
        self.visit_pos_mut(&mut |p| *p = ptransform(*p, translation, scale));
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()>;
}

pub struct SetRGB(pub f32, pub f32, pub f32);
pub struct Point(pub Position, pub f32);
pub struct Points(pub Vec<Position>, pub f32);
pub struct Line(pub Position, pub Position);
pub struct Lines(pub Vec<(Position, Position)>);
pub struct PolyLine(pub Vec<Position>);

impl Shape for SetRGB {
    fn visit_pos(&self, _cb: &mut FnMut(&Position)) {}
    fn visit_pos_mut(&mut self, _cb: &mut FnMut(&mut Position)) {}

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        writeln!(wr, "{:.2} {:.2} {:.2} setrgbcolor", self.0, self.1, self.2)
    }
}

impl Shape for Point {
    fn visit_pos(&self, cb: &mut FnMut(&Position)) {
        cb(&self.0);
    }
    fn visit_pos_mut(&mut self, cb: &mut FnMut(&mut Position)) {
        cb(&mut self.0);
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        writeln!(wr,
                 "newpath {} {} {} 0 360 arc fill",
                 self.0.x,
                 self.0.y,
                 self.1)
    }
}

impl Shape for Points {
    fn visit_pos(&self, cb: &mut FnMut(&Position)) {
        for p in &self.0 {
            cb(p);
        }
    }
    fn visit_pos_mut(&mut self, cb: &mut FnMut(&mut Position)) {
        for p in &mut self.0 {
            cb(p);
        }
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        try!(writeln!(wr,
                      "/p {{
2 dict begin
/y exch def
/x exch def
gsave
newpath x y {} 0 360 \
                       arc fill
grestore
end
}} def",
                      self.1));
        for pos in &self.0 {
            try!(writeln!(wr, "{:.4} {:.4} p", pos.x, pos.y));
        }

        Ok(())
    }
}

impl Shape for Lines {
    fn visit_pos(&self, cb: &mut FnMut(&Position)) {
        for &(ref p1, ref p2) in &self.0 {
            cb(p1);
            cb(p2);
        }
    }
    fn visit_pos_mut(&mut self, cb: &mut FnMut(&mut Position)) {
        for &mut (ref mut p1, ref mut p2) in &mut self.0 {
            cb(p1);
            cb(p2);
        }
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        try!(writeln!(wr,
                      "/l {{
2 dict begin
/y2 exch def
/x2 exch def
/y1 exch def
/x1 exch def
\
                       gsave
newpath x1 y1 moveto x2 y2 lineto stroke
grestore
end
}} def"));
        for &(p1, p2) in &self.0 {
            try!(writeln!(wr, "{:.4} {:.4} {:.4} {:.4} l", p1.x, p1.y, p2.x, p2.y));
        }

        Ok(())
    }
}

impl Shape for Line {
    fn visit_pos(&self, cb: &mut FnMut(&Position)) {
        cb(&self.0);
        cb(&self.1);
    }
    fn visit_pos_mut(&mut self, cb: &mut FnMut(&mut Position)) {
        cb(&mut self.0);
        cb(&mut self.1);
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        writeln!(wr,
                 "newpath {} {} moveto {} {} lineto stroke",
                 self.0.x,
                 self.0.y,
                 self.1.x,
                 self.1.y)
    }
}

impl Shape for PolyLine {
    fn visit_pos(&self, cb: &mut FnMut(&Position)) {
        for p in &self.0 {
            cb(p);
        }
    }
    fn visit_pos_mut(&mut self, cb: &mut FnMut(&mut Position)) {
        for p in &mut self.0 {
            cb(p);
        }
    }

    fn write_eps(&self, wr: &mut Write) -> io::Result<()> {
        match self.0.split_first() {
            Some((first, tail)) if tail.len() > 0 => {
                try!(write!(wr, "newpath {:.4} {:.4} moveto ", first.x, first.y));
                for l in tail {
                    try!(write!(wr, "{:.4} {:.4} lineto ", l.x, l.y));
                }
                try!(writeln!(wr, "stroke"));
            }
            _ => {}
        }
        Ok(())
    }
}

pub struct EpsDocument {
    shapes: Vec<Box<Shape>>,
}

impl EpsDocument {
    pub fn new() -> EpsDocument {
        EpsDocument { shapes: Vec::new() }
    }

    pub fn add_shape(&mut self, shape: Box<Shape>) {
        self.shapes.push(shape);
    }

    pub fn get_bounds(&self) -> Bounds {
        // Determine extend of canvas
        let mut bounds = Bounds::new();

        for shape in &self.shapes {
            bounds.extend(shape.bounds());
        }

        bounds
    }

    pub fn transform(&mut self, translate: Vec2<f32>, scale: Vec2<f32>) {
        for shape in self.shapes.iter_mut() {
            shape.transform(translate, scale);
        }
    }

    /// Write as Embedded Postscript (EPS)
    pub fn write_eps(&self, wr: &mut Write, min_width: f32, min_height: f32) -> io::Result<()> {
        let bounds = self.get_bounds();

        let width = bounds.width().max(min_width);
        let height = bounds.height().max(min_height);
        let border_percent = 0.1;

        let scale = 1.0 + 2.0 * border_percent;

        try!(writeln!(wr,
                      r#"%%!PS-Adobe-3.0 EPSF-3.0
%%Creator: https://github.com/mneumann/eps-writer-rs
%%DocumentData: Clean7Bit
%%Origin: 0 0
%%BoundingBox: {} {} {} {}
%%HiResBoundingBox: {} {} {} {}
%%LanguageLevel: 2
%%Pages: 1
%%Page: 1 1
"#,
                      (bounds.min_x() - border_percent * width) as isize,
                      (bounds.min_y() - border_percent * height) as isize,
                      (bounds.max_x() + border_percent * width) as isize,
                      (bounds.max_y() + border_percent * height) as isize,

                      bounds.min_x() - border_percent * width,
                      bounds.min_y() - border_percent * height,
                      bounds.max_x() + border_percent * width,
                      bounds.max_y() + border_percent * height));

        // use a stroke width of 0.1% of the width or height of the canvas
        let stroke_width = scale * width.max(height) / 1000.0;
        try!(writeln!(wr, r#"{} setlinewidth"#, stroke_width));

        for shape in &self.shapes {
            try!(shape.write_eps(wr));
        }

        writeln!(wr, "%%EOF")
    }
}
<|endoftext|>


<commit_before>use std::io::Command;
use std::io::process::InheritFd;
use std::default::Default;

/// Extra configuration to pass to gcc.
pub struct Config {
    /// Directories where gcc will look for header files.
    pub include_directories: Vec<Path>,
    /// Additional definitions (`-DKEY` or `-DKEY=VALUE`).
    pub definitions: Vec<(String, Option<String>)>,
    /// Additional object files to link into the final archive
    pub objects: Vec<Path>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
        }
    }
}

fn getenv(v: &str) -> Option<String> {
    use std::os::getenv;
    let r = getenv(v);
    println!("{} = {}", v, r);
    r
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// # Example
///
/// ```no_run
/// use std::default::Default;
/// gcc::compile_library("libfoo.a", &Default::default(), &[
///     "foo.c",
///     "bar.c",
/// ]);
/// ```
pub fn compile_library(output: &str, config: &Config, files: &[&str]) {
    assert!(output.starts_with("lib"));
    assert!(output.ends_with(".a"));

    let target = getenv("TARGET").unwrap();
    let opt_level = getenv("OPT_LEVEL").unwrap();

    let mut cmd = Command::new(gcc());
    cmd.arg(format!("-O{}", opt_level));
    cmd.arg("-c");
    cmd.arg("-ffunction-sections").arg("-fdata-sections");
    cmd.args(cflags().as_slice());

    if target.as_slice().contains("-ios") {
        cmd.args(ios_flags(target.as_slice()).as_slice());
    } else {
        if target.as_slice().contains("i686") {
            cmd.arg("-m32");
        } else if target.as_slice().contains("x86_64") {
            cmd.arg("-m64");
        }

        if !target.as_slice().contains("i686") {
            cmd.arg("-fPIC");
        }
    }

    for directory in config.include_directories.iter() {
        cmd.arg("-I").arg(directory);
    }

    for &(ref key, ref value) in config.definitions.iter() {
        if let &Some(ref value) = value {
            cmd.arg(format!("-D{}={}", key, value));
        } else {
            cmd.arg(format!("-D{}", key));
        }
    }

    let src = Path::new(getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(getenv("OUT_DIR").unwrap());
    let mut objects = Vec::new();
    for file in files.iter() {
        let obj = dst.join(*file).with_extension("o");
        std::io::fs::mkdir_recursive(&obj.dir_path(), std::io::USER_RWX).unwrap();
        run(cmd.clone().arg(src.join(*file)).arg("-o").arg(&obj));
        objects.push(obj);
    }

    run(Command::new(ar()).arg("crus")
                          .arg(dst.join(output))
                          .args(objects.as_slice())
                          .args(config.objects.as_slice()));
    println!("cargo:rustc-flags=-L {} -l {}:static",
             dst.display(), output.slice(3, output.len() - 2));
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    let status = match cmd.stdout(InheritFd(1)).stderr(InheritFd(2)).status() {
        Ok(status) => status,
        Err(e) => panic!("failed to spawn process: {}", e),
    };
    if !status.success() {
        panic!("nonzero exit status: {}", status);
    }
}

fn get_var(var_base: &str) -> Result<String, String> {
    let target = getenv("TARGET")
        .expect("Environment variable 'TARGET' is unset");
    let host = match getenv("HOST") {
            None => { return Err("Environment variable 'HOST' is unset".to_string()); }
            Some(x) => x
        };
    let kind = if host == target { "HOST" } else { "TARGET" };
    let target_u = target.split('-')
        .collect::<Vec<&str>>()
        .connect("_");
    let res = getenv(format!("{}_{}", var_base, target).as_slice())
        .or_else(|| getenv(format!("{}_{}", var_base, target_u).as_slice()))
        .or_else(|| getenv(format!("{}_{}", kind, var_base).as_slice()))
        .or_else(|| getenv(var_base));

    match res {
        Some(res) => Ok(res),
        None => Err("Could not get environment variable".to_string()),
    }
}

fn gcc() -> String {
    get_var("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else {
        "cc".to_string()
    })
}

fn ar() -> String {
    get_var("AR").unwrap_or("ar".to_string())
}

fn cflags() -> Vec<String> {
    get_var("CFLAGS").unwrap_or(String::new())
       .as_slice().words().map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    let mut is_device_arch = false;
    let mut res = Vec::new();

    if target.starts_with("arm-") {
        res.push("-arch");
        res.push("armv7");
        is_device_arch = true;
    } else if target.starts_with("arm64-") {
        res.push("-arch");
        res.push("arm64");
        is_device_arch = true;
    } else if target.starts_with("i386-") {
        res.push("-m32");
    } else if target.starts_with("x86_64-") {
        res.push("-m64");
    }

    let sdk = if is_device_arch {"iphoneos"} else {"iphonesimulator"};

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(InheritFd(2))
        .output()
        .unwrap()
        .output;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot");
    res.push(sdk_path.as_slice().trim());

    res.iter().map(|s| s.to_string()).collect::<Vec<_>>()
}
<commit_msg>Set default gcc/ar based on target when compiling android target.<commit_after>use std::io::Command;
use std::io::process::InheritFd;
use std::default::Default;

/// Extra configuration to pass to gcc.
pub struct Config {
    /// Directories where gcc will look for header files.
    pub include_directories: Vec<Path>,
    /// Additional definitions (`-DKEY` or `-DKEY=VALUE`).
    pub definitions: Vec<(String, Option<String>)>,
    /// Additional object files to link into the final archive
    pub objects: Vec<Path>,
}

impl Default for Config {
    fn default() -> Config {
        Config {
            include_directories: Vec::new(),
            definitions: Vec::new(),
            objects: Vec::new(),
        }
    }
}

fn getenv(v: &str) -> Option<String> {
    use std::os::getenv;
    let r = getenv(v);
    println!("{} = {}", v, r);
    r
}

/// Compile a library from the given set of input C files.
///
/// This will simply compile all files into object files and then assemble them
/// into the output. This will read the standard environment variables to detect
/// cross compilations and such.
///
/// # Example
///
/// ```no_run
/// use std::default::Default;
/// gcc::compile_library("libfoo.a", &Default::default(), &[
///     "foo.c",
///     "bar.c",
/// ]);
/// ```
pub fn compile_library(output: &str, config: &Config, files: &[&str]) {
    assert!(output.starts_with("lib"));
    assert!(output.ends_with(".a"));

    let target = getenv("TARGET").unwrap();
    let opt_level = getenv("OPT_LEVEL").unwrap();

    let mut cmd = Command::new(gcc(target.as_slice()));
    cmd.arg(format!("-O{}", opt_level));
    cmd.arg("-c");
    cmd.arg("-ffunction-sections").arg("-fdata-sections");
    cmd.args(cflags().as_slice());

    if target.as_slice().contains("-ios") {
        cmd.args(ios_flags(target.as_slice()).as_slice());
    } else {
        if target.as_slice().contains("i686") {
            cmd.arg("-m32");
        } else if target.as_slice().contains("x86_64") {
            cmd.arg("-m64");
        }

        if !target.as_slice().contains("i686") {
            cmd.arg("-fPIC");
        }
    }

    for directory in config.include_directories.iter() {
        cmd.arg("-I").arg(directory);
    }

    for &(ref key, ref value) in config.definitions.iter() {
        if let &Some(ref value) = value {
            cmd.arg(format!("-D{}={}", key, value));
        } else {
            cmd.arg(format!("-D{}", key));
        }
    }

    let src = Path::new(getenv("CARGO_MANIFEST_DIR").unwrap());
    let dst = Path::new(getenv("OUT_DIR").unwrap());
    let mut objects = Vec::new();
    for file in files.iter() {
        let obj = dst.join(*file).with_extension("o");
        std::io::fs::mkdir_recursive(&obj.dir_path(), std::io::USER_RWX).unwrap();
        run(cmd.clone().arg(src.join(*file)).arg("-o").arg(&obj));
        objects.push(obj);
    }

    run(Command::new(ar(target.as_slice())).arg("crus")
                                           .arg(dst.join(output))
                                           .args(objects.as_slice())
                                           .args(config.objects.as_slice()));
    println!("cargo:rustc-flags=-L {} -l {}:static",
             dst.display(), output.slice(3, output.len() - 2));
}

fn run(cmd: &mut Command) {
    println!("running: {}", cmd);
    let status = match cmd.stdout(InheritFd(1)).stderr(InheritFd(2)).status() {
        Ok(status) => status,
        Err(e) => panic!("failed to spawn process: {}", e),
    };
    if !status.success() {
        panic!("nonzero exit status: {}", status);
    }
}

fn get_var(var_base: &str) -> Result<String, String> {
    let target = getenv("TARGET")
        .expect("Environment variable 'TARGET' is unset");
    let host = match getenv("HOST") {
            None => { return Err("Environment variable 'HOST' is unset".to_string()); }
            Some(x) => x
        };
    let kind = if host == target { "HOST" } else { "TARGET" };
    let target_u = target.split('-')
        .collect::<Vec<&str>>()
        .connect("_");
    let res = getenv(format!("{}_{}", var_base, target).as_slice())
        .or_else(|| getenv(format!("{}_{}", var_base, target_u).as_slice()))
        .or_else(|| getenv(format!("{}_{}", kind, var_base).as_slice()))
        .or_else(|| getenv(var_base));

    match res {
        Some(res) => Ok(res),
        None => Err("Could not get environment variable".to_string()),
    }
}

fn gcc(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("CC").unwrap_or(if cfg!(windows) {
        "gcc".to_string()
    } else if is_android {
        format!("{}-gcc", target)
    } else {
        "cc".to_string()
    })
}

fn ar(target: &str) -> String {
    let is_android = target.find_str("android").is_some();

    get_var("AR").unwrap_or(if is_android {
        format!("{}-ar", target)
    } else {
        "ar".to_string()
    })
}

fn cflags() -> Vec<String> {
    get_var("CFLAGS").unwrap_or(String::new())
       .as_slice().words().map(|s| s.to_string())
       .collect()
}

fn ios_flags(target: &str) -> Vec<String> {
    let mut is_device_arch = false;
    let mut res = Vec::new();

    if target.starts_with("arm-") {
        res.push("-arch");
        res.push("armv7");
        is_device_arch = true;
    } else if target.starts_with("arm64-") {
        res.push("-arch");
        res.push("arm64");
        is_device_arch = true;
    } else if target.starts_with("i386-") {
        res.push("-m32");
    } else if target.starts_with("x86_64-") {
        res.push("-m64");
    }

    let sdk = if is_device_arch {"iphoneos"} else {"iphonesimulator"};

    println!("Detecting iOS SDK path for {}", sdk);
    let sdk_path = Command::new("xcrun")
        .arg("--show-sdk-path")
        .arg("--sdk")
        .arg(sdk)
        .stderr(InheritFd(2))
        .output()
        .unwrap()
        .output;

    let sdk_path = String::from_utf8(sdk_path).unwrap();

    res.push("-isysroot");
    res.push(sdk_path.as_slice().trim());

    res.iter().map(|s| s.to_string()).collect::<Vec<_>>()
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate error_chain;

use std::path::{Path,PathBuf};
use std::process::{Command,ExitStatus};
use std::io;
use std::fs::{self, DirEntry};
use std::borrow::ToOwned;

error_chain!{
    foreign_links {
        Io(::std::io::Error);
    }
    errors{
        MissingSourceDir{
            description("Couldn't locate source directory")
            display("Couldn't locate your source directory")
        }
        ForkFailure(command: &'static str){
            description("Failed to fork command")
            display("Failed to fork command {}",command)
        }
        ExitFailure(command: &'static str, status: ExitStatus){
            description("Command exited with failure status")
            display("Command {} exited with status: {}",command,status)
        }
        DistNotDir(dist_path: PathBuf){
            description("The dist path did not point to a directory")
            display("The path {:?} must not point to an existing non-directory file",dist_path)
        }
        NoSources(source_path: PathBuf){
            description("The located source path contains no source files")
            display("The located source path ({:?}) contained no `.java` files",source_path)
        }
    }
}

fn visit_dirs<P: AsRef<Path>,F: FnMut(&DirEntry)>(dir: P, cb: &mut F) -> io::Result<()> {
    let dir = dir.as_ref();
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

fn find_in_dirs<P: AsRef<Path>,F:FnMut(&DirEntry) -> Option<T>,T>(dir: P, cb: &mut F) -> io::Result<Option<T>> {
    let dir = dir.as_ref();
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                match try!(find_in_dirs(&path, cb)){
                    Some(t) => return Ok(Some(t)),
                    None => continue
                }
            } else {
                match cb(&entry){
                    Some(t) => return Ok(Some(t)),
                    None => continue,
                }
            }
        }
    }
    Ok(None)
}

fn dir_exists<P: AsRef<Path>>(path: P) -> bool{
    let path = path.as_ref();
    path.exists() && path.is_dir()
}

fn source_root() -> Result<PathBuf>{
    const SEARCH_PATHS: &'static [&'static str] = &[
        "./src/main/java/",
        "./src/java/",
        "./src/"
    ];

    SEARCH_PATHS.iter().map(|&s| Path::new(s).to_path_buf()).find(|p| dir_exists(p)).ok_or(ErrorKind::MissingSourceDir.into())
}

fn libs_root() -> Option<PathBuf>{
    const SEARCH_PATHS: &'static [&'static str] = &[
        "./libs/",
        "./deps/"
    ];

    SEARCH_PATHS.iter().map(|&s| Path::new(s).to_path_buf()).find(|p| dir_exists(p))
}

fn find_files_by_extension<P: AsRef<Path>>(root_path: P,extension: &str, strip_root_prefix: bool) -> Result<Vec<PathBuf>>{
    let mut found = vec![];
    visit_dirs(root_path.as_ref(),&mut |entry: &DirEntry|{
        let path = entry.path();
        if path.extension().is_some() && path.extension().unwrap() == extension{
            let path = if strip_root_prefix {
                path.strip_prefix(&root_path).expect("Found something outside of $root_path in $root_path ???").to_path_buf()
            }else{
                path
            };
            found.push(path);
        }
    })?;
    Ok(found)
}

fn source_files<P: AsRef<Path>>(source_root: P) -> Result<Vec<PathBuf>>{
    find_files_by_extension(source_root,"java",false)
}

fn class_files() -> Result<Vec<PathBuf>>{
    find_files_by_extension("dist","class",true)
}

fn libs() -> Result<Vec<PathBuf>>{
    if let Some(dir) = libs_root(){
        find_files_by_extension(dir,"jar",false)
    }else{
        Ok(vec![])
    }
}

pub struct Kohi{
    dist_path: PathBuf,
    libs: Vec<PathBuf>,
    source_path: PathBuf,
    source_files: Vec<PathBuf>
}

impl Kohi{
    pub fn new() -> Result<Self>{
        let source_root = source_root()?;
        let source_files = source_files(&source_root)?;
        if source_files.len() == 0 {
            bail!(ErrorKind::NoSources(source_root));
        }
        Ok(Kohi{
            dist_path: Path::new("./dist/").to_path_buf(),
            libs: libs()?,
            source_path: source_root,
            source_files: source_files,
        })
    }

    pub fn compile<I: Into<Option<String>>>(self,target_version: I) -> Result<Self>{
        let classpath = std::env::join_paths(&self.libs).unwrap();

        if !self.dist_path.exists(){
            std::fs::create_dir_all(&self.dist_path)?;
        }else{
            if !self.dist_path.is_dir(){
                bail!(ErrorKind::DistNotDir(self.dist_path));
            }
        }

        let mut cmd = Command::new("javac");

        if let Some(target_version) = target_version.into(){
            cmd.arg("-target").arg(target_version);
        }

        let status = cmd
            .arg("-d")
            .arg(&self.dist_path)
            .arg("-cp")
            .arg(classpath)
            .arg("-sourcepath")
            .arg(&self.source_path)
            .args(self.source_files.as_slice())
            .status()
            .chain_err(|| ErrorKind::ForkFailure("javac"))?;

        if status.success(){
            Ok(self)
        }else{
            bail!(ErrorKind::ExitFailure("javac",status))
        }
    }

    pub fn run(self, run_class: String) -> Result<Self>{
        //blah.class -> blah
        let run_class = run_class.trim_right_matches(".class");

        let classpath = std::env::join_paths(std::iter::once(&self.dist_path).chain(&self.libs)).unwrap();

        let main = self.find_class(run_class).expect("Couldn't locate the class to run");

        let status = Command::new("java")
                          .arg("-cp")
                          .arg(classpath)
                          .arg(main)
                          .status()
                          .chain_err(|| ErrorKind::ForkFailure("java"))?;

        if status.success(){
            Ok(self)
        }else{
            bail!(ErrorKind::ExitFailure("java",status))
        }
    }

    pub fn package(self, jar_name: &str, entry_point: Option<&str>) -> Result<Self>{
        let mut cmd = Command::new("jar");
        if let Some(entry_point) = entry_point{
            cmd.arg("-cfe")
                .arg(jar_name)
                .arg(entry_point);
        }else{
            cmd.arg("-cf")
                .arg(jar_name);
        }

        let status = cmd
            .arg("-C")
            .arg("dist")
            .args(class_files()?.as_slice())
            .status()
            .chain_err(|| ErrorKind::ForkFailure("jar"))?;

        if status.success(){
            Ok(self)
        }else{
            bail!(ErrorKind::ExitFailure("jar",status))
        }
    }

    fn find_class(&self,class: &str) -> Option<String>{

        let class = class.to_lowercase();
        let mut class_name: Vec<_> = class.split(".").map(ToOwned::to_owned).collect();

        //kinda hacky, but this means we don't have to continuously strip off the dist prefix in the loop
        class_name.insert(0,"dist".to_owned());

        //also a hack to avoid removing the ".class" from the last component constantly
        let len = class_name.len();
        class_name[len-1].push_str(".class");

        let path = find_in_dirs(self.dist_path.as_path(),&mut |entry|{
            let path = entry.path();
            {
                let components = path.components().filter_map(|comp|{
                    use std::path::Component;
                    match comp{
                        Component::Normal(str) => Some(str),
                        _ => None
                    }
                });

                for (a,b) in components.zip(class_name.iter()){
                    if let Some(a) = a.to_str().map(str::to_lowercase){
                        if &a == b{
                            continue
                        }else{
                            return None
                        }
                    }else{
                        return None
                    }
                }
            }
            Some(path)
        }).expect("IO Error while finding class file");

        if let Some(path) = path{
            let mut path = path.strip_prefix(self.dist_path.as_path()).expect("Found something outside of ./dist/ in ./dist/ ???").to_path_buf();
            path.set_extension("");

            let path: Vec<_> = path.iter().flat_map(|s| s.to_str()).map(|s| s.to_owned()).collect();
            let path = path.join(".");

            let path_as_class = path.trim_left_matches(".");
            Some(path_as_class.to_owned())
        }else{
            None
        }
    }
}<commit_msg>Need to pass source flag too<commit_after>#[macro_use]
extern crate error_chain;

use std::path::{Path,PathBuf};
use std::process::{Command,ExitStatus};
use std::io;
use std::fs::{self, DirEntry};
use std::borrow::ToOwned;

error_chain!{
    foreign_links {
        Io(::std::io::Error);
    }
    errors{
        MissingSourceDir{
            description("Couldn't locate source directory")
            display("Couldn't locate your source directory")
        }
        ForkFailure(command: &'static str){
            description("Failed to fork command")
            display("Failed to fork command {}",command)
        }
        ExitFailure(command: &'static str, status: ExitStatus){
            description("Command exited with failure status")
            display("Command {} exited with status: {}",command,status)
        }
        DistNotDir(dist_path: PathBuf){
            description("The dist path did not point to a directory")
            display("The path {:?} must not point to an existing non-directory file",dist_path)
        }
        NoSources(source_path: PathBuf){
            description("The located source path contains no source files")
            display("The located source path ({:?}) contained no `.java` files",source_path)
        }
    }
}

fn visit_dirs<P: AsRef<Path>,F: FnMut(&DirEntry)>(dir: P, cb: &mut F) -> io::Result<()> {
    let dir = dir.as_ref();
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                try!(visit_dirs(&path, cb));
            } else {
                cb(&entry);
            }
        }
    }
    Ok(())
}

fn find_in_dirs<P: AsRef<Path>,F:FnMut(&DirEntry) -> Option<T>,T>(dir: P, cb: &mut F) -> io::Result<Option<T>> {
    let dir = dir.as_ref();
    if dir.is_dir() {
        for entry in try!(fs::read_dir(dir)) {
            let entry = try!(entry);
            let path = entry.path();
            if path.is_dir() {
                match try!(find_in_dirs(&path, cb)){
                    Some(t) => return Ok(Some(t)),
                    None => continue
                }
            } else {
                match cb(&entry){
                    Some(t) => return Ok(Some(t)),
                    None => continue,
                }
            }
        }
    }
    Ok(None)
}

fn dir_exists<P: AsRef<Path>>(path: P) -> bool{
    let path = path.as_ref();
    path.exists() && path.is_dir()
}

fn source_root() -> Result<PathBuf>{
    const SEARCH_PATHS: &'static [&'static str] = &[
        "./src/main/java/",
        "./src/java/",
        "./src/"
    ];

    SEARCH_PATHS.iter().map(|&s| Path::new(s).to_path_buf()).find(|p| dir_exists(p)).ok_or(ErrorKind::MissingSourceDir.into())
}

fn libs_root() -> Option<PathBuf>{
    const SEARCH_PATHS: &'static [&'static str] = &[
        "./libs/",
        "./deps/"
    ];

    SEARCH_PATHS.iter().map(|&s| Path::new(s).to_path_buf()).find(|p| dir_exists(p))
}

fn find_files_by_extension<P: AsRef<Path>>(root_path: P,extension: &str, strip_root_prefix: bool) -> Result<Vec<PathBuf>>{
    let mut found = vec![];
    visit_dirs(root_path.as_ref(),&mut |entry: &DirEntry|{
        let path = entry.path();
        if path.extension().is_some() && path.extension().unwrap() == extension{
            let path = if strip_root_prefix {
                path.strip_prefix(&root_path).expect("Found something outside of $root_path in $root_path ???").to_path_buf()
            }else{
                path
            };
            found.push(path);
        }
    })?;
    Ok(found)
}

fn source_files<P: AsRef<Path>>(source_root: P) -> Result<Vec<PathBuf>>{
    find_files_by_extension(source_root,"java",false)
}

fn class_files() -> Result<Vec<PathBuf>>{
    find_files_by_extension("dist","class",true)
}

fn libs() -> Result<Vec<PathBuf>>{
    if let Some(dir) = libs_root(){
        find_files_by_extension(dir,"jar",false)
    }else{
        Ok(vec![])
    }
}

pub struct Kohi{
    dist_path: PathBuf,
    libs: Vec<PathBuf>,
    source_path: PathBuf,
    source_files: Vec<PathBuf>
}

impl Kohi{
    pub fn new() -> Result<Self>{
        let source_root = source_root()?;
        let source_files = source_files(&source_root)?;
        if source_files.len() == 0 {
            bail!(ErrorKind::NoSources(source_root));
        }
        Ok(Kohi{
            dist_path: Path::new("./dist/").to_path_buf(),
            libs: libs()?,
            source_path: source_root,
            source_files: source_files,
        })
    }

    pub fn compile<I: Into<Option<String>>>(self,target_version: I) -> Result<Self>{
        let classpath = std::env::join_paths(&self.libs).unwrap();

        if !self.dist_path.exists(){
            std::fs::create_dir_all(&self.dist_path)?;
        }else{
            if !self.dist_path.is_dir(){
                bail!(ErrorKind::DistNotDir(self.dist_path));
            }
        }

        let mut cmd = Command::new("javac");

        if let Some(target_version) = target_version.into(){
            cmd.arg("-source").arg(target_version).arg("-target").arg(target_version);
        }

        let status = cmd
            .arg("-d")
            .arg(&self.dist_path)
            .arg("-cp")
            .arg(classpath)
            .arg("-sourcepath")
            .arg(&self.source_path)
            .args(self.source_files.as_slice())
            .status()
            .chain_err(|| ErrorKind::ForkFailure("javac"))?;

        if status.success(){
            Ok(self)
        }else{
            bail!(ErrorKind::ExitFailure("javac",status))
        }
    }

    pub fn run(self, run_class: String) -> Result<Self>{
        //blah.class -> blah
        let run_class = run_class.trim_right_matches(".class");

        let classpath = std::env::join_paths(std::iter::once(&self.dist_path).chain(&self.libs)).unwrap();

        let main = self.find_class(run_class).expect("Couldn't locate the class to run");

        let status = Command::new("java")
                          .arg("-cp")
                          .arg(classpath)
                          .arg(main)
                          .status()
                          .chain_err(|| ErrorKind::ForkFailure("java"))?;

        if status.success(){
            Ok(self)
        }else{
            bail!(ErrorKind::ExitFailure("java",status))
        }
    }

    pub fn package(self, jar_name: &str, entry_point: Option<&str>) -> Result<Self>{
        let mut cmd = Command::new("jar");
        if let Some(entry_point) = entry_point{
            cmd.arg("-cfe")
                .arg(jar_name)
                .arg(entry_point);
        }else{
            cmd.arg("-cf")
                .arg(jar_name);
        }

        let status = cmd
            .arg("-C")
            .arg("dist")
            .args(class_files()?.as_slice())
            .status()
            .chain_err(|| ErrorKind::ForkFailure("jar"))?;

        if status.success(){
            Ok(self)
        }else{
            bail!(ErrorKind::ExitFailure("jar",status))
        }
    }

    fn find_class(&self,class: &str) -> Option<String>{

        let class = class.to_lowercase();
        let mut class_name: Vec<_> = class.split(".").map(ToOwned::to_owned).collect();

        //kinda hacky, but this means we don't have to continuously strip off the dist prefix in the loop
        class_name.insert(0,"dist".to_owned());

        //also a hack to avoid removing the ".class" from the last component constantly
        let len = class_name.len();
        class_name[len-1].push_str(".class");

        let path = find_in_dirs(self.dist_path.as_path(),&mut |entry|{
            let path = entry.path();
            {
                let components = path.components().filter_map(|comp|{
                    use std::path::Component;
                    match comp{
                        Component::Normal(str) => Some(str),
                        _ => None
                    }
                });

                for (a,b) in components.zip(class_name.iter()){
                    if let Some(a) = a.to_str().map(str::to_lowercase){
                        if &a == b{
                            continue
                        }else{
                            return None
                        }
                    }else{
                        return None
                    }
                }
            }
            Some(path)
        }).expect("IO Error while finding class file");

        if let Some(path) = path{
            let mut path = path.strip_prefix(self.dist_path.as_path()).expect("Found something outside of ./dist/ in ./dist/ ???").to_path_buf();
            path.set_extension("");

            let path: Vec<_> = path.iter().flat_map(|s| s.to_str()).map(|s| s.to_owned()).collect();
            let path = path.join(".");

            let path_as_class = path.trim_left_matches(".");
            Some(path_as_class.to_owned())
        }else{
            None
        }
    }
}<|endoftext|>