<commit_before>
use std;
use input;
use {
    Action,
    AlwaysSucceed,
    Behavior,
    Event,
    Failure,
    If,
    Input,
    Not,
    Pressed,
    Released,
    Running,
    Select,
    Sequence,
    Status,
    Success,
    Update,
    UpdateArgs,
    Wait,
    WaitForever,
    WhenAll,
    While,
};

/// Keeps track of a behavior.
#[deriving(Clone, PartialEq)]
pub enum State<A, S> {
    /// Returns `Success` when button is pressed.
    PressedState(input::Button),
    /// Returns `Success` when button is released.
    ReleasedState(input::Button),
    /// Executes an action.
    ActionState(A, Option<S>),
    /// Converts `Success` into `Failure` and vice versa.
    NotState(Box<State<A, S>>),
    /// Ignores failures and always return `Success`.
    AlwaysSucceedState(Box<State<A, S>>),
    /// Keeps track of waiting for a period of time before continuing.
    ///
    /// f64: Total time in seconds to wait
    ///
    /// f64: Time elapsed in seconds
    WaitState(f64, f64),
    /// Waits forever.
    WaitForeverState,
    /// Keeps track of an `If` behavior.
    /// If status is `Running`, then it evaluates the condition.
    /// If status is `Success`, then it evaluates the success behavior.
    /// If status is `Failure`, then it evaluates the failure behavior.
    IfState(Box<Behavior<A>>, Box<Behavior<A>>, Status, Box<State<A, S>>),
    /// Keeps track of a `Select` behavior.
    SelectState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of an `Sequence` behavior.
    SequenceState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `While` behavior.
    WhileState(Box<State<A, S>>, Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of an `WhenAll` behavior.
    WhenAllState(Vec<Option<State<A, S>>>),
}

impl<A: Clone, S> State<A, S> {
    /// Creates a state from a behavior.
    pub fn new(behavior: Behavior<A>) -> State<A, S> {
        match behavior {
            Pressed(button) => PressedState(button),
            Released(button) => ReleasedState(button),
            Action(action) => ActionState(action, None),
            Not(ev) => NotState(box State::new(*ev)),
            AlwaysSucceed(ev) => AlwaysSucceedState(box State::new(*ev)),
            Wait(dt) => WaitState(dt, 0.0),
            WaitForever => WaitForeverState,
            If(condition, success, failure) => {
                let state = State::new(*condition);
                IfState(success, failure, Running, box state)
            }
            Select(sel) => {
                let state = State::new(sel[0].clone());
                SelectState(sel, 0, box state)
            }
            Sequence(seq) => {
                let state = State::new(seq[0].clone());
                SequenceState(seq, 0, box state)
            }
            While(ev, rep) => {
                let state = State::new(rep[0].clone());
                WhileState(box State::new(*ev), rep, 0, box state)
            }
            WhenAll(all)
                => WhenAllState(all.move_iter().map(
                    |ev| Some(State::new(ev))).collect()),
        }
    }

    /// Updates the cursor that tracks an event.
    ///
    /// The action need to return status and remaining delta time.
    /// Returns status and the remaining delta time.
    pub fn update(
        &mut self,
        e: &Event,
        f: |dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
    ) -> (Status, f64) {
        match (e, self) {
            (&Input(input::Press(button_pressed)), &PressedState(button))
            if button_pressed == button => {
                // Button press is considered to happen instantly.
                // There is no remaining delta time because this is input event.
                (Success, 0.0)
            }
            (&Input(input::Release(button_released)), &ReleasedState(button))
            if button_released == button => {
                // Button release is considered to happen instantly.
                // There is no remaining delta time because this is input event.
                (Success, 0.0)
            }
            (&Update(UpdateArgs { dt }),
             &ActionState(ref action, ref mut state)) => {
                // Execute action.
                f(dt, action, state)
            }
            (_, &NotState(ref mut cur)) => {
                match cur.update(e, f) {
                    (Running, dt) => (Running, dt),
                    (Failure, dt) => (Success, dt),
                    (Success, dt) => (Failure, dt),
                }
            }
            (_, &AlwaysSucceedState(ref mut cur)) => {
                match cur.update(e, f) {
                    (Running, dt) => (Running, dt),
                    (_, dt) => (Success, dt),
                }
            }
            (&Update(UpdateArgs { dt }), &WaitState(wait_t, ref mut t)) => {
                if *t + dt >= wait_t {
                    let remaining_dt = *t + dt - wait_t;
                    *t = wait_t;
                    (Success, remaining_dt)
                } else {
                    *t += dt;
                    (Running, 0.0)
                }
            }
            (_, &IfState(ref success, ref failure,
                         ref mut status, ref mut state)) => {
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                // Run in a loop to evaluate success or failure with
                // remaining delta time after condition.
                loop {
                    *status = match *status {
                        Running => {
                            match state.update(e, |dt, a, s| f(dt, a, s)) {
                                (Running, dt) => { return (Running, dt); },
                                (Success, dt) => {
                                    **state = State::new((**success).clone());
                                    remaining_dt = dt;
                                    Success
                                }
                                (Failure, dt) => {
                                    **state = State::new((**failure).clone());
                                    remaining_dt = dt;
                                    Failure
                                }
                            }
                        }
                        _ => {
                            return state.update(match *e {
                                Update(_) => {
                                    remaining_e = Update(UpdateArgs {
                                            dt: remaining_dt
                                        });
                                    &remaining_e
                                }
                                _ => e
                            }, |dt, a, s| f(dt, a, s));
                        }
                    }
                }
            }
            (_, &SelectState(
                ref seq,
                ref mut i,
                ref mut cursor
            )) => {
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                while *i < seq.len() {
                    match cursor.update(
                        match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Success, x) => { return (Success, x) }
                        (Running, _) => { break }
                        (Failure, new_dt) => { remaining_dt = new_dt }
                    };
                    *i += 1;
                    // If end of sequence,
                    // return the 'dt' that is left.
                    if *i >= seq.len() { return (Failure, remaining_dt); }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cursor = State::new(seq[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &SequenceState(ref seq, ref mut i, ref mut cursor)) => {
                let cur = cursor;
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                while *i < seq.len() {
                    match cur.update(match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                // If this is the last event, then the sequence succeeded.
                                _ => if *i == seq.len() - 1 {
                                        return (Success, new_dt)
                                    } else {
                                        return (Running, 0.0)
                                    }
                            }
                        }
                    };
                    *i += 1;
                    // If end of sequence,
                    // return the 'dt' that is left.
                    if *i >= seq.len() { return (Success, remaining_dt); }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(seq[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &WhileState(ref mut ev_cursor, ref rep, ref mut i,
                            ref mut cursor)) => {
                // If the event terminates, do not execute the loop.
                match ev_cursor.update(e, |dt, a, s| f(dt, a, s)) {
                    (Running, _) => {}
                    x => return x,
                };
                let cur = cursor;
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                loop {
                    match cur.update(match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                _ => return (Running, 0.0)
                            }
                        }
                    };
                    *i += 1;
                    // If end of repeated events,
                    // start over from the first one.
                    if *i >= rep.len() { *i = 0; }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(rep[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &WhenAllState(ref mut cursors)) => {
                // Get the least delta time left over.
                let mut min_dt = std::f64::MAX_VALUE;
                // Count number of terminated events.
                let mut terminated = 0;
                for cur in cursors.mut_iter() {
                    match *cur {
                        None => terminated += 1,
                        Some(ref mut cur) => {
                            match cur.update(e, |dt, a, s| f(dt, a, s)) {
                                (Running, _) => {},
                                (Failure, new_dt) => return (Failure, new_dt),
                                (Success, new_dt) => {
                                    min_dt = min_dt.min(new_dt);
                                    terminated += 1;
                                }
                            }
                        }
                    }
                }
                match terminated {
                    // If there are no events, there is a whole 'dt' left.
                    0 if cursors.len() == 0 => (Success, match *e {
                            Update(UpdateArgs { dt }) => dt,
                            // Other kind of events happen instantly.
                            _ => 0.0
                        }),
                    // If all events terminated, the least delta time is left.
                    n if cursors.len() == n => (Success, min_dt),
                    _ => (Running, 0.0)
                }
            }
            _ => (Running, 0.0)
        }
    }
}
<commit_msg>Upgraded to latest Rust<commit_after>
use std;
use input;
use {
    Action,
    AlwaysSucceed,
    Behavior,
    Event,
    Failure,
    If,
    Input,
    Not,
    Pressed,
    Released,
    Running,
    Select,
    Sequence,
    Status,
    Success,
    Update,
    UpdateArgs,
    Wait,
    WaitForever,
    WhenAll,
    While,
};

/// Keeps track of a behavior.
#[deriving(Clone, PartialEq)]
pub enum State<A, S> {
    /// Returns `Success` when button is pressed.
    PressedState(input::Button),
    /// Returns `Success` when button is released.
    ReleasedState(input::Button),
    /// Executes an action.
    ActionState(A, Option<S>),
    /// Converts `Success` into `Failure` and vice versa.
    NotState(Box<State<A, S>>),
    /// Ignores failures and always return `Success`.
    AlwaysSucceedState(Box<State<A, S>>),
    /// Keeps track of waiting for a period of time before continuing.
    ///
    /// f64: Total time in seconds to wait
    ///
    /// f64: Time elapsed in seconds
    WaitState(f64, f64),
    /// Waits forever.
    WaitForeverState,
    /// Keeps track of an `If` behavior.
    /// If status is `Running`, then it evaluates the condition.
    /// If status is `Success`, then it evaluates the success behavior.
    /// If status is `Failure`, then it evaluates the failure behavior.
    IfState(Box<Behavior<A>>, Box<Behavior<A>>, Status, Box<State<A, S>>),
    /// Keeps track of a `Select` behavior.
    SelectState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of an `Sequence` behavior.
    SequenceState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `While` behavior.
    WhileState(Box<State<A, S>>, Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of an `WhenAll` behavior.
    WhenAllState(Vec<Option<State<A, S>>>),
}

impl<A: Clone, S> State<A, S> {
    /// Creates a state from a behavior.
    pub fn new(behavior: Behavior<A>) -> State<A, S> {
        match behavior {
            Pressed(button) => PressedState(button),
            Released(button) => ReleasedState(button),
            Action(action) => ActionState(action, None),
            Not(ev) => NotState(box State::new(*ev)),
            AlwaysSucceed(ev) => AlwaysSucceedState(box State::new(*ev)),
            Wait(dt) => WaitState(dt, 0.0),
            WaitForever => WaitForeverState,
            If(condition, success, failure) => {
                let state = State::new(*condition);
                IfState(success, failure, Running, box state)
            }
            Select(sel) => {
                let state = State::new(sel[0].clone());
                SelectState(sel, 0, box state)
            }
            Sequence(seq) => {
                let state = State::new(seq[0].clone());
                SequenceState(seq, 0, box state)
            }
            While(ev, rep) => {
                let state = State::new(rep[0].clone());
                WhileState(box State::new(*ev), rep, 0, box state)
            }
            WhenAll(all)
                => WhenAllState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
        }
    }

    /// Updates the cursor that tracks an event.
    ///
    /// The action need to return status and remaining delta time.
    /// Returns status and the remaining delta time.
    pub fn update(
        &mut self,
        e: &Event,
        f: |dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
    ) -> (Status, f64) {
        match (e, self) {
            (&Input(input::Press(button_pressed)), &PressedState(button))
            if button_pressed == button => {
                // Button press is considered to happen instantly.
                // There is no remaining delta time because this is input event.
                (Success, 0.0)
            }
            (&Input(input::Release(button_released)), &ReleasedState(button))
            if button_released == button => {
                // Button release is considered to happen instantly.
                // There is no remaining delta time because this is input event.
                (Success, 0.0)
            }
            (&Update(UpdateArgs { dt }),
             &ActionState(ref action, ref mut state)) => {
                // Execute action.
                f(dt, action, state)
            }
            (_, &NotState(ref mut cur)) => {
                match cur.update(e, f) {
                    (Running, dt) => (Running, dt),
                    (Failure, dt) => (Success, dt),
                    (Success, dt) => (Failure, dt),
                }
            }
            (_, &AlwaysSucceedState(ref mut cur)) => {
                match cur.update(e, f) {
                    (Running, dt) => (Running, dt),
                    (_, dt) => (Success, dt),
                }
            }
            (&Update(UpdateArgs { dt }), &WaitState(wait_t, ref mut t)) => {
                if *t + dt >= wait_t {
                    let remaining_dt = *t + dt - wait_t;
                    *t = wait_t;
                    (Success, remaining_dt)
                } else {
                    *t += dt;
                    (Running, 0.0)
                }
            }
            (_, &IfState(ref success, ref failure,
                         ref mut status, ref mut state)) => {
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                // Run in a loop to evaluate success or failure with
                // remaining delta time after condition.
                loop {
                    *status = match *status {
                        Running => {
                            match state.update(e, |dt, a, s| f(dt, a, s)) {
                                (Running, dt) => { return (Running, dt); },
                                (Success, dt) => {
                                    **state = State::new((**success).clone());
                                    remaining_dt = dt;
                                    Success
                                }
                                (Failure, dt) => {
                                    **state = State::new((**failure).clone());
                                    remaining_dt = dt;
                                    Failure
                                }
                            }
                        }
                        _ => {
                            return state.update(match *e {
                                Update(_) => {
                                    remaining_e = Update(UpdateArgs {
                                            dt: remaining_dt
                                        });
                                    &remaining_e
                                }
                                _ => e
                            }, |dt, a, s| f(dt, a, s));
                        }
                    }
                }
            }
            (_, &SelectState(
                ref seq,
                ref mut i,
                ref mut cursor
            )) => {
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                while *i < seq.len() {
                    match cursor.update(
                        match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Success, x) => { return (Success, x) }
                        (Running, _) => { break }
                        (Failure, new_dt) => { remaining_dt = new_dt }
                    };
                    *i += 1;
                    // If end of sequence,
                    // return the 'dt' that is left.
                    if *i >= seq.len() { return (Failure, remaining_dt); }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cursor = State::new(seq[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &SequenceState(ref seq, ref mut i, ref mut cursor)) => {
                let cur = cursor;
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                while *i < seq.len() {
                    match cur.update(match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                // If this is the last event, then the sequence succeeded.
                                _ => if *i == seq.len() - 1 {
                                        return (Success, new_dt)
                                    } else {
                                        return (Running, 0.0)
                                    }
                            }
                        }
                    };
                    *i += 1;
                    // If end of sequence,
                    // return the 'dt' that is left.
                    if *i >= seq.len() { return (Success, remaining_dt); }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(seq[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &WhileState(ref mut ev_cursor, ref rep, ref mut i,
                            ref mut cursor)) => {
                // If the event terminates, do not execute the loop.
                match ev_cursor.update(e, |dt, a, s| f(dt, a, s)) {
                    (Running, _) => {}
                    x => return x,
                };
                let cur = cursor;
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                loop {
                    match cur.update(match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                _ => return (Running, 0.0)
                            }
                        }
                    };
                    *i += 1;
                    // If end of repeated events,
                    // start over from the first one.
                    if *i >= rep.len() { *i = 0; }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(rep[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &WhenAllState(ref mut cursors)) => {
                // Get the least delta time left over.
                let mut min_dt = std::f64::MAX_VALUE;
                // Count number of terminated events.
                let mut terminated = 0;
                for cur in cursors.iter_mut() {
                    match *cur {
                        None => terminated += 1,
                        Some(ref mut cur) => {
                            match cur.update(e, |dt, a, s| f(dt, a, s)) {
                                (Running, _) => {},
                                (Failure, new_dt) => return (Failure, new_dt),
                                (Success, new_dt) => {
                                    min_dt = min_dt.min(new_dt);
                                    terminated += 1;
                                }
                            }
                        }
                    }
                }
                match terminated {
                    // If there are no events, there is a whole 'dt' left.
                    0 if cursors.len() == 0 => (Success, match *e {
                            Update(UpdateArgs { dt }) => dt,
                            // Other kind of events happen instantly.
                            _ => 0.0
                        }),
                    // If all events terminated, the least delta time is left.
                    n if cursors.len() == n => (Success, min_dt),
                    _ => (Running, 0.0)
                }
            }
            _ => (Running, 0.0)
        }
    }
}
<|endoftext|>


<commit_before>extern crate regex;
use self::regex::Regex;
use super::*;

#[test]
fn parse_args_help_works() {
    assert_eq!(parse_args(vec!["-h".to_string()]), Ok(ShowHelp));
    assert_eq!(parse_args(vec!["--help".to_string()]), Ok(ShowHelp));
}

#[test]
fn parse_args_version_works() {
    assert_eq!(parse_args(vec!["-v".to_string()]), Ok(ShowVersion));
    assert_eq!(parse_args(vec!["--version".to_string()]), Ok(ShowVersion));
}

#[test]
fn parse_args_uses_default_string() {
    assert_eq!(parse_args(vec![]), Ok(RepeatString(DEFAULT_STRING.to_string())));
}

#[test]
fn parse_args_uses_arguments() {
    assert_eq!(parse_args(vec!["str".to_string()]),
               Ok(RepeatString("str".to_string())));
}

#[test]
fn parse_args_concatenates_arguments() {
    assert_eq!(parse_args(vec!["str".to_string(), "dup".to_string()]),
               Ok(RepeatString("str dup".to_string())));
}

#[test]
fn parse_args_allows_escaped_flags() {
    assert_eq!(parse_args(vec!["--".to_string(), "-h".to_string()]),
               Ok(RepeatString("-h".to_string())));
}

#[test]
fn parse_args_raises_error_on_illegal_argument() {
    assert!(parse_args(vec!["-g".to_string()]).is_err());
    match parse_args(vec!["--global".to_string()]) {
        Err(InvalidOption(_)) => assert!(true),
        _ => unreachable!()
    }
}

#[test]
fn parse_args_error_has_message() {
    let re = Regex::new(r"Unrecognized option").unwrap();

    assert!(parse_args(vec!["-g".to_string()]).is_err());
    match parse_args(vec!["--global".to_string()]) {
        Err(e) => assert!(re.is_match(&e.message())),
        _ => unreachable!()
    }
}

#[test]
fn string_newline_terminate_works() {
    assert_eq!("word".to_string().newline_terminate(), "word\n");
    assert_eq!("myname".to_string().newline_terminate(), "myname\n");
}

#[test]
fn string_fill_works() {
    let max = 1500;
    let buf = "myword\n".to_string().fill(max);

    // make sure string isn't too long
    assert!(buf.len() <= max);

    // make sure buf only contains the word followed by a newline
    let re = Regex::new(r"^(myword\n)+$").unwrap();
    assert!(re.is_match(&buf));
}

#[test]
fn version_text_returns_version() {
    let re = Regex::new(r"^.* version \d+(\.\d+)*.*$").unwrap();
    assert!(re.is_match(&version_text()));
}

#[test]
fn help_text_documents_options() {
    // test if it documents the help flag
    let help_flag = Regex::new(r"--help").unwrap();
    assert!(help_flag.is_match(&help_text()));

    // test if it documents the version flag
    let version_flag = Regex::new(r"--version").unwrap();
    assert!(version_flag.is_match(&help_text()));

    // test if it documents the usage
    let usage = Regex::new(r"Usage: ").unwrap();
    assert!(usage.is_match(&help_text()));
}
<commit_msg>adds test for Write::write_repeat()<commit_after>extern crate regex;
use self::regex::Regex;
use super::*;

#[test]
fn parse_args_help_works() {
    assert_eq!(parse_args(vec!["-h".to_string()]), Ok(ShowHelp));
    assert_eq!(parse_args(vec!["--help".to_string()]), Ok(ShowHelp));
}

#[test]
fn parse_args_version_works() {
    assert_eq!(parse_args(vec!["-v".to_string()]), Ok(ShowVersion));
    assert_eq!(parse_args(vec!["--version".to_string()]), Ok(ShowVersion));
}

#[test]
fn parse_args_uses_default_string() {
    assert_eq!(parse_args(vec![]), Ok(RepeatString(DEFAULT_STRING.to_string())));
}

#[test]
fn parse_args_uses_arguments() {
    assert_eq!(parse_args(vec!["str".to_string()]),
               Ok(RepeatString("str".to_string())));
}

#[test]
fn parse_args_concatenates_arguments() {
    assert_eq!(parse_args(vec!["str".to_string(), "dup".to_string()]),
               Ok(RepeatString("str dup".to_string())));
}

#[test]
fn parse_args_allows_escaped_flags() {
    assert_eq!(parse_args(vec!["--".to_string(), "-h".to_string()]),
               Ok(RepeatString("-h".to_string())));
}

#[test]
fn parse_args_raises_error_on_illegal_argument() {
    assert!(parse_args(vec!["-g".to_string()]).is_err());
    match parse_args(vec!["--global".to_string()]) {
        Err(InvalidOption(_)) => assert!(true),
        _ => unreachable!()
    }
}

#[test]
fn parse_args_error_has_message() {
    let re = Regex::new(r"Unrecognized option").unwrap();

    assert!(parse_args(vec!["-g".to_string()]).is_err());
    match parse_args(vec!["--global".to_string()]) {
        Err(e) => assert!(re.is_match(&e.message())),
        _ => unreachable!()
    }
}

#[test]
fn string_newline_terminate_works() {
    assert_eq!("word".to_string().newline_terminate(), "word\n");
    assert_eq!("myname".to_string().newline_terminate(), "myname\n");
}

#[test]
fn string_fill_works() {
    let max = 1500;
    let buf = "myword\n".to_string().fill(max);

    // make sure string isn't too long
    assert!(buf.len() <= max);

    // make sure buf only contains the word followed by a newline
    let re = Regex::new(r"^(myword\n)+$").unwrap();
    assert!(re.is_match(&buf));
}

#[test]
fn version_text_returns_version() {
    let re = Regex::new(r"^.* version \d+(\.\d+)*.*$").unwrap();
    assert!(re.is_match(&version_text()));
}

#[test]
fn help_text_documents_options() {
    // test if it documents the help flag
    let help_flag = Regex::new(r"--help").unwrap();
    assert!(help_flag.is_match(&help_text()));

    // test if it documents the version flag
    let version_flag = Regex::new(r"--version").unwrap();
    assert!(version_flag.is_match(&help_text()));

    // test if it documents the usage
    let usage = Regex::new(r"Usage: ").unwrap();
    assert!(usage.is_match(&help_text()));
}

struct Full {
}

impl Full {
    fn new() -> Self {
        Full{}
    }
}

impl Write for Full {
    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::BrokenPipe, "full"))
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

#[test]
fn write_repeat_stops_on_error() {
    assert_eq!(Full::new().write_repeat("some data".as_bytes()).kind(),
               io::ErrorKind::BrokenPipe);
}
<|endoftext|>


<commit_before>//! Various utility functionality.
use std::io;
use std::fs;
use std::mem;
use std::env;
use std::time;
use std::process;
use std::path::{Path, PathBuf};
use std::io::{Read, Write, Seek, SeekFrom};

use term;
use log;
use uuid::{Uuid, UuidVersion};
use sha1::Sha1;
use clap::{App, AppSettings};
use zip::ZipArchive;

use prelude::*;

#[cfg(not(windows))]
use chan_signal::{notify, Signal};

/// A simple logger
pub struct Logger;

impl log::Log for Logger {
    fn enabled(&self, _metadata: &log::LogMetadata) -> bool {
        true
    }
    fn log(&self, record: &log::LogRecord) {
        if !self.enabled(record.metadata()) {
            return;
        }

        let mut out_term;
        let mut out_stderr;

        let mut w = if let Some(mut term) = term::stderr() {
            term.fg(match record.level() {
                    log::LogLevel::Error | log::LogLevel::Warn => term::color::RED,
                    log::LogLevel::Info => term::color::CYAN,
                    log::LogLevel::Debug | log::LogLevel::Trace => term::color::YELLOW,
                })
                .ok();
            out_term = term;
            &mut out_term as &mut Write
        } else {
            out_stderr = io::stderr();
            &mut out_stderr as &mut Write
        };
        writeln!(w,
                 "[{}] {} {}",
                 record.level(),
                 record.target(),
                 record.args())
            .ok();
        if let Some(mut term) = term::stderr() {
            term.reset().ok();
        }
    }
}

/// Helper for temporary file access
pub struct TempFile {
    f: Option<fs::File>,
    path: PathBuf,
}

impl TempFile {
    /// Creates a new tempfile.
    pub fn new() -> io::Result<TempFile> {
        let mut path = env::temp_dir();
        path.push(Uuid::new(UuidVersion::Random).unwrap().hyphenated().to_string());
        let f = fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)
            .unwrap();
        Ok(TempFile {
            f: Some(f),
            path: path.to_path_buf(),
        })
    }

    /// Opens the tempfile
    pub fn open(&self) -> fs::File {
        let mut f = self.f.as_ref().unwrap().try_clone().unwrap();
        let _ = f.seek(SeekFrom::Start(0));
        f
    }

    /// Returns the path to the tempfile
    pub fn path(&self) -> &Path {
        &self.path
    }
}

impl Drop for TempFile {
    fn drop(&mut self) {
        mem::drop(self.f.take());
        let _ = fs::remove_file(&self.path);
    }
}

/// On non windows platforms this runs the function until it's
/// being interrupted by a signal.
#[cfg(not(windows))]
pub fn run_or_interrupt<F>(f: F) -> Option<Signal>
    where F: FnOnce() -> (),
          F: Send + 'static
{
    use chan;
    let run = |_sdone: chan::Sender<()>| f();
    let signal = notify(&[Signal::INT, Signal::TERM]);
    let (sdone, rdone) = chan::sync(0);
    ::std::thread::spawn(move || run(sdone));

    let mut rv = None;

    chan_select! {
        signal.recv() -> signal => { rv = signal; },
        rdone.recv() => {}
    }

    rv
}

/// Helper function to create a clap app for subcommands
pub fn make_subcommand<'a, 'b: 'a>(name: &str) -> App<'a, 'b> {
    App::new(name)
        .max_term_width(100)
        .setting(AppSettings::UnifiedHelpMessage)
        .setting(AppSettings::DisableVersion)
}

/// Given a path returns the SHA1 checksum for it.
pub fn get_sha1_checksum<R: Read>(mut rdr: R) -> Result<String> {
    let mut sha = Sha1::new();
    let mut buf = [0u8; 16384];
    loop {
        let read = rdr.read(&mut buf)?;
        if read == 0 {
            break;
        }
        sha.update(&buf[..read]);
    }
    Ok(sha.digest().to_string())
}

/// Checks if a path is writable.
pub fn is_writable<P: AsRef<Path>>(path: P) -> bool {
    fs::OpenOptions::new().write(true).open(&path).map(|_| true).unwrap_or(false)
}

/// Set the mode of a path to 755 if we're on a Unix machine, otherwise
/// don't do anything with the given path.
pub fn set_executable_mode<P: AsRef<Path>>(path: P) -> io::Result<()> {
    #[cfg(not(windows))]
    fn exec<P: AsRef<Path>>(path: P) -> io::Result<()> {
        use std::os::unix::fs::PermissionsExt;
        let mut perm = fs::metadata(&path)?.permissions();
        perm.set_mode(0o755);
        fs::set_permissions(&path, perm)
    }

    #[cfg(windows)]
    fn exec<P: AsRef<Path>>(_path: P) -> io::Result<()> {
        Ok(())
    }

    exec(path)
}

/// Prints a message and loops until yes or no is entered.
pub fn prompt_to_continue(message: &str) -> io::Result<bool> {
    loop {
        print!("{} [y/n] ", message);
        io::stdout().flush()?;

        let mut buf = String::new();
        io::stdin().read_line(&mut buf)?;
        let input = buf.trim();

        if input == "y" {
            return Ok(true);
        } else if input == "n" {
            return Ok(false);
        }
        println!("invalid input!");
    }
}

/// Prompts for input and returns it.
pub fn prompt(message: &str) -> io::Result<String> {
    loop {
        print!("{}: ", message);
        io::stdout().flush()?;
        let mut buf = String::new();
        io::stdin().read_line(&mut buf)?;
        let input = buf.trim();
        if input.len() > 0 {
            return Ok(input.to_owned());
        }
    }
}

/// Given a system time returns the unix timestamp as f64
pub fn to_timestamp(tm: time::SystemTime) -> f64 {
    let duration = tm.duration_since(time::UNIX_EPOCH).unwrap();
    (duration.as_secs() as f64) + (duration.subsec_nanos() as f64 / 1e09)
}

/// Capitalizes a string and returns it.
pub fn capitalize_string(s: &str) -> String {
    use std::ascii::AsciiExt;
    let mut bytes = s.as_bytes().to_vec();
    bytes.make_ascii_lowercase();
    bytes[0] = bytes[0].to_ascii_uppercase();
    String::from_utf8(bytes).unwrap()
}

/// Checks if a file is a zip file and returns a result
pub fn is_zip_file_as_result<R: Read + Seek>(mut rdr: R) -> Result<()> {
    ZipArchive::new(&mut rdr)?;
    Ok(())
}

/// Checks if a file is a zip file but only returns a bool
pub fn is_zip_file<R: Read + Seek>(rdr: R) -> bool {
    match is_zip_file_as_result(rdr) {
        Ok(_) => true,
        Err(_) => false,
    }
}

/// Propagate an exit status outwarts
pub fn propagate_exit_status(status: process::ExitStatus) {
    if !status.success() {
        if let Some(code) = status.code() {
            process::exit(code);
        } else {
            process::exit(1);
        }
    }
}

/// Checks if we were installed from homebrew
pub fn is_homebrew_install_result() -> Result<bool> {
    let mut exe = env::current_exe()?.canonicalize()?;
    exe.pop();
    exe.push("INSTALL_RECEIPT.json");
    Ok(exe.is_file())
}

/// Checks if we were installed from homebrew
pub fn is_homebrew_install() -> bool {
    is_homebrew_install_result().unwrap_or(false)
}
<commit_msg>Fixed homebrew detection<commit_after>//! Various utility functionality.
use std::io;
use std::fs;
use std::mem;
use std::env;
use std::time;
use std::process;
use std::path::{Path, PathBuf};
use std::io::{Read, Write, Seek, SeekFrom};

use term;
use log;
use uuid::{Uuid, UuidVersion};
use sha1::Sha1;
use clap::{App, AppSettings};
use zip::ZipArchive;

use prelude::*;

#[cfg(not(windows))]
use chan_signal::{notify, Signal};

/// A simple logger
pub struct Logger;

impl log::Log for Logger {
    fn enabled(&self, _metadata: &log::LogMetadata) -> bool {
        true
    }
    fn log(&self, record: &log::LogRecord) {
        if !self.enabled(record.metadata()) {
            return;
        }

        let mut out_term;
        let mut out_stderr;

        let mut w = if let Some(mut term) = term::stderr() {
            term.fg(match record.level() {
                    log::LogLevel::Error | log::LogLevel::Warn => term::color::RED,
                    log::LogLevel::Info => term::color::CYAN,
                    log::LogLevel::Debug | log::LogLevel::Trace => term::color::YELLOW,
                })
                .ok();
            out_term = term;
            &mut out_term as &mut Write
        } else {
            out_stderr = io::stderr();
            &mut out_stderr as &mut Write
        };
        writeln!(w,
                 "[{}] {} {}",
                 record.level(),
                 record.target(),
                 record.args())
            .ok();
        if let Some(mut term) = term::stderr() {
            term.reset().ok();
        }
    }
}

/// Helper for temporary file access
pub struct TempFile {
    f: Option<fs::File>,
    path: PathBuf,
}

impl TempFile {
    /// Creates a new tempfile.
    pub fn new() -> io::Result<TempFile> {
        let mut path = env::temp_dir();
        path.push(Uuid::new(UuidVersion::Random).unwrap().hyphenated().to_string());
        let f = fs::OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)
            .unwrap();
        Ok(TempFile {
            f: Some(f),
            path: path.to_path_buf(),
        })
    }

    /// Opens the tempfile
    pub fn open(&self) -> fs::File {
        let mut f = self.f.as_ref().unwrap().try_clone().unwrap();
        let _ = f.seek(SeekFrom::Start(0));
        f
    }

    /// Returns the path to the tempfile
    pub fn path(&self) -> &Path {
        &self.path
    }
}

impl Drop for TempFile {
    fn drop(&mut self) {
        mem::drop(self.f.take());
        let _ = fs::remove_file(&self.path);
    }
}

/// On non windows platforms this runs the function until it's
/// being interrupted by a signal.
#[cfg(not(windows))]
pub fn run_or_interrupt<F>(f: F) -> Option<Signal>
    where F: FnOnce() -> (),
          F: Send + 'static
{
    use chan;
    let run = |_sdone: chan::Sender<()>| f();
    let signal = notify(&[Signal::INT, Signal::TERM]);
    let (sdone, rdone) = chan::sync(0);
    ::std::thread::spawn(move || run(sdone));

    let mut rv = None;

    chan_select! {
        signal.recv() -> signal => { rv = signal; },
        rdone.recv() => {}
    }

    rv
}

/// Helper function to create a clap app for subcommands
pub fn make_subcommand<'a, 'b: 'a>(name: &str) -> App<'a, 'b> {
    App::new(name)
        .max_term_width(100)
        .setting(AppSettings::UnifiedHelpMessage)
        .setting(AppSettings::DisableVersion)
}

/// Given a path returns the SHA1 checksum for it.
pub fn get_sha1_checksum<R: Read>(mut rdr: R) -> Result<String> {
    let mut sha = Sha1::new();
    let mut buf = [0u8; 16384];
    loop {
        let read = rdr.read(&mut buf)?;
        if read == 0 {
            break;
        }
        sha.update(&buf[..read]);
    }
    Ok(sha.digest().to_string())
}

/// Checks if a path is writable.
pub fn is_writable<P: AsRef<Path>>(path: P) -> bool {
    fs::OpenOptions::new().write(true).open(&path).map(|_| true).unwrap_or(false)
}

/// Set the mode of a path to 755 if we're on a Unix machine, otherwise
/// don't do anything with the given path.
pub fn set_executable_mode<P: AsRef<Path>>(path: P) -> io::Result<()> {
    #[cfg(not(windows))]
    fn exec<P: AsRef<Path>>(path: P) -> io::Result<()> {
        use std::os::unix::fs::PermissionsExt;
        let mut perm = fs::metadata(&path)?.permissions();
        perm.set_mode(0o755);
        fs::set_permissions(&path, perm)
    }

    #[cfg(windows)]
    fn exec<P: AsRef<Path>>(_path: P) -> io::Result<()> {
        Ok(())
    }

    exec(path)
}

/// Prints a message and loops until yes or no is entered.
pub fn prompt_to_continue(message: &str) -> io::Result<bool> {
    loop {
        print!("{} [y/n] ", message);
        io::stdout().flush()?;

        let mut buf = String::new();
        io::stdin().read_line(&mut buf)?;
        let input = buf.trim();

        if input == "y" {
            return Ok(true);
        } else if input == "n" {
            return Ok(false);
        }
        println!("invalid input!");
    }
}

/// Prompts for input and returns it.
pub fn prompt(message: &str) -> io::Result<String> {
    loop {
        print!("{}: ", message);
        io::stdout().flush()?;
        let mut buf = String::new();
        io::stdin().read_line(&mut buf)?;
        let input = buf.trim();
        if input.len() > 0 {
            return Ok(input.to_owned());
        }
    }
}

/// Given a system time returns the unix timestamp as f64
pub fn to_timestamp(tm: time::SystemTime) -> f64 {
    let duration = tm.duration_since(time::UNIX_EPOCH).unwrap();
    (duration.as_secs() as f64) + (duration.subsec_nanos() as f64 / 1e09)
}

/// Capitalizes a string and returns it.
pub fn capitalize_string(s: &str) -> String {
    use std::ascii::AsciiExt;
    let mut bytes = s.as_bytes().to_vec();
    bytes.make_ascii_lowercase();
    bytes[0] = bytes[0].to_ascii_uppercase();
    String::from_utf8(bytes).unwrap()
}

/// Checks if a file is a zip file and returns a result
pub fn is_zip_file_as_result<R: Read + Seek>(mut rdr: R) -> Result<()> {
    ZipArchive::new(&mut rdr)?;
    Ok(())
}

/// Checks if a file is a zip file but only returns a bool
pub fn is_zip_file<R: Read + Seek>(rdr: R) -> bool {
    match is_zip_file_as_result(rdr) {
        Ok(_) => true,
        Err(_) => false,
    }
}

/// Propagate an exit status outwarts
pub fn propagate_exit_status(status: process::ExitStatus) {
    if !status.success() {
        if let Some(code) = status.code() {
            process::exit(code);
        } else {
            process::exit(1);
        }
    }
}

/// Checks if we were installed from homebrew
pub fn is_homebrew_install_result() -> Result<bool> {
    let mut exe = env::current_exe()?.canonicalize()?;
    exe.pop();
    exe.set_file_name("INSTALL_RECEIPT.json");
    Ok(exe.is_file())
}

/// Checks if we were installed from homebrew
pub fn is_homebrew_install() -> bool {
    is_homebrew_install_result().unwrap_or(false)
}
<|endoftext|>


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

use std::process::Command;

pub fn enable_ipv4_forwarding() -> Result<(), String> {
    let sysctl_arg = if cfg!(target_os = "linux") {
        "net.ipv4.ip_forward=1"
    } else if cfg!(target_os = "macos") {
        "net.inet.ip.forwarding=1"
    } else {
        unimplemented!()
    };
    let status = Command::new("sysctl")
        .arg("-w")
        .arg(sysctl_arg)
        .status()
        .unwrap();
    if status.success() {
        Ok(())
    } else {
        Err(format!("sysctl: {}", status))
    }
}

pub enum RouteType {
    Net,
    Host,
}

pub struct DefaultGateway {
    origin: String,
    remote: String,
}

impl DefaultGateway {
    pub fn create(gateway: &str, remote: &str) -> DefaultGateway {
        let origin = get_default_gateway().unwrap();
        add_route(RouteType::Host, remote, &origin).unwrap();
        delete_default_gateway().unwrap();
        set_default_gateway(gateway).unwrap();
        DefaultGateway {
            origin: origin,
            remote: String::from(remote),
        }
    }
}

impl Drop for DefaultGateway {
    fn drop(&mut self) {
        delete_default_gateway().unwrap();
        set_default_gateway(&self.origin).unwrap();
        delete_route(RouteType::Host, &self.remote).unwrap();
    }
}

pub fn delete_route(route_type: RouteType, route: &str) -> Result<(), String> {
    let mode = match route_type {
        RouteType::Net => "-net",
        RouteType::Host => "-host",
    };
    let cmd = if cfg!(target_os = "linux") {
        format!("route -n del {} {}", mode, route)
    } else if cfg!(target_os = "macos") {
        format!("route -n delete {} {}", mode, route)
    } else {
        unimplemented!()
    };
    let status = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .status()
        .unwrap();
    if status.success() {
        Ok(())
    } else {
        Err(format!("route: {}", status))
    }
}

pub fn add_route(route_type: RouteType, route: &str, gateway: &str) -> Result<(), String> {
    let mode = match route_type {
        RouteType::Net => "-net",
        RouteType::Host => "-host",
    };
    let cmd = if cfg!(target_os = "linux") {
        format!("route -n add {} {} gw {}", mode, route, gateway)
    } else if cfg!(target_os = "macos") {
        format!("route -n add {} {} {}", mode, route, gateway)
    } else {
        unimplemented!()
    };
    let status = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .status()
        .unwrap();
    if status.success() {
        Ok(())
    } else {
        Err(format!("route: {}", status))
    }
}

pub fn set_default_gateway(gateway: &str) -> Result<(), String> {
    add_route(RouteType::Net, "default", gateway)
}

pub fn delete_default_gateway() -> Result<(), String> {
    delete_route(RouteType::Net, "default")
}

pub fn get_default_gateway() -> Result<String, String> {
    let cmd = if cfg!(target_os = "linux") {
        "ip -4 route list 0/0 | awk '{print $3}'"
    } else if cfg!(target_os = "macos") {
        "route -n get default | grep gateway | awk '{print $2}'"
    } else {
        unimplemented!()
    };
    let output = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .output()
        .unwrap();
    if output.status.success() {
        Ok(String::from_utf8(output.stdout).unwrap())
    } else {
        Err(String::from_utf8(output.stderr).unwrap())
    }
}
<commit_msg>Add unit test for utils<commit_after>// Copyright 2016-2017 Chang Lan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::process::Command;

pub fn enable_ipv4_forwarding() -> Result<(), String> {
    let sysctl_arg = if cfg!(target_os = "linux") {
        "net.ipv4.ip_forward=1"
    } else if cfg!(target_os = "macos") {
        "net.inet.ip.forwarding=1"
    } else {
        unimplemented!()
    };
    let status = Command::new("sysctl")
        .arg("-w")
        .arg(sysctl_arg)
        .status()
        .unwrap();
    if status.success() {
        Ok(())
    } else {
        Err(format!("sysctl: {}", status))
    }
}

#[test]
fn enable_ipv4_forwarding_test() {
    enable_ipv4_forwarding().unwrap();
}

pub enum RouteType {
    Net,
    Host,
}

pub struct DefaultGateway {
    origin: String,
    remote: String,
}

impl DefaultGateway {
    pub fn create(gateway: &str, remote: &str) -> DefaultGateway {
        let origin = get_default_gateway().unwrap();
        add_route(RouteType::Host, remote, &origin).unwrap();
        delete_default_gateway().unwrap();
        set_default_gateway(gateway).unwrap();
        DefaultGateway {
            origin: origin,
            remote: String::from(remote),
        }
    }
}

impl Drop for DefaultGateway {
    fn drop(&mut self) {
        delete_default_gateway().unwrap();
        set_default_gateway(&self.origin).unwrap();
        delete_route(RouteType::Host, &self.remote).unwrap();
    }
}

pub fn delete_route(route_type: RouteType, route: &str) -> Result<(), String> {
    let mode = match route_type {
        RouteType::Net => "-net",
        RouteType::Host => "-host",
    };
    let cmd = if cfg!(target_os = "linux") {
        format!("route -n del {} {}", mode, route)
    } else if cfg!(target_os = "macos") {
        format!("route -n delete {} {}", mode, route)
    } else {
        unimplemented!()
    };
    let status = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .status()
        .unwrap();
    if status.success() {
        Ok(())
    } else {
        Err(format!("route: {}", status))
    }
}

pub fn add_route(route_type: RouteType, route: &str, gateway: &str) -> Result<(), String> {
    let mode = match route_type {
        RouteType::Net => "-net",
        RouteType::Host => "-host",
    };
    let cmd = if cfg!(target_os = "linux") {
        format!("route -n add {} {} gw {}", mode, route, gateway)
    } else if cfg!(target_os = "macos") {
        format!("route -n add {} {} {}", mode, route, gateway)
    } else {
        unimplemented!()
    };
    let status = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .status()
        .unwrap();
    if status.success() {
        Ok(())
    } else {
        Err(format!("route: {}", status))
    }
}

pub fn set_default_gateway(gateway: &str) -> Result<(), String> {
    add_route(RouteType::Net, "default", gateway)
}

pub fn delete_default_gateway() -> Result<(), String> {
    delete_route(RouteType::Net, "default")
}

pub fn get_default_gateway() -> Result<String, String> {
    let cmd = if cfg!(target_os = "linux") {
        "ip -4 route list 0/0 | awk '{print $3}'"
    } else if cfg!(target_os = "macos") {
        "route -n get default | grep gateway | awk '{print $2}'"
    } else {
        unimplemented!()
    };
    let output = Command::new("bash")
        .arg("-c")
        .arg(cmd)
        .output()
        .unwrap();
    if output.status.success() {
        Ok(String::from_utf8(output.stdout).unwrap())
    } else {
        Err(String::from_utf8(output.stderr).unwrap())
    }
}

#[test]
fn gateway_test() {
    let gw = get_default_gateway().unwrap();
    add_route(RouteType::Host, "1.1.1.1", &gw).unwrap();
    delete_route(RouteType::Host, "1.1.1.1").unwrap();
}
<|endoftext|>


<commit_before><commit_msg>Review feedback<commit_after><|endoftext|>


<commit_before>/// Detect NIF version to build against

use std::env;
use std::process::Command;

extern crate lazy_static;
use lazy_static::lazy_static;

extern crate which;
use which::which;

lazy_static! {
    // keep this sorted by version number
    static ref ERTS_VERSIONS: Vec<&'static str> = vec![
        "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14"
    ];
}

fn main() {
    let version = match env::var("RUSTLER_NIF_VERSION") {
        Ok(version) => version,
        Err(_) => get_version_from_erl()
    };

    activate_versions(&version);
}

fn get_version_from_erl() -> String {
    let erl = which("erl").expect("expected to find 'erl' executable");
    let args = vec![
        "-noshell",
        "-eval",
        r#"io:format("~s~n", [erlang:system_info(nif_version)]), init:stop()."#
    ];

    let version = Command::new(erl)
        .args(&args)
        .output()
        .expect("failed to execute 'erl'")
        .stdout;

    let version = String::from_utf8(version).expect("convert version to String");

    version.trim().into()
}

fn activate_versions(version: &str) {
    let index = ERTS_VERSIONS
        .iter()
        .position(|&v| v == version)
        .expect(&format!("Erlang version {} not handled, please file a a bug report.", version));

    for i in 0..=index {
        println!("cargo:rustc-cfg=nif_version_{}", version_feature(ERTS_VERSIONS[i]));
    }
}

fn version_feature(version: &str) -> String {
    version.replace(".", "_")
}
<commit_msg>Rename variable in build.rs (#187)<commit_after>/// Detect NIF version to build against

use std::env;
use std::process::Command;

extern crate lazy_static;
use lazy_static::lazy_static;

extern crate which;
use which::which;

lazy_static! {
    // keep this sorted by version number
    static ref NIF_VERSION: Vec<&'static str> = vec![
        "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13", "2.14"
    ];
}

fn main() {
    let version = match env::var("RUSTLER_NIF_VERSION") {
        Ok(version) => version,
        Err(_) => get_version_from_erl()
    };

    activate_versions(&version);
}

fn get_version_from_erl() -> String {
    let erl = which("erl").expect("expected to find 'erl' executable");
    let args = vec![
        "-noshell",
        "-eval",
        r#"io:format("~s~n", [erlang:system_info(nif_version)]), init:stop()."#
    ];

    let version = Command::new(erl)
        .args(&args)
        .output()
        .expect("failed to execute 'erl'")
        .stdout;

    let version = String::from_utf8(version).expect("convert version to String");

    version.trim().into()
}

fn activate_versions(version: &str) {
    let index = NIF_VERSION
        .iter()
        .position(|&v| v == version)
        .expect(&format!("Erlang version {} not handled, please file a a bug report.", version));

    for i in 0..=index {
        println!("cargo:rustc-cfg=nif_version_{}", version_feature(NIF_VERSION[i]));
    }
}

fn version_feature(version: &str) -> String {
    version.replace(".", "_")
}
<|endoftext|>


<commit_before><commit_msg>Slight maximize/fullscreen X11 cleanup<commit_after><|endoftext|>


<commit_before>// Copyright 2014 Mitchell Kember. Subject to the MIT License.

extern crate time;

use std::io::stdio;
use std::iter::range_inclusive;
use time::precise_time_ns;

mod problem_01; mod problem_02; mod problem_03; mod problem_04; mod problem_05;
mod problem_06; mod problem_07; mod problem_08; mod problem_09; mod problem_10;
mod problem_11; mod problem_12; mod problem_13; mod problem_14; mod problem_15;
mod problem_16; mod problem_17; mod problem_18; mod problem_19; mod problem_20;

static n_solved: uint = 20;
static answers: [int, ..n_solved] = [
	233168, 4613732, 6857, 906609, 232792560, 25164150, 104743, 23514624000,
	31875000, 142913828922, 70600674, 76576500, 5537376230, 837799, 137846528820,
	1366, 21124, 1074, 171, 648
];

static solvers: [fn() -> int, ..n_solved] = [
	problem_01::solve, problem_02::solve, problem_03::solve, problem_04::solve,
	problem_05::solve, problem_06::solve, problem_07::solve, problem_08::solve,
	problem_09::solve, problem_10::solve, problem_11::solve, problem_12::solve,
	problem_13::solve, problem_14::solve, problem_15::solve, problem_16::solve,
	problem_17::solve, problem_18::solve, problem_19::solve, problem_20::solve
];

// Returns true if there is a solution to the nth problem.
fn has_solution(n: uint) -> bool {
	n >= 1 && n <= n_solved
}

// Indicates the that the program has failed by setting the exit status to 1.
fn failure() {
	std::os::set_exit_status(1);
}

// Prints the usage message to stdout, or to stderr if err is true.
fn print_usage(err: bool) {
	let mut stream = if err { stdio::stderr() } else { stdio::stdout() };
	let _ = stream.write_str("usage: test [ -h | problem_number]\n");
	if err { failure(); }
}

// Prints an error message to stderr with context.
fn print_error(context: &str, msg: &str) {
	let _ = write!(stdio::stderr(), "error: {}: {}\n", context, msg);
	failure();
}

// Returns a string to indicate the given success status.
fn status_str(success: bool) -> &'static str {
	if success { "ok" } else { "FAIL" }
}

// Tests the solution to the nth Euler problem. Prints the number n, the result
// the program produces, the success status, and the time elapsed. Returns true
// if the answer was correct.
fn test(n: uint) -> bool {
	let idx = n - 1;
	let start_ns = precise_time_ns();
	let result = (solvers[idx])();
	let end_ns = precise_time_ns();
	let elapsed_s = (end_ns - start_ns) as f64 / 1e9;
	let success = result == answers[idx];
	let msg = status_str(success);
	println!("{:02}: {:12} ... {:4} ({:.6e} s)", n, result, msg, elapsed_s);
	success
}

// Tests the solutions to all the Euler problems. At the end, prints a summary
// of how many passed and how many failed.
fn test_all() {
	let passes = range_inclusive(1, n_solved).filter(|&i| test(i)).count();
	let fails = n_solved - passes;
	let success = fails == 0;
	let msg = status_str(success);
	println!("{}. {} passed; {} failed", msg, passes, fails);
	if !success { failure(); }
}

// Handles the case where a single command-line argument is supplied.
fn one_argument(arg: &str) {
	if arg == "-h" {
		print_usage(false);
	} else {
		match from_str(arg) {
			Some(n) if has_solution(n) => { test(n); }
			Some(_) => print_error(arg, "out of bounds"),
			None => print_error(arg, "not a uint")
		}
	}
}

fn main() {
	let args = ::std::os::args();
	match args.len() {
		1 => test_all(),
		2 => one_argument(args.get(1).as_slice()),
		_ => print_usage(true)
	}
}
<commit_msg>Reformat numbers in rust test file<commit_after>// Copyright 2014 Mitchell Kember. Subject to the MIT License.

extern crate time;

use std::io::stdio;
use std::iter::range_inclusive;
use time::precise_time_ns;

mod problem_01; mod problem_02; mod problem_03; mod problem_04; mod problem_05;
mod problem_06; mod problem_07; mod problem_08; mod problem_09; mod problem_10;
mod problem_11; mod problem_12; mod problem_13; mod problem_14; mod problem_15;
mod problem_16; mod problem_17; mod problem_18; mod problem_19; mod problem_20;

static n_solved: uint = 20;
static answers: [int, ..n_solved] = [
	233168, 4613732, 6857, 906609, 232792560, 25164150, 104743, 23514624000,
	31875000, 142913828922, 70600674, 76576500, 5537376230, 837799,
	137846528820, 1366, 21124, 1074, 171, 648
];

static solvers: [fn() -> int, ..n_solved] = [
	problem_01::solve, problem_02::solve, problem_03::solve, problem_04::solve,
	problem_05::solve, problem_06::solve, problem_07::solve, problem_08::solve,
	problem_09::solve, problem_10::solve, problem_11::solve, problem_12::solve,
	problem_13::solve, problem_14::solve, problem_15::solve, problem_16::solve,
	problem_17::solve, problem_18::solve, problem_19::solve, problem_20::solve
];

// Returns true if there is a solution to the nth problem.
fn has_solution(n: uint) -> bool {
	n >= 1 && n <= n_solved
}

// Indicates the that the program has failed by setting the exit status to 1.
fn failure() {
	std::os::set_exit_status(1);
}

// Prints the usage message to stdout, or to stderr if err is true.
fn print_usage(err: bool) {
	let mut stream = if err { stdio::stderr() } else { stdio::stdout() };
	let _ = stream.write_str("usage: test [ -h | problem_number]\n");
	if err { failure(); }
}

// Prints an error message to stderr with context.
fn print_error(context: &str, msg: &str) {
	let _ = write!(stdio::stderr(), "error: {}: {}\n", context, msg);
	failure();
}

// Returns a string to indicate the given success status.
fn status_str(success: bool) -> &'static str {
	if success { "ok" } else { "FAIL" }
}

// Tests the solution to the nth Euler problem. Prints the number n, the result
// the program produces, the success status, and the time elapsed. Returns true
// if the answer was correct.
fn test(n: uint) -> bool {
	let idx = n - 1;
	let start_ns = precise_time_ns();
	let result = (solvers[idx])();
	let end_ns = precise_time_ns();
	let elapsed_s = (end_ns - start_ns) as f64 / 1e9;
	let success = result == answers[idx];
	let msg = status_str(success);
	println!("{:02}: {:12} ... {:4} ({:.6e} s)", n, result, msg, elapsed_s);
	success
}

// Tests the solutions to all the Euler problems. At the end, prints a summary
// of how many passed and how many failed.
fn test_all() {
	let passes = range_inclusive(1, n_solved).filter(|&i| test(i)).count();
	let fails = n_solved - passes;
	let success = fails == 0;
	let msg = status_str(success);
	println!("{}. {} passed; {} failed", msg, passes, fails);
	if !success { failure(); }
}

// Handles the case where a single command-line argument is supplied.
fn one_argument(arg: &str) {
	if arg == "-h" {
		print_usage(false);
	} else {
		match from_str(arg) {
			Some(n) if has_solution(n) => { test(n); }
			Some(_) => print_error(arg, "out of bounds"),
			None => print_error(arg, "not a uint")
		}
	}
}

fn main() {
	let args = ::std::os::args();
	match args.len() {
		1 => test_all(),
		2 => one_argument(args.get(1).as_slice()),
		_ => print_usage(true)
	}
}
<|endoftext|>


<commit_before>extern crate crusty_chip;
extern crate sfml;
extern crate getopts;

use getopts::Options;

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    use sfml::window::{ContextSettings, Event, VideoMode, style};
    use sfml::graphics::{Color, RenderTarget, RenderWindow, Sprite, Texture, Transformable};
    use sfml::system::Clock;
    use std::fs::File;
    use std::io::{Read, Write};
    use crusty_chip::{DISPLAY_HEIGHT, DISPLAY_WIDTH, VirtualMachine, decode};

    let stderr = &mut std::io::stderr();

    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            let _ = writeln!(stderr, "{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            let _ = writeln!(stderr, "Required filename as first positional argument.\n");
            let _ = writeln!(stderr, "{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            let _ = writeln!(stderr, "Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        let _ = writeln!(stderr,
                         "File \"{}\" is too big to be a proper CHIP-8 ROM.",
                         filename);
        return 1;
    }

    let mut data = [0; crusty_chip::MEM_SIZE];
    // TODO: Dunno if this always reads the whole file
    let bytes_read = file.read(&mut data).unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data[..bytes_read]) {
        Ok(data) => data,
        Err(e) => {
            let _ = writeln!(stderr, "Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(VideoMode::new(DISPLAY_WIDTH as u32 * scale,
                                                   DISPLAY_HEIGHT as u32 * scale,
                                                   32),
                                    "CrustyChip",
                                    style::CLOSE,
                                    &ctx)
            .unwrap();

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();

    win.clear(&Color::black());
    win.display();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        let mut redisplay = false;
        for event in win.events() {
            use sfml::window::Key;
            fn key_mapping(code: Key) -> Option<usize> {
                match code {
                    Key::Num1 => Some(1),
                    Key::Num2 => Some(2),
                    Key::Num3 => Some(3),
                    Key::Num4 => Some(0xC),
                    Key::Q => Some(4),
                    Key::W => Some(5),
                    Key::E => Some(6),
                    Key::R => Some(0xD),
                    Key::A => Some(7),
                    Key::S => Some(8),
                    Key::D => Some(9),
                    Key::F => Some(0xE),
                    Key::Z => Some(0xA),
                    Key::X => Some(0),
                    Key::C => Some(0xB),
                    Key::V => Some(0xF),
                    _ => None,
                }
            }
            match event {
                Event::Closed => return 0,
                Event::KeyPressed { code, ctrl, shift, .. } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::Period {
                        advance = true;
                    } else if let Some(key) = key_mapping(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    println!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    println!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => {
                    if let Some(key) = key_mapping(code) {
                        ch8.release_key(key);
                    }
                }
                Event::GainedFocus => redisplay = true,
                _ => {}
            }
        }

        if redisplay {
            win.display();
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused {
            std::thread::sleep(std::time::Duration::from_millis(25));
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!("Cycle {}, pc @ {:x}, ins: {:?} ({:x})",
                     cycles_made,
                     ch8.pc(),
                     decode(raw_ins),
                     raw_ins);
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        if ch8.display_updated() {
            let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

            for (i, b) in ch8.display().iter().enumerate() {
                let idx = i * 4;
                if *b == 0u8 {
                    for p in pixels[idx..idx + 3].iter_mut() {
                        *p = 0;
                    }
                }
            }

            tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
            let mut sprite = Sprite::with_texture(&tex);
            sprite.set_scale2f(scale as f32, scale as f32);
            win.draw(&sprite);
            win.display();
        }
    }
}

fn main() {
    std::process::exit(run());
}
<commit_msg>Eprintln time<commit_after>extern crate crusty_chip;
extern crate sfml;
extern crate getopts;

use getopts::Options;

fn usage(progname: &str, opts: &Options) -> String {
    let brief = format!("{} rom_file", progname);
    format!("Usage: {}", opts.usage(&brief))
}

fn run() -> i32 {
    use sfml::window::{ContextSettings, Event, VideoMode, style};
    use sfml::graphics::{Color, RenderTarget, RenderWindow, Sprite, Texture, Transformable};
    use sfml::system::Clock;
    use std::fs::File;
    use std::io::Read;
    use crusty_chip::{DISPLAY_HEIGHT, DISPLAY_WIDTH, VirtualMachine, decode};

    let mut args = std::env::args();
    let progname = args.next().expect("Missing program name?");
    let mut opts = Options::new();
    opts.optflag("", "pause", "Start in a paused state");

    let matches = match opts.parse(args) {
        Ok(matches) => matches,
        Err(e) => {
            eprintln!("{}\n\n{}", e, usage(&progname, &opts));
            return 1;
        }
    };

    let mut paused = matches.opt_present("pause");

    let filename = match matches.free.get(0) {
        Some(filename) => filename,
        None => {
            eprintln!("Required filename as first positional argument.\n");
            eprintln!("{}", usage(&progname, &opts));
            return 1;
        }
    };

    let mut clock = Clock::start();

    let mut file = match File::open(&filename) {
        Ok(f) => f,
        Err(e) => {
            eprintln!("Failed to open \"{}\": {}", filename, e);
            return 1;
        }
    };

    if file.metadata().unwrap().len() > crusty_chip::MEM_SIZE as u64 {
        eprintln!("File \"{}\" is too big to be a proper CHIP-8 ROM.", filename);
        return 1;
    }

    let mut data = [0; crusty_chip::MEM_SIZE];
    // TODO: Dunno if this always reads the whole file
    let bytes_read = file.read(&mut data).unwrap_or_else(|e| panic!("Failed to read rom: {}", e));

    let scale = 10;

    let mut ch8 = VirtualMachine::new();
    match ch8.load_rom(&data[..bytes_read]) {
        Ok(data) => data,
        Err(e) => {
            eprintln!("Error loading rom: \"{}\". Aborting.", e);
            return 1;
        }
    }

    let ctx = ContextSettings::default();
    let mut win = RenderWindow::new(VideoMode::new(DISPLAY_WIDTH as u32 * scale,
                                                   DISPLAY_HEIGHT as u32 * scale,
                                                   32),
                                    "CrustyChip",
                                    style::CLOSE,
                                    &ctx)
            .unwrap();

    let mut tex = Texture::new(DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32).unwrap();

    win.clear(&Color::black());
    win.display();
    let mut saved_states = [None; 10];
    let mut printed_info = false;
    let mut cycles_made: u64 = 0;

    loop {
        let mut advance = false;
        let mut redisplay = false;
        for event in win.events() {
            use sfml::window::Key;
            fn key_mapping(code: Key) -> Option<usize> {
                match code {
                    Key::Num1 => Some(1),
                    Key::Num2 => Some(2),
                    Key::Num3 => Some(3),
                    Key::Num4 => Some(0xC),
                    Key::Q => Some(4),
                    Key::W => Some(5),
                    Key::E => Some(6),
                    Key::R => Some(0xD),
                    Key::A => Some(7),
                    Key::S => Some(8),
                    Key::D => Some(9),
                    Key::F => Some(0xE),
                    Key::Z => Some(0xA),
                    Key::X => Some(0),
                    Key::C => Some(0xB),
                    Key::V => Some(0xF),
                    _ => None,
                }
            }
            match event {
                Event::Closed => return 0,
                Event::KeyPressed { code, ctrl, shift, .. } => {
                    if code == Key::P {
                        paused = !paused;
                    } else if code == Key::R && ctrl {
                        ch8 = VirtualMachine::new();
                        ch8.load_rom(&data).expect("ROM data too big? It changed?");
                    } else if code == Key::Period {
                        advance = true;
                    } else if let Some(key) = key_mapping(code) {
                        ch8.press_key(key);
                    }
                    macro_rules! state_key (
                        ($s: expr, $k: ident) => (
                            if code == Key::$k {
                                if shift {
                                    saved_states[$s] = Some(ch8);
                                    eprintln!("Saved state {}.", $s);
                                } else if let Some(state) = saved_states[$s] {
                                    ch8 = state;
                                    eprintln!("Loaded state {}.", $s);
                                }
                            }
                        )
                    );
                    state_key!(0, F1);
                    state_key!(1, F2);
                    state_key!(2, F3);
                    state_key!(3, F4);
                    state_key!(4, F5);
                    state_key!(5, F6);
                    state_key!(6, F7);
                    state_key!(7, F8);
                    state_key!(8, F9);
                    state_key!(9, F10);
                }
                Event::KeyReleased { code, .. } => {
                    if let Some(key) = key_mapping(code) {
                        ch8.release_key(key);
                    }
                }
                Event::GainedFocus => redisplay = true,
                _ => {}
            }
        }

        if redisplay {
            win.display();
        }

        if clock.elapsed_time().as_seconds() >= 1.0 / 60.0 {
            ch8.decrement_timers();
            clock.restart();
        }

        if paused {
            std::thread::sleep(std::time::Duration::from_millis(25));
        }

        if paused && !printed_info {
            let raw_ins = ch8.get_ins();
            println!("Cycle {}, pc @ {:x}, ins: {:?} ({:x})",
                     cycles_made,
                     ch8.pc(),
                     decode(raw_ins),
                     raw_ins);
            printed_info = true;
        }

        if !paused || advance {
            ch8.do_cycle();
            cycles_made += 1;
            printed_info = false;
        }

        if ch8.display_updated() {
            let mut pixels = [255u8; DISPLAY_WIDTH * DISPLAY_HEIGHT * 4];

            for (i, b) in ch8.display().iter().enumerate() {
                let idx = i * 4;
                if *b == 0u8 {
                    for p in pixels[idx..idx + 3].iter_mut() {
                        *p = 0;
                    }
                }
            }

            tex.update_from_pixels(&pixels, DISPLAY_WIDTH as u32, DISPLAY_HEIGHT as u32, 0, 0);
            let mut sprite = Sprite::with_texture(&tex);
            sprite.set_scale2f(scale as f32, scale as f32);
            win.draw(&sprite);
            win.display();
        }
    }
}

fn main() {
    std::process::exit(run());
}
<|endoftext|>


<commit_before>//! # crateinfo
//!
//! Loads crate information.
//!

#[cfg(test)]
#[path = "crateinfo_test.rs"]
mod crateinfo_test;

use crate::command;
use crate::types::{CargoMetadata, CrateDependency, CrateInfo};
use fsio;
use glob::glob;
use serde_json;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use toml::{self, Value};

fn expand_glob_members(glob_member: &str) -> Vec<String> {
    match glob(glob_member) {
        Ok(entries) => {
            let mut members = vec![];

            for entry in entries {
                match entry {
                    Ok(path) => {
                        let mut updated_path = path.to_str().unwrap().to_string();
                        updated_path = updated_path.replace("\\", "/");
                        members.push(updated_path);
                    }
                    _ => (),
                };
            }

            members
        }
        _ => vec![],
    }
}

fn normalize_members(crate_info: &mut CrateInfo) {
    match crate_info.workspace {
        Some(ref mut workspace) => {
            match workspace.members {
                Some(ref mut members) => {
                    let existing_members = members.clone();

                    let mut index = 0;
                    for member in existing_members.iter() {
                        // glob
                        if member.contains("*") {
                            let mut expanded_members = expand_glob_members(&member);

                            members.remove(index);
                            members.append(&mut expanded_members);
                        } else {
                            index = index + 1;
                        }
                    }
                }
                None => (),
            };
        }
        None => (), //not a workspace
    }
}

fn get_members_from_dependencies(crate_info: &CrateInfo) -> Vec<String> {
    let mut members = vec![];

    match crate_info.dependencies {
        Some(ref dependencies) => {
            for value in dependencies.values() {
                match *value {
                    CrateDependency::Info(ref info) => match info.path {
                        Some(ref path) => {
                            if path.starts_with("./") {
                                let member_path =
                                    path.chars().skip(2).take(path.len() - 2).collect();
                                members.push(member_path);
                            }
                        }
                        None => (),
                    },
                    _ => (),
                };
            }
        }
        None => (),
    };

    members
}

fn add_members(crate_info: &mut CrateInfo, new_members: Vec<String>) {
    if new_members.len() > 0 {
        match crate_info.workspace {
            Some(ref mut workspace) => match workspace.members {
                Some(ref mut members) => {
                    for new_member in new_members.iter() {
                        let member_string = new_member.to_string();

                        match members.iter().position(|member| *member == member_string) {
                            None => members.push(member_string),
                            _ => (),
                        }
                    }
                }
                None => workspace.members = Some(new_members),
            },
            None => (), //not a workspace
        }
    }
}

fn remove_excludes(crate_info: &mut CrateInfo) -> bool {
    let mut removed = false;

    match crate_info.workspace {
        Some(ref mut workspace) => match workspace.exclude {
            Some(ref excludes) => match workspace.members {
                Some(ref mut members) => {
                    for exclude in excludes.iter() {
                        let exclude_string = exclude.to_string();

                        let result = members.iter().position(|member| *member == exclude_string);
                        match result {
                            Some(index) => {
                                members.remove(index);

                                removed = true;

                                ()
                            }
                            None => (),
                        };
                    }
                }
                None => (),
            },
            None => (),
        },
        None => (), //not a workspace
    };

    removed
}

fn load_workspace_members(crate_info: &mut CrateInfo) {
    if crate_info.workspace.is_some() {
        normalize_members(crate_info);

        let dependencies = get_members_from_dependencies(&crate_info);

        add_members(crate_info, dependencies);

        remove_excludes(crate_info);
    }
}

/// Loads the crate info based on the Cargo.toml found in the current working directory.
pub(crate) fn load() -> CrateInfo {
    load_from(Path::new("Cargo.toml").to_path_buf())
}

pub(crate) fn load_from(file_path: PathBuf) -> CrateInfo {
    if file_path.exists() {
        debug!("Reading file: {:#?}", &file_path);
        let crate_info_string = match fsio::file::read_text_file(&file_path) {
            Ok(content) => content,
            Err(error) => panic!("Unable to open Cargo.toml, error: {}", error),
        };

        let mut crate_info: CrateInfo = match toml::from_str(&crate_info_string) {
            Ok(value) => value,
            Err(error) => panic!("Unable to parse Cargo.toml, {}", error),
        };

        load_workspace_members(&mut crate_info);

        debug!("Loaded Cargo.toml: {:#?}", &crate_info);

        crate_info
    } else {
        CrateInfo::new()
    }
}

#[derive(Debug, Deserialize)]
struct CargoConfig {
    build: Option<CargoConfigBuild>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
struct CargoConfigBuild {
    target: Option<String>,
    target_dir: Option<String>,
}

fn get_cargo_config(home: Option<PathBuf>) -> Option<CargoConfig> {
    let path = env::current_dir().ok()?;

    let config_file = path
        .ancestors()
        .map(|ancestor| ancestor.join(".cargo"))
        .chain(home)
        .map(|config_file| config_file.join("config"))
        .filter_map(|config_file| {
            let config_file_with_extension = config_file.with_extension("toml");

            if config_file.exists() {
                Some(config_file)
            } else if config_file_with_extension.exists() {
                Some(config_file_with_extension)
            } else {
                None
            }
        })
        .next()?;

    let config_file = fsio::file::read_text_file(&config_file).ok()?;
    toml::from_str(&config_file).ok()
}

pub(crate) fn crate_target_triple(
    default_target_triple: Option<String>,
    home: Option<PathBuf>,
) -> Option<String> {
    get_cargo_config(home)
        .and_then(|config| config.build)
        .and_then(|build| build.target)
        .map(|target| target.trim_end_matches(".json"))
        .map(str::to_owned)
        .or(default_target_triple)
}

pub(crate) fn crate_target_dir(home: Option<PathBuf>) -> String {
    env::var("CARGO_TARGET_DIR")
        .ok()
        .or_else(|| {
            get_cargo_config(home)
                .and_then(|config| config.build)
                .and_then(|build| build.target_dir)
        })
        .unwrap_or_else(|| "target".to_string())
}

pub(crate) fn search_workspace_root() -> Option<String> {
    if envmnt::is("CARGO_MAKE_WORKSPACE_EMULATION") {
        search_workspace_root_for_emulation()
    } else {
        search_workspace_root_via_metadata()
    }
}

fn search_workspace_root_for_emulation() -> Option<String> {
    let path_value = envmnt::get_any(
        &vec![
            "CARGO_MAKE_WORKSPACE_EMULATION_ROOT_DIRECTORY",
            "CARGO_MAKE_WORKING_DIRECTORY",
        ],
        "",
    );

    if path_value.is_empty() {
        None
    } else {
        Some(path_value)
    }
}

fn search_workspace_root_via_metadata() -> Option<String> {
    debug!("Getting cargo metadata.");

    let mut command_struct = Command::new("cargo");
    let result = command_struct.arg("metadata").output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);

            if exit_code == 0 {
                let stdout = String::from_utf8_lossy(&output.stdout);
                let metadata: CargoMetadata = match serde_json::from_str(&stdout) {
                    Ok(metadata) => metadata,
                    Err(error) => {
                        debug!("Unable to extract cargo metadata, error: {:#?}", &error);
                        CargoMetadata::new()
                    }
                };

                metadata.workspace_root
            } else {
                debug!(
                    "Unable to extract cargo metadata, error code: {}",
                    exit_code
                );
                None
            }
        }
        Err(error) => {
            debug!("Unable to extract cargo metadata, error: {:#?}", &error);
            None
        }
    }
}
<commit_msg>Remove unused imports<commit_after>//! # crateinfo
//!
//! Loads crate information.
//!

#[cfg(test)]
#[path = "crateinfo_test.rs"]
mod crateinfo_test;

use crate::command;
use crate::types::{CargoMetadata, CrateDependency, CrateInfo};
use fsio;
use glob::glob;
use serde_json;
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;

fn expand_glob_members(glob_member: &str) -> Vec<String> {
    match glob(glob_member) {
        Ok(entries) => {
            let mut members = vec![];

            for entry in entries {
                match entry {
                    Ok(path) => {
                        let mut updated_path = path.to_str().unwrap().to_string();
                        updated_path = updated_path.replace("\\", "/");
                        members.push(updated_path);
                    }
                    _ => (),
                };
            }

            members
        }
        _ => vec![],
    }
}

fn normalize_members(crate_info: &mut CrateInfo) {
    match crate_info.workspace {
        Some(ref mut workspace) => {
            match workspace.members {
                Some(ref mut members) => {
                    let existing_members = members.clone();

                    let mut index = 0;
                    for member in existing_members.iter() {
                        // glob
                        if member.contains("*") {
                            let mut expanded_members = expand_glob_members(&member);

                            members.remove(index);
                            members.append(&mut expanded_members);
                        } else {
                            index = index + 1;
                        }
                    }
                }
                None => (),
            };
        }
        None => (), //not a workspace
    }
}

fn get_members_from_dependencies(crate_info: &CrateInfo) -> Vec<String> {
    let mut members = vec![];

    match crate_info.dependencies {
        Some(ref dependencies) => {
            for value in dependencies.values() {
                match *value {
                    CrateDependency::Info(ref info) => match info.path {
                        Some(ref path) => {
                            if path.starts_with("./") {
                                let member_path =
                                    path.chars().skip(2).take(path.len() - 2).collect();
                                members.push(member_path);
                            }
                        }
                        None => (),
                    },
                    _ => (),
                };
            }
        }
        None => (),
    };

    members
}

fn add_members(crate_info: &mut CrateInfo, new_members: Vec<String>) {
    if new_members.len() > 0 {
        match crate_info.workspace {
            Some(ref mut workspace) => match workspace.members {
                Some(ref mut members) => {
                    for new_member in new_members.iter() {
                        let member_string = new_member.to_string();

                        match members.iter().position(|member| *member == member_string) {
                            None => members.push(member_string),
                            _ => (),
                        }
                    }
                }
                None => workspace.members = Some(new_members),
            },
            None => (), //not a workspace
        }
    }
}

fn remove_excludes(crate_info: &mut CrateInfo) -> bool {
    let mut removed = false;

    match crate_info.workspace {
        Some(ref mut workspace) => match workspace.exclude {
            Some(ref excludes) => match workspace.members {
                Some(ref mut members) => {
                    for exclude in excludes.iter() {
                        let exclude_string = exclude.to_string();

                        let result = members.iter().position(|member| *member == exclude_string);
                        match result {
                            Some(index) => {
                                members.remove(index);

                                removed = true;

                                ()
                            }
                            None => (),
                        };
                    }
                }
                None => (),
            },
            None => (),
        },
        None => (), //not a workspace
    };

    removed
}

fn load_workspace_members(crate_info: &mut CrateInfo) {
    if crate_info.workspace.is_some() {
        normalize_members(crate_info);

        let dependencies = get_members_from_dependencies(&crate_info);

        add_members(crate_info, dependencies);

        remove_excludes(crate_info);
    }
}

/// Loads the crate info based on the Cargo.toml found in the current working directory.
pub(crate) fn load() -> CrateInfo {
    load_from(Path::new("Cargo.toml").to_path_buf())
}

pub(crate) fn load_from(file_path: PathBuf) -> CrateInfo {
    if file_path.exists() {
        debug!("Reading file: {:#?}", &file_path);
        let crate_info_string = match fsio::file::read_text_file(&file_path) {
            Ok(content) => content,
            Err(error) => panic!("Unable to open Cargo.toml, error: {}", error),
        };

        let mut crate_info: CrateInfo = match toml::from_str(&crate_info_string) {
            Ok(value) => value,
            Err(error) => panic!("Unable to parse Cargo.toml, {}", error),
        };

        load_workspace_members(&mut crate_info);

        debug!("Loaded Cargo.toml: {:#?}", &crate_info);

        crate_info
    } else {
        CrateInfo::new()
    }
}

#[derive(Debug, Deserialize)]
struct CargoConfig {
    build: Option<CargoConfigBuild>,
}

#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
struct CargoConfigBuild {
    target: Option<String>,
    target_dir: Option<String>,
}

fn get_cargo_config(home: Option<PathBuf>) -> Option<CargoConfig> {
    let path = env::current_dir().ok()?;

    let config_file = path
        .ancestors()
        .map(|ancestor| ancestor.join(".cargo"))
        .chain(home)
        .map(|config_file| config_file.join("config"))
        .filter_map(|config_file| {
            let config_file_with_extension = config_file.with_extension("toml");

            if config_file.exists() {
                Some(config_file)
            } else if config_file_with_extension.exists() {
                Some(config_file_with_extension)
            } else {
                None
            }
        })
        .next()?;

    let config_file = fsio::file::read_text_file(&config_file).ok()?;
    toml::from_str(&config_file).ok()
}

pub(crate) fn crate_target_triple(
    default_target_triple: Option<String>,
    home: Option<PathBuf>,
) -> Option<String> {
    get_cargo_config(home)
        .and_then(|config| config.build)
        .and_then(|build| build.target)
        .map(|target| target.trim_end_matches(".json"))
        .map(str::to_owned)
        .or(default_target_triple)
}

pub(crate) fn crate_target_dir(home: Option<PathBuf>) -> String {
    env::var("CARGO_TARGET_DIR")
        .ok()
        .or_else(|| {
            get_cargo_config(home)
                .and_then(|config| config.build)
                .and_then(|build| build.target_dir)
        })
        .unwrap_or_else(|| "target".to_string())
}

pub(crate) fn search_workspace_root() -> Option<String> {
    if envmnt::is("CARGO_MAKE_WORKSPACE_EMULATION") {
        search_workspace_root_for_emulation()
    } else {
        search_workspace_root_via_metadata()
    }
}

fn search_workspace_root_for_emulation() -> Option<String> {
    let path_value = envmnt::get_any(
        &vec![
            "CARGO_MAKE_WORKSPACE_EMULATION_ROOT_DIRECTORY",
            "CARGO_MAKE_WORKING_DIRECTORY",
        ],
        "",
    );

    if path_value.is_empty() {
        None
    } else {
        Some(path_value)
    }
}

fn search_workspace_root_via_metadata() -> Option<String> {
    debug!("Getting cargo metadata.");

    let mut command_struct = Command::new("cargo");
    let result = command_struct.arg("metadata").output();

    match result {
        Ok(output) => {
            let exit_code = command::get_exit_code(Ok(output.status), false);

            if exit_code == 0 {
                let stdout = String::from_utf8_lossy(&output.stdout);
                let metadata: CargoMetadata = match serde_json::from_str(&stdout) {
                    Ok(metadata) => metadata,
                    Err(error) => {
                        debug!("Unable to extract cargo metadata, error: {:#?}", &error);
                        CargoMetadata::new()
                    }
                };

                metadata.workspace_root
            } else {
                debug!(
                    "Unable to extract cargo metadata, error code: {}",
                    exit_code
                );
                None
            }
        }
        Err(error) => {
            debug!("Unable to extract cargo metadata, error: {:#?}", &error);
            None
        }
    }
}
<|endoftext|>