<commit_before>use rand;
use rand::distributions::{IndependentSample, Range};

#[derive(Debug, Clone)]
pub struct NQueens {
    queens: Vec<Option<usize>>,
}

impl NQueens {
    /// Creates a new board of size `usize` with None in each position
    pub fn new_empty(size: usize) -> NQueens {
        let mut queens = Vec::new();
        for _ in 0..size {
            queens.push(None);
        }

        NQueens {
            queens: queens,
        }
    }

    /// Creates a new board of size `usize` with each queen's position selected uniformly at random
    pub fn new_random(size: usize) -> NQueens {
        let mut queens = Vec::new();

        let mut rng = rand::thread_rng();
        for _ in 0..size {
            queens.push(Some(Range::new(0, size).ind_sample(&mut rng)));
        }

        NQueens {
            queens: queens,
        }
    }

    /// Returns the size of the board i.e. the width and height, which are equal
    pub fn size(&self) -> usize {
        self.queens.len()
    }

    /// Returns true if queen's position is set in the given column
    pub fn is_set(&self, column: usize) -> bool {
        assert!(column < self.size());
        self.queens[column].is_some()
    }

    /// Returns the position of the queen in the given column. Panics if queen is not set in that
    /// column
    pub fn get(&self, column: usize) -> usize {
        assert!(column < self.size());
        self.queens[column].unwrap()
    }

    /// Returns a reference to the position of the queen in the given column. Panics if queen is
    /// not set in that column
    pub fn get_ref(&self, column: usize) -> &usize {
        assert!(column < self.size());
        self.queens[column].as_ref().unwrap()
    }

    /// Returns an Option contains the position of the queen in the given column
    pub fn get_option(&self, column: usize) -> Option<usize> {
        assert!(column < self.size());
        self.queens[column]
    }

    /// Sets the queen in the given column to the value of `row`.
    pub fn set(&mut self, column: usize, row: usize) {
        assert!(column < self.size());
        assert!(row < self.size());

        self.queens[column] = Some(row);
    }

    /// Sets the queen in the given column to a position selected uniformly at random
    pub fn set_random(&mut self, column: usize) {
        let mut rng = rand::thread_rng();

        let size = self.size();
        self.set(column, Range::new(0, size).ind_sample(&mut rng));
    }

    /// Creates a struct that implements `Iterator` which provides all possible successors of the
    /// current board configuration. A successor is created by moving or placing a queen in a
    /// single column.
    ///
    /// E.g. if all queens are filled on an 8 by 8 board, the iterator will return 56 boards,
    /// while if no queens are filled the iterator will iterate over 64 boards.
    //pub fn to_successors_iter(&self) -> NQueensSuccessorIter {
    //    NQueensSuccessorIter::new(&self)
    //}

    /// Checks if the current configuration of the board is a valid solution
    pub fn is_valid(&self) -> bool {
        // Check if all entries are not None; this lets us use unwrap everywhere and provides a
        // quick exit.
        for q in &self.queens {
            if q.is_none() { return false; }
        }

        // do not need to check columns because by definition of our struct we only have one queen
        // per column

        // check rows
        for (i, q) in self.queens.iter().enumerate() {
            let q = q.unwrap();
            for q2 in &self.queens[i+1..] {
                let q2 = q2.unwrap();
                if q == q2 {
                    return false;
                }
            }
        }

        // check diagonals
        // This "row+column are all distinct" test works because if you imagine an addition table,
        // all the elements on a rising diagonal are the same. Similarly, all the elements on a
        // falling diagonal are the same in a subtraction table. Additionally, they are symmetric
        // (up to sign, see below) so we only have to do the computations for (i,j) pairs and not
        // (j,i) as well.
        for (i, q) in self.queens.iter().enumerate() {
            let q = q.unwrap();
            // optimization so we don't compare (i,j) and (j,i)
            for (j, q2) in (&self.queens[i+1..]).iter().enumerate() {
                let q2 = q2.unwrap();
                // we need to add i+1 to account for the shifting that we did in the second
                // enumeration
                if i+q == i+1+j+q2 {
                    return false;
                }

                // This should be correct for all useful inputs. We don't actually need the signed
                // answer; we just don't want them to be equal. If the numbers are too large we may
                // be incorrect (i.e. if things are around USIZE_MAX, USIZE_MAX/2 etc.) but that
                // would be way too many queens.
                if i.wrapping_sub(q) == (i+1+j).wrapping_sub(q2) {
                    return false;
                }
            }
        }

        // if above checks pass, this is a valid solution and we return true
        return true;
    }
}

use std::ops::Index;
impl Index<usize> for NQueens {
    type Output = usize;

    fn index(&self, column: usize) -> &usize {
        self.get_ref(column)
    }
}

#[cfg(test)]
mod test {
    use super::NQueens;

    // Note that the set(x, y) function is (column, row), so the Q in a diagram on the same line
    // as a set call is not necessarily being set by that call.

    #[test]
    pub fn test_valid_1() {
        let mut q = NQueens::new_empty(4);
        q.set(0, 1); // X X Q X
        q.set(1, 3); // Q X X X
        q.set(2, 0); // X X X Q
        q.set(3, 2); // X Q X X

        assert!(q.is_valid() == true);
    }

    #[test]
    pub fn test_valid_2() {
        let mut q = NQueens::new_empty(4);
        q.set(0, 2); // X Q X X
        q.set(1, 0); // X X X Q
        q.set(2, 3); // Q X X X
        q.set(3, 1); // X X Q X

        assert!(q.is_valid() == true);
    }

    #[test]
    pub fn test_valid_3() {
        let mut q = NQueens::new_empty(5);
        q.set(0, 2); // X Q X X X
        q.set(1, 0); // X X X Q X
        q.set(2, 3); // Q X X X X
        q.set(3, 1); // X X Q X X
        q.set(4, 4); // X X X X Q

        assert!(q.is_valid() == true);
    }

    #[test]
    pub fn test_valid_4() {
        let mut q = NQueens::new_empty(5);
        q.set(0, 1); // X X X Q X
        q.set(1, 4); // Q X X X X
        q.set(2, 2); // X X Q X X
        q.set(3, 0); // X X X X Q
        q.set(4, 3); // X Q X X X

        assert!(q.is_valid() == true);
    }

    // of course we have to test an actual 8 queens
    #[test]
    pub fn test_valid_5() {
        let mut q = NQueens::new_empty(8);
        q.set(0, 3); // X X X X X Q X X
        q.set(1, 5); // X X X Q X X X X
        q.set(2, 7); // X X X X X X Q X
        q.set(3, 1); // Q X X X X X X X
        q.set(4, 6); // X X X X X X X Q
        q.set(5, 0); // X Q X X X X X X
        q.set(6, 2); // X X X X Q X X X
        q.set(7, 4); // X X Q X X X X X

        assert!(q.is_valid() == true);
    }

    // and another nonsymmetric one
    #[test]
    pub fn test_valid_6() {
        let mut q = NQueens::new_empty(8);
        q.set(0, 7); // X X X X Q X X X
        q.set(1, 1); // X Q X X X X X X
        q.set(2, 4); // X X X Q X X X X
        q.set(3, 2); // X X X X X X Q X
        q.set(4, 0); // X X Q X X X X X
        q.set(5, 6); // X X X X X X X Q
        q.set(6, 3); // X X X X X Q X X
        q.set(7, 5); // Q X X X X X X X

        assert!(q.is_valid() == true);
    }

    #[test]
    pub fn test_horizontals_1() {
        let mut q = NQueens::new_empty(2);
        q.set(0, 0); // Q Q
        q.set(1, 0); // X X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_horizontals_2() {
        let mut q = NQueens::new_empty(2);
        q.set(0, 0); // X X
        q.set(1, 0); // Q Q
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_horizontals_3() {
        let mut q = NQueens::new_empty(3);
        q.set(0, 0); // Q X Q
        q.set(1, 2); // X X X
        q.set(2, 0); // X Q X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_horizontals_4() {
        let mut q = NQueens::new_empty(6);
        q.set(0, 0); // X X Q X X X
        q.set(1, 2); // Q X X X Q X
        q.set(2, 0); // X X X X X X
        q.set(2, 0); // X Q X X X X
        q.set(2, 0); // X X X X X Q
        q.set(2, 0); // X X X Q X X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_1() {
        let mut q = NQueens::new_empty(2);
        q.set(0, 0); // Q X
        q.set(1, 1); // X Q
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_2() {
        let mut q = NQueens::new_empty(2);
        q.set(0, 1); // X Q
        q.set(1, 0); // Q X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_3() {
        let mut q = NQueens::new_empty(3);
        q.set(0, 0); // Q X X
        q.set(1, 2); // X X Q
        q.set(2, 1); // X Q X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_4() {
        let mut q = NQueens::new_empty(5);
        q.set(0, 2); // X Q X X X
        q.set(1, 0); // X X X Q X
        q.set(2, 4); // Q X X X X
        q.set(3, 1); // X X X X Q
        q.set(3, 3); // X X Q X X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_5() {
        let mut q = NQueens::new_empty(5);
        q.set(0, 3); // X X X Q X
        q.set(1, 1); // X Q X X X
        q.set(2, 4); // X X X X Q
        q.set(3, 0); // Q X X X X
        q.set(3, 2); // X X Q X X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_none_1() {
        let q = NQueens::new_empty(3);
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_none_2() {
        let mut q = NQueens::new_empty(3);
        q.set(0, 0); // Q X X
        q.set(1, 2); // X X X
                     // X Q X

        assert!(q.is_valid() == false);
    }
}
<commit_msg>Apply FEARLESS CONCURRENCY<commit_after>use rand;
use rand::distributions::{IndependentSample, Range};

use rayon::prelude::*;

#[derive(Debug, Clone)]
pub struct NQueens {
    queens: Vec<Option<usize>>,
}

impl NQueens {
    /// Creates a new board of size `usize` with None in each position
    pub fn new_empty(size: usize) -> NQueens {
        let mut queens = Vec::new();
        for _ in 0..size {
            queens.push(None);
        }

        NQueens {
            queens: queens,
        }
    }

    /// Creates a new board of size `usize` with each queen's position selected uniformly at random
    pub fn new_random(size: usize) -> NQueens {
        let mut queens = Vec::new();

        let mut rng = rand::thread_rng();
        for _ in 0..size {
            queens.push(Some(Range::new(0, size).ind_sample(&mut rng)));
        }

        NQueens {
            queens: queens,
        }
    }

    /// Returns the size of the board i.e. the width and height, which are equal
    pub fn size(&self) -> usize {
        self.queens.len()
    }

    /// Returns true if queen's position is set in the given column
    pub fn is_set(&self, column: usize) -> bool {
        assert!(column < self.size());
        self.queens[column].is_some()
    }

    /// Returns the position of the queen in the given column. Panics if queen is not set in that
    /// column
    pub fn get(&self, column: usize) -> usize {
        assert!(column < self.size());
        self.queens[column].unwrap()
    }

    /// Returns a reference to the position of the queen in the given column. Panics if queen is
    /// not set in that column
    pub fn get_ref(&self, column: usize) -> &usize {
        assert!(column < self.size());
        self.queens[column].as_ref().unwrap()
    }

    /// Returns an Option contains the position of the queen in the given column
    pub fn get_option(&self, column: usize) -> Option<usize> {
        assert!(column < self.size());
        self.queens[column]
    }

    /// Sets the queen in the given column to the value of `row`.
    pub fn set(&mut self, column: usize, row: usize) {
        assert!(column < self.size());
        assert!(row < self.size());

        self.queens[column] = Some(row);
    }

    /// Sets the queen in the given column to a position selected uniformly at random
    pub fn set_random(&mut self, column: usize) {
        let mut rng = rand::thread_rng();

        let size = self.size();
        self.set(column, Range::new(0, size).ind_sample(&mut rng));
    }

    /// Creates a struct that implements `Iterator` which provides all possible successors of the
    /// current board configuration. A successor is created by moving or placing a queen in a
    /// single column.
    ///
    /// E.g. if all queens are filled on an 8 by 8 board, the iterator will return 56 boards,
    /// while if no queens are filled the iterator will iterate over 64 boards.
    //pub fn to_successors_iter(&self) -> NQueensSuccessorIter {
    //    NQueensSuccessorIter::new(&self)
    //}

    /// Checks if the current configuration of the board is a valid solution
    pub fn is_valid(&self) -> bool {
        // Check if all entries are not None; this lets us use unwrap everywhere and provides a
        // quick exit.
        let full_board = self.queens.par_iter()
                             .all(|q| !q.is_none());
        if !full_board {
            return false;
        }

        // do not need to check columns because by definition of our struct we only have one queen
        // per column

        // check rows
        let all_rows_distinct = self.queens.par_iter().enumerate().all( |(i,q)| {
            let q = q.unwrap();
            self.queens[i+1..].par_iter().all( |q2| {
                let q2 = q2.unwrap();
                q != q2
            })
        } );

        if !all_rows_distinct {
            return false;
        }

        // check diagonals
        // This "row+column are all distinct" test works because if you imagine an addition table,
        // all the elements on a rising diagonal are the same. Similarly, all the elements on a
        // falling diagonal are the same in a subtraction table. Additionally, they are symmetric
        // (up to sign, see below) so we only have to do the computations for (i,j) pairs and not
        // (j,i) as well.
        let all_diagonals_distinct = self.queens.par_iter().enumerate().all( |(i, q)| {
            let q = q.unwrap();
            // optimization so we don't compare (i,j) and (j,i) as noted above
            self.queens[i+1..].par_iter().enumerate().all( |(j, q2)| {
                let q2 = q2.unwrap();
                // The i+1 term appears to account for the shifting that we did in the second
                // enumeration.

                // This should be correct for all useful inputs. We don't actually need the signed
                // answer; we just don't want them to be equal. If the numbers are too large we may
                // be incorrect (i.e. if things are around USIZE_MAX, USIZE_MAX/2 etc.) but that
                // would be way too many queens.
                (i+q != i+1+j+q2) && (i.wrapping_sub(q) != (i+1+j).wrapping_sub(q2))
            })
        });

        if !all_diagonals_distinct {
            return false;
        }

        // if above checks pass, this is a valid solution and we return true
        return true;
    }
}

use std::ops::Index;
impl Index<usize> for NQueens {
    type Output = usize;

    fn index(&self, column: usize) -> &usize {
        self.get_ref(column)
    }
}

#[cfg(test)]
mod test {
    use super::NQueens;

    // Note that the set(x, y) function is (column, row), so the Q in a diagram on the same line
    // as a set call is not necessarily being set by that call.

    #[test]
    pub fn test_valid_1() {
        let mut q = NQueens::new_empty(4);
        q.set(0, 1); // X X Q X
        q.set(1, 3); // Q X X X
        q.set(2, 0); // X X X Q
        q.set(3, 2); // X Q X X

        assert!(q.is_valid() == true);
    }

    #[test]
    pub fn test_valid_2() {
        let mut q = NQueens::new_empty(4);
        q.set(0, 2); // X Q X X
        q.set(1, 0); // X X X Q
        q.set(2, 3); // Q X X X
        q.set(3, 1); // X X Q X

        assert!(q.is_valid() == true);
    }

    #[test]
    pub fn test_valid_3() {
        let mut q = NQueens::new_empty(5);
        q.set(0, 2); // X Q X X X
        q.set(1, 0); // X X X Q X
        q.set(2, 3); // Q X X X X
        q.set(3, 1); // X X Q X X
        q.set(4, 4); // X X X X Q

        assert!(q.is_valid() == true);
    }

    #[test]
    pub fn test_valid_4() {
        let mut q = NQueens::new_empty(5);
        q.set(0, 1); // X X X Q X
        q.set(1, 4); // Q X X X X
        q.set(2, 2); // X X Q X X
        q.set(3, 0); // X X X X Q
        q.set(4, 3); // X Q X X X

        assert!(q.is_valid() == true);
    }

    // of course we have to test an actual 8 queens
    #[test]
    pub fn test_valid_5() {
        let mut q = NQueens::new_empty(8);
        q.set(0, 3); // X X X X X Q X X
        q.set(1, 5); // X X X Q X X X X
        q.set(2, 7); // X X X X X X Q X
        q.set(3, 1); // Q X X X X X X X
        q.set(4, 6); // X X X X X X X Q
        q.set(5, 0); // X Q X X X X X X
        q.set(6, 2); // X X X X Q X X X
        q.set(7, 4); // X X Q X X X X X

        assert!(q.is_valid() == true);
    }

    // and another nonsymmetric one
    #[test]
    pub fn test_valid_6() {
        let mut q = NQueens::new_empty(8);
        q.set(0, 7); // X X X X Q X X X
        q.set(1, 1); // X Q X X X X X X
        q.set(2, 4); // X X X Q X X X X
        q.set(3, 2); // X X X X X X Q X
        q.set(4, 0); // X X Q X X X X X
        q.set(5, 6); // X X X X X X X Q
        q.set(6, 3); // X X X X X Q X X
        q.set(7, 5); // Q X X X X X X X

        assert!(q.is_valid() == true);
    }

    #[test]
    pub fn test_horizontals_1() {
        let mut q = NQueens::new_empty(2);
        q.set(0, 0); // Q Q
        q.set(1, 0); // X X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_horizontals_2() {
        let mut q = NQueens::new_empty(2);
        q.set(0, 0); // X X
        q.set(1, 0); // Q Q
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_horizontals_3() {
        let mut q = NQueens::new_empty(3);
        q.set(0, 0); // Q X Q
        q.set(1, 2); // X X X
        q.set(2, 0); // X Q X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_horizontals_4() {
        let mut q = NQueens::new_empty(6);
        q.set(0, 0); // X X Q X X X
        q.set(1, 2); // Q X X X Q X
        q.set(2, 0); // X X X X X X
        q.set(2, 0); // X Q X X X X
        q.set(2, 0); // X X X X X Q
        q.set(2, 0); // X X X Q X X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_1() {
        let mut q = NQueens::new_empty(2);
        q.set(0, 0); // Q X
        q.set(1, 1); // X Q
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_2() {
        let mut q = NQueens::new_empty(2);
        q.set(0, 1); // X Q
        q.set(1, 0); // Q X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_3() {
        let mut q = NQueens::new_empty(3);
        q.set(0, 0); // Q X X
        q.set(1, 2); // X X Q
        q.set(2, 1); // X Q X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_4() {
        let mut q = NQueens::new_empty(5);
        q.set(0, 2); // X Q X X X
        q.set(1, 0); // X X X Q X
        q.set(2, 4); // Q X X X X
        q.set(3, 1); // X X X X Q
        q.set(3, 3); // X X Q X X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_diagonals_5() {
        let mut q = NQueens::new_empty(5);
        q.set(0, 3); // X X X Q X
        q.set(1, 1); // X Q X X X
        q.set(2, 4); // X X X X Q
        q.set(3, 0); // Q X X X X
        q.set(3, 2); // X X Q X X
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_none_1() {
        let q = NQueens::new_empty(3);
        assert!(q.is_valid() == false);
    }

    #[test]
    pub fn test_none_2() {
        let mut q = NQueens::new_empty(3);
        q.set(0, 0); // Q X X
        q.set(1, 2); // X X X
                     // X Q X

        assert!(q.is_valid() == false);
    }
}
<|endoftext|>


<commit_before>use std::char;
use std::str::{self, FromStr};

use nom::{
    digit,
    is_alphanumeric,
    IResult
};

/// Parsed StatsD metric.
///
/// See here for more details: https://github.com/b/statsd_spec#metric-types--formats
#[derive(Debug, PartialEq)]
pub enum ParsedMetric {
    Gauge(String, u64),
}

pub type ParseResult<'a> = IResult<&'a [u8], ParsedMetric>;

fn bytes_to_u64(i: &[u8]) -> u64 {
    let s = str::from_utf8(i).unwrap();

    u64::from_str(s).unwrap()
}

pub fn parse_gauge(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: digit            ~ tag!("|g") ,

        ||{ ParsedMetric::Gauge(name, bytes_to_u64(value)) }
    )
}

fn parse_metric_name(i: &[u8]) -> IResult<&[u8], String> {
    #[inline]
    fn is_metric_name_char(i: u8) -> bool {
        let c = char::from_u32(i as u32).unwrap();

        is_alphanumeric(i) || c == '.' || c == '_'
    }

    map!(i,
        take_while!(is_metric_name_char),
        |name| { String::from_utf8_lossy(name).into_owned() }
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::any::Any;
    use nom::IResult;

    fn complete<'a, T>(value: T) -> IResult<&'a [u8], T>
        where T: Any {
        IResult::Done(&b""[..], value)
    }

    #[test]
    fn it_parses_gauge() {
        assert_eq!(
            parse_gauge(&b"foo.bar_baz:1|g"[..]),
            complete(ParsedMetric::Gauge("foo.bar_baz".to_owned(), 1))
        )
    }
}
<commit_msg>Implement parsing of StatsD counter metrics<commit_after>use std::char;
use std::num::ParseIntError;
use std::str::{self, FromStr};

use nom::{
    digit,
    is_alphanumeric,
    IResult
};

/// Parsed StatsD metric.
///
/// See here for more details: https://github.com/b/statsd_spec#metric-types--formats
#[derive(Debug, PartialEq)]
pub enum ParsedMetric {
    Gauge(String, u64),
    Counter(String, u64),
}

pub type ParseResult<'a> = IResult<&'a [u8], ParsedMetric>;

fn bytes_to_u64(i: &[u8]) -> Result<u64, ParseIntError> {
    let s = str::from_utf8(i).unwrap();

    u64::from_str(s)
}

pub fn parse_gauge(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|g") ,

        ||{ ParsedMetric::Gauge(name, value) }
    )
}

pub fn parse_counter(i: &[u8]) -> ParseResult {
    chain!(i,
        name: parse_metric_name ~ tag!(":")  ~
        value: parse_value      ~ tag!("|c") ~
        sample_rate: opt!(complete!(parse_sample_rate)) ,

        ||{ ParsedMetric::Counter(name, value) }
    )
}

pub fn parse_value(i: &[u8]) -> IResult<&[u8], u64> {
    map_res!(i,
        digit,
        |value| { bytes_to_u64(value) }
    )
}

pub fn parse_sample_rate(i: &[u8]) -> IResult<&[u8], u64> {
    preceded!(i,
        tag!("|@"),
        map_res!(digit, |rate| { bytes_to_u64(rate) })
    )
}

fn parse_metric_name(i: &[u8]) -> IResult<&[u8], String> {
    #[inline]
    fn is_metric_name_char(i: u8) -> bool {
        let c = char::from_u32(i as u32).unwrap();

        is_alphanumeric(i) || c == '.' || c == '_'
    }

    map!(i,
        take_while!(is_metric_name_char),
        |name| { String::from_utf8_lossy(name).into_owned() }
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::any::Any;
    use nom::IResult;

    fn complete<'a, T>(value: T) -> IResult<&'a [u8], T>
        where T: Any {
        IResult::Done(&b""[..], value)
    }

    #[test]
    fn it_parses_gauge() {
        assert_eq!(
            parse_gauge(&b"foo.bar_baz:12|g"[..]),
            complete(ParsedMetric::Gauge("foo.bar_baz".to_owned(), 12))
        )
    }

    #[test]
    fn it_parses_counter() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:23|c"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 23))
        )
    }

    #[test]
    fn it_parses_counter_with_sample_rate() {
        assert_eq!(
            parse_counter(&b"foo.bar_baz:34|c|@5"[..]),
            complete(ParsedMetric::Counter("foo.bar_baz".to_owned(), 34))
        )
    }
}
<|endoftext|>


<commit_before>use super::directory_stack::DirectoryStack;
use super::plugins::namespaces::{self, StringNamespace};
use super::status::{FAILURE, SUCCESS};
use app_dirs::{AppDataType, AppInfo, app_root};
use fnv::FnvHashMap;
use liner::Context;
use std::env;
use std::io::{self, BufRead};
use std::process;
use types::{Array, ArrayVariableContext, HashMap, HashMapVariableContext, Identifier, Key, Value, VariableContext};

#[cfg(target_os = "redox")]
use sys::getpid;

#[cfg(all(unix, not(target_os = "unix")))]
use sys::getpid;

use sys;
use sys::variables as self_sys;

lazy_static! {
    static ref STRING_NAMESPACES: FnvHashMap<Identifier, StringNamespace> = namespaces::collect();
}

lazy_static! {
    static ref COLORS: FnvHashMap<&'static str, &'static str> = {
        let mut map = FnvHashMap::default();
        map.insert("reset", "\x1b[0m");
        map.insert("bold", "\x1b[1m");
        map.insert("dim", "\x1b[2m");
        map.insert("underlined", "\x1b[4m");
        map.insert("blink", "\x1b[5m");
        map.insert("reverse", "\x1b[7m");
        map.insert("hidden", "\x1b[8m");
        map.insert("black", "\x1b[30m");
        map.insert("red", "\x1b[31m");
        map.insert("green", "\x1b[32m");
        map.insert("yellow", "\x1b[33m");
        map.insert("blue", "\x1b[34m");
        map.insert("magenta", "\x1b[35m");
        map.insert("cyan", "\x1b[36m");
        map.insert("light_gray", "\x1b[37m");
        map.insert("default", "\x1b[39m");
        map.insert("blackbg", "\x1b[40m");
        map.insert("redbg", "\x1b[41m");
        map.insert("greenbg", "\x1b[42m");
        map.insert("yellowbg", "\x1b[43m");
        map.insert("bluebg", "\x1b[44m");
        map.insert("magentabg", "\x1b[45m");
        map.insert("cyanbg", "\x1b[46m");
        map.insert("light_graybg", "\x1b[47m");
        map.insert("defaultbg", "\x1b[49m");
        map.insert("dark_gray", "\x1b[90m");
        map.insert("light_red", "\x1b[91m");
        map.insert("light_green", "\x1b[92m");
        map.insert("light_yellow", "\x1b[93m");
        map.insert("light_blue", "\x1b[94m");
        map.insert("light_magenta", "\x1b[95m");
        map.insert("light_cyan", "\x1b[96m");
        map.insert("dark_graybg", "\x1b[100m");
        map.insert("light_redbg", "\x1b[101m");
        map.insert("light_greenbg", "\x1b[102m");
        map.insert("light_yellowbg",  "\x1b[103m");
        map.insert("light_bluebg", "\x1b[104m");
        map.insert("light_magentabg", "\x1b[105m");
        map.insert("light_cyanbg", "\x1b[106m");
        map.insert("white_bg", "\x1b[107m");
        map
    };
}

#[derive(Debug)]
pub struct Variables {
    pub hashmaps: HashMapVariableContext,
    pub arrays: ArrayVariableContext,
    pub variables: VariableContext,
    pub aliases: VariableContext,
}

impl Default for Variables {
    fn default() -> Variables {
        let mut map = FnvHashMap::with_capacity_and_hasher(64, Default::default());
        map.insert("DIRECTORY_STACK_SIZE".into(), "1000".into());
        map.insert("HISTORY_SIZE".into(), "1000".into());
        map.insert("HISTFILE_SIZE".into(), "1000".into());
        map.insert("PROMPT".into(), "\x1B\']\'0;${USER}: ${PWD}\x07\x1B\'[\'0m\x1B\'[\'1;38;5;85m${USER}\x1B\'[\'37m:\x1B\'[\'38;5;75m${PWD}\x1B\'[\'37m#\x1B\'[\'0m ".into());
        // Set the PID variable to the PID of the shell
        let pid = getpid().map(|p| p.to_string()).unwrap_or_else(
            |e| e.to_string(),
        );
        map.insert("PID".into(), pid.into());

        // Initialize the HISTFILE variable
        if let Ok(mut home_path) =
            app_root(
                AppDataType::UserData,
                &AppInfo {
                    name: "ion",
                    author: "Redox OS Developers",
                },
            )
        {
            home_path.push("history");
            map.insert("HISTFILE".into(), home_path.to_str().unwrap_or("?").into());
            map.insert("HISTFILE_ENABLED".into(), "1".into());
        }

        // Initialize the PWD (Present Working Directory) variable
        env::current_dir().ok().map_or_else(
            || env::set_var("PWD", "?"),
            |path| {
                env::set_var("PWD", path.to_str().unwrap_or("?"))
            },
        );

        // Initialize the HOME variable
        env::home_dir().map_or_else(|| env::set_var("HOME", "?"), |path| {
            env::set_var("HOME", path.to_str().unwrap_or("?"))
        });
        Variables {
            hashmaps: FnvHashMap::with_capacity_and_hasher(64, Default::default()),
            arrays: FnvHashMap::with_capacity_and_hasher(64, Default::default()),
            variables: map,
            aliases: FnvHashMap::with_capacity_and_hasher(64, Default::default()),
        }
    }
}

impl Variables {
    pub fn read<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        if sys::isatty(sys::STDIN_FILENO) {
            let mut con = Context::new();
            for arg in args.into_iter().skip(1) {
                match con.read_line(format!("{}=", arg.as_ref().trim()), &mut |_| {}) {
                    Ok(buffer) => self.set_var(arg.as_ref(), buffer.trim()),
                    Err(_) => return FAILURE,
                }
            }
        } else {
            let stdin = io::stdin();
            let handle = stdin.lock();
            let mut lines = handle.lines();
            for arg in args.into_iter().skip(1) {
                if let Some(Ok(line)) = lines.next() {
                    self.set_var(arg.as_ref(), line.trim());
                }
            }
        }
        SUCCESS
    }

    pub fn set_var(&mut self, name: &str, value: &str) {
        if !name.is_empty() {
            if value.is_empty() {
                self.variables.remove(name);
            } else {
                self.variables.insert(name.into(), value.into());
            }
        }
    }

    pub fn set_array(&mut self, name: &str, value: Array) {
        if !name.is_empty() {
            if value.is_empty() {
                self.arrays.remove(name);
            } else {
                self.arrays.insert(name.into(), value);
            }
        }
    }

    pub fn set_hashmap_value(&mut self, name: &str, key: &str, value: &str) {
        if !name.is_empty() {
            if let Some(map) = self.hashmaps.get_mut(name) {
                map.insert(key.into(), value.into());
                return;
            }

            let mut map = HashMap::with_capacity_and_hasher(4, Default::default());
            map.insert(key.into(), value.into());
            self.hashmaps.insert(name.into(), map);
        }
    }

    pub fn get_map(&self, name: &str) -> Option<&HashMap> { self.hashmaps.get(name) }

    pub fn get_array(&self, name: &str) -> Option<&Array> { self.arrays.get(name) }

    pub fn unset_array(&mut self, name: &str) -> Option<Array> { self.arrays.remove(name) }

    pub fn get_var(&self, name: &str) -> Option<Value> {
        if let Some((name, variable)) = name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) {
            // If the parsed name contains the '::' pattern, then a namespace was designated. Find it.
            match name {
                "color" => match COLORS.get(&variable) {
                    Some(color) => Some((*color).into()),
                    None => {
                        eprintln!("ion: {} is not a valid color", name);
                        None
                    }
                }
                "env" => env::var(variable).map(Into::into).ok(),
                _ => {
                    // Attempt to obtain the given namespace from our lazily-generated map of namespaces.
                    if let Some(namespace) = STRING_NAMESPACES.get(name.into()) {
                        // Attempt to execute the given function from that namespace, and map it's results.
                        match namespace.execute(variable.into()) {
                            Ok(value) => value.map(Into::into),
                            Err(why) => {
                                eprintln!("ion: string namespace erorr: {}: {}", name, why);
                                None
                            }
                        }
                    } else {
                        eprintln!("ion: unsupported namespace: '{}'", name);
                        None
                    }
                }
            }
        } else {
            // Otherwise, it's just a simple variable name.
            self.variables.get(name).cloned().or_else(|| {
                env::var(name).map(Into::into).ok()
            })
        }
    }

    pub fn get_var_or_empty(&self, name: &str) -> Value { self.get_var(name).unwrap_or_default() }

    pub fn unset_var(&mut self, name: &str) -> Option<Value> { self.variables.remove(name) }

    pub fn get_vars(&self) -> Vec<Identifier> {
        self.variables
            .keys()
            .cloned()
            .chain(env::vars().map(|(k, _)| k.into()))
            .collect()
    }

    pub fn is_valid_variable_character(c: char) -> bool { c.is_alphanumeric() || c == '_' || c == '?' }

    pub fn is_valid_variable_name(name: &str) -> bool { name.chars().all(Variables::is_valid_variable_character) }

    pub fn tilde_expansion(&self, word: &str, dir_stack: &DirectoryStack) -> Option<String> {
        let mut chars = word.char_indices();

        let tilde_prefix;
        let remainder;

        loop {
            if let Some((ind, c)) = chars.next() {
                if c == '/' || c == '$' {
                    tilde_prefix = &word[1..ind];
                    remainder = &word[ind..];
                    break;
                }
            } else {
                tilde_prefix = &word[1..];
                remainder = "";
                break;
            }
        }

        match tilde_prefix {
            "" => {
                if let Some(home) = env::home_dir() {
                    return Some(home.to_string_lossy().to_string() + remainder);
                }
            }
            "+" => {
                if let Some(pwd) = self.get_var("PWD") {
                    return Some(pwd.to_string() + remainder);
                } else if let Ok(pwd) = env::current_dir() {
                    return Some(pwd.to_string_lossy().to_string() + remainder);
                }
            }
            "-" => {
                if let Some(oldpwd) = self.get_var("OLDPWD") {
                    return Some(oldpwd.to_string() + remainder);
                }
            }
            _ => {
                let neg;
                let tilde_num;

                if tilde_prefix.starts_with('+') {
                    tilde_num = &tilde_prefix[1..];
                    neg = false;
                } else if tilde_prefix.starts_with('-') {
                    tilde_num = &tilde_prefix[1..];
                    neg = true;
                } else {
                    tilde_num = tilde_prefix;
                    neg = false;
                }

                match tilde_num.parse() {
                    Ok(num) => {
                        let res = if neg { dir_stack.dir_from_top(num) } else { dir_stack.dir_from_bottom(num) };

                        if let Some(path) = res {
                            return Some(path.to_str().unwrap().to_string());
                        }
                    }
                    Err(_) => {
                        if let Some(home) = self_sys::get_user_home(tilde_prefix) {
                            return Some(home + remainder);
                        }
                    }
                }
            }
        }
        None
    }

    pub fn command_expansion(&self, command: &str) -> Option<Value> {
        if let Ok(exe) = env::current_exe() {
            if let Ok(output) = process::Command::new(exe).arg("-c").arg(command).output() {
                if let Ok(mut stdout) = String::from_utf8(output.stdout) {
                    if stdout.ends_with('\n') {
                        stdout.pop();
                    }

                    return Some(stdout.into());
                }
            }
        }

        None
    }

    pub fn is_hashmap_reference(key: &str) -> Option<(Identifier, Key)> {
        let mut key_iter = key.split('[');

        if let Some(map_name) = key_iter.next() {
            if Variables::is_valid_variable_name(map_name) {
                if let Some(mut inner_key) = key_iter.next() {
                    if inner_key.ends_with(']') {
                        inner_key = inner_key.split(']').next().unwrap_or("");
                        inner_key = inner_key.trim_matches(|c| c == '\'' || c == '\"');
                        return Some((map_name.into(), inner_key.into()));
                    }
                }
            }
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::{Expander, expand_string};
    use shell::directory_stack::DirectoryStack;

    struct VariableExpander(pub Variables);

    impl Expander for VariableExpander {
        fn variable(&self, var: &str, _: bool) -> Option<Value> { self.0.get_var(var) }
    }

    #[test]
    fn undefined_variable_expands_to_empty_string() {
        let variables = Variables::default();
        let expanded = expand_string("$FOO", &VariableExpander(variables), false).join("");
        assert_eq!("", &expanded);
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::default();
        variables.set_var("FOO", "BAR");
        let expanded = expand_string("$FOO", &VariableExpander(variables), false).join("");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn decompose_map_reference() {
        if let Some((map_name, inner_key)) = Variables::is_hashmap_reference("map[\'key\']") {
            assert!(map_name == "map".into());
            assert!(inner_key == "key".into());
        } else {
            assert!(false);
        }
    }
}
<commit_msg>Fix syntax error in src/shell/variables.rs<commit_after>use super::directory_stack::DirectoryStack;
use super::plugins::namespaces::{self, StringNamespace};
use super::status::{FAILURE, SUCCESS};
use app_dirs::{AppDataType, AppInfo, app_root};
use fnv::FnvHashMap;
use liner::Context;
use std::env;
use std::io::{self, BufRead};
use std::process;
use types::{Array, ArrayVariableContext, HashMap, HashMapVariableContext, Identifier, Key, Value, VariableContext};

#[cfg(target_os = "redox")]
use sys::getpid;

#[cfg(all(unix, not(target_os = "unix")))]
use sys::getpid;

use sys;
use sys::variables as self_sys;

lazy_static! {
    static ref STRING_NAMESPACES: FnvHashMap<Identifier, StringNamespace> = namespaces::collect();
}

lazy_static! {
    static ref COLORS: FnvHashMap<&'static str, &'static str> = {
        let mut map = FnvHashMap::default();
        map.insert("reset", "\x1b[0m");
        map.insert("bold", "\x1b[1m");
        map.insert("dim", "\x1b[2m");
        map.insert("underlined", "\x1b[4m");
        map.insert("blink", "\x1b[5m");
        map.insert("reverse", "\x1b[7m");
        map.insert("hidden", "\x1b[8m");
        map.insert("black", "\x1b[30m");
        map.insert("red", "\x1b[31m");
        map.insert("green", "\x1b[32m");
        map.insert("yellow", "\x1b[33m");
        map.insert("blue", "\x1b[34m");
        map.insert("magenta", "\x1b[35m");
        map.insert("cyan", "\x1b[36m");
        map.insert("light_gray", "\x1b[37m");
        map.insert("default", "\x1b[39m");
        map.insert("blackbg", "\x1b[40m");
        map.insert("redbg", "\x1b[41m");
        map.insert("greenbg", "\x1b[42m");
        map.insert("yellowbg", "\x1b[43m");
        map.insert("bluebg", "\x1b[44m");
        map.insert("magentabg", "\x1b[45m");
        map.insert("cyanbg", "\x1b[46m");
        map.insert("light_graybg", "\x1b[47m");
        map.insert("defaultbg", "\x1b[49m");
        map.insert("dark_gray", "\x1b[90m");
        map.insert("light_red", "\x1b[91m");
        map.insert("light_green", "\x1b[92m");
        map.insert("light_yellow", "\x1b[93m");
        map.insert("light_blue", "\x1b[94m");
        map.insert("light_magenta", "\x1b[95m");
        map.insert("light_cyan", "\x1b[96m");
        map.insert("dark_graybg", "\x1b[100m");
        map.insert("light_redbg", "\x1b[101m");
        map.insert("light_greenbg", "\x1b[102m");
        map.insert("light_yellowbg",  "\x1b[103m");
        map.insert("light_bluebg", "\x1b[104m");
        map.insert("light_magentabg", "\x1b[105m");
        map.insert("light_cyanbg", "\x1b[106m");
        map.insert("white_bg", "\x1b[107m");
        map
    };
}

#[derive(Debug)]
pub struct Variables {
    pub hashmaps: HashMapVariableContext,
    pub arrays: ArrayVariableContext,
    pub variables: VariableContext,
    pub aliases: VariableContext,
}

impl Default for Variables {
    fn default() -> Variables {
        let mut map = FnvHashMap::with_capacity_and_hasher(64, Default::default());
        map.insert("DIRECTORY_STACK_SIZE".into(), "1000".into());
        map.insert("HISTORY_SIZE".into(), "1000".into());
        map.insert("HISTFILE_SIZE".into(), "1000".into());
        map.insert("PROMPT".into(), "\x1B\']\'0;${USER}: ${PWD}\x07\x1B\'[\'0m\x1B\'[\'1;38;5;85m${USER}\x1B\'[\'37m:\x1B\'[\'38;5;75m${PWD}\x1B\'[\'37m#\x1B\'[\'0m ".into());
        // Set the PID variable to the PID of the shell
        let pid = getpid().map(|p| p.to_string()).unwrap_or_else(
            |e| e.to_string(),
        );
        map.insert("PID".into(), pid.into());

        // Initialize the HISTFILE variable
        if let Ok(mut home_path) =
            app_root(
                AppDataType::UserData,
                &AppInfo {
                    name: "ion",
                    author: "Redox OS Developers",
                },
            )
        {
            home_path.push("history");
            map.insert("HISTFILE".into(), home_path.to_str().unwrap_or("?").into());
            map.insert("HISTFILE_ENABLED".into(), "1".into());
        }

        // Initialize the PWD (Present Working Directory) variable
        env::current_dir().ok().map_or_else(
            || env::set_var("PWD", "?"),
            |path| {
                env::set_var("PWD", path.to_str().unwrap_or("?"))
            },
        );

        // Initialize the HOME variable
        env::home_dir().map_or_else(|| env::set_var("HOME", "?"), |path| {
            env::set_var("HOME", path.to_str().unwrap_or("?"))
        });
        Variables {
            hashmaps: FnvHashMap::with_capacity_and_hasher(64, Default::default()),
            arrays: FnvHashMap::with_capacity_and_hasher(64, Default::default()),
            variables: map,
            aliases: FnvHashMap::with_capacity_and_hasher(64, Default::default()),
        }
    }
}

impl Variables {
    pub fn read<I: IntoIterator>(&mut self, args: I) -> i32
        where I::Item: AsRef<str>
    {
        if sys::isatty(sys::STDIN_FILENO) {
            let mut con = Context::new();
            for arg in args.into_iter().skip(1) {
                match con.read_line(format!("{}=", arg.as_ref().trim()), &mut |_| {}) {
                    Ok(buffer) => self.set_var(arg.as_ref(), buffer.trim()),
                    Err(_) => return FAILURE,
                }
            }
        } else {
            let stdin = io::stdin();
            let handle = stdin.lock();
            let mut lines = handle.lines();
            for arg in args.into_iter().skip(1) {
                if let Some(Ok(line)) = lines.next() {
                    self.set_var(arg.as_ref(), line.trim());
                }
            }
        }
        SUCCESS
    }

    pub fn set_var(&mut self, name: &str, value: &str) {
        if !name.is_empty() {
            if value.is_empty() {
                self.variables.remove(name);
            } else {
                self.variables.insert(name.into(), value.into());
            }
        }
    }

    pub fn set_array(&mut self, name: &str, value: Array) {
        if !name.is_empty() {
            if value.is_empty() {
                self.arrays.remove(name);
            } else {
                self.arrays.insert(name.into(), value);
            }
        }
    }

    pub fn set_hashmap_value(&mut self, name: &str, key: &str, value: &str) {
        if !name.is_empty() {
            if let Some(map) = self.hashmaps.get_mut(name) {
                map.insert(key.into(), value.into());
                return;
            }

            let mut map = HashMap::with_capacity_and_hasher(4, Default::default());
            map.insert(key.into(), value.into());
            self.hashmaps.insert(name.into(), map);
        }
    }

    pub fn get_map(&self, name: &str) -> Option<&HashMap> { self.hashmaps.get(name) }

    pub fn get_array(&self, name: &str) -> Option<&Array> { self.arrays.get(name) }

    pub fn unset_array(&mut self, name: &str) -> Option<Array> { self.arrays.remove(name) }

    pub fn get_var(&self, name: &str) -> Option<Value> {
        if let Some((name, variable)) = name.find("::").map(|pos| (&name[..pos], &name[pos + 2..])) {
            // If the parsed name contains the '::' pattern, then a namespace was designated. Find it.
            match name {
                "color" => match COLORS.get(&variable) {
                    Some(color) => Some((*color).into()),
                    None => {
                        eprintln!("ion: {} is not a valid color", name);
                        None
                    }
                },
                "env" => env::var(variable).map(Into::into).ok(),
                _ => {
                    // Attempt to obtain the given namespace from our lazily-generated map of namespaces.
                    if let Some(namespace) = STRING_NAMESPACES.get(name.into()) {
                        // Attempt to execute the given function from that namespace, and map it's results.
                        match namespace.execute(variable.into()) {
                            Ok(value) => value.map(Into::into),
                            Err(why) => {
                                eprintln!("ion: string namespace erorr: {}: {}", name, why);
                                None
                            }
                        }
                    } else {
                        eprintln!("ion: unsupported namespace: '{}'", name);
                        None
                    }
                }
            }
        } else {
            // Otherwise, it's just a simple variable name.
            self.variables.get(name).cloned().or_else(|| {
                env::var(name).map(Into::into).ok()
            })
        }
    }

    pub fn get_var_or_empty(&self, name: &str) -> Value { self.get_var(name).unwrap_or_default() }

    pub fn unset_var(&mut self, name: &str) -> Option<Value> { self.variables.remove(name) }

    pub fn get_vars(&self) -> Vec<Identifier> {
        self.variables
            .keys()
            .cloned()
            .chain(env::vars().map(|(k, _)| k.into()))
            .collect()
    }

    pub fn is_valid_variable_character(c: char) -> bool { c.is_alphanumeric() || c == '_' || c == '?' }

    pub fn is_valid_variable_name(name: &str) -> bool { name.chars().all(Variables::is_valid_variable_character) }

    pub fn tilde_expansion(&self, word: &str, dir_stack: &DirectoryStack) -> Option<String> {
        let mut chars = word.char_indices();

        let tilde_prefix;
        let remainder;

        loop {
            if let Some((ind, c)) = chars.next() {
                if c == '/' || c == '$' {
                    tilde_prefix = &word[1..ind];
                    remainder = &word[ind..];
                    break;
                }
            } else {
                tilde_prefix = &word[1..];
                remainder = "";
                break;
            }
        }

        match tilde_prefix {
            "" => {
                if let Some(home) = env::home_dir() {
                    return Some(home.to_string_lossy().to_string() + remainder);
                }
            }
            "+" => {
                if let Some(pwd) = self.get_var("PWD") {
                    return Some(pwd.to_string() + remainder);
                } else if let Ok(pwd) = env::current_dir() {
                    return Some(pwd.to_string_lossy().to_string() + remainder);
                }
            }
            "-" => {
                if let Some(oldpwd) = self.get_var("OLDPWD") {
                    return Some(oldpwd.to_string() + remainder);
                }
            }
            _ => {
                let neg;
                let tilde_num;

                if tilde_prefix.starts_with('+') {
                    tilde_num = &tilde_prefix[1..];
                    neg = false;
                } else if tilde_prefix.starts_with('-') {
                    tilde_num = &tilde_prefix[1..];
                    neg = true;
                } else {
                    tilde_num = tilde_prefix;
                    neg = false;
                }

                match tilde_num.parse() {
                    Ok(num) => {
                        let res = if neg { dir_stack.dir_from_top(num) } else { dir_stack.dir_from_bottom(num) };

                        if let Some(path) = res {
                            return Some(path.to_str().unwrap().to_string());
                        }
                    }
                    Err(_) => {
                        if let Some(home) = self_sys::get_user_home(tilde_prefix) {
                            return Some(home + remainder);
                        }
                    }
                }
            }
        }
        None
    }

    pub fn command_expansion(&self, command: &str) -> Option<Value> {
        if let Ok(exe) = env::current_exe() {
            if let Ok(output) = process::Command::new(exe).arg("-c").arg(command).output() {
                if let Ok(mut stdout) = String::from_utf8(output.stdout) {
                    if stdout.ends_with('\n') {
                        stdout.pop();
                    }

                    return Some(stdout.into());
                }
            }
        }

        None
    }

    pub fn is_hashmap_reference(key: &str) -> Option<(Identifier, Key)> {
        let mut key_iter = key.split('[');

        if let Some(map_name) = key_iter.next() {
            if Variables::is_valid_variable_name(map_name) {
                if let Some(mut inner_key) = key_iter.next() {
                    if inner_key.ends_with(']') {
                        inner_key = inner_key.split(']').next().unwrap_or("");
                        inner_key = inner_key.trim_matches(|c| c == '\'' || c == '\"');
                        return Some((map_name.into(), inner_key.into()));
                    }
                }
            }
        }
        None
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parser::{Expander, expand_string};
    use shell::directory_stack::DirectoryStack;

    struct VariableExpander(pub Variables);

    impl Expander for VariableExpander {
        fn variable(&self, var: &str, _: bool) -> Option<Value> { self.0.get_var(var) }
    }

    #[test]
    fn undefined_variable_expands_to_empty_string() {
        let variables = Variables::default();
        let expanded = expand_string("$FOO", &VariableExpander(variables), false).join("");
        assert_eq!("", &expanded);
    }

    #[test]
    fn set_var_and_expand_a_variable() {
        let mut variables = Variables::default();
        variables.set_var("FOO", "BAR");
        let expanded = expand_string("$FOO", &VariableExpander(variables), false).join("");
        assert_eq!("BAR", &expanded);
    }

    #[test]
    fn decompose_map_reference() {
        if let Some((map_name, inner_key)) = Variables::is_hashmap_reference("map[\'key\']") {
            assert!(map_name == "map".into());
            assert!(inner_key == "key".into());
        } else {
            assert!(false);
        }
    }
}
<|endoftext|>


<commit_before>extern crate collections;

use std::str;
use collections::HashMap;
use std::io::File;
use std::io::BufferedReader;

fn sort_string(string: ~str) -> ~str {
	let mut chars = string.to_utf16();
	chars.sort();
	str::from_utf16(chars).unwrap()
}

fn main () {
	let path = Path::new("unixdict.txt");
	let mut file = BufferedReader::new(File::open(&path));

	let mut map: HashMap<~str, ~[~str]> = HashMap::new();

	for line in file.lines() {
		let s = line.trim().to_owned();
		map.mangle(sort_string(s.clone()), s,
				   |_k, v| ~[v],
				   |_k, v, string| v.push(string)
				);//, sort_string(line))
	}

	let mut max_length = 0;
	for (_k, v) in map.iter() {
		if v.len() > max_length {
			max_length = v.len()
		}
	}

	for (_k, v) in map.iter() {
		if v.len() == max_length {
			for s in v.iter() {
				print!("{} ", *s)
			}
			println!("")
		}
	}
}<commit_msg>Changes suggested in IRC<commit_after>extern crate collections;

use std::str;
use collections::HashMap;
use std::io::File;
use std::io::BufferedReader;
use std::cmp;

fn sort_string(string: &str) -> ~str {
	let mut chars = string.chars().to_owned_vec();
	chars.sort();
	str::from_chars(chars)
}

fn main () {
	let path = Path::new("unixdict.txt");
	let mut file = BufferedReader::new(File::open(&path));

	let mut map: HashMap<~str, ~[~str]> = HashMap::new();

	for line in file.lines() {
		let s = line.trim().to_owned();
		map.mangle(sort_string(s.clone()), s,
				   |_k, v| ~[v],
				   |_k, v, string| v.push(string)
				);
	}

	let max_length = map.iter().fold(0, |s, (_k, v)| cmp::max(s, v.len()));

	for (_k, v) in map.iter() {
		if v.len() == max_length {
			for s in v.iter() {
				print!("{} ", *s)
			}
			println!("")
		}
	}
}<|endoftext|>


<commit_before>#![feature(custom_attribute)]

extern crate regex;

use std::io;
use std::io::prelude::*;

use regex::Regex;

const LANGUAGES: &'static str = "_div abap actionscript actionscript3 ada apache applescript \
                                 apt_sources asm asp autoit avisynth bash basic4gl bf blitzbasic \
                                 bnf boo c c_mac caddcl cadlisp cfdg cfm cil cobol cpp cpp-qt \
                                 csharp css d delphi diff dos dot eiffel email fortran freebasic \
                                 genero gettext glsl gml gnuplot groovy haskell hq9plus \
                                 html4strict idl ini inno intercal io java java5 javascript \
                                 kixtart klonec klonecpp latex lisp lolcode lotusformulas \
                                 lotusscript lscript lua m68k make matlab mirc modula3 mpasm mxml \
                                 mysql nsis objc ocaml ocaml-brief oobas oracle11 oracle8 pascal \
                                 per perl php php-brief pic16 pixelbender plsql povray powershell \
                                 progress prolog providex python qbasic rails reg robots ruby \
                                 rust sas scala scheme scilab sdlbasic smalltalk smarty sql tcl \
                                 teraterm text thinbasic tsql typoscript vb vbnet verilog vhdl \
                                 vim visualfoxpro visualprolog whitespace winbatch xml xorg_conf \
                                 xpp z80";

fn fix_tags(languages: Vec<&str>, text: &str) -> String {
    let mut replaced_text = text.to_owned();

    for lang in languages.iter() {
        let bad_open = Regex::new(&format!("<{lang}>|", lang = lang)).unwrap();
        let bad_close = Regex::new(&format!("</{lang}>|", lang = lang)).unwrap();
        let open = format!("<lang {}>", lang);
        let close = "</lang>";

        replaced_text = bad_open.replace_all(&replaced_text, &open[..]);
        replaced_text = bad_close.replace_all(&replaced_text, &close[..]);
    }

    replaced_text.to_owned()
}

fn main() {
    let stdin = io::stdin();
    let mut buf = String::new();
    stdin.lock().read_to_string(&mut buf).unwrap();
    println!("{}", fix_tags(LANGUAGES.split_whitespace().collect(), &buf));
}

#[test]
fn test_replace() {
    let input = "Lorem ipsum saepe audire elaboraret ne quo, id equidem atomorum \
                 inciderint usu. <foo>In sit inermis deleniti percipit</foo>, ius ex tale civibus \
                 omittam. <barf>Vix ut doctus cetero invenire</barf>, his eu altera electram. \
                 Tota adhuc altera te sea, soluta appetere ut mel</bar>. Quo quis \
                 graecis vivendo te, <baz>posse nullam lobortis ex usu. Eam volumus \
                 perpetua constituto id, mea an omittam fierent vituperatoribus.";

    let expected = "Lorem ipsum <lang foo>saepe audire</lang> elaboraret ne quo, id equidem \
                    atomorum inciderint usu. <lang foo>In sit inermis deleniti percipit</lang>, \
                    ius ex tale civibus omittam. <barf>Vix ut doctus cetero invenire</barf>, his \
                    eu altera electram. Tota adhuc altera te sea, <lang bar>soluta appetere ut \
                    mel</lang>. Quo quis graecis vivendo te, <lang baz>posse nullam lobortis ex \
                    usu</lang>. Eam volumus perpetua constituto id, mea an omittam fierent \
                    vituperatoribus.";

    let languages = vec!["foo", "bar", "baz"];

    assert_eq!(expected, fix_tags(languages, &input));
}
<commit_msg>add task link to top of "Fix code tags"<commit_after>// http://rosettacode.org/wiki/Rosetta_Code/Fix_code_tags
extern crate regex;

use std::io;
use std::io::prelude::*;

use regex::Regex;

const LANGUAGES: &'static str = "_div abap actionscript actionscript3 ada apache applescript \
                                 apt_sources asm asp autoit avisynth bash basic4gl bf blitzbasic \
                                 bnf boo c c_mac caddcl cadlisp cfdg cfm cil cobol cpp cpp-qt \
                                 csharp css d delphi diff dos dot eiffel email fortran freebasic \
                                 genero gettext glsl gml gnuplot groovy haskell hq9plus \
                                 html4strict idl ini inno intercal io java java5 javascript \
                                 kixtart klonec klonecpp latex lisp lolcode lotusformulas \
                                 lotusscript lscript lua m68k make matlab mirc modula3 mpasm mxml \
                                 mysql nsis objc ocaml ocaml-brief oobas oracle11 oracle8 pascal \
                                 per perl php php-brief pic16 pixelbender plsql povray powershell \
                                 progress prolog providex python qbasic rails reg robots ruby \
                                 rust sas scala scheme scilab sdlbasic smalltalk smarty sql tcl \
                                 teraterm text thinbasic tsql typoscript vb vbnet verilog vhdl \
                                 vim visualfoxpro visualprolog whitespace winbatch xml xorg_conf \
                                 xpp z80";

fn fix_tags(languages: Vec<&str>, text: &str) -> String {
    let mut replaced_text = text.to_owned();

    for lang in languages.iter() {
        let bad_open = Regex::new(&format!("<{lang}>|", lang = lang)).unwrap();
        let bad_close = Regex::new(&format!("</{lang}>|", lang = lang)).unwrap();
        let open = format!("<lang {}>", lang);
        let close = "</lang>";

        replaced_text = bad_open.replace_all(&replaced_text, &open[..]);
        replaced_text = bad_close.replace_all(&replaced_text, &close[..]);
    }

    replaced_text.to_owned()
}

fn main() {
    let stdin = io::stdin();
    let mut buf = String::new();
    stdin.lock().read_to_string(&mut buf).unwrap();
    println!("{}", fix_tags(LANGUAGES.split_whitespace().collect(), &buf));
}

#[test]
fn test_replace() {
    let input = "Lorem ipsum saepe audire elaboraret ne quo, id equidem atomorum \
                 inciderint usu. <foo>In sit inermis deleniti percipit</foo>, ius ex tale civibus \
                 omittam. <barf>Vix ut doctus cetero invenire</barf>, his eu altera electram. \
                 Tota adhuc altera te sea, soluta appetere ut mel</bar>. Quo quis \
                 graecis vivendo te, <baz>posse nullam lobortis ex usu. Eam volumus \
                 perpetua constituto id, mea an omittam fierent vituperatoribus.";

    let expected = "Lorem ipsum <lang foo>saepe audire</lang> elaboraret ne quo, id equidem \
                    atomorum inciderint usu. <lang foo>In sit inermis deleniti percipit</lang>, \
                    ius ex tale civibus omittam. <barf>Vix ut doctus cetero invenire</barf>, his \
                    eu altera electram. Tota adhuc altera te sea, <lang bar>soluta appetere ut \
                    mel</lang>. Quo quis graecis vivendo te, <lang baz>posse nullam lobortis ex \
                    usu</lang>. Eam volumus perpetua constituto id, mea an omittam fierent \
                    vituperatoribus.";

    let languages = vec!["foo", "bar", "baz"];

    assert_eq!(expected, fix_tags(languages, &input));
}
<|endoftext|>


<commit_before>use crate::remotes::{MergeRequest, Remote};
use log::{debug, trace};
use regex::Regex;
use reqwest;
use serde_derive::{Deserialize, Serialize};

#[derive(Debug)]
pub struct GitHub {
    pub id: String,
    pub name: String,
    pub origin: String,
    pub api_root: String,
    pub api_key: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct GitHubPullRequest {
    id: i64,
    number: i64,
    title: String,
    body: Option<String>,
    html_url: String,
}

impl Remote for GitHub {
    fn get_project_id(&mut self) -> Result<&str, &str> {
        Ok(&self.id)
    }

    fn get_req_branch(&mut self, mr_id: i64) -> Result<String, &str> {
        Ok(format!("pr/{}", mr_id))
    }

    fn get_req_names(&mut self) -> Result<Vec<MergeRequest>, &str> {
        retrieve_github_project_pull_requests(self)
    }
}

/// Convert a GitHub PR to a git-req MergeRequest
fn github_to_mr(req: GitHubPullRequest) -> MergeRequest {
    MergeRequest {
        id: req.number,
        title: req.title,
        description: req.body,
        source_branch: format!("pr/{}", req.number),
    }
}

/// Query the GitHub API
fn query_github_api(url: reqwest::Url, token: String) -> reqwest::Response {
    let client = reqwest::Client::new();
    client
        .get(url)
        .header("Authorization", format!("token {}", token))
        .send()
        .expect("failed to send request")
}

/// Get the pull requests for the current project
fn retrieve_github_project_pull_requests(
    remote: &GitHub,
) -> Result<Vec<MergeRequest>, &'static str> {
    trace!("Querying for GitHub PR for {:?}", remote);
    let url = reqwest::Url::parse(&format!("{}/{}/pulls", remote.api_root, remote.id)).unwrap();
    let mut resp = query_github_api(url, remote.api_key.to_string());
    debug!("PR list query response: {:?}", resp);
    let buf: Vec<GitHubPullRequest> = match resp.json() {
        Ok(buf) => buf,
        Err(_) => {
            return Err("failed to read API response");
        }
    };
    Ok(buf.into_iter().map(github_to_mr).collect())
}

/// Extract the project name from a Github origin URL
pub fn get_github_project_name(origin: &str) -> String {
    trace!("Getting project name for: {}", origin);
    let project_regex = Regex::new(r".*:(.*/\S+)\.git\w*$").unwrap();
    let captures = project_regex.captures(origin).unwrap();
    String::from(&captures[1])
}
<commit_msg>Add test for github project name querying.<commit_after>use crate::remotes::{MergeRequest, Remote};
use log::{debug, trace};
use regex::Regex;
use reqwest;
use serde_derive::{Deserialize, Serialize};

#[derive(Debug)]
pub struct GitHub {
    pub id: String,
    pub name: String,
    pub origin: String,
    pub api_root: String,
    pub api_key: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct GitHubPullRequest {
    id: i64,
    number: i64,
    title: String,
    body: Option<String>,
    html_url: String,
}

impl Remote for GitHub {
    fn get_project_id(&mut self) -> Result<&str, &str> {
        Ok(&self.id)
    }

    fn get_req_branch(&mut self, mr_id: i64) -> Result<String, &str> {
        Ok(format!("pr/{}", mr_id))
    }

    fn get_req_names(&mut self) -> Result<Vec<MergeRequest>, &str> {
        retrieve_github_project_pull_requests(self)
    }
}

/// Convert a GitHub PR to a git-req MergeRequest
fn github_to_mr(req: GitHubPullRequest) -> MergeRequest {
    MergeRequest {
        id: req.number,
        title: req.title,
        description: req.body,
        source_branch: format!("pr/{}", req.number),
    }
}

/// Query the GitHub API
fn query_github_api(url: reqwest::Url, token: String) -> reqwest::Response {
    let client = reqwest::Client::new();
    client
        .get(url)
        .header("Authorization", format!("token {}", token))
        .send()
        .expect("failed to send request")
}

/// Get the pull requests for the current project
fn retrieve_github_project_pull_requests(
    remote: &GitHub,
) -> Result<Vec<MergeRequest>, &'static str> {
    trace!("Querying for GitHub PR for {:?}", remote);
    let url = reqwest::Url::parse(&format!("{}/{}/pulls", remote.api_root, remote.id)).unwrap();
    let mut resp = query_github_api(url, remote.api_key.to_string());
    debug!("PR list query response: {:?}", resp);
    let buf: Vec<GitHubPullRequest> = match resp.json() {
        Ok(buf) => buf,
        Err(_) => {
            return Err("failed to read API response");
        }
    };
    Ok(buf.into_iter().map(github_to_mr).collect())
}

/// Extract the project name from a Github origin URL
pub fn get_github_project_name(origin: &str) -> String {
    trace!("Getting project name for: {}", origin);
    let project_regex = Regex::new(r".*:(.*/\S+)\.git\w*$").unwrap();
    let captures = project_regex.captures(origin).unwrap();
    String::from(&captures[1])
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_get_github_project_name() {
        let name = get_github_project_name("git@github.com:my_org/my_project.git");
        assert_eq!("my_org/my_project", name);
    }
}
<|endoftext|>


<commit_before>use rand::Rng;
use rand::thread_rng;

pub fn get_rand_f64_vec(lower: u64, upper: u64) -> Vec<f64> {
    // create the floats
    let mut items: Vec<f64> = (lower..upper + 1)
                                  .map(|x: u64| x as f64)
                                  .collect();
    assert_eq!(upper - lower + 1, items.len() as u64);

    // now shuffle them
    thread_rng().shuffle(&mut items);

    items
}
<commit_msg>add test for get_rand_f64_vec<commit_after>use rand::Rng;
use rand::thread_rng;

pub fn get_rand_f64_vec(lower: u64, upper: u64) -> Vec<f64> {
    // create the floats
    let mut items: Vec<f64> = (lower..upper + 1)
                                  .map(|x: u64| x as f64)
                                  .collect();

    // now shuffle them
    thread_rng().shuffle(&mut items);

    items
}

#[cfg(test)]
mod tests {
    use std::cmp::Ordering;

    use super::get_rand_f64_vec;

    #[test]
    fn test_get_rand_f64_vec() {
        // construct a sorted version of the same vector
        let expected: Vec<f64> = (1..101).map(|x: u64| x as f64).collect();

        // get some random vectors
        let mut vec = get_rand_f64_vec(1, 100);
        let vec2 = get_rand_f64_vec(1, 100);

        // it isn't constant
        assert!(vec != vec2);

        // it isn't sorted
        assert!(vec != expected);

        // it has the right size
        assert_eq!(vec.len(), 100);

        // now sort the vector
        vec.sort_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal));

        // the sorted vector is now equal to the one we made ourselves
        assert_eq!(vec, expected);
    }
}
<|endoftext|>


<commit_before>pub use std::any::Any;

pub use self::actor_cell::{ActorCell, ActorContext, ControlMessage, InnerMessage, SystemMessage};
pub use self::actor_ref::{ActorPath, ActorRef};
pub use self::actor_system::ActorSystem;
pub use self::props::Props;

/// Module for ActorRef and CanReceive, the interface given to the user to interract with  actors.
pub mod actor_ref;

/// Module for the ActorSystem.
pub mod actor_system;

/// Module for Actor factories (Props).
pub mod props;

/// Module with the internals of Actors.
pub mod actor_cell;

/// Module allowing the use of the ask pattern.
pub mod ask;

/// Module containing the original actor.
mod cthulhu;

/// Module containing the root actor pattern, used for the `user actor` and the `systel actor`.
mod root_actor;

/// Module with the name resolver actor.
mod name_resolver;

/// Trait to be implemented by messages, this is automatically given if a struct is
/// already `Clone + Send + Sync + 'static + Any`.
pub trait Message: Clone + Send + Sync + 'static + Any {}
impl<T> Message for T where T: Clone + Send + Sync + 'static + Any
{}

/// Trait to be implemented by args, this is automatically given if a struct is
/// already `Clone + Send + Sync + 'static + Any`.
pub trait Arguments: Clone + Send + Sync + 'static {}
impl<T> Arguments for T where T: Clone + Send + Sync + 'static
{}

/// This is the trait to implement to become an Actor.
///
/// Normaly only the receive method has to be implemented.
// NOTE: Not sure about the 'static
pub trait Actor: Send + Sync + 'static {

    /// Single method to be implemented for an Actor.
    ///
    /// This defines the Actor's behaviour.
    // NOTE: we have a Box<Any> in the API even though that is a Box<Message> in reality, this is
    // done in order to have nicer code for the downcasts (indeed, I can't implement downcast
    // methods for Box<Message>).
    // Checks for sending data with the Message trait is done in the sending phase.
    fn receive(&self, message: Box<Any>, context: ActorCell);

    /// Method called when a monitored actor is terminated.
    ///
    /// This is put in a separated method because match in rust must check all variations and we
    /// chose not to force the user to make a case for terminations if it doesn not monitor any
    /// actor.
    // NOTE: this currently panic! because termination notices are not sent in the current
    // implementation.
    fn receive_termination(&self, _context: ActorCell) {
        panic!("Not implemented");
    }

    /// Method called before the Actor is started.
    fn pre_start(&self, _context: ActorCell) {}

    /// Method called after the Actor is stopped.
    fn post_stop(&self) {}

    /// Method called before the Actor is restarted.
    fn pre_restart(&self, _context: ActorCell) {
        self.post_stop();
    }

    /// Method called after the Actor is restarted.
    fn post_restart(&self, context: ActorCell) {
        self.pre_start(context);
    }
}
<commit_msg>Fix build.<commit_after>pub use std::any::Any;

pub use self::actor_cell::{ActorCell, ActorContext, ControlMessage, InnerMessage, SystemMessage};
pub use self::actor_ref::{ActorPath, ActorRef};
pub use self::actor_system::ActorSystem;
pub use self::props::Props;

/// Module for ActorRef and CanReceive, the interface given to the user to interract with  actors.
pub mod actor_ref;

/// Module for the ActorSystem.
pub mod actor_system;

/// Module for Actor factories (Props).
pub mod props;

/// Module with the internals of Actors.
pub mod actor_cell;

/// Module containing the original actor.
mod cthulhu;

/// Module containing the root actor pattern, used for the `user actor` and the `systel actor`.
mod root_actor;

/// Module with the name resolver actor.
mod name_resolver;

/// Trait to be implemented by messages, this is automatically given if a struct is
/// already `Clone + Send + Sync + 'static + Any`.
pub trait Message: Clone + Send + Sync + 'static + Any {}
impl<T> Message for T where T: Clone + Send + Sync + 'static + Any
{}

/// Trait to be implemented by args, this is automatically given if a struct is
/// already `Clone + Send + Sync + 'static + Any`.
pub trait Arguments: Clone + Send + Sync + 'static {}
impl<T> Arguments for T where T: Clone + Send + Sync + 'static
{}

/// This is the trait to implement to become an Actor.
///
/// Normaly only the receive method has to be implemented.
// NOTE: Not sure about the 'static
pub trait Actor: Send + Sync + 'static {

    /// Single method to be implemented for an Actor.
    ///
    /// This defines the Actor's behaviour.
    // NOTE: we have a Box<Any> in the API even though that is a Box<Message> in reality, this is
    // done in order to have nicer code for the downcasts (indeed, I can't implement downcast
    // methods for Box<Message>).
    // Checks for sending data with the Message trait is done in the sending phase.
    fn receive(&self, message: Box<Any>, context: ActorCell);

    /// Method called when a monitored actor is terminated.
    ///
    /// This is put in a separated method because match in rust must check all variations and we
    /// chose not to force the user to make a case for terminations if it doesn not monitor any
    /// actor.
    // NOTE: this currently panic! because termination notices are not sent in the current
    // implementation.
    fn receive_termination(&self, _context: ActorCell) {
        panic!("Not implemented");
    }

    /// Method called before the Actor is started.
    fn pre_start(&self, _context: ActorCell) {}

    /// Method called after the Actor is stopped.
    fn post_stop(&self) {}

    /// Method called before the Actor is restarted.
    fn pre_restart(&self, _context: ActorCell) {
        self.post_stop();
    }

    /// Method called after the Actor is restarted.
    fn post_restart(&self, context: ActorCell) {
        self.pre_start(context);
    }
}
<|endoftext|>


<commit_before>//! A concrete implementation of `futures::Future`. It is similar in spirit as
//! `futures::Promise`, but is better suited for use with Tokio.

use futures::{Future, Poll, Task};
use std::mem;
use std::cell::Cell;
use std::sync::{Arc, Mutex};
use self::State::*;

/// A future representing the completion of an asynchronous computation.
///
/// This is created by the `pair` function.
pub struct Val<T, E> {
    inner: Arc<Inner<T, E>>,
}

/// The `Complete` half of `Val` used to send the result of an asynchronous
/// computation to the consumer of `Val`.
///
/// This is created by the `pair` function.
pub struct Complete<T, E> {
    inner: Arc<Inner<T, E>>,
    cancellation: Cell<bool>,
}

/// A future representing the cancellation in interest by the consumer of
/// `Val`.
///
/// If a `Val` is dropped without ever attempting to read the value, then it
/// becomes impossible to ever receive the result of the underlying
/// computation. This indicates that there is no interest in the computation
/// and it may be cancelled.
///
/// In this case, this future will be completed. The asynchronous computation
/// is able to listen for this completion and abort work early.
pub struct Cancellation {
    inner: Arc<SyncFuture>,
}

// Currently implemented with a mutex, but this is only to get something
// working. This should be rewritten to use a lock free strategy.
struct Inner<T, E> {
    state: Mutex<State<T, E>>,
}

enum State<T, E> {
    Init {
        consumer: Option<Callback>,
        cancellation: Option<Callback>
    },
    Completed(Option<Result<T, E>>),
    Cancelled,
    Consumed,
}

type Callback = Box<FnBox>;

/// Create and return a new `Complete` / `Val` pair.
///
/// `Complete` is used to send the result of an asynchronous computation to the
/// consumer of `Val`.
pub fn pair<T, E>() -> (Complete<T, E>, Val<T, E>) {
    let inner = Arc::new(Inner {
        state: Mutex::new(State::Init {
            consumer: None,
            cancellation: None,
        }),
    });

    let tx = Complete {
        inner: inner.clone(),
        cancellation: Cell::new(false),
    };
    let rx = Val {
        inner: inner,
    };

    (tx, rx)
}

/*
 *
 * ===== Val =====
 *
 */

impl<T, E> Future for Val<T, E>
    where T: Send + 'static,
          E: Send + 'static,
{
    type Item = T;
    type Error = E;

    fn poll(&mut self, task: &mut Task) -> Poll<T, E> {
        self.inner.poll(task)
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

impl<T, E> Drop for Val<T, E> {
    fn drop(&mut self) {
        self.inner.cancel();
    }
}

/*
 *
 * ===== Complete =====
 *
 */

impl<T, E> Complete<T, E>
    where T: Send + 'static,
          E: Send + 'static,
{
    /// Successfully complete the associated `Val` with the given value.
    pub fn complete(self, val: T) {
        self.inner.complete(Some(Ok(val)), false);
    }

    /// Complete the associated `Val` with the given error
    pub fn error(self, err: E) {
        self.inner.complete(Some(Err(err)), false);
    }

    /// Abort the computation. This will cause the associated `Val` to panic on
    /// a call to `poll`.
    pub fn abort(self) {
        self.inner.complete(None, false);
    }

    /// Returns a `Future` representing the consuming end cancelling interest
    /// in the future.
    ///
    /// This function can only be called once.
    ///
    /// # Panics
    ///
    /// A second call to this function will result in a panic.
    pub fn cancellation(&self) -> Cancellation {
        if self.cancellation.get() {
            panic!("cancellation future already obtained");
        }

        self.cancellation.set(true);
        Cancellation { inner: self.inner.clone() }
    }
}

impl<T, E> Drop for Complete<T, E> {
    fn drop(&mut self) {
        self.inner.complete(None, true);
    }
}

/*
 *
 * ===== Cancellation =====
 *
 */

impl Future for Cancellation {
    type Item = bool;
    type Error = ();

    fn poll(&mut self, task: &mut Task) -> Poll<bool, ()> {
        self.inner.poll(task)
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

/*
 *
 * ===== Inner =====
 *
 */

impl<T, E> Inner<T, E> {
    /// Complete the future with the given result
    fn complete(&self, res: Option<Result<T, E>>, panic: bool) {
        let mut state = match self.state.lock() {
            Ok(s) => s,
            Err(_) => {
                if panic { panic!("failed to lock mutex") };
                return;
            }
        };

        let cb;

        match state.take() {
            Init { consumer, .. } => cb = consumer,
            s => {
                if res.is_some() {
                    panic!("attempting to complete already completed future");
                } else {
                    *state = s;
                    return;
                }
            }
        }

        *state = Completed(res);
        drop(state);

        if let Some(cb) = cb {
            cb.call_box(); // Invoke callback
        }
    }

    /// Cancel interest in the future
    fn cancel(&self) {
        let mut state = match self.state.lock() {
            Ok(s) => s,
            Err(_) => return,
        };

        let cb;

        match state.take() {
            Init { cancellation, .. } => cb = cancellation,
            Completed(_) | Cancelled | Consumed => {
                return; // Cannot cancel from these states
            }
        }

        *state = Cancelled;
        drop(state);

        if let Some(cb) = cb {
            cb.call_box(); // Invoke callback
        }
    }

    /// Poll the inner state for a value
    fn poll(&self, _: &mut Task) -> Poll<T, E> {
        let mut state = self.state.lock().unwrap();

        if state.is_complete() {
            match state.take() {
                Completed(Some(Ok(v))) => Poll::Ok(v),
                Completed(Some(Err(e))) => Poll::Err(e),
                Completed(None) => panic!("Complete dropped without producing a value"),
                Consumed => panic!("Val already consumed"),
                _ => unreachable!(),
            }
        } else {
            Poll::NotReady
        }
    }

    /// Associate completion with the given task
    fn schedule(&self, task: &mut Task) {
        let mut state = self.state.lock().unwrap();

        if state.in_flight() {
            let handle = task.handle().clone();
            state.set_consumer_cb(Box::new(move || handle.notify()));
        } else {
            task.handle().notify();
        }
    }
}

// A little hacky, but implementing Future on Inner allows losing the generics
// on Cancellation
trait SyncFuture: Send + Sync + 'static {
    fn poll(&self, task: &mut Task) -> Poll<bool, ()>;

    fn schedule(&self, task: &mut Task);
}

impl<T, E> SyncFuture for Inner<T, E>
    where T: Send + 'static,
          E: Send + 'static,
{
    fn poll(&self, _: &mut Task) -> Poll<bool, ()> {
        let state = self.state.lock().unwrap();

        match *state {
            Init { .. } => Poll::NotReady,
            Cancelled => Poll::Ok(true),
            _ => Poll::Ok(false),
        }
    }

    fn schedule(&self, task: &mut Task) {
        let mut state = self.state.lock().unwrap();

        if state.in_flight() {
            let handle = task.handle().clone();
            state.set_cancellation_cb(Box::new(move || handle.notify()));
        } else {
            task.handle().notify();
        }
    }
}

impl<T, E> State<T, E> {
    fn in_flight(&self) -> bool {
        match *self {
            Init { .. } => true,
            _ => false,
        }
    }

    /// Returns true if in a completed state.
    fn is_complete(&self) -> bool {
        match *self {
            Completed(_) | Consumed => true,
             _ => false,
        }
    }

    fn set_consumer_cb(&mut self, cb: Callback) {
        match *self {
            Init { ref mut consumer, .. } => *consumer = Some(cb),
            _ => panic!("unexpected state"),
        }
    }

    fn set_cancellation_cb(&mut self, cb: Callback) {
        match *self {
            Init { ref mut cancellation, .. } => *cancellation = Some(cb),
            _ => panic!("unexpected state"),
        }
    }

    /// Sets the current state to Consumed and returns the original value
    fn take(&mut self) -> State<T, E> {
        mem::replace(self, State::Consumed)
    }
}

trait FnBox: Send + 'static {
    fn call_box(self: Box<Self>);
}

impl<F> FnBox for F
    where F: FnOnce() + Send + 'static
{
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use futures::Future;
    use std::sync::mpsc;

    #[test]
    fn test_complete_after_listen() {
        let (c, val) = pair::<u32, ()>();
        let (tx, rx) = mpsc::channel();

        val.then(move |res| {
            tx.send(res.unwrap()).unwrap();
            res
        }).forget();

        c.complete(123);

        assert_eq!(123, rx.recv().unwrap());
    }

    #[test]
    fn test_complete_before_listen() {
        let (c, val) = pair::<u32, ()>();
        let (tx, rx) = mpsc::channel();

        c.complete(123);

        val.then(move |res| {
            tx.send(res.unwrap()).unwrap();
            res
        }).forget();

        assert_eq!(123, rx.recv().unwrap());
    }

    #[test]
    fn test_polling_aborted_future_panics() {
        use std::thread;

        let res = thread::spawn(|| {
            let (c, val) = pair::<u32, ()>();
            val.then(move |res| {
                println!("WAT: {:?}", res);
                res
            }).forget();

            c.abort();
        });

        assert!(res.join().is_err());
    }

    #[test]
    fn test_cancellation_future() {
        let (c, val) = pair::<u32, ()>();
        let (tx, rx) = mpsc::channel();

        c.cancellation().then(move |res| {
            tx.send(123).unwrap();
            res
        }).forget();

        assert!(rx.try_recv().is_err());

        drop(val);
        assert_eq!(123, rx.recv().unwrap());
    }
}
<commit_msg>Fix future::Val and panics<commit_after>//! A concrete implementation of `futures::Future`. It is similar in spirit as
//! `futures::Promise`, but is better suited for use with Tokio.

use futures::{Future, Poll, Task};
use std::mem;
use std::cell::Cell;
use std::sync::{Arc, Mutex};
use self::State::*;

/// A future representing the completion of an asynchronous computation.
///
/// This is created by the `pair` function.
pub struct Val<T, E> {
    inner: Arc<Inner<T, E>>,
}

/// The `Complete` half of `Val` used to send the result of an asynchronous
/// computation to the consumer of `Val`.
///
/// This is created by the `pair` function.
pub struct Complete<T, E> {
    inner: Arc<Inner<T, E>>,
    cancellation: Cell<bool>,
}

/// A future representing the cancellation in interest by the consumer of
/// `Val`.
///
/// If a `Val` is dropped without ever attempting to read the value, then it
/// becomes impossible to ever receive the result of the underlying
/// computation. This indicates that there is no interest in the computation
/// and it may be cancelled.
///
/// In this case, this future will be completed. The asynchronous computation
/// is able to listen for this completion and abort work early.
pub struct Cancellation {
    inner: Arc<SyncFuture>,
}

// Currently implemented with a mutex, but this is only to get something
// working. This should be rewritten to use a lock free strategy.
struct Inner<T, E> {
    state: Mutex<State<T, E>>,
}

enum State<T, E> {
    Init {
        consumer: Option<Callback>,
        cancellation: Option<Callback>
    },
    Completed(Option<Result<T, E>>),
    Cancelled,
    Consumed,
}

type Callback = Box<FnBox>;

/// Create and return a new `Complete` / `Val` pair.
///
/// `Complete` is used to send the result of an asynchronous computation to the
/// consumer of `Val`.
pub fn pair<T, E>() -> (Complete<T, E>, Val<T, E>) {
    let inner = Arc::new(Inner {
        state: Mutex::new(State::Init {
            consumer: None,
            cancellation: None,
        }),
    });

    let tx = Complete {
        inner: inner.clone(),
        cancellation: Cell::new(false),
    };
    let rx = Val {
        inner: inner,
    };

    (tx, rx)
}

/*
 *
 * ===== Val =====
 *
 */

impl<T, E> Future for Val<T, E>
    where T: Send + 'static,
          E: Send + 'static,
{
    type Item = T;
    type Error = E;

    fn poll(&mut self, task: &mut Task) -> Poll<T, E> {
        self.inner.poll(task)
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

impl<T, E> Drop for Val<T, E> {
    fn drop(&mut self) {
        self.inner.cancel();
    }
}

/*
 *
 * ===== Complete =====
 *
 */

impl<T, E> Complete<T, E>
    where T: Send + 'static,
          E: Send + 'static,
{
    /// Successfully complete the associated `Val` with the given value.
    pub fn complete(self, val: T) {
        self.inner.complete(Some(Ok(val)), true);
    }

    /// Complete the associated `Val` with the given error
    pub fn error(self, err: E) {
        self.inner.complete(Some(Err(err)), true);
    }

    /// Abort the computation. This will cause the associated `Val` to panic on
    /// a call to `poll`.
    pub fn abort(self) {
        self.inner.complete(None, true);
    }

    /// Returns a `Future` representing the consuming end cancelling interest
    /// in the future.
    ///
    /// This function can only be called once.
    ///
    /// # Panics
    ///
    /// A second call to this function will result in a panic.
    pub fn cancellation(&self) -> Cancellation {
        if self.cancellation.get() {
            panic!("cancellation future already obtained");
        }

        self.cancellation.set(true);
        Cancellation { inner: self.inner.clone() }
    }
}

impl<T, E> Drop for Complete<T, E> {
    fn drop(&mut self) {
        self.inner.complete(None, false);
    }
}

/*
 *
 * ===== Cancellation =====
 *
 */

impl Future for Cancellation {
    type Item = bool;
    type Error = ();

    fn poll(&mut self, task: &mut Task) -> Poll<bool, ()> {
        self.inner.poll(task)
    }

    fn schedule(&mut self, task: &mut Task) {
        self.inner.schedule(task)
    }
}

/*
 *
 * ===== Inner =====
 *
 */

impl<T, E> Inner<T, E> {
    /// Complete the future with the given result
    fn complete(&self, res: Option<Result<T, E>>, panic: bool) {
        let mut state = match self.state.lock() {
            Ok(s) => s,
            Err(_) => {
                if panic { panic!("failed to lock mutex") };
                return;
            }
        };

        let cb;

        match state.take() {
            Init { consumer, .. } => cb = consumer,
            s => {
                if res.is_some() {
                    panic!("attempting to complete already completed future");
                } else {
                    *state = s;
                    return;
                }
            }
        }

        *state = Completed(res);
        drop(state);

        if let Some(cb) = cb {
            cb.call_box(); // Invoke callback
        }
    }

    /// Cancel interest in the future
    fn cancel(&self) {
        let mut state = match self.state.lock() {
            Ok(s) => s,
            Err(_) => return,
        };

        let cb;

        match state.take() {
            Init { cancellation, .. } => cb = cancellation,
            Completed(_) | Cancelled | Consumed => {
                return; // Cannot cancel from these states
            }
        }

        *state = Cancelled;
        drop(state);

        if let Some(cb) = cb {
            cb.call_box(); // Invoke callback
        }
    }

    /// Poll the inner state for a value
    fn poll(&self, _: &mut Task) -> Poll<T, E> {
        let mut state = self.state.lock().unwrap();

        if state.is_complete() {
            match state.take() {
                Completed(Some(Ok(v))) => Poll::Ok(v),
                Completed(Some(Err(e))) => Poll::Err(e),
                Completed(None) => panic!("Complete dropped without producing a value"),
                Consumed => panic!("Val already consumed"),
                _ => unreachable!(),
            }
        } else {
            Poll::NotReady
        }
    }

    /// Associate completion with the given task
    fn schedule(&self, task: &mut Task) {
        let mut state = self.state.lock().unwrap();

        if state.in_flight() {
            let handle = task.handle().clone();
            state.set_consumer_cb(Box::new(move || handle.notify()));
        } else {
            task.handle().notify();
        }
    }
}

// A little hacky, but implementing Future on Inner allows losing the generics
// on Cancellation
trait SyncFuture: Send + Sync + 'static {
    fn poll(&self, task: &mut Task) -> Poll<bool, ()>;

    fn schedule(&self, task: &mut Task);
}

impl<T, E> SyncFuture for Inner<T, E>
    where T: Send + 'static,
          E: Send + 'static,
{
    fn poll(&self, _: &mut Task) -> Poll<bool, ()> {
        let state = self.state.lock().unwrap();

        match *state {
            Init { .. } => Poll::NotReady,
            Cancelled => Poll::Ok(true),
            _ => Poll::Ok(false),
        }
    }

    fn schedule(&self, task: &mut Task) {
        let mut state = self.state.lock().unwrap();

        if state.in_flight() {
            let handle = task.handle().clone();
            state.set_cancellation_cb(Box::new(move || handle.notify()));
        } else {
            task.handle().notify();
        }
    }
}

impl<T, E> State<T, E> {
    fn in_flight(&self) -> bool {
        match *self {
            Init { .. } => true,
            _ => false,
        }
    }

    /// Returns true if in a completed state.
    fn is_complete(&self) -> bool {
        match *self {
            Completed(_) | Consumed => true,
             _ => false,
        }
    }

    fn set_consumer_cb(&mut self, cb: Callback) {
        match *self {
            Init { ref mut consumer, .. } => *consumer = Some(cb),
            _ => panic!("unexpected state"),
        }
    }

    fn set_cancellation_cb(&mut self, cb: Callback) {
        match *self {
            Init { ref mut cancellation, .. } => *cancellation = Some(cb),
            _ => panic!("unexpected state"),
        }
    }

    /// Sets the current state to Consumed and returns the original value
    fn take(&mut self) -> State<T, E> {
        mem::replace(self, State::Consumed)
    }
}

trait FnBox: Send + 'static {
    fn call_box(self: Box<Self>);
}

impl<F> FnBox for F
    where F: FnOnce() + Send + 'static
{
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use futures::Future;
    use std::sync::mpsc;

    #[test]
    fn test_complete_after_listen() {
        let (c, val) = pair::<u32, ()>();
        let (tx, rx) = mpsc::channel();

        val.then(move |res| {
            tx.send(res.unwrap()).unwrap();
            res
        }).forget();

        c.complete(123);

        assert_eq!(123, rx.recv().unwrap());
    }

    #[test]
    fn test_complete_before_listen() {
        let (c, val) = pair::<u32, ()>();
        let (tx, rx) = mpsc::channel();

        c.complete(123);

        val.then(move |res| {
            tx.send(res.unwrap()).unwrap();
            res
        }).forget();

        assert_eq!(123, rx.recv().unwrap());
    }

    #[test]
    #[should_panic(expected = "Complete dropped without producing a value")]
    fn test_polling_aborted_future_panics() {
        let (c, val) = pair::<u32, ()>();
        val.then(move |res| {
            println!("WAT: {:?}", res);
            res
        }).forget();

        c.abort();
    }

    #[test]
    fn test_cancellation_future() {
        let (c, val) = pair::<u32, ()>();
        let (tx, rx) = mpsc::channel();

        c.cancellation().then(move |res| {
            tx.send(123).unwrap();
            res
        }).forget();

        assert!(rx.try_recv().is_err());

        drop(val);
        assert_eq!(123, rx.recv().unwrap());
    }
}
<|endoftext|>