<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

use std::borrow::Cow;

use regex::Regex;

use common::{NB_CHAR, NB_CHAR_NARROW, NB_CHAR_EM};

/// Escape non breaking spaces for HTML.
///
/// This is done so there is no problem for
/// displaying them if the font or browser doesn't know what to do
/// with them (particularly the narrow non breaking space which isn't
/// very well supported).
///
/// In order to work correctly, this will require a CSS style with
///
/// ```css
/// .nnbsp {
///    white-space: nowrap;
/// }
/// ```
///
/// Else, narrow spaces won't be no-breaking, and that might be ugly.
pub fn nb_spaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if let Some(first) = input.chars().position(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false,
    }) {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                NB_CHAR_NARROW => output.push_str(r#" "#),
                NB_CHAR_EM => output.push_str(r#" "#),
                NB_CHAR => output.push_str(r#" "#),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape non breaking spaces for LaTeX, replacing them with `~`.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::nb_spaces_tex("Des espaces insécables ? Ça alors !");
/// assert_eq!(&s, "Des espaces insécables~? Ça alors~!");
/// ```
pub fn nb_spaces_tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if let Some(first) = input.chars().position(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false,
    }) {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                NB_CHAR_NARROW | NB_CHAR_EM | NB_CHAR => output.push('~'),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape characters for HTML output, replacing  `<`, `>`, and `&` with appropriate
/// HTML entities.
///
/// **Warning**: this function was written for escaping text in a markdown
/// text processor that is designed to run on a local machine, where the content
/// can actually be trusted. It should *not* be used for untrusted content.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::html("<foo> & <bar>");
/// assert_eq!(&s, "<foo> & <bar>");
/// ```
pub fn html<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new("[<>&]").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let len = input.len();
        let mut output = Vec::with_capacity(len + len / 2);
        output.extend_from_slice(input[0..first].as_bytes());
        let rest = input[first..].bytes();
        for c in rest {
            match c {
                b'<' => output.extend_from_slice(b"<"),
                b'>' => output.extend_from_slice(b">"),
                b'&' => output.extend_from_slice(b"&"),
                _ => output.push(c),
            }
        }
        Cow::Owned(String::from_utf8(output).unwrap())
    } else {
        input
    }
}

/// Escape quotes
///
/// Simply replace `"` by `'`
pub fn quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if input.contains('"') {
        let mut output = String::with_capacity(input.len());
        for c in input.chars() {
            match c {
                '"' => output.push('\''),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input
    }
}

/// Escape characters for LaTeX
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::tex("command --foo # calls command with option foo");
/// assert_eq!(&s, r"command -{}-foo \# calls command with option foo");
/// ```
pub fn tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    const REGEX_LITERAL: &'static str = r"[&%$#_\x7E\x2D\{\}\^\\]";
    lazy_static! {
       static ref REGEX: Regex = Regex::new(REGEX_LITERAL).unwrap();
    }

    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let len = input.len();
        let mut output = Vec::with_capacity(len + len / 2);
        output.extend_from_slice(input[0..first].as_bytes());
        let mut bytes: Vec<_> = input[first..].bytes().collect();
        bytes.push(b' '); // add a dummy char for call to .windows()
        // for &[c, next] in chars.windows(2) { // still experimental, uncomment when stable
        for win in bytes.windows(2) {
            let c = win[0];
            let next = win[1];
            match c {
                b'-' => {
                    if next == b'-' {
                        // if next char is also a -, to avoid tex ligatures
                        output.extend_from_slice(br"-{}");
                    } else {
                        output.push(c);
                    }
                }
                b'&' => output.extend_from_slice(br"\&"),
                b'%' => output.extend_from_slice(br"\%"),
                b'$' => output.extend_from_slice(br"\$"),
                b'#' => output.extend_from_slice(br"\#"),
                b'_' => output.extend_from_slice(br"\_"),
                b'{' => output.extend_from_slice(br"\{"),
                b'}' => output.extend_from_slice(br"\}"),
                b'~' => output.extend_from_slice(br"\textasciitilde{}"),
                b'^' => output.extend_from_slice(br"\textasciicircum{}"),
                b'\\' => output.extend_from_slice(br"\textbackslash{}"),
                _ => output.push(c),
            }
        }
        Cow::Owned(String::from_utf8(output).unwrap())
    } else {
        input
    }
}

#[test]
fn html_0() {
    let s = "Some string without any character to escape";
    let result = html(s);
    assert_eq!(s, &result);
}

#[test]
fn tex_0() {
    let s = "Some string without any character to escape";
    let result = tex(s);
    assert_eq!(s, &result);
}

#[test]
fn nb_spaces_0() {
    let s = "Some string without any character to escape";
    let result = nb_spaces(s);
    assert_eq!(s, &result);
}

#[test]
fn tex_nb_spaces_0() {
    let s = "Some string without any character to escape";
    let result = nb_spaces_tex(s);
    assert_eq!(s, &result);
}

#[test]
fn quotes_0() {
    let s = "Some string without any character to escape";
    let result = quotes(s);
    assert_eq!(s, &result);
}

#[test]
fn html_1() {
    let s = "
Some characters need escaping & something
";
    let expected = "<p>Some characters need escaping & something</p>";
    let actual = html(s);
    assert_eq!(expected, &actual);
}

#[test]
fn html_2() {
    let actual = html("<foo> & <bar>");
    let expected = "<foo> & <bar>";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_braces() {
    let actual = tex(r"\foo{bar}");
    let expected = r"\textbackslash{}foo\{bar\}";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_dashes() {
    let actual = tex("--foo, ---bar");
    let expected = r"-{}-foo, -{}-{}-bar";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_numbers() {
    let actual = tex(r"30000$ is 10% of number #1 income");
    let expected = r"30000\$ is 10\% of number \#1 income";
    assert_eq!(&actual, expected);
}

#[test]
fn quotes_escape() {
    let actual = quotes(r#"Some text with "quotes""#);
    let expected = r#"Some text with 'quotes'"#;
    assert_eq!(&actual, expected);
}

#[test]
fn nb_spaces_escape() {
    let actual = nb_spaces("This contains non breaking spaces");
    let expected = "This contains\
                     non breaking spaces";
    assert_eq!(&actual, expected);
}
<commit_msg>Add doc for escape module<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at https://mozilla.org/MPL/2.0/.

//! Some functions to escape character for display in HTML or LaTeX.
//!
//! The two most useful ones are `tex` and `html`.
//!
//! # Example
//!
//! ```
//! use crowbook_text_processing::escape;
//! let input = "<foo> & <bar>";
//! let output = escape::html(input);
//! assert_eq!(&output, "<foo> & <bar>");
//!
//! let input = "#2: 20%";
//! let output = escape::tex(input);
//! assert_eq!(&output, r"\#2: 20\%");
//! ```

use std::borrow::Cow;

use regex::Regex;

use common::{NB_CHAR, NB_CHAR_NARROW, NB_CHAR_EM};

/// Escape non breaking spaces for HTML.
///
/// This is done so there is no problem for
/// displaying them if the font or browser doesn't know what to do
/// with them (particularly the narrow non breaking space which isn't
/// very well supported).
///
/// In order to work correctly, this will require a CSS style with
///
/// ```css
/// .nnbsp {
///    white-space: nowrap;
/// }
/// ```
///
/// Else, narrow spaces won't be no-breaking, and that might be ugly.
pub fn nb_spaces<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if let Some(first) = input.chars().position(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false,
    }) {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                NB_CHAR_NARROW => output.push_str(r#" "#),
                NB_CHAR_EM => output.push_str(r#" "#),
                NB_CHAR => output.push_str(r#" "#),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape non breaking spaces for LaTeX, replacing them with `~`.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::nb_spaces_tex("Des espaces insécables ? Ça alors !");
/// assert_eq!(&s, "Des espaces insécables~? Ça alors~!");
/// ```
pub fn nb_spaces_tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if let Some(first) = input.chars().position(|c| match c {
        NB_CHAR | NB_CHAR_NARROW | NB_CHAR_EM => true,
        _ => false,
    }) {
        let mut chars = input.chars().collect::<Vec<_>>();
        let rest = chars.split_off(first);
        let mut output = chars.into_iter().collect::<String>();
        for c in rest {
            match c {
                NB_CHAR_NARROW | NB_CHAR_EM | NB_CHAR => output.push('~'),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input.into()
    }
}

/// Escape characters for HTML output, replacing  `<`, `>`, and `&` with appropriate
/// HTML entities.
///
/// **Warning**: this function was written for escaping text in a markdown
/// text processor that is designed to run on a local machine, where the content
/// can actually be trusted. It should *not* be used for untrusted content.
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::html("<foo> & <bar>");
/// assert_eq!(&s, "<foo> & <bar>");
/// ```
pub fn html<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    lazy_static! {
        static ref REGEX: Regex = Regex::new("[<>&]").unwrap();
    }
    let input = input.into();
    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let len = input.len();
        let mut output = Vec::with_capacity(len + len / 2);
        output.extend_from_slice(input[0..first].as_bytes());
        let rest = input[first..].bytes();
        for c in rest {
            match c {
                b'<' => output.extend_from_slice(b"<"),
                b'>' => output.extend_from_slice(b">"),
                b'&' => output.extend_from_slice(b"&"),
                _ => output.push(c),
            }
        }
        Cow::Owned(String::from_utf8(output).unwrap())
    } else {
        input
    }
}

/// Escape quotes
///
/// Simply replace `"` by `'`
pub fn quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    if input.contains('"') {
        let mut output = String::with_capacity(input.len());
        for c in input.chars() {
            match c {
                '"' => output.push('\''),
                _ => output.push(c),
            }
        }
        Cow::Owned(output)
    } else {
        input
    }
}

/// Escape characters for LaTeX
///
/// # Example
///
/// ```
/// use crowbook_text_processing::escape;
/// let s = escape::tex("command --foo # calls command with option foo");
/// assert_eq!(&s, r"command -{}-foo \# calls command with option foo");
/// ```
pub fn tex<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
    let input = input.into();
    const REGEX_LITERAL: &'static str = r"[&%$#_\x7E\x2D\{\}\^\\]";
    lazy_static! {
       static ref REGEX: Regex = Regex::new(REGEX_LITERAL).unwrap();
    }

    let first = REGEX.find(&input);
    if let Some((first, _)) = first {
        let len = input.len();
        let mut output = Vec::with_capacity(len + len / 2);
        output.extend_from_slice(input[0..first].as_bytes());
        let mut bytes: Vec<_> = input[first..].bytes().collect();
        bytes.push(b' '); // add a dummy char for call to .windows()
        // for &[c, next] in chars.windows(2) { // still experimental, uncomment when stable
        for win in bytes.windows(2) {
            let c = win[0];
            let next = win[1];
            match c {
                b'-' => {
                    if next == b'-' {
                        // if next char is also a -, to avoid tex ligatures
                        output.extend_from_slice(br"-{}");
                    } else {
                        output.push(c);
                    }
                }
                b'&' => output.extend_from_slice(br"\&"),
                b'%' => output.extend_from_slice(br"\%"),
                b'$' => output.extend_from_slice(br"\$"),
                b'#' => output.extend_from_slice(br"\#"),
                b'_' => output.extend_from_slice(br"\_"),
                b'{' => output.extend_from_slice(br"\{"),
                b'}' => output.extend_from_slice(br"\}"),
                b'~' => output.extend_from_slice(br"\textasciitilde{}"),
                b'^' => output.extend_from_slice(br"\textasciicircum{}"),
                b'\\' => output.extend_from_slice(br"\textbackslash{}"),
                _ => output.push(c),
            }
        }
        Cow::Owned(String::from_utf8(output).unwrap())
    } else {
        input
    }
}

#[test]
fn html_0() {
    let s = "Some string without any character to escape";
    let result = html(s);
    assert_eq!(s, &result);
}

#[test]
fn tex_0() {
    let s = "Some string without any character to escape";
    let result = tex(s);
    assert_eq!(s, &result);
}

#[test]
fn nb_spaces_0() {
    let s = "Some string without any character to escape";
    let result = nb_spaces(s);
    assert_eq!(s, &result);
}

#[test]
fn tex_nb_spaces_0() {
    let s = "Some string without any character to escape";
    let result = nb_spaces_tex(s);
    assert_eq!(s, &result);
}

#[test]
fn quotes_0() {
    let s = "Some string without any character to escape";
    let result = quotes(s);
    assert_eq!(s, &result);
}

#[test]
fn html_1() {
    let s = "
Some characters need escaping & something
";
    let expected = "<p>Some characters need escaping & something</p>";
    let actual = html(s);
    assert_eq!(expected, &actual);
}

#[test]
fn html_2() {
    let actual = html("<foo> & <bar>");
    let expected = "<foo> & <bar>";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_braces() {
    let actual = tex(r"\foo{bar}");
    let expected = r"\textbackslash{}foo\{bar\}";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_dashes() {
    let actual = tex("--foo, ---bar");
    let expected = r"-{}-foo, -{}-{}-bar";
    assert_eq!(&actual, expected);
}

#[test]
fn tex_numbers() {
    let actual = tex(r"30000$ is 10% of number #1 income");
    let expected = r"30000\$ is 10\% of number \#1 income";
    assert_eq!(&actual, expected);
}

#[test]
fn quotes_escape() {
    let actual = quotes(r#"Some text with "quotes""#);
    let expected = r#"Some text with 'quotes'"#;
    assert_eq!(&actual, expected);
}

#[test]
fn nb_spaces_escape() {
    let actual = nb_spaces("This contains non breaking spaces");
    let expected = "This contains\
                     non breaking spaces";
    assert_eq!(&actual, expected);
}
<|endoftext|>


<commit_before>#[derive(Clone, Debug, Copy)]
pub enum Event {
    /// The size of the window has changed.
    Resized(u32, u32),

    /// The position of the window has changed.
    Moved(i32, i32),

    /// The window has been closed.
    Closed,

    /// The window received a unicode character.
    ReceivedCharacter(char),

    /// The window gained or lost focus.
    ///
    /// The parameter is true if the window has gained focus, and false if it has lost focus.
    Focused(bool),

    /// An event from the keyboard has been received.
    KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>),

    /// The cursor has moved on the window.
    ///
    /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
    MouseMoved((i32, i32)),

    /// A mouse wheel movement or touchpad scroll occurred.
    MouseWheel(MouseScrollDelta),

    /// An event from the mouse has been received.
    MouseInput(ElementState, MouseButton),

    /// The event loop was woken up by another thread.
    Awakened,

    /// The window needs to be redrawn.
    Refresh,

    /// App has been suspended or resumed.
    ///
    /// The parameter is true if app was suspended, and false if it has been resumed.
    Suspended(bool),

    /// Touch event has been received
    Touch(Touch)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum TouchPhase {
    Started,
    Moved,
    Ended,
    Cancelled
}

#[derive(Debug, Clone, Copy)]
/// Represents touch event
///
/// Every time user touches screen new Start event with some finger id is generated.
/// When the finger is removed from the screen End event with same id is generated.
///
/// For every id there will be at least 2 events with phases Start and End (or Cancelled).
/// There may be 0 or more Move events.
///
///
/// Depending on platform implementation id may or may not be reused by system after End event.
///
/// Gesture regonizer using this event should assume that Start event received with same id
/// as previously received End event is a new finger and has nothing to do with an old one.
///
/// Touch may be cancelled if for example window lost focus.
pub struct Touch {
    pub phase: TouchPhase,
    pub location: (f64,f64),
    /// unique identifier of a finger.
    pub id: u64
}

pub type ScanCode = u8;

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ElementState {
    Pressed,
    Released,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    Left,
    Right,
    Middle,
    Other(u8),
}

#[derive(Debug, Clone, Copy)]
pub enum MouseScrollDelta {
	/// Amount in lines or rows to scroll in the horizontal
	/// and vertical directions.
	///
	/// Positive values indicate movement forward
	/// (away from the user) or rightwards.
	LineDelta(f32, f32),
	/// Amount in pixels to scroll in the horizontal and
	/// vertical direction.
	///
	/// Scroll events are expressed as a PixelDelta if
	/// supported by the device (eg. a touchpad) and
	/// platform.
	PixelDelta(f32, f32)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum VirtualKeyCode {
    /// The '1' key over the letters.
    Key1,
    /// The '2' key over the letters.
    Key2,
    /// The '3' key over the letters.
    Key3,
    /// The '4' key over the letters.
    Key4,
    /// The '5' key over the letters.
    Key5,
    /// The '6' key over the letters.
    Key6,
    /// The '7' key over the letters.
    Key7,
    /// The '8' key over the letters.
    Key8,
    /// The '9' key over the letters.
    Key9,
    /// The '0' key over the 'O' and 'P' keys.
    Key0,

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,

    /// The Escape key, next to F1.
    Escape,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,

    /// Print Screen/SysRq.
    Snapshot,
    /// Scroll Lock.
    Scroll,
    /// Pause/Break key, next to Scroll lock.
    Pause,

    /// `Insert`, next to Backspace.
    Insert,
    Home,
    Delete,
    End,
    PageDown,
    PageUp,

    Left,
    Up,
    Right,
    Down,

    /// The Backspace key, right over Enter.
    // TODO: rename
    Back,
    /// The Enter key.
    Return,
    /// The space bar.
    Space,

    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,

    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    Backslash,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    Decimal,
    Divide,
    Equals,
    Grave,
    Kana,
    Kanji,
    LAlt,
    LBracket,
    LControl,
    LMenu,
    LShift,
    LWin,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    NextTrack,
    NoConvert,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    OEM102,
    Period,
    Playpause,
    Power,
    Prevtrack,
    RAlt,
    RBracket,
    RControl,
    RMenu,
    RShift,
    RWin,
    Semicolon,
    Slash,
    Sleep,
    Stop,
    Subtract,
    Sysrq,
    Tab,
    Underline,
    Unlabeled,
    VolumeDown,
    VolumeUp,
    Wake,
    Webback,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    Yen,
}
<commit_msg>Fix some inconsistencies in VirtualKeyCode variant names<commit_after>#[derive(Clone, Debug, Copy)]
pub enum Event {
    /// The size of the window has changed.
    Resized(u32, u32),

    /// The position of the window has changed.
    Moved(i32, i32),

    /// The window has been closed.
    Closed,

    /// The window received a unicode character.
    ReceivedCharacter(char),

    /// The window gained or lost focus.
    ///
    /// The parameter is true if the window has gained focus, and false if it has lost focus.
    Focused(bool),

    /// An event from the keyboard has been received.
    KeyboardInput(ElementState, ScanCode, Option<VirtualKeyCode>),

    /// The cursor has moved on the window.
    ///
    /// The parameter are the (x,y) coords in pixels relative to the top-left corner of the window.
    MouseMoved((i32, i32)),

    /// A mouse wheel movement or touchpad scroll occurred.
    MouseWheel(MouseScrollDelta),

    /// An event from the mouse has been received.
    MouseInput(ElementState, MouseButton),

    /// The event loop was woken up by another thread.
    Awakened,

    /// The window needs to be redrawn.
    Refresh,

    /// App has been suspended or resumed.
    ///
    /// The parameter is true if app was suspended, and false if it has been resumed.
    Suspended(bool),

    /// Touch event has been received
    Touch(Touch)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum TouchPhase {
    Started,
    Moved,
    Ended,
    Cancelled
}

#[derive(Debug, Clone, Copy)]
/// Represents touch event
///
/// Every time user touches screen new Start event with some finger id is generated.
/// When the finger is removed from the screen End event with same id is generated.
///
/// For every id there will be at least 2 events with phases Start and End (or Cancelled).
/// There may be 0 or more Move events.
///
///
/// Depending on platform implementation id may or may not be reused by system after End event.
///
/// Gesture regonizer using this event should assume that Start event received with same id
/// as previously received End event is a new finger and has nothing to do with an old one.
///
/// Touch may be cancelled if for example window lost focus.
pub struct Touch {
    pub phase: TouchPhase,
    pub location: (f64,f64),
    /// unique identifier of a finger.
    pub id: u64
}

pub type ScanCode = u8;

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum ElementState {
    Pressed,
    Released,
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum MouseButton {
    Left,
    Right,
    Middle,
    Other(u8),
}

#[derive(Debug, Clone, Copy)]
pub enum MouseScrollDelta {
	/// Amount in lines or rows to scroll in the horizontal
	/// and vertical directions.
	///
	/// Positive values indicate movement forward
	/// (away from the user) or rightwards.
	LineDelta(f32, f32),
	/// Amount in pixels to scroll in the horizontal and
	/// vertical direction.
	///
	/// Scroll events are expressed as a PixelDelta if
	/// supported by the device (eg. a touchpad) and
	/// platform.
	PixelDelta(f32, f32)
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum VirtualKeyCode {
    /// The '1' key over the letters.
    Key1,
    /// The '2' key over the letters.
    Key2,
    /// The '3' key over the letters.
    Key3,
    /// The '4' key over the letters.
    Key4,
    /// The '5' key over the letters.
    Key5,
    /// The '6' key over the letters.
    Key6,
    /// The '7' key over the letters.
    Key7,
    /// The '8' key over the letters.
    Key8,
    /// The '9' key over the letters.
    Key9,
    /// The '0' key over the 'O' and 'P' keys.
    Key0,

    A,
    B,
    C,
    D,
    E,
    F,
    G,
    H,
    I,
    J,
    K,
    L,
    M,
    N,
    O,
    P,
    Q,
    R,
    S,
    T,
    U,
    V,
    W,
    X,
    Y,
    Z,

    /// The Escape key, next to F1.
    Escape,

    F1,
    F2,
    F3,
    F4,
    F5,
    F6,
    F7,
    F8,
    F9,
    F10,
    F11,
    F12,
    F13,
    F14,
    F15,

    /// Print Screen/SysRq.
    Snapshot,
    /// Scroll Lock.
    Scroll,
    /// Pause/Break key, next to Scroll lock.
    Pause,

    /// `Insert`, next to Backspace.
    Insert,
    Home,
    Delete,
    End,
    PageDown,
    PageUp,

    Left,
    Up,
    Right,
    Down,

    /// The Backspace key, right over Enter.
    // TODO: rename
    Back,
    /// The Enter key.
    Return,
    /// The space bar.
    Space,

    Numlock,
    Numpad0,
    Numpad1,
    Numpad2,
    Numpad3,
    Numpad4,
    Numpad5,
    Numpad6,
    Numpad7,
    Numpad8,
    Numpad9,

    AbntC1,
    AbntC2,
    Add,
    Apostrophe,
    Apps,
    At,
    Ax,
    Backslash,
    Calculator,
    Capital,
    Colon,
    Comma,
    Convert,
    Decimal,
    Divide,
    Equals,
    Grave,
    Kana,
    Kanji,
    LAlt,
    LBracket,
    LControl,
    LMenu,
    LShift,
    LWin,
    Mail,
    MediaSelect,
    MediaStop,
    Minus,
    Multiply,
    Mute,
    MyComputer,
    NextTrack,
    NoConvert,
    NumpadComma,
    NumpadEnter,
    NumpadEquals,
    OEM102,
    Period,
    PlayPause,
    Power,
    PrevTrack,
    RAlt,
    RBracket,
    RControl,
    RMenu,
    RShift,
    RWin,
    Semicolon,
    Slash,
    Sleep,
    Stop,
    Subtract,
    Sysrq,
    Tab,
    Underline,
    Unlabeled,
    VolumeDown,
    VolumeUp,
    Wake,
    WebBack,
    WebFavorites,
    WebForward,
    WebHome,
    WebRefresh,
    WebSearch,
    WebStop,
    Yen,
}
<|endoftext|>


<commit_before>extern crate zoom;
extern crate rand;

use super::bot::*;
use super::Vec3;

static BOTS_RADIUS_MULTIPLIER: f32 = 2.5;
static RADIUS_STATIC: f32 = 5.0;
static ENERGY_RATIO: f64 = 0.002;
static ENERGY_VARIATION: f64 = 0.1;
pub static ENERGY_THRESHOLD: i64 = 500000;
static ENERGY_FULL_COST: i64 = 5000;
static PHYSICS_RADIUS: f64 = 1.0;

static EDGE_FOOD_BENEFIT: f64 = 2.0;

static DRAG: f64 = 0.1;

#[derive(Clone)]
pub struct RadParticle {
    pub p: zoom::BasicParticle<Vec3, f64>,
}

impl zoom::Position<Vec3> for RadParticle {
    fn position(&self) -> Vec3 {
        self.p.position()
    }
}

impl zoom::Velocity<Vec3> for RadParticle {
    fn velocity(&self) -> Vec3 {
        self.p.velocity()
    }
}

impl zoom::Particle<Vec3, f64> for RadParticle {
    fn impulse(&self, v: &Vec3) {
        self.p.impulse(v);
    }

    fn advance(&mut self, time: f64) {
        self.p.advance(time);
    }
}

impl zoom::Inertia<f64> for RadParticle {
    fn inertia(&self) -> f64 {
        self.p.inertia()
    }
}

impl zoom::Quanta<f64> for RadParticle {
    fn quanta(&self) -> f64 {
        self.p.quanta()
    }
}

impl zoom::PhysicsParticle<Vec3, f64> for RadParticle {

}

impl zoom::Ball<f64> for RadParticle {
    fn radius(&self) -> f64 {
        PHYSICS_RADIUS
    }
}

pub struct Node {
    pub particle: RadParticle,
    pub energy: i64,
    pub bots: Vec<Box<Bot>>,
    pub moved_bots: Vec<Box<Bot>>,
    pub deaths: i64,
    pub moves: i64,
    pub connections: i64,
    pub pull: i64,
}

impl Node {
    pub fn new(energy: i64, particle: zoom::BasicParticle<Vec3, f64>) -> Self {
        Node{
            energy: energy,
            particle: RadParticle{p: particle},
            bots: Vec::new(),
            moved_bots: Vec::new(),
            deaths: 0,
            moves: 0,
            connections: 0,
            pull: 0,
        }
    }

    pub fn grow(&mut self, full: bool, rng: &mut rand::Isaac64Rng) {
        use rand::Rng;
        if full {
            if self.bots.is_empty() {
                self.energy = self.energy.saturating_sub((ENERGY_FULL_COST as f64 *
                    (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION))) as i64);
            }
        } else {
            self.energy = self.energy.saturating_add((self.energy as f64 * ENERGY_RATIO *
                //Create rate differential
                (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION) +
                    //Add food for having more connections
                    EDGE_FOOD_BENEFIT * self.connections as f64)
                ) as i64);
        }
    }

    pub fn advance(&mut self) {
        use zoom::{Particle, PhysicsParticle};
        self.particle.drag(DRAG);
        self.particle.advance(1.0);
    }

    pub fn should_split(&self) -> bool {
        self.energy >= ENERGY_THRESHOLD
    }
    pub fn should_obliterate(&self) -> bool {
        use std::num::FpCategory;
        use zoom::Position;
        let clos = |x: f64| {
            match x.classify() {
                FpCategory::Nan | FpCategory::Infinite => true,
                _ => false,
            }
        };
        self.energy <= 0 || match self.particle.position() {
            Vec3{x, y, z} => {clos(x) || clos(y) || clos(z)}
        }
    }

    pub fn color(&self) -> [f32; 4] {
        [
            1.0 - self.energy as f32 / ENERGY_THRESHOLD as f32,
            self.energy as f32 / ENERGY_THRESHOLD as f32,
            if self.bots.len() == 0 {
                0.0
            } else {
                self.moves as f32 / self.bots.len() as f32
            },
            1.0,
        ]
    }
    pub fn radius(&self) -> f32 {
        RADIUS_STATIC + BOTS_RADIUS_MULTIPLIER * (self.bots.len() as f32)
    }
}
<commit_msg>make bot scaling smaller nodes too big<commit_after>extern crate zoom;
extern crate rand;

use super::bot::*;
use super::Vec3;

static BOTS_RADIUS_MULTIPLIER: f32 = 1.0;
static RADIUS_STATIC: f32 = 5.0;
static ENERGY_RATIO: f64 = 0.002;
static ENERGY_VARIATION: f64 = 0.1;
pub static ENERGY_THRESHOLD: i64 = 500000;
static ENERGY_FULL_COST: i64 = 5000;
static PHYSICS_RADIUS: f64 = 1.0;

static EDGE_FOOD_BENEFIT: f64 = 2.0;

static DRAG: f64 = 0.1;

#[derive(Clone)]
pub struct RadParticle {
    pub p: zoom::BasicParticle<Vec3, f64>,
}

impl zoom::Position<Vec3> for RadParticle {
    fn position(&self) -> Vec3 {
        self.p.position()
    }
}

impl zoom::Velocity<Vec3> for RadParticle {
    fn velocity(&self) -> Vec3 {
        self.p.velocity()
    }
}

impl zoom::Particle<Vec3, f64> for RadParticle {
    fn impulse(&self, v: &Vec3) {
        self.p.impulse(v);
    }

    fn advance(&mut self, time: f64) {
        self.p.advance(time);
    }
}

impl zoom::Inertia<f64> for RadParticle {
    fn inertia(&self) -> f64 {
        self.p.inertia()
    }
}

impl zoom::Quanta<f64> for RadParticle {
    fn quanta(&self) -> f64 {
        self.p.quanta()
    }
}

impl zoom::PhysicsParticle<Vec3, f64> for RadParticle {

}

impl zoom::Ball<f64> for RadParticle {
    fn radius(&self) -> f64 {
        PHYSICS_RADIUS
    }
}

pub struct Node {
    pub particle: RadParticle,
    pub energy: i64,
    pub bots: Vec<Box<Bot>>,
    pub moved_bots: Vec<Box<Bot>>,
    pub deaths: i64,
    pub moves: i64,
    pub connections: i64,
    pub pull: i64,
}

impl Node {
    pub fn new(energy: i64, particle: zoom::BasicParticle<Vec3, f64>) -> Self {
        Node{
            energy: energy,
            particle: RadParticle{p: particle},
            bots: Vec::new(),
            moved_bots: Vec::new(),
            deaths: 0,
            moves: 0,
            connections: 0,
            pull: 0,
        }
    }

    pub fn grow(&mut self, full: bool, rng: &mut rand::Isaac64Rng) {
        use rand::Rng;
        if full {
            if self.bots.is_empty() {
                self.energy = self.energy.saturating_sub((ENERGY_FULL_COST as f64 *
                    (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION))) as i64);
            }
        } else {
            self.energy = self.energy.saturating_add((self.energy as f64 * ENERGY_RATIO *
                //Create rate differential
                (1.0 + rng.gen_range(-ENERGY_VARIATION, ENERGY_VARIATION) +
                    //Add food for having more connections
                    EDGE_FOOD_BENEFIT * self.connections as f64)
                ) as i64);
        }
    }

    pub fn advance(&mut self) {
        use zoom::{Particle, PhysicsParticle};
        self.particle.drag(DRAG);
        self.particle.advance(1.0);
    }

    pub fn should_split(&self) -> bool {
        self.energy >= ENERGY_THRESHOLD
    }
    pub fn should_obliterate(&self) -> bool {
        use std::num::FpCategory;
        use zoom::Position;
        let clos = |x: f64| {
            match x.classify() {
                FpCategory::Nan | FpCategory::Infinite => true,
                _ => false,
            }
        };
        self.energy <= 0 || match self.particle.position() {
            Vec3{x, y, z} => {clos(x) || clos(y) || clos(z)}
        }
    }

    pub fn color(&self) -> [f32; 4] {
        [
            1.0 - self.energy as f32 / ENERGY_THRESHOLD as f32,
            self.energy as f32 / ENERGY_THRESHOLD as f32,
            if self.bots.len() == 0 {
                0.0
            } else {
                self.moves as f32 / self.bots.len() as f32
            },
            1.0,
        ]
    }
    pub fn radius(&self) -> f32 {
        RADIUS_STATIC + BOTS_RADIUS_MULTIPLIER * (self.bots.len() as f32)
    }
}
<|endoftext|>


<commit_before>//! Define table formatting utilities

use std::io::{Write, Error};

use encode_unicode::Utf8Char;

use super::utils::NEWLINE;

/// Alignment for cell's content
#[derive(Clone, Debug, PartialEq, Copy, Hash, Eq)]
pub enum Alignment {
    /// Align left
    LEFT,
    /// Align in the center
    CENTER,
    /// Align right
    RIGHT,
}

/// Position of a line separator in a table
#[derive(Clone, Debug, PartialEq, Copy, Hash, Eq)]
pub enum LinePosition {
    /// Table's border on top
    Top,
    /// Line separator between the titles row,
    /// and the first data row
    Title,
    /// Line separator between data rows
    Intern,
    /// Bottom table's border
    Bottom,
}

/// Position of a column separator in a row
#[derive(Clone, Debug, PartialEq, Copy, Hash, Eq)]
pub enum ColumnPosition {
    /// Left table's border
    Left,
    /// Internal column separators
    Intern,
    /// Rigth table's border
    Right,
}

/// Contains the character used for printing a line separator
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
pub struct LineSeparator {
    /// Line separator
    line: char,
    /// Internal junction separator
    junc: char,
    /// Left junction separator
    ljunc: char,
    /// Right junction separator
    rjunc: char,
}

impl LineSeparator {
    /// Create a new line separator instance where `line` is the character used to separate 2 lines
    /// and `junc` is the one used for junctions between columns and lines
    pub fn new(line: char, junc: char, ljunc: char, rjunc: char) -> LineSeparator {
        LineSeparator {
            line: line,
            junc: junc,
            ljunc: ljunc,
            rjunc: rjunc,
        }
    }

    /// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
    #[deprecated(since = "0.6.7", note = "function will be removed. See [issue #57](https://github.com/phsym/prettytable-rs/pull/57).")]
    pub fn print<T: Write + ?Sized>(&self,
                                    out: &mut T,
                                    col_width: &[usize],
                                    colsep: bool,
                                    lborder: bool,
                                    rborder: bool)
                                    -> Result<(), Error> {
        self._print(out, col_width, (1, 1), colsep, lborder, rborder)
    }

    fn _print<T: Write + ?Sized>(&self,
                                 out: &mut T,
                                 col_width: &[usize],
                                 padding: (usize, usize),
                                 colsep: bool,
                                 lborder: bool,
                                 rborder: bool)
                                 -> Result<(), Error> {
        if lborder {
            out.write_all(Utf8Char::from(self.ljunc).as_bytes())?;
        }
        let mut iter = col_width.into_iter().peekable();
        while let Some(width) = iter.next() {
            for _ in 0..width + padding.0 + padding.1 {
                out.write_all(Utf8Char::from(self.line).as_bytes())?;
            }
            if colsep && iter.peek().is_some() {
                out.write_all(Utf8Char::from(self.junc).as_bytes())?;
            }
        }
        if rborder {
            out.write_all(Utf8Char::from(self.rjunc).as_bytes())?;
        }
        out.write_all(NEWLINE)
    }
}

impl Default for LineSeparator {
    fn default() -> Self {
        LineSeparator::new('-', '+', '+', '+')
    }
}

/// Contains the table formatting rules
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
pub struct TableFormat {
    /// Optional column separator character
    csep: Option<char>,
    /// Optional left border character
    lborder: Option<char>,
    /// Optional right border character
    rborder: Option<char>,
    /// Optional internal line separator
    lsep: Option<LineSeparator>,
    /// Optional title line separator
    tsep: Option<LineSeparator>,
    /// Optional top line separator
    top_sep: Option<LineSeparator>,
    /// Optional bottom line separator
    bottom_sep: Option<LineSeparator>,
    /// Left padding
    pad_left: usize,
    /// Right padding
    pad_right: usize,
    /// Global indentation when rendering the table
    indent: usize,
}

impl TableFormat {
    /// Create a new empty TableFormat.
    pub fn new() -> TableFormat {
        TableFormat {
            csep: None,
            lborder: None,
            rborder: None,
            lsep: None,
            tsep: None,
            top_sep: None,
            bottom_sep: None,
            pad_left: 0,
            pad_right: 0,
            indent: 0,
        }
    }

    /// Return a tuple with left and right padding
    pub fn get_padding(&self) -> (usize, usize) {
        (self.pad_left, self.pad_right)
    }

    /// Set left and right padding
    pub fn padding(&mut self, left: usize, right: usize) {
        self.pad_left = left;
        self.pad_right = right;
    }

    /// Set the character used for internal column separation
    pub fn column_separator(&mut self, separator: char) {
        self.csep = Some(separator);
    }

    /// Set the character used for table borders
    pub fn borders(&mut self, border: char) {
        self.lborder = Some(border);
        self.rborder = Some(border);
    }

    /// Set a line separator
    pub fn separator(&mut self, what: LinePosition, separator: LineSeparator) {
        *match what {
             LinePosition::Top => &mut self.top_sep,
             LinePosition::Bottom => &mut self.bottom_sep,
             LinePosition::Title => &mut self.tsep,
             LinePosition::Intern => &mut self.lsep,
         } = Some(separator);
    }

    /// Set format for multiple kind of line separator
    pub fn separators(&mut self, what: &[LinePosition], separator: LineSeparator) {
        for pos in what {
            self.separator(*pos, separator);
        }
    }

    fn get_sep_for_line(&self, pos: LinePosition) -> &Option<LineSeparator> {
        match pos {
            LinePosition::Intern => &self.lsep,
            LinePosition::Top => &self.top_sep,
            LinePosition::Bottom => &self.bottom_sep,
            LinePosition::Title => {
                match &self.tsep {
                    s @ &Some(_) => s,
                    &None => &self.lsep,
                }
            }
        }
    }

    /// Set global indentation in spaces used when rendering a table
    pub fn indent(&mut self, spaces: usize) {
        self.indent = spaces;
    }

    /// Get global indentation in spaces used when rendering a table
    pub fn get_indent(&self) -> usize {
        self.indent
    }

    /// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
    pub fn print_line_separator<T: Write + ?Sized>(&self,
                                                   out: &mut T,
                                                   col_width: &[usize],
                                                   pos: LinePosition)
                                                   -> Result<(), Error> {
        match *self.get_sep_for_line(pos) {
            Some(ref l) => {
                //TODO: Wrap this into dedicated function one day
                out.write_all(&vec![b' '; self.get_indent()])?;
                l._print(out,
                         col_width,
                         self.get_padding(),
                         self.csep.is_some(),
                         self.lborder.is_some(),
                         self.rborder.is_some())
            }
            None => Ok(()),
        }
    }

    /// Returns the character used to separate columns.
    /// `pos` specify if the separator is left/right final or internal to the table
    pub fn get_column_separator(&self, pos: ColumnPosition) -> Option<char> {
        match pos {
            ColumnPosition::Left => self.lborder,
            ColumnPosition::Intern => self.csep,
            ColumnPosition::Right => self.rborder,
        }
    }

    /// Print a column separator or a table border
    pub fn print_column_separator<T: Write + ?Sized>(&self,
                                                     out: &mut T,
                                                     pos: ColumnPosition)
                                                     -> Result<(), Error> {
        match self.get_column_separator(pos) {
            Some(s) => out.write_all(Utf8Char::from(s).as_bytes()),
            None => Ok(()),
        }
    }
}

impl Default for TableFormat {
    fn default() -> Self {
        TableFormat::new()
    }
}

/// A builder to create a `TableFormat`
pub struct FormatBuilder {
    format: Box<TableFormat>,
}

impl FormatBuilder {
    /// Creates a new builder
    pub fn new() -> FormatBuilder {
        FormatBuilder { format: Box::new(TableFormat::new()) }
    }

    /// Set left and right padding
    pub fn padding(mut self, left: usize, right: usize) -> Self {
        self.format.padding(left, right);
        self
    }

    /// Set the character used for internal column separation
    pub fn column_separator(mut self, separator: char) -> Self {
        self.format.column_separator(separator);
        self
    }

    /// Set the character used for table borders
    pub fn borders(mut self, border: char) -> Self {
        self.format.borders(border);
        self
    }

    /// Set a line separator format
    pub fn separator(mut self, what: LinePosition, separator: LineSeparator) -> Self {
        self.format.separator(what, separator);
        self
    }

    /// Set separator format for multiple kind of line separators
    pub fn separators(mut self, what: &[LinePosition], separator: LineSeparator) -> Self {
        self.format.separators(what, separator);
        self
    }

    /// Set global indentation in spaces used when rendering a table
    pub fn indent(mut self, spaces: usize) -> Self {
        self.format.indent(spaces);
        self
    }

    /// Return the generated `TableFormat`
    pub fn build(&self) -> TableFormat {
        *self.format
    }
}

impl Into<TableFormat> for FormatBuilder {
    fn into(self) -> TableFormat {
        *self.format
    }
}

impl From<TableFormat> for FormatBuilder {
    fn from(fmt: TableFormat) -> Self {
        FormatBuilder { format: Box::new(fmt) }
    }
}

/// Predifined formats. Those constants are lazily evaluated when
/// the corresponding struct is dereferenced
pub mod consts {
    use super::{TableFormat, LineSeparator, FormatBuilder, LinePosition};

    lazy_static! {
        /// A line separator made of `-` and `+`
        static ref MINUS_PLUS_SEP: LineSeparator = LineSeparator::new('-', '+', '+', '+');
        /// A line separator made of `=` and `+`
        static ref EQU_PLUS_SEP: LineSeparator = LineSeparator::new('=', '+', '+', '+');

        /// Default table format
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +====+====+
        /// | a  | b  |
        /// +----+----+
        /// | d  | c  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_DEFAULT: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// Similar to `FORMAT_DEFAULT` but without special separator after title line
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +----+----+
        /// | a  | b  |
        /// +----+----+
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_TITLE: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// With no line separator, but with title separator
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +----+----+
        /// | a  | b  |
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_LINESEP_WITH_TITLE: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// With no line or title separator
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// | a  | b  |
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_LINESEP: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// No column separator
        ///
        /// # Example
        /// ```text
        /// --------
        ///  T1  T2
        /// ========
        ///  a   b
        /// --------
        ///  d   c
        /// --------
        /// ```
        pub static ref FORMAT_NO_COLSEP: TableFormat = FormatBuilder::new()
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// Format for printing a table without any separators (only alignment)
        ///
        /// # Example
        /// ```text
        ///  T1  T2
        ///  a   b
        ///  d   c
        /// ```
        pub static ref FORMAT_CLEAN: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .build();

        /// Format for a table with only external borders and title separator
        ///
        /// # Example
        /// ```text
        /// +--------+
        /// | T1  T2 |
        /// +========+
        /// | a   b  |
        /// | c   d  |
        /// +--------+
        /// ```
        pub static ref FORMAT_BORDERS_ONLY: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .borders('|')
                                                                    .build();

        /// A table with no external border
        ///
        /// # Example
        /// ```text
        ///  T1 | T2
        /// ====+====
        ///  a  | b
        /// ----+----
        ///  c  | d
        /// ```
        pub static ref FORMAT_NO_BORDER: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .column_separator('|')
                                                                    .build();

        /// A table with no external border and no line separation
        ///
        /// # Example
        /// ```text
        ///  T1 | T2
        /// ----+----
        ///  a  | b
        ///  c  | d
        /// ```
        pub static ref FORMAT_NO_BORDER_LINE_SEPARATOR: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .column_separator('|')
                                                                    .build();
    }
}
<commit_msg>Added the possibility to style the left and right border separately.<commit_after>//! Define table formatting utilities

use std::io::{Write, Error};

use encode_unicode::Utf8Char;

use super::utils::NEWLINE;

/// Alignment for cell's content
#[derive(Clone, Debug, PartialEq, Copy, Hash, Eq)]
pub enum Alignment {
    /// Align left
    LEFT,
    /// Align in the center
    CENTER,
    /// Align right
    RIGHT,
}

/// Position of a line separator in a table
#[derive(Clone, Debug, PartialEq, Copy, Hash, Eq)]
pub enum LinePosition {
    /// Table's border on top
    Top,
    /// Line separator between the titles row,
    /// and the first data row
    Title,
    /// Line separator between data rows
    Intern,
    /// Bottom table's border
    Bottom,
}

/// Position of a column separator in a row
#[derive(Clone, Debug, PartialEq, Copy, Hash, Eq)]
pub enum ColumnPosition {
    /// Left table's border
    Left,
    /// Internal column separators
    Intern,
    /// Rigth table's border
    Right,
}

/// Contains the character used for printing a line separator
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
pub struct LineSeparator {
    /// Line separator
    line: char,
    /// Internal junction separator
    junc: char,
    /// Left junction separator
    ljunc: char,
    /// Right junction separator
    rjunc: char,
}

impl LineSeparator {
    /// Create a new line separator instance where `line` is the character used to separate 2 lines
    /// and `junc` is the one used for junctions between columns and lines
    pub fn new(line: char, junc: char, ljunc: char, rjunc: char) -> LineSeparator {
        LineSeparator {
            line: line,
            junc: junc,
            ljunc: ljunc,
            rjunc: rjunc,
        }
    }

    /// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
    #[deprecated(since = "0.6.7", note = "function will be removed. See [issue #57](https://github.com/phsym/prettytable-rs/pull/57).")]
    pub fn print<T: Write + ?Sized>(&self,
                                    out: &mut T,
                                    col_width: &[usize],
                                    colsep: bool,
                                    lborder: bool,
                                    rborder: bool)
                                    -> Result<(), Error> {
        self._print(out, col_width, (1, 1), colsep, lborder, rborder)
    }

    fn _print<T: Write + ?Sized>(&self,
                                 out: &mut T,
                                 col_width: &[usize],
                                 padding: (usize, usize),
                                 colsep: bool,
                                 lborder: bool,
                                 rborder: bool)
                                 -> Result<(), Error> {
        if lborder {
            out.write_all(Utf8Char::from(self.ljunc).as_bytes())?;
        }
        let mut iter = col_width.into_iter().peekable();
        while let Some(width) = iter.next() {
            for _ in 0..width + padding.0 + padding.1 {
                out.write_all(Utf8Char::from(self.line).as_bytes())?;
            }
            if colsep && iter.peek().is_some() {
                out.write_all(Utf8Char::from(self.junc).as_bytes())?;
            }
        }
        if rborder {
            out.write_all(Utf8Char::from(self.rjunc).as_bytes())?;
        }
        out.write_all(NEWLINE)
    }
}

impl Default for LineSeparator {
    fn default() -> Self {
        LineSeparator::new('-', '+', '+', '+')
    }
}

/// Contains the table formatting rules
#[derive(Clone, Debug, Copy, Hash, PartialEq, Eq)]
pub struct TableFormat {
    /// Optional column separator character
    csep: Option<char>,
    /// Optional left border character
    lborder: Option<char>,
    /// Optional right border character
    rborder: Option<char>,
    /// Optional internal line separator
    lsep: Option<LineSeparator>,
    /// Optional title line separator
    tsep: Option<LineSeparator>,
    /// Optional top line separator
    top_sep: Option<LineSeparator>,
    /// Optional bottom line separator
    bottom_sep: Option<LineSeparator>,
    /// Left padding
    pad_left: usize,
    /// Right padding
    pad_right: usize,
    /// Global indentation when rendering the table
    indent: usize,
}

impl TableFormat {
    /// Create a new empty TableFormat.
    pub fn new() -> TableFormat {
        TableFormat {
            csep: None,
            lborder: None,
            rborder: None,
            lsep: None,
            tsep: None,
            top_sep: None,
            bottom_sep: None,
            pad_left: 0,
            pad_right: 0,
            indent: 0,
        }
    }

    /// Return a tuple with left and right padding
    pub fn get_padding(&self) -> (usize, usize) {
        (self.pad_left, self.pad_right)
    }

    /// Set left and right padding
    pub fn padding(&mut self, left: usize, right: usize) {
        self.pad_left = left;
        self.pad_right = right;
    }

    /// Set the character used for internal column separation
    pub fn column_separator(&mut self, separator: char) {
        self.csep = Some(separator);
    }

    /// Set the character used for table borders
    pub fn borders(&mut self, border: char) {
        self.lborder = Some(border);
        self.rborder = Some(border);
    }

    /// Set the character used for left table border
    pub fn left_border(&mut self, border: char) {
        self.lborder = Some(border);
    }

    /// Set the character used for right table border
    pub fn right_border(&mut self, border: char) {
        self.rborder = Some(border);
    }

    /// Set a line separator
    pub fn separator(&mut self, what: LinePosition, separator: LineSeparator) {
        *match what {
             LinePosition::Top => &mut self.top_sep,
             LinePosition::Bottom => &mut self.bottom_sep,
             LinePosition::Title => &mut self.tsep,
             LinePosition::Intern => &mut self.lsep,
         } = Some(separator);
    }

    /// Set format for multiple kind of line separator
    pub fn separators(&mut self, what: &[LinePosition], separator: LineSeparator) {
        for pos in what {
            self.separator(*pos, separator);
        }
    }

    fn get_sep_for_line(&self, pos: LinePosition) -> &Option<LineSeparator> {
        match pos {
            LinePosition::Intern => &self.lsep,
            LinePosition::Top => &self.top_sep,
            LinePosition::Bottom => &self.bottom_sep,
            LinePosition::Title => {
                match &self.tsep {
                    s @ &Some(_) => s,
                    &None => &self.lsep,
                }
            }
        }
    }

    /// Set global indentation in spaces used when rendering a table
    pub fn indent(&mut self, spaces: usize) {
        self.indent = spaces;
    }

    /// Get global indentation in spaces used when rendering a table
    pub fn get_indent(&self) -> usize {
        self.indent
    }

    /// Print a full line separator to `out`. `col_width` is a slice containing the width of each column
    pub fn print_line_separator<T: Write + ?Sized>(&self,
                                                   out: &mut T,
                                                   col_width: &[usize],
                                                   pos: LinePosition)
                                                   -> Result<(), Error> {
        match *self.get_sep_for_line(pos) {
            Some(ref l) => {
                //TODO: Wrap this into dedicated function one day
                out.write_all(&vec![b' '; self.get_indent()])?;
                l._print(out,
                         col_width,
                         self.get_padding(),
                         self.csep.is_some(),
                         self.lborder.is_some(),
                         self.rborder.is_some())
            }
            None => Ok(()),
        }
    }

    /// Returns the character used to separate columns.
    /// `pos` specify if the separator is left/right final or internal to the table
    pub fn get_column_separator(&self, pos: ColumnPosition) -> Option<char> {
        match pos {
            ColumnPosition::Left => self.lborder,
            ColumnPosition::Intern => self.csep,
            ColumnPosition::Right => self.rborder,
        }
    }

    /// Print a column separator or a table border
    pub fn print_column_separator<T: Write + ?Sized>(&self,
                                                     out: &mut T,
                                                     pos: ColumnPosition)
                                                     -> Result<(), Error> {
        match self.get_column_separator(pos) {
            Some(s) => out.write_all(Utf8Char::from(s).as_bytes()),
            None => Ok(()),
        }
    }
}

impl Default for TableFormat {
    fn default() -> Self {
        TableFormat::new()
    }
}

/// A builder to create a `TableFormat`
pub struct FormatBuilder {
    format: Box<TableFormat>,
}

impl FormatBuilder {
    /// Creates a new builder
    pub fn new() -> FormatBuilder {
        FormatBuilder { format: Box::new(TableFormat::new()) }
    }

    /// Set left and right padding
    pub fn padding(mut self, left: usize, right: usize) -> Self {
        self.format.padding(left, right);
        self
    }

    /// Set the character used for internal column separation
    pub fn column_separator(mut self, separator: char) -> Self {
        self.format.column_separator(separator);
        self
    }

    /// Set the character used for table borders
    pub fn borders(mut self, border: char) -> Self {
        self.format.borders(border);
        self
    }

    /// Set the character used for left table border
    pub fn left_border(mut self, border: char) -> Self {
        self.format.left_border(border);
        self
    }

    /// Set the character used for right table border
    pub fn right_border(mut self, border: char) -> Self {
        self.format.right_border(border);
        self
    }

    /// Set a line separator format
    pub fn separator(mut self, what: LinePosition, separator: LineSeparator) -> Self {
        self.format.separator(what, separator);
        self
    }

    /// Set separator format for multiple kind of line separators
    pub fn separators(mut self, what: &[LinePosition], separator: LineSeparator) -> Self {
        self.format.separators(what, separator);
        self
    }

    /// Set global indentation in spaces used when rendering a table
    pub fn indent(mut self, spaces: usize) -> Self {
        self.format.indent(spaces);
        self
    }

    /// Return the generated `TableFormat`
    pub fn build(&self) -> TableFormat {
        *self.format
    }
}

impl Into<TableFormat> for FormatBuilder {
    fn into(self) -> TableFormat {
        *self.format
    }
}

impl From<TableFormat> for FormatBuilder {
    fn from(fmt: TableFormat) -> Self {
        FormatBuilder { format: Box::new(fmt) }
    }
}

/// Predifined formats. Those constants are lazily evaluated when
/// the corresponding struct is dereferenced
pub mod consts {
    use super::{TableFormat, LineSeparator, FormatBuilder, LinePosition};

    lazy_static! {
        /// A line separator made of `-` and `+`
        static ref MINUS_PLUS_SEP: LineSeparator = LineSeparator::new('-', '+', '+', '+');
        /// A line separator made of `=` and `+`
        static ref EQU_PLUS_SEP: LineSeparator = LineSeparator::new('=', '+', '+', '+');

        /// Default table format
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +====+====+
        /// | a  | b  |
        /// +----+----+
        /// | d  | c  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_DEFAULT: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// Similar to `FORMAT_DEFAULT` but without special separator after title line
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +----+----+
        /// | a  | b  |
        /// +----+----+
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_TITLE: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// With no line separator, but with title separator
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// +----+----+
        /// | a  | b  |
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_LINESEP_WITH_TITLE: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// With no line or title separator
        ///
        /// # Example
        /// ```text
        /// +----+----+
        /// | T1 | T2 |
        /// | a  | b  |
        /// | c  | d  |
        /// +----+----+
        /// ```
        pub static ref FORMAT_NO_LINESEP: TableFormat = FormatBuilder::new()
                                                                    .column_separator('|')
                                                                    .borders('|')
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// No column separator
        ///
        /// # Example
        /// ```text
        /// --------
        ///  T1  T2
        /// ========
        ///  a   b
        /// --------
        ///  d   c
        /// --------
        /// ```
        pub static ref FORMAT_NO_COLSEP: TableFormat = FormatBuilder::new()
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .padding(1, 1)
                                                                    .build();

        /// Format for printing a table without any separators (only alignment)
        ///
        /// # Example
        /// ```text
        ///  T1  T2
        ///  a   b
        ///  d   c
        /// ```
        pub static ref FORMAT_CLEAN: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .build();

        /// Format for a table with only external borders and title separator
        ///
        /// # Example
        /// ```text
        /// +--------+
        /// | T1  T2 |
        /// +========+
        /// | a   b  |
        /// | c   d  |
        /// +--------+
        /// ```
        pub static ref FORMAT_BORDERS_ONLY: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .separator(LinePosition::Bottom, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Top, *MINUS_PLUS_SEP)
                                                                    .borders('|')
                                                                    .build();

        /// A table with no external border
        ///
        /// # Example
        /// ```text
        ///  T1 | T2
        /// ====+====
        ///  a  | b
        /// ----+----
        ///  c  | d
        /// ```
        pub static ref FORMAT_NO_BORDER: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Intern, *MINUS_PLUS_SEP)
                                                                    .separator(LinePosition::Title, *EQU_PLUS_SEP)
                                                                    .column_separator('|')
                                                                    .build();

        /// A table with no external border and no line separation
        ///
        /// # Example
        /// ```text
        ///  T1 | T2
        /// ----+----
        ///  a  | b
        ///  c  | d
        /// ```
        pub static ref FORMAT_NO_BORDER_LINE_SEPARATOR: TableFormat = FormatBuilder::new()
                                                                    .padding(1, 1)
                                                                    .separator(LinePosition::Title, *MINUS_PLUS_SEP)
                                                                    .column_separator('|')
                                                                    .build();
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The rust-gobject authors.
//
// 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.

#[link(name = "gi", vers = "0.1")];
#[crate_type = "lib"];

extern mod glib;
extern mod gobject;

use glib::detail::error::GError;
use glib::strfuncs::Strdupv;
use std::c_str::CString;
use std::cast;
use std::libc;
use std::option::Option;
use std::ptr;
use std::result::Result;
use std::str;
use std::unstable::raw::Slice;

mod detail;

pub struct AttributeIter {
    priv ptr: *mut detail::GIBaseInfo,
    priv it: detail::GIAttributeIter
}

impl Drop for AttributeIter {
    fn drop(&mut self) {
        unsafe {
            detail::g_base_info_unref(self.ptr);
            self.ptr = ptr::mut_null();
        }
    }
}

impl Iterator<(~str, ~str)> for AttributeIter {
    fn next(&mut self) -> Option<(~str, ~str)> {
        unsafe {
            let mut name_c_str: *libc::c_char = ptr::null();
            let mut value_c_str: *libc::c_char = ptr::null();
            if !detail::g_base_info_iterate_attributes(self.ptr, &mut self.it, &mut name_c_str, &mut value_c_str) {
                None
            } else {
                Some((str::raw::from_c_str(name_c_str), str::raw::from_c_str(value_c_str)))
            }
        }
    }
}

#[deriving(ToStr)]
pub enum InfoType {
    Invalid = 0,
    Function = 1,
    Callback = 2,
    Struct = 3,
    Boxed = 4,
    Enum = 5,
    Flags = 6,
    Object = 7,
    Interface = 8,
    Constant = 9,
    // Invalid0
    Union = 11,
    Value = 12,
    Signal = 13,
    Vfunc = 14,
    Property = 15,
    Field = 16,
    Arg = 17,
    Type = 18,
    Unresolved = 19
}

pub struct BaseInfo {
    priv ptr: *mut detail::GIBaseInfo,
    priv owns: bool
}

impl BaseInfo {
    pub fn type_(&self) -> InfoType {
        unsafe {
            detail::g_base_info_get_type(self.ptr)
        }
    }

    pub fn name(&self) -> Option<~str> {
        unsafe {
            let name_c_str = detail::g_base_info_get_name(self.ptr);
            if ptr::is_null(name_c_str) {
                None
            } else {
                Some(str::raw::from_c_str(name_c_str))
            }
        }
    }

    pub unsafe fn raw_name(&self) -> Option<&str> {
        let name_c_str = detail::g_base_info_get_name(self.ptr);
        if ptr::is_null(name_c_str) {
            None
        } else {
            let mut name_len = 0u;
            while *ptr::offset(name_c_str, name_len as int) != 0 {
                name_len += 1;
            }
            Some(cast::transmute(Slice {
                data: name_c_str,
                len: name_len
            }))
        }
    }

    pub fn namespace(&self) -> ~str {
        unsafe {
            let namespace_c_str = detail::g_base_info_get_namespace(self.ptr);
            str::raw::from_c_str(namespace_c_str)
        }
    }

    pub fn is_deprecated(&self) -> bool {
        unsafe {
            detail::g_base_info_is_deprecated(self.ptr)
        }
    }

    pub fn attribute(&self, name: &str) -> Option<~str> {
        unsafe {
            do name.with_c_str |name_c_str| {
                let attribute_c_str = detail::g_base_info_get_attribute(self.ptr, name_c_str);
                if ptr::is_null(attribute_c_str) {
                    None
                } else {
                    Some(str::raw::from_c_str(attribute_c_str))
                }
            }
        }
    }

    pub fn attribute_iter(&self) -> AttributeIter {
        unsafe {
            AttributeIter {
                ptr: detail::g_base_info_ref(self.ptr),
                it: detail::GIAttributeIter::new()
            }
        }
    }
}

impl Clone for BaseInfo {
    fn clone(&self) -> BaseInfo {
        unsafe {
            BaseInfo {
                ptr: detail::g_base_info_ref(self.ptr),
                owns: true
            }
        }
    }
}

impl Drop for BaseInfo {
    fn drop(&mut self) {
        unsafe {
            if self.owns {
                detail::g_base_info_unref(self.ptr);
            }
            self.ptr = ptr::mut_null();
            self.owns = false;
        }
    }
}

impl Eq for BaseInfo {
    fn eq(&self, other: &BaseInfo) -> bool {
        unsafe {
            detail::g_base_info_equal(self.ptr, other.ptr)
        }
    }
}

pub struct Typelib {
    priv ptr: *mut detail::GITypelib,
    priv owns: bool
}

impl Drop for Typelib {
    fn drop(&mut self) {
        unsafe {
            if self.owns {
                detail::g_typelib_free(self.ptr);
            }
            self.ptr = ptr::mut_null();
            self.owns = false;
        }
    }
}

pub struct Repository {
    priv ptr: *mut detail::GIRepository,
    priv owns: bool
}

#[deriving(ToStr)]
pub enum RepositoryLoadFlag {
    Lazy = 1
}

impl Repository {
    pub fn default() -> Repository {
        unsafe {
            Repository {
                ptr: detail::g_irepository_get_default(),
                owns: false
            }
        }
    }

    pub fn info(&self, namespace_cstring: &CString, index: glib::gint) -> BaseInfo {
        unsafe {
            do namespace_cstring.with_ref |namespace_c_str| {
                BaseInfo {
                    ptr: detail::g_irepository_get_info(self.ptr, namespace_c_str, index),
                    owns: true
                }
            }
        }
    }

    pub fn loaded_namespaces(&self) -> ~[~str] {
        unsafe {
            let mut res: ~[~str] = ~[];
            let mut namespaces_strdupv = Strdupv::new(detail::g_irepository_get_loaded_namespaces(self.ptr));
            do namespaces_strdupv.with_mut_ptr |namespaces_array| {
                let mut p = namespaces_array;
                loop {
                    let namespace_c_str = ptr::read_ptr(p);
                    if ptr::is_null(namespace_c_str) {
                        break;
                    }
                    res.push(str::raw::from_c_str(namespace_c_str as *glib::gchar));
                    p = ptr::mut_offset(p, 1);
                }
            };
            res
        }
    }

    pub fn n_infos(&self, namespace_cstring: &CString) -> glib::gint {
        unsafe {
            do namespace_cstring.with_ref |namespace_c_str| {
                detail::g_irepository_get_n_infos(self.ptr, namespace_c_str)
            }
        }
    }

    pub fn require(&self, namespace: &str, opt_version: Option<&str>, flags: &[RepositoryLoadFlag]) -> Result<Typelib, glib::Error> {
        unsafe {
            do namespace.with_c_str |namespace_c_str| {
                let mut error: *mut GError = ptr::mut_null();
                let typelib_ptr = match opt_version {
                    None => detail::g_irepository_require(self.ptr, namespace_c_str, ptr::null(), flags, &mut error),
                    Some(version) => {
                        do version.with_c_str |version_c_str| {
                            detail::g_irepository_require(self.ptr, namespace_c_str, version_c_str, flags, &mut error)
                        }
                    }
                };
                if ptr::is_null(typelib_ptr) {
                    Err(glib::Error::new(error))
                } else {
                    Ok(Typelib {
                        ptr: typelib_ptr,
                        owns: false
                    })
                }
            }
        }
    }
}

impl Drop for Repository {
    fn drop(&mut self) {
        unsafe {
            if self.owns {
                gobject::detail::g_object_unref(self.ptr as glib::gpointer);
            }
            self.ptr = ptr::mut_null();
            self.owns = false;
        }
    }
}
<commit_msg>Add `#[inline]`<commit_after>// Copyright 2013 The rust-gobject authors.
//
// 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.

#[link(name = "gi", vers = "0.1")];
#[crate_type = "lib"];

extern mod glib;
extern mod gobject;

use glib::detail::error::GError;
use glib::strfuncs::Strdupv;
use std::c_str::CString;
use std::cast;
use std::libc;
use std::option::Option;
use std::ptr;
use std::result::Result;
use std::str;
use std::unstable::raw::Slice;

mod detail;

pub struct AttributeIter {
    priv ptr: *mut detail::GIBaseInfo,
    priv it: detail::GIAttributeIter
}

impl Drop for AttributeIter {
    fn drop(&mut self) {
        unsafe {
            detail::g_base_info_unref(self.ptr);
            self.ptr = ptr::mut_null();
        }
    }
}

impl Iterator<(~str, ~str)> for AttributeIter {
    fn next(&mut self) -> Option<(~str, ~str)> {
        unsafe {
            let mut name_c_str: *libc::c_char = ptr::null();
            let mut value_c_str: *libc::c_char = ptr::null();
            if !detail::g_base_info_iterate_attributes(self.ptr, &mut self.it, &mut name_c_str, &mut value_c_str) {
                None
            } else {
                Some((str::raw::from_c_str(name_c_str), str::raw::from_c_str(value_c_str)))
            }
        }
    }
}

#[deriving(ToStr)]
pub enum InfoType {
    Invalid = 0,
    Function = 1,
    Callback = 2,
    Struct = 3,
    Boxed = 4,
    Enum = 5,
    Flags = 6,
    Object = 7,
    Interface = 8,
    Constant = 9,
    // Invalid0
    Union = 11,
    Value = 12,
    Signal = 13,
    Vfunc = 14,
    Property = 15,
    Field = 16,
    Arg = 17,
    Type = 18,
    Unresolved = 19
}

pub struct BaseInfo {
    priv ptr: *mut detail::GIBaseInfo,
    priv owns: bool
}

impl BaseInfo {
    pub fn type_(&self) -> InfoType {
        unsafe {
            detail::g_base_info_get_type(self.ptr)
        }
    }

    pub fn name(&self) -> Option<~str> {
        unsafe {
            let name_c_str = detail::g_base_info_get_name(self.ptr);
            if ptr::is_null(name_c_str) {
                None
            } else {
                Some(str::raw::from_c_str(name_c_str))
            }
        }
    }

    #[inline]
    pub unsafe fn raw_name(&self) -> Option<&str> {
        let name_c_str = detail::g_base_info_get_name(self.ptr);
        if ptr::is_null(name_c_str) {
            None
        } else {
            let mut name_len = 0u;
            while *ptr::offset(name_c_str, name_len as int) != 0 {
                name_len += 1;
            }
            Some(cast::transmute(Slice {
                data: name_c_str,
                len: name_len
            }))
        }
    }

    pub fn namespace(&self) -> ~str {
        unsafe {
            let namespace_c_str = detail::g_base_info_get_namespace(self.ptr);
            str::raw::from_c_str(namespace_c_str)
        }
    }

    pub fn is_deprecated(&self) -> bool {
        unsafe {
            detail::g_base_info_is_deprecated(self.ptr)
        }
    }

    pub fn attribute(&self, name: &str) -> Option<~str> {
        unsafe {
            do name.with_c_str |name_c_str| {
                let attribute_c_str = detail::g_base_info_get_attribute(self.ptr, name_c_str);
                if ptr::is_null(attribute_c_str) {
                    None
                } else {
                    Some(str::raw::from_c_str(attribute_c_str))
                }
            }
        }
    }

    pub fn attribute_iter(&self) -> AttributeIter {
        unsafe {
            AttributeIter {
                ptr: detail::g_base_info_ref(self.ptr),
                it: detail::GIAttributeIter::new()
            }
        }
    }
}

impl Clone for BaseInfo {
    fn clone(&self) -> BaseInfo {
        unsafe {
            BaseInfo {
                ptr: detail::g_base_info_ref(self.ptr),
                owns: true
            }
        }
    }
}

impl Drop for BaseInfo {
    fn drop(&mut self) {
        unsafe {
            if self.owns {
                detail::g_base_info_unref(self.ptr);
            }
            self.ptr = ptr::mut_null();
            self.owns = false;
        }
    }
}

impl Eq for BaseInfo {
    fn eq(&self, other: &BaseInfo) -> bool {
        unsafe {
            detail::g_base_info_equal(self.ptr, other.ptr)
        }
    }
}

pub struct Typelib {
    priv ptr: *mut detail::GITypelib,
    priv owns: bool
}

impl Drop for Typelib {
    fn drop(&mut self) {
        unsafe {
            if self.owns {
                detail::g_typelib_free(self.ptr);
            }
            self.ptr = ptr::mut_null();
            self.owns = false;
        }
    }
}

pub struct Repository {
    priv ptr: *mut detail::GIRepository,
    priv owns: bool
}

#[deriving(ToStr)]
pub enum RepositoryLoadFlag {
    Lazy = 1
}

impl Repository {
    pub fn default() -> Repository {
        unsafe {
            Repository {
                ptr: detail::g_irepository_get_default(),
                owns: false
            }
        }
    }

    pub fn info(&self, namespace_cstring: &CString, index: glib::gint) -> BaseInfo {
        unsafe {
            do namespace_cstring.with_ref |namespace_c_str| {
                BaseInfo {
                    ptr: detail::g_irepository_get_info(self.ptr, namespace_c_str, index),
                    owns: true
                }
            }
        }
    }

    pub fn loaded_namespaces(&self) -> ~[~str] {
        unsafe {
            let mut res: ~[~str] = ~[];
            let mut namespaces_strdupv = Strdupv::new(detail::g_irepository_get_loaded_namespaces(self.ptr));
            do namespaces_strdupv.with_mut_ptr |namespaces_array| {
                let mut p = namespaces_array;
                loop {
                    let namespace_c_str = ptr::read_ptr(p);
                    if ptr::is_null(namespace_c_str) {
                        break;
                    }
                    res.push(str::raw::from_c_str(namespace_c_str as *glib::gchar));
                    p = ptr::mut_offset(p, 1);
                }
            };
            res
        }
    }

    pub fn n_infos(&self, namespace_cstring: &CString) -> glib::gint {
        unsafe {
            do namespace_cstring.with_ref |namespace_c_str| {
                detail::g_irepository_get_n_infos(self.ptr, namespace_c_str)
            }
        }
    }

    pub fn require(&self, namespace: &str, opt_version: Option<&str>, flags: &[RepositoryLoadFlag]) -> Result<Typelib, glib::Error> {
        unsafe {
            do namespace.with_c_str |namespace_c_str| {
                let mut error: *mut GError = ptr::mut_null();
                let typelib_ptr = match opt_version {
                    None => detail::g_irepository_require(self.ptr, namespace_c_str, ptr::null(), flags, &mut error),
                    Some(version) => {
                        do version.with_c_str |version_c_str| {
                            detail::g_irepository_require(self.ptr, namespace_c_str, version_c_str, flags, &mut error)
                        }
                    }
                };
                if ptr::is_null(typelib_ptr) {
                    Err(glib::Error::new(error))
                } else {
                    Ok(Typelib {
                        ptr: typelib_ptr,
                        owns: false
                    })
                }
            }
        }
    }
}

impl Drop for Repository {
    fn drop(&mut self) {
        unsafe {
            if self.owns {
                gobject::detail::g_object_unref(self.ptr as glib::gpointer);
            }
            self.ptr = ptr::mut_null();
            self.owns = false;
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Stdin;
use std::io::Stdout;
use std::io::Write;

use super::lexer::Lexer;
use super::token::TokenType;

const PROMPT: &'static str = ">> ";

pub fn start(mut in_: Stdin, mut out: Stdout) {
    loop {
        print!("{}", PROMPT);
        out.flush().unwrap();

        let mut s = String::new();
        in_.read_line(&mut s).expect("Did not enter a correct string");

        let mut l = Lexer::new(s);
        let mut tok = l.next_token();
        while tok.token_type != TokenType::EOF {
            write!(&mut out, "{:?}\n", tok).unwrap();
            out.flush().unwrap();
            tok = l.next_token();
        }
    }
}
<commit_msg>Unneeded mutability.<commit_after>use std::io::Stdin;
use std::io::Stdout;
use std::io::Write;

use super::lexer::Lexer;
use super::token::TokenType;

const PROMPT: &'static str = ">> ";

pub fn start(in_: Stdin, mut out: Stdout) {
    loop {
        print!("{}", PROMPT);
        out.flush().unwrap();

        let mut s = String::new();
        in_.read_line(&mut s).expect("Did not enter a correct string");

        let mut l = Lexer::new(s);
        let mut tok = l.next_token();
        while tok.token_type != TokenType::EOF {
            write!(&mut out, "{:?}\n", tok).unwrap();
            out.flush().unwrap();
            tok = l.next_token();
        }
    }
}
<|endoftext|>