<commit_before>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use model::{Color, FieldCoord, HexCoord};

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
    white_pieces: u32,
    black_pieces: u32,
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5],
            white_pieces: 18,
            black_pieces: 18,
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }

    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    pub fn get_available_moves(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            self.get_field_vertex_neighbors(field)
                .into_iter()
                .filter(|c| !self.is_piece_on_field(c))
                .collect()
        } else {
            vec![]
        }
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to)
            && self.get_field_vertex_neighbors(from).contains(to)
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert!(
            self.is_piece_on_field(coord),
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
        match coord.color() {
            Color::Black => self.black_pieces -= 1,
            Color::White => self.white_pieces -= 1,
        }
    }
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        self.try_hex(x, y)
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex != [Field::Empty; 6] {
                return false;
            },
            None => return false,
        }

        let has_neighbor = |f| self.get_hex_neighbor(coord, f).is_some();
        let is_adjacent = |f| has_neighbor((f + 1) % 6) || has_neighbor((f + 5) % 6);

        let mut neighbor_count = 0;
        for f in 0..6 {
            if has_neighbor(f) {
                if is_adjacent(f) {
                    neighbor_count += 1;
                } else {
                    return false;
                }
            }
        }

        match neighbor_count {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 | 2 | 3 => true,
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    fn try_hex(&self, x: i32, y: i32) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(x, y) {
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return true if the passed hex has not been removed yet.
    pub fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if let Some(hex) = self.try_hex(x, y) {
                    coords.push(hex);
                }
            }
        }
        coords
    }
    pub fn black_pieces(&self) -> u32 {
        self.black_pieces
    }
    pub fn white_pieces(&self) -> u32 {
        self.white_pieces
    }
}
<commit_msg>Shuffle Board methods<commit_after>/*
 * Copyright (C) 2017-2018 Ryan Huang
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

use model::{Color, FieldCoord, HexCoord};

pub struct Board {
    /*
                ____
               /    \
          ____/  +y  \____
         /    \      /    \
        /      \____/  +x  \
        \      /    \      /
         \____/      \____/
         /    \      /    \
        /  -x  \____/      \
        \      /    \      /
         \____/  -y  \____/
              \      /
               \____/

        The hex board uses an axial coordinate system with (0, 0) at the center. The x-axis slopes
        up to the right, and the y-axis goes up and down. The board is stored as a dense 2D array,
        because a ragged array won't work (since each row would have to be a different type).

        See http://www.redblobgames.com/grids/hexagons/#coordinates-axial for more info.
    */
    board: [[Option<Hex>; 5]; 5],
    white_pieces: u32,
    black_pieces: u32,
}

// Fields are numbered clockwise from the top. Even indicies are black, odd indicies are white.
type Hex = [Field; 6];

// There's no need to store the color of the piece on this field, since only white pieces can be on
// white fields, and vice versa.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Field {
    Piece,
    Empty,
}

impl Board {
    #[cfg_attr(rustfmt, rustfmt_skip)]
    /// Create a new board with the "Laurentius" starting position.
    pub fn new() -> Board {
        let mut board = Board {
            board: [[None; 5]; 5],
            white_pieces: 18,
            black_pieces: 18,
        };

        // (0, 0) is the only empty hex.
        board.set_hex(&HexCoord::new(0, 0), Some([Field::Empty; 6]));

        // All other hexes have exactly two pieces on them in the starting position.
        let piece_locations = [
            (-2,  2, 0, 4),
            (-2,  1, 0, 3),
            (-2,  0, 3, 5),
            (-1,  2, 1, 4),
            (-1,  1, 0, 4),
            (-1,  0, 3, 5),
            (-1, -1, 2, 5),
            ( 0,  2, 1, 5),
            ( 0,  1, 1, 5),
            ( 0, -1, 2, 4),
            ( 0, -2, 2, 4),
            ( 1,  1, 2, 5),
            ( 1,  0, 0, 2),
            ( 1, -1, 1, 3),
            ( 1, -2, 1, 4),
            ( 2,  0, 0, 2),
            ( 2, -1, 0, 3),
            ( 2, -2, 1, 3),
        ];

        for &(x, y, f1, f2) in &piece_locations {
            let mut hex = [Field::Empty; 6];
            hex[f1] = Field::Piece;
            hex[f2] = Field::Piece;
            board.set_hex(&HexCoord::new(x, y), Some(hex));
        }

        board
    }
    pub fn move_piece(&mut self, from: &FieldCoord, to: &FieldCoord) {
        assert!(
            self.can_move_piece(from, to),
            "Can't move {:?} at {:?} to {:?} at {:?}. These fields {} vertex neighbors.",
            self.get_field(from),
            from,
            self.get_field(to),
            to,
            if self.get_field_vertex_neighbors(from).contains(to) {
                "ARE"
            } else {
                "ARE NOT"
            },
        );

        self.set_field(from, Field::Empty);
        self.set_field(to, Field::Piece);
    }
    pub fn can_move_piece(&self, from: &FieldCoord, to: &FieldCoord) -> bool {
        self.is_piece_on_field(from) && !self.is_piece_on_field(to)
            && self.get_field_vertex_neighbors(from).contains(to)
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return true if the passed hex has not been removed yet.
    pub fn is_hex_extant(&self, coord: &HexCoord) -> bool {
        self.get_hex(coord).is_some()
    }
    /// > extant (adj.): Still in existence; not destroyed, lost, or extinct (The Free Dictionary)
    ///
    /// Return the coordinates of the hexes that have not been removed yet.
    pub fn extant_hexes(&self) -> Vec<HexCoord> {
        let mut coords = vec![];

        for x in -2..3 {
            for y in -2..3 {
                if let Some(hex) = self.try_hex(x, y) {
                    coords.push(hex);
                }
            }
        }
        coords
    }
    pub fn black_pieces(&self) -> u32 {
        self.black_pieces
    }
    pub fn white_pieces(&self) -> u32 {
        self.white_pieces
    }
}

// Field and piece methods
impl Board {
    fn get_field(&self, coord: &FieldCoord) -> &Field {
        match *self.get_hex(&coord.to_hex()) {
            Some(ref hex) => &hex[coord.f as usize],
            None => panic!(
                "Cannot get field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    fn set_field(&mut self, coord: &FieldCoord, field: Field) {
        match *self.get_hex(&coord.to_hex()) {
            Some(mut hex) => {
                hex[coord.f as usize] = field;
                self.set_hex(&coord.to_hex(), Some(hex));
            }
            None => panic!(
                "Cannot set field {} on removed hex at {:?}",
                coord.f,
                coord.to_hex()
            ),
        }
    }
    /// Return fields that share an edge with the given field. These fields are always the opposite
    /// color of the given field. If all of a piece's edge neighbors are occupied, that piece might
    /// be capturable.
    pub fn get_field_edge_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        let mut neighbors = vec![
            // There are always two edge neighbors on the same hex as the given field
            FieldCoord::new(coord.x, coord.y, (coord.f + 1) % 6),
            FieldCoord::new(coord.x, coord.y, (coord.f + 5) % 6),
        ];

        if let Some(hex) = self.get_hex_neighbor(&coord.to_hex(), coord.f) {
            neighbors.push(hex.to_field((coord.f + 3) % 6));
        }

        neighbors
    }
    /// Return fields that share a vertex with the given field and have the same color as the given
    /// field. Pieces can move to fields that are vertex neighbors of the field they are on.
    pub fn get_field_vertex_neighbors(&self, coord: &FieldCoord) -> Vec<FieldCoord> {
        // A field's vertex neighbors can be defined as the edge neighbors of its edge neighbors
        let mut neighbors = vec![];
        for field in self.get_field_edge_neighbors(coord) {
            neighbors.append(&mut self.get_field_edge_neighbors(&field));
        }
        // A field is not its own neighbor
        neighbors.into_iter().filter(|n| n != coord).collect()
    }
    pub fn is_piece_on_field(&self, coord: &FieldCoord) -> bool {
        self.get_field(coord) == &Field::Piece
    }
    pub fn get_available_moves(&self, field: &FieldCoord) -> Vec<FieldCoord> {
        if self.is_piece_on_field(field) {
            self.get_field_vertex_neighbors(field)
                .into_iter()
                .filter(|c| !self.is_piece_on_field(c))
                .collect()
        } else {
            vec![]
        }
    }
    pub fn remove_piece(&mut self, coord: &FieldCoord) {
        assert!(
            self.is_piece_on_field(coord),
            "There is no piece at {:?} to remove",
            coord
        );
        self.set_field(coord, Field::Empty);
        match coord.color() {
            Color::Black => self.black_pieces -= 1,
            Color::White => self.white_pieces -= 1,
        }
    }
}

// Hex methods
impl Board {
    fn get_hex(&self, coord: &HexCoord) -> &Option<Hex> {
        &self.board[(coord.x + 2) as usize][(coord.y + 2) as usize]
    }
    fn set_hex(&mut self, coord: &HexCoord, hex: Option<Hex>) {
        self.board[(coord.x + 2) as usize][(coord.y + 2) as usize] = hex;
    }
    pub fn get_hex_neighbor(&self, coord: &HexCoord, direction: u32) -> Option<HexCoord> {
        assert!(direction < 6);

        let neighbors = [
            (coord.x, coord.y + 1),
            (coord.x + 1, coord.y),
            (coord.x + 1, coord.y - 1),
            (coord.x, coord.y - 1),
            (coord.x - 1, coord.y),
            (coord.x - 1, coord.y + 1),
        ];

        let (x, y) = neighbors[direction as usize];
        self.try_hex(x, y)
    }
    /// A hex is removable (and must be removed) if it is empty and is "attached to the board by 3
    /// or less adjacent sides."
    pub fn is_hex_removable(&self, coord: &HexCoord) -> bool {
        match *self.get_hex(coord) {
            Some(hex) => if hex != [Field::Empty; 6] {
                return false;
            },
            None => return false,
        }

        let has_neighbor = |f| self.get_hex_neighbor(coord, f).is_some();
        let is_adjacent = |f| has_neighbor((f + 1) % 6) || has_neighbor((f + 5) % 6);

        let mut neighbor_count = 0;
        for f in 0..6 {
            if has_neighbor(f) {
                if is_adjacent(f) {
                    neighbor_count += 1;
                } else {
                    return false;
                }
            }
        }

        match neighbor_count {
            0 => panic!("A hex at {:?} is empty and has no neighbors", coord),
            1 | 2 | 3 => true,
            _ => false,
        }
    }
    pub fn remove_hex(&mut self, coord: &HexCoord) {
        assert!(
            self.is_hex_removable(coord),
            "Cannot remove the hex at {:?} which is {:?} and has {} neighbors",
            coord,
            self.get_hex(coord),
            [0, 1, 2, 3, 4, 5]
                .into_iter()
                .filter(|&&f| self.get_hex_neighbor(coord, f).is_some())
                .collect::<Vec<_>>()
                .len(),
        );
        self.set_hex(coord, None);
    }
    fn try_hex(&self, x: i32, y: i32) -> Option<HexCoord> {
        if let Some(coord) = HexCoord::try_new(x, y) {
            if self.is_hex_extant(&coord) {
                return Some(coord);
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt;

use ansi_term::{Color, Style};

/// Holds information about how to style a module
pub struct ModuleStyle {
    pub background: Color,
    pub foreground: Color,
    /// Attributes like bold, italicized, underlined, etc...
    pub text_properties: Vec<Style>,
}

/// Attempts to convert a string into an `ansi_term::Color`.
///
/// Returns a `FromStringError` if the provided string doesn't match
/// any of the colors defined in crate `ansi_term`.
pub fn try_color_from_str(s: &str) -> Result<Color, FromStringError> {
    match s {
        "black" => Ok(Color::Black),
        "red" => Ok(Color::Red),
        "green" => Ok(Color::Green),
        "yellow" => Ok(Color::Yellow),
        "blue" => Ok(Color::Blue),
        "purple" => Ok(Color::Purple),
        "cyan" => Ok(Color::Cyan),
        "white" => Ok(Color::White),
        _ => Err(FromStringError),
    }
}

#[derive(Debug, PartialEq)]
/// Error type for when converting a string fails
pub struct FromStringError;

impl fmt::Display for FromStringError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl Error for FromStringError {
    fn description(&self) -> &str {
        "unrecognized input"
    }
}

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

    #[test]
    fn test_color_try_from_str() {
        assert_eq!(try_color_from_str("blue"), Ok(Color::Blue));
        assert_eq!(try_color_from_str("teal"), Err(FromStringError));
    }
}
<commit_msg>refactor: rename FromStringError to TryFromError<commit_after>use std::error::Error;
use std::fmt;

use ansi_term::{Color, Style};

/// Holds information about how to style a module
pub struct ModuleStyle {
    pub background: Color,
    pub foreground: Color,
    /// Attributes like bold, italicized, underlined, etc...
    pub text_properties: Vec<Style>,
}

/// Attempts to convert a string into an `ansi_term::Color`.
///
/// Returns a `TryFromError` if the provided string doesn't match
/// any of the colors defined in crate `ansi_term`.
pub fn try_color_from_str(s: &str) -> Result<Color, TryFromError> {
    match s {
        "black" => Ok(Color::Black),
        "red" => Ok(Color::Red),
        "green" => Ok(Color::Green),
        "yellow" => Ok(Color::Yellow),
        "blue" => Ok(Color::Blue),
        "purple" => Ok(Color::Purple),
        "cyan" => Ok(Color::Cyan),
        "white" => Ok(Color::White),
        _ => Err(TryFromError),
    }
}

#[derive(Debug, PartialEq)]
/// Error type for when converting a string fails
pub struct TryFromError;

impl fmt::Display for TryFromError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl Error for TryFromError {
    fn description(&self) -> &str {
        "unrecognized input"
    }
}

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

    #[test]
    fn test_color_try_from_str() {
        assert_eq!(try_color_from_str("blue"), Ok(Color::Blue));
        assert_eq!(try_color_from_str("teal"), Err(TryFromError));
    }
}
<|endoftext|>


<commit_before>//! Support for patterns of arbitrary element types.
use std;

mod walk;
use self::walk::{action,Action,Walkable,Walker};

/// An iterator that produces its input item exactly once.
struct Once<'a,T: 'a>(Option<&'a T>);

impl<'a,T> Once<'a,T> {
    fn new(obj: &'a T) -> Once<'a,T> {
        Once(Some(obj))
    }
}

impl<'a,T> Iterator for Once<'a,T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        let out = self.0;
        self.0 = None;
        out
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        match self.0 {
            Some(..) => (1, Some(1)),
            None => (0, Some(0))
        }
    }
}

/// A pattern's first set is the set of elements that may begin a sequence
/// matching that pattern.
trait FirstSet: MarkerTrait {}
/// The atomic first set is like the first set above, but yields only the
/// atomic values within the set.
trait AtomicFirstSet: MarkerTrait {}
pub type ElementIterator<'a,T> = Box<Iterator<Item=&'a Element<T>> + 'a>;
pub type AtomicIterator<'a,T> = Box<Iterator<Item=&'a T> + 'a>;

/// Provides a method to determine whether a pattern is "nullable", i.e., can
/// match an empty sequence.
pub trait Nullable {
    /// Check if the token is nullable.
    fn is_nullable(&self) -> bool { false }
}

/// A component in a pattern.  Each element is either an atomic value, or
/// a Pattern trait object.
pub enum Element<T> {
    Atom(T),
    Pattern(Box<Pattern<T>>)
}

/// Interface for descriptions of syntactic patterns.
pub trait Pattern<T>: Walkable<PatternWalk::FirstSet,Element> + Walkable<PatternWalk::AtomicFirstSet,T> + Nullable {}

impl<'a,T> Nullable for Element<T> {
    fn is_nullable(&self) -> bool {
        match *self {
            Element::Atom(..) => false,
            Element::Pattern(ref pat) => pat.is_nullable(),
        }
    }
}

/// A sequence of atoms or subpatterns.
struct Sequence<T> {
    elements: Vec<Element<T>>
}

impl<'a,T: 'a> Walkable<AtomicFirstSet,&'a T> for Sequence<T> {
    type BaseIterator = std::slice::Iter<'a,Element<T>>;

    #[inline(always)]
    fn iter(&self) -> <Self as Walkable<AtomicFirstSet,&T>>::BaseIterator { self.elements.iter() }

    fn action<'b>(&self, element: &'b Element<T>) -> (Option<&T>, u8) {
        match *element {
            Element::Atom(..) =>
                Action{yield_value: Some(element),
                       recurse_on: None,
                       flags: action::TERMINATE},
            Element::Pattern(ref pat) =>
                Action{yield_value: None,
                       recurse_on: Some(element),
                       flags: if pat.is_nullable() { 0 } else { action::TERMINATE }}
        }
    }
}

impl<'a,T: 'a> Walkable<FirstSet,&'a Element<T>> for Sequence<T> {
    type BaseIterator = std::slice::Iter<'a,Element<T>>;

    #[inline(always)]
    fn iter(&self) -> <Self as Walkable<FirstSet,&Element<T>>>::BaseIterator { self.elements.iter() }

    #[inline(always)]
    fn action<'b>(&self, element: &'b Element<T>) -> (Option<&Element<T>>, u8) {
        match *element {
            Element::Atom(..) =>
                Action{yield_value: Some(element),
                       recurse_on: None,
                       flags: action::TERMINATE},
            Element::Pattern(ref pat) =>
                Action{yield_value: Some(element),
                       recurse_on: Some(element),
                       flags: if pat.is_nullable() { 0 } else { action::TERMINATE }}
        }
    }
}

impl<T> Nullable for Sequence<T> {
    fn is_nullable(&self) -> bool {
        if self.elements.is_empty() { true }
        else {
            for elt in self.elements.iter() {
                match *elt {
                    Element::Atom(..) => return false,
                    Element::Pattern(pat) => if ! pat.is_nullable() { return false; }
                }
            }
            true
        }
    }
}
<commit_msg>pattern: remove unused iterator type definitions<commit_after>//! Support for patterns of arbitrary element types.
use std;

mod walk;
use self::walk::{action,Action,Walkable,Walker};

/// An iterator that produces its input item exactly once.
struct Once<'a,T: 'a>(Option<&'a T>);

impl<'a,T> Once<'a,T> {
    fn new(obj: &'a T) -> Once<'a,T> {
        Once(Some(obj))
    }
}

impl<'a,T> Iterator for Once<'a,T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        let out = self.0;
        self.0 = None;
        out
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        match self.0 {
            Some(..) => (1, Some(1)),
            None => (0, Some(0))
        }
    }
}

/// A pattern's first set is the set of elements that may begin a sequence
/// matching that pattern.
trait FirstSet: MarkerTrait {}
/// The atomic first set is like the first set above, but yields only the
/// atomic values within the set.
trait AtomicFirstSet: MarkerTrait {}

/// Provides a method to determine whether a pattern is "nullable", i.e., can
/// match an empty sequence.
pub trait Nullable {
    /// Check if the token is nullable.
    fn is_nullable(&self) -> bool { false }
}

/// A component in a pattern.  Each element is either an atomic value, or
/// a Pattern trait object.
pub enum Element<T> {
    Atom(T),
    Pattern(Box<Pattern<T>>)
}

/// Interface for descriptions of syntactic patterns.
pub trait Pattern<T>: Walkable<PatternWalk::FirstSet,Element> + Walkable<PatternWalk::AtomicFirstSet,T> + Nullable {}

impl<'a,T> Nullable for Element<T> {
    fn is_nullable(&self) -> bool {
        match *self {
            Element::Atom(..) => false,
            Element::Pattern(ref pat) => pat.is_nullable(),
        }
    }
}

/// A sequence of atoms or subpatterns.
struct Sequence<T> {
    elements: Vec<Element<T>>
}

impl<'a,T: 'a> Walkable<AtomicFirstSet,&'a T> for Sequence<T> {
    type BaseIterator = std::slice::Iter<'a,Element<T>>;

    #[inline(always)]
    fn iter(&self) -> <Self as Walkable<AtomicFirstSet,&T>>::BaseIterator { self.elements.iter() }

    fn action<'b>(&self, element: &'b Element<T>) -> (Option<&T>, u8) {
        match *element {
            Element::Atom(..) =>
                Action{yield_value: Some(element),
                       recurse_on: None,
                       flags: action::TERMINATE},
            Element::Pattern(ref pat) =>
                Action{yield_value: None,
                       recurse_on: Some(element),
                       flags: if pat.is_nullable() { 0 } else { action::TERMINATE }}
        }
    }
}

impl<'a,T: 'a> Walkable<FirstSet,&'a Element<T>> for Sequence<T> {
    type BaseIterator = std::slice::Iter<'a,Element<T>>;

    #[inline(always)]
    fn iter(&self) -> <Self as Walkable<FirstSet,&Element<T>>>::BaseIterator { self.elements.iter() }

    #[inline(always)]
    fn action<'b>(&self, element: &'b Element<T>) -> (Option<&Element<T>>, u8) {
        match *element {
            Element::Atom(..) =>
                Action{yield_value: Some(element),
                       recurse_on: None,
                       flags: action::TERMINATE},
            Element::Pattern(ref pat) =>
                Action{yield_value: Some(element),
                       recurse_on: Some(element),
                       flags: if pat.is_nullable() { 0 } else { action::TERMINATE }}
        }
    }
}

impl<T> Nullable for Sequence<T> {
    fn is_nullable(&self) -> bool {
        if self.elements.is_empty() { true }
        else {
            for elt in self.elements.iter() {
                match *elt {
                    Element::Atom(..) => return false,
                    Element::Pattern(pat) => if ! pat.is_nullable() { return false; }
                }
            }
            true
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use ffi_helpers::Ffi__Array;
use host::Host;
use host::ffi::Ffi__Host;
use libc::{c_char, uint8_t};
use std::convert;
use std::ffi::CString;
use std::panic::catch_unwind;
use std::path::PathBuf;
use super::*;

#[repr(C)]
pub struct Ffi__Payload {
    path: *const c_char,
    artifact: *const c_char,
    language: Language,
}

impl convert::From<Payload> for Ffi__Payload {
    fn from(payload: Payload) -> Ffi__Payload {
        Ffi__Payload {
            path: CString::new(payload.path.to_str().unwrap()).unwrap().into_raw(),
            artifact: CString::new(payload.artifact).unwrap().into_raw(),
            language: payload.language,
        }
    }
}

impl convert::Into<Payload> for Ffi__Payload {
    fn into(self) -> Payload {
        let path: String = trypanic!(ptrtostr!(self.path, "path string")).into();

        Payload {
            path: PathBuf::from(&path),
            artifact: trypanic!(ptrtostr!(self.artifact, "artifact string")).into(),
            language: self.language,
        }
    }
}

pub extern "C" fn payload_new(payload_artifact_ptr: *const c_char) -> *mut Ffi__Payload {
    let payload_artifact = trynull!(ptrtostr!(payload_artifact_ptr, "payload::artifact string"));
    let payload = trynull!(Payload::new(&payload_artifact));
    let ffi_payload: Ffi__Payload = trynull!(catch_unwind(|| payload.into()));
    Box::into_raw(Box::new(ffi_payload))
}

pub extern "C" fn payload_build(ffi_payload_ptr: *mut Ffi__Payload) -> uint8_t {
    let payload: Payload = tryrc!(readptr!(ffi_payload_ptr, "Payload struct"));
    tryrc!(payload.build());
    0
}

pub extern "C" fn payload_run(ffi_payload_ptr: *mut Ffi__Payload, ffi_host_ptr: *mut Ffi__Host, ffi_user_args: *mut Ffi__Array<*const c_char>) -> uint8_t {
    let payload: Payload = tryrc!(readptr!(ffi_payload_ptr, "Payload struct"));
    let mut host: Host = tryrc!(readptr!(ffi_host_ptr, "Host struct"));

    let user_args = if ffi_user_args.is_null() {
        None
    } else {
        let a: Vec<_> = tryrc!(readptr!(ffi_user_args, "User args array"));
        let mut b = Vec::new();
        for ptr in a {
            b.push(tryrc!(ptrtostr!(ptr, "User arg string")));
        }
        Some(b)
    };

    tryrc!(payload.run(&mut host, user_args));
    0
}

#[cfg(test)]
mod tests {
    use host::Host;
    use host::ffi::Ffi__Host;
    use payload::config::Config;
    use payload::Language;
    use std::ffi::CString;
    use std::{fs, ptr};
    use super::*;
    use tempdir::TempDir;
    use zdaemon::ConfigFile;

    #[test]
    fn test_new() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_ffi_new").unwrap();
        let mut buf = tempdir.path().to_owned();

        buf.push("bootstrap.php");
        fs::File::create(&buf).expect("Failed to create bootstrap.php");
        buf.pop();

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Php,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload_artifact = CString::new(buf.to_str().unwrap()).unwrap();
        assert!(!payload_new(payload_artifact.as_ptr()).is_null());
    }

    #[test]
    fn test_build() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_ffi_build").unwrap();

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Php,
            dependencies: None,
        };

        let mut buf = tempdir.path().to_owned();
        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload_artifact = CString::new(buf.to_str().unwrap()).unwrap();
        let payload_ptr = payload_new(payload_artifact.as_ptr());
        assert!(!payload_ptr.is_null());
        assert_eq!(payload_build(payload_ptr), 0);
    }

    #[test]
    fn test_run() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_run").unwrap();
        let mut buf = tempdir.path().to_owned();

        buf.push("default.php");
        fs::File::create(&buf).expect("Failed to create default.php");
        buf.pop();

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Php,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload_artifact = CString::new(buf.to_str().unwrap()).unwrap();
        let payload_ptr = payload_new(payload_artifact.as_ptr());
        assert!(!payload_ptr.is_null());

        let mut host = Ffi__Host::from(Host::test_new(None, None, None, None));
        assert_eq!(payload_run(payload_ptr, &mut host, ptr::null_mut()), 0);
    }
}
<commit_msg>Fix array handling logic<commit_after>// Copyright 2015-2016 Intecture Developers. See the COPYRIGHT file at the
// top-level directory of this distribution and at
// https://intecture.io/COPYRIGHT.
//
// Licensed under the Mozilla Public License 2.0 <LICENSE or
// https://www.tldrlegal.com/l/mpl-2.0>. This file may not be copied,
// modified, or distributed except according to those terms.

use ffi_helpers::Ffi__Array;
use host::Host;
use host::ffi::Ffi__Host;
use libc::{c_char, size_t, uint8_t};
use std::convert;
use std::ffi::CString;
use std::panic::catch_unwind;
use std::path::PathBuf;
use super::*;

#[repr(C)]
pub struct Ffi__Payload {
    path: *const c_char,
    artifact: *const c_char,
    language: Language,
}

impl convert::From<Payload> for Ffi__Payload {
    fn from(payload: Payload) -> Ffi__Payload {
        Ffi__Payload {
            path: CString::new(payload.path.to_str().unwrap()).unwrap().into_raw(),
            artifact: CString::new(payload.artifact).unwrap().into_raw(),
            language: payload.language,
        }
    }
}

impl convert::Into<Payload> for Ffi__Payload {
    fn into(self) -> Payload {
        let path: String = trypanic!(ptrtostr!(self.path, "path string")).into();

        Payload {
            path: PathBuf::from(&path),
            artifact: trypanic!(ptrtostr!(self.artifact, "artifact string")).into(),
            language: self.language,
        }
    }
}

pub extern "C" fn payload_new(payload_artifact_ptr: *const c_char) -> *mut Ffi__Payload {
    let payload_artifact = trynull!(ptrtostr!(payload_artifact_ptr, "payload::artifact string"));
    let payload = trynull!(Payload::new(&payload_artifact));
    let ffi_payload: Ffi__Payload = trynull!(catch_unwind(|| payload.into()));
    Box::into_raw(Box::new(ffi_payload))
}

pub extern "C" fn payload_build(ffi_payload_ptr: *mut Ffi__Payload) -> uint8_t {
    let payload: Payload = tryrc!(readptr!(ffi_payload_ptr, "Payload struct"));
    tryrc!(payload.build());
    0
}

pub extern "C" fn payload_run(ffi_payload_ptr: *mut Ffi__Payload,
                              ffi_host_ptr: *mut Ffi__Host,
                              ffi_user_args: *mut *const c_char,
                              ffi_user_args_len: size_t) -> uint8_t {
    let payload: Payload = tryrc!(readptr!(ffi_payload_ptr, "Payload struct"));
    let mut host: Host = tryrc!(readptr!(ffi_host_ptr, "Host struct"));

    let user_args = if ffi_user_args.is_null() {
        None
    } else {
        let a: Vec<_> = tryrc!(catch_unwind(|| Ffi__Array {
            ptr: ffi_user_args,
            length: ffi_user_args_len,
            capacity: ffi_user_args_len,
        }.into()));
        let mut b = Vec::new();
        for ptr in a {
            b.push(tryrc!(ptrtostr!(ptr, "User arg string")));
        }
        Some(b)
    };

    tryrc!(payload.run(&mut host, user_args));
    0
}

#[cfg(test)]
mod tests {
    use host::Host;
    use host::ffi::Ffi__Host;
    use payload::config::Config;
    use payload::Language;
    use std::ffi::CString;
    use std::{fs, ptr};
    use super::*;
    use tempdir::TempDir;
    use zdaemon::ConfigFile;

    #[test]
    fn test_new() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_ffi_new").unwrap();
        let mut buf = tempdir.path().to_owned();

        buf.push("bootstrap.php");
        fs::File::create(&buf).expect("Failed to create bootstrap.php");
        buf.pop();

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Php,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload_artifact = CString::new(buf.to_str().unwrap()).unwrap();
        assert!(!payload_new(payload_artifact.as_ptr()).is_null());
    }

    #[test]
    fn test_build() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_ffi_build").unwrap();

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Php,
            dependencies: None,
        };

        let mut buf = tempdir.path().to_owned();
        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload_artifact = CString::new(buf.to_str().unwrap()).unwrap();
        let payload_ptr = payload_new(payload_artifact.as_ptr());
        assert!(!payload_ptr.is_null());
        assert_eq!(payload_build(payload_ptr), 0);
    }

    #[test]
    fn test_run() {
        let _ = ::_MOCK_ENV.init();

        let tempdir = TempDir::new("test_payload_run").unwrap();
        let mut buf = tempdir.path().to_owned();

        buf.push("default.php");
        fs::File::create(&buf).expect("Failed to create default.php");
        buf.pop();

        let conf = Config {
            author: "Dr. Hibbert".into(),
            repository: "https://github.com/dhibbz/hehehe.git".into(),
            language: Language::Php,
            dependencies: None,
        };

        buf.push("payload.json");
        conf.save(&buf).unwrap();
        buf.pop();

        let payload_artifact = CString::new(buf.to_str().unwrap()).unwrap();
        let payload_ptr = payload_new(payload_artifact.as_ptr());
        assert!(!payload_ptr.is_null());

        let mut host = Ffi__Host::from(Host::test_new(None, None, None, None));
        assert_eq!(payload_run(payload_ptr, &mut host, &mut ptr::null(), 0), 0);
    }
}
<|endoftext|>


<commit_before>// See the LICENSE file at the top-level directory of this distribution
// for information about copyright and licensing of this code.

use std::ops::Rem;

extern crate num;
use self::num::Zero;

/// Returns greatest common divisor of 2 given numbers.
///
/// # Examples
///
/// ```rust
/// # use red_orange::numeric::gcd;
///
/// assert_eq!(1, gcd(1, 1));
///
/// assert_eq!(1, gcd(2, 1));
/// assert_eq!(1, gcd(1, 2));
///
/// assert_eq!(2, gcd(2, 2));
///
/// assert_eq!(3, gcd(6, 9));
/// assert_eq!(3, gcd(9, 6));
///
/// assert_eq!(21, gcd(252, 105));
/// assert_eq!(21, gcd(105, 252));
/// ```
pub fn gcd<T: Copy + Zero + PartialOrd + Rem<Output=T>>(a : T, b : T) -> T
{
   assert!(a > T::zero());
   assert!(b > T::zero());

   let mut aa = a;
   let mut bb = b;

   while bb > T::zero() {
      let t = bb;
      bb = aa % bb;
      aa = t;
   }

   aa
}
<commit_msg>shorten gcd code, pass by mutable value<commit_after>// See the LICENSE file at the top-level directory of this distribution
// for information about copyright and licensing of this code.

use std::ops::Rem;

extern crate num;
use self::num::Zero;

/// Returns greatest common divisor of 2 given numbers.
///
/// # Examples
///
/// ```rust
/// # use red_orange::numeric::gcd;
///
/// assert_eq!(1, gcd(1, 1));
///
/// assert_eq!(1, gcd(2, 1));
/// assert_eq!(1, gcd(1, 2));
///
/// assert_eq!(2, gcd(2, 2));
///
/// assert_eq!(3, gcd(6, 9));
/// assert_eq!(3, gcd(9, 6));
///
/// assert_eq!(21, gcd(252, 105));
/// assert_eq!(21, gcd(105, 252));
/// ```
pub fn gcd<T: Copy + Zero + PartialOrd + Rem<Output=T>>(mut a : T, mut b : T) -> T
{
   assert!(a > T::zero());
   assert!(b > T::zero());

   while b > T::zero() {
      let t = b;
      b = a % b;
      a = t;
   }

   a
}
<|endoftext|>


<commit_before>use entities::{ EntitiesState, EntitiesHelper, EntityID, ComponentID, NativeComponentType };
use std::collections::{ HashSet, HashMap };
use std::cell::RefCell;
use std::rc::Rc;
use nalgebra::na;
use nalgebra::na::{ Norm, Translation, Vec2, Vec3 };
use ncollide::geom::geom::Geom;
use nphysics::world::World;
use nphysics::object::{ RigidBody };
use log;

pub struct PhysicsSystem {
    world: World,
    bodies: HashMap<EntityID, Rc<RefCell<RigidBody>>>,
}

impl PhysicsSystem {
    pub fn new(_: &EntitiesState, log: |log::LogRecord|)
        -> PhysicsSystem
    {
        let mut world = World::new();
        world.set_gravity(Vec2::new(1.0f32, 1.0));

        let shape = ::ncollide::geom::Plane::new(Vec2::new(0.0f32, 1.0));
        let body = Rc::new(RefCell::new(RigidBody::new_static(shape, 0.3, 0.6)));
        world.add_body(body);

        PhysicsSystem {
            world: world,
            bodies: HashMap::new()
        }
    }

    pub fn process(&mut self, state: &mut EntitiesState, elapsed: &f64, log: |log::LogRecord|)
    {
        // getting the list of all entities that have physics activated
        let listOfEntities: HashSet<EntityID> = state.get_components_iter()
            .filter(|c| state.is_component_visible(*c).unwrap())
            .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "physics", _ => false })
            .filter(|c| match state.get_as_boolean(*c, "activated") { Some(b) => b, _ => false })
            .map(|c| state.get_owner(c).unwrap())
            .collect();

        // removing from the world the elements that have disappeared
        {
            let toRemove: Vec<EntityID> = self.bodies.keys().filter(|e| !listOfEntities.contains(e.clone())).map(|e| e.clone()).collect();
            for e in toRemove.move_iter() {
                //self.bodies.find(&e).     // TODO: remove body from the world
                self.bodies.remove(&e);
            }
        }

        // adding elements that are not yet in the world
        {
            let toCreate: Vec<EntityID> = listOfEntities.iter().filter(|e| !self.bodies.contains_key(e.clone())).map(|e| e.clone()).collect();
            for e in toCreate.move_iter() {
                let shape = ::ncollide::geom::Cuboid::new(Vec2::new(0.5f32, 0.5f32));
                let body = Rc::new(RefCell::new(RigidBody::new_dynamic(shape, 1.0, 0.5, 0.0)));

                // initializing body with current position and movement
                body.borrow_mut().set_translation({ let p = PhysicsSystem::get_entity_position(state, &e); na::Vec2::new(p.x,p.y) });
                body.borrow_mut().set_lin_vel({ let p = PhysicsSystem::get_entity_movement(state, &e); na::Vec2::new(p.x,p.y) });

                self.bodies.insert(e.clone(), body.clone());
                self.world.add_body(body.clone());
            }
        }

        // setting all positions and movements
        for (entity, body) in self.bodies.iter() {
            let position = { let p = PhysicsSystem::get_entity_position(state, entity); na::Vec2::new(p.x,p.y) };
            let movement = { let p = PhysicsSystem::get_entity_movement(state, entity); na::Vec2::new(p.x,p.y) };
            let requestedMovement = PhysicsSystem::get_requested_movement(state, entity);

            let mut borrowedBody = body.borrow_mut();
            borrowedBody.set_translation(position);
            borrowedBody.set_lin_vel(movement);

            if requestedMovement.is_some() && requestedMovement != Some(movement) {
                let acceleration = na::normalize(&(requestedMovement.unwrap() - movement)) * 5.0f32;
                borrowedBody.set_lin_acc_scale(acceleration);
            }
        }

        // step
        self.world.step(*elapsed as f32);

        //
        for (entity, body) in self.bodies.iter() {
            PhysicsSystem::set_position(state, entity, &body.borrow().translation());
            PhysicsSystem::set_movement(state, entity, &body.borrow().lin_vel());
        }
    }

    /// returns the position of an entity
    pub fn get_entity_position(state: &EntitiesState, id: &EntityID)
        -> na::Vec3<f32>
    {
        state
            .get_visible_native_components("position")
            .move_iter()

            // take only the components owned by the entity
            .filter(|c| state.get_owner(c).unwrap() == *id)

            // build a vector from each of the component
            .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
                (Some(x), Some(y), Some(z))
                    => Some(na::Vec3::new(x as f32, y as f32, z as f32)),
                (Some(x), Some(y), _)
                    => Some(na::Vec3::new(x as f32, y as f32, 0.0)),
                _ => None
            })

            // add all the elements together
            .fold(na::Vec3::new(0.0, 0.0, 0.0), |vec, a| vec + a)
    }

    /// Returns the total movement of an entity.
    pub fn get_entity_movement(state: &EntitiesState, id: &EntityID)
        -> na::Vec3<f32>
    {
        state
            .get_visible_native_components("movement")
            .move_iter()

            // take only the components owned by the entity
            .filter(|c| state.get_owner(c).unwrap() == *id)

            // build a vector from each of the component
            .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
                (Some(x), Some(y), Some(z))
                    => Some(na::Vec3::new(x as f32, y as f32, z as f32)),
                (Some(x), Some(y), _)
                    => Some(na::Vec3::new(x as f32, y as f32, 0.0)),
                _ => None
            })

            // add all the elements together
            .fold(na::Vec3::new(0.0, 0.0, 0.0), |vec, a| vec + a)
    }

    /// returns the total requested movement of an entity
    fn get_requested_movement(state: &EntitiesState, id: &EntityID)
        -> Option<Vec2<f32>>
    {
        state
            .get_visible_native_components("requestedMovement")
            .move_iter()

            // take only the components owned by the entity
            .filter(|c| state.get_owner(c).unwrap() == *id)

            // build a vector from each of the component
            .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
                (Some(x), Some(y), _)
                    => Some(Vec2::new(x as f32, y as f32)),
                _ => None
            })

            // add all the elements together
            .fold(None, |vec: Option<Vec2<f32>>, a| match vec { None => Some(a), Some(v) => Some(v + a) })
    }

    /// changes the position of an entity
    /// TODO: this is wrong
    fn set_position(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
    {
        let list: Vec<ComponentID> = state
            .get_components_iter()
            // take only the components owned by the entity
            .filter(|c| state.get_owner(*c).unwrap() == *id)
            // take only the "position" components
            .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })
            .map(|c| c.clone()).collect();

        for cmp in list.iter()
        {
            state.set(cmp, "x", ::entities::Number(pos.x as f64));
            state.set(cmp, "y", ::entities::Number(pos.y as f64));
        }
    }

    /// changes the movement of an entity
    /// TODO: this is wrong
    fn set_movement(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
    {
        let list: Vec<ComponentID> = state
            .get_components_iter()
            // take only the components owned by the entity
            .filter(|c| state.get_owner(*c).unwrap() == *id)
            // take only the "position" components
            .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "movement", _ => false })
            .map(|c| c.clone()).collect();

        for cmp in list.iter()
        {
            state.set(cmp, "x", ::entities::Number(pos.x as f64));
            state.set(cmp, "y", ::entities::Number(pos.y as f64));
        }
    }
}
<commit_msg>Fix set_position and set_movement a bit<commit_after>use entities::{ EntitiesState, EntitiesHelper, EntityID, ComponentID, NativeComponentType };
use std::collections::{ HashSet, HashMap };
use std::cell::RefCell;
use std::rc::Rc;
use nalgebra::na;
use nalgebra::na::{ Norm, Translation, Vec2, Vec3 };
use ncollide::geom::geom::Geom;
use nphysics::world::World;
use nphysics::object::{ RigidBody };
use log;

pub struct PhysicsSystem {
    world: World,
    bodies: HashMap<EntityID, Rc<RefCell<RigidBody>>>,
}

impl PhysicsSystem {
    pub fn new(_: &EntitiesState, log: |log::LogRecord|)
        -> PhysicsSystem
    {
        let mut world = World::new();
        world.set_gravity(Vec2::new(1.0f32, 1.0));

        let shape = ::ncollide::geom::Plane::new(Vec2::new(0.0f32, 1.0));
        let body = Rc::new(RefCell::new(RigidBody::new_static(shape, 0.3, 0.6)));
        world.add_body(body);

        PhysicsSystem {
            world: world,
            bodies: HashMap::new()
        }
    }

    pub fn process(&mut self, state: &mut EntitiesState, elapsed: &f64, log: |log::LogRecord|)
    {
        // getting the list of all entities that have physics activated
        let listOfEntities: HashSet<EntityID> = state.get_components_iter()
            .filter(|c| state.is_component_visible(*c).unwrap())
            .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "physics", _ => false })
            .filter(|c| match state.get_as_boolean(*c, "activated") { Some(b) => b, _ => false })
            .map(|c| state.get_owner(c).unwrap())
            .collect();

        // removing from the world the elements that have disappeared
        {
            let toRemove: Vec<EntityID> = self.bodies.keys().filter(|e| !listOfEntities.contains(e.clone())).map(|e| e.clone()).collect();
            for e in toRemove.move_iter() {
                //self.bodies.find(&e).     // TODO: remove body from the world
                self.bodies.remove(&e);
            }
        }

        // adding elements that are not yet in the world
        {
            let toCreate: Vec<EntityID> = listOfEntities.iter().filter(|e| !self.bodies.contains_key(e.clone())).map(|e| e.clone()).collect();
            for e in toCreate.move_iter() {
                let shape = ::ncollide::geom::Cuboid::new(Vec2::new(0.5f32, 0.5f32));
                let body = Rc::new(RefCell::new(RigidBody::new_dynamic(shape, 1.0, 0.5, 0.0)));

                // initializing body with current position and movement
                body.borrow_mut().set_translation({ let p = PhysicsSystem::get_entity_position(state, &e); na::Vec2::new(p.x,p.y) });
                body.borrow_mut().set_lin_vel({ let p = PhysicsSystem::get_entity_movement(state, &e); na::Vec2::new(p.x,p.y) });

                self.bodies.insert(e.clone(), body.clone());
                self.world.add_body(body.clone());
            }
        }

        // setting all positions and movements
        for (entity, body) in self.bodies.iter() {
            let position = { let p = PhysicsSystem::get_entity_position(state, entity); na::Vec2::new(p.x,p.y) };
            let movement = { let p = PhysicsSystem::get_entity_movement(state, entity); na::Vec2::new(p.x,p.y) };
            let requestedMovement = PhysicsSystem::get_requested_movement(state, entity);

            let mut borrowedBody = body.borrow_mut();
            borrowedBody.set_translation(position);
            borrowedBody.set_lin_vel(movement);

            if requestedMovement.is_some() && requestedMovement != Some(movement) {
                let acceleration = na::normalize(&(requestedMovement.unwrap() - movement)) * 5.0f32;
                borrowedBody.set_lin_acc_scale(acceleration);
            }
        }

        // step
        self.world.step(*elapsed as f32);

        //
        for (entity, body) in self.bodies.iter() {
            PhysicsSystem::set_position(state, entity, &body.borrow().translation());
            PhysicsSystem::set_movement(state, entity, &body.borrow().lin_vel());
        }
    }

    /// returns the position of an entity
    pub fn get_entity_position(state: &EntitiesState, id: &EntityID)
        -> na::Vec3<f32>
    {
        state
            .get_visible_native_components("position")
            .move_iter()

            // take only the components owned by the entity
            .filter(|c| state.get_owner(c).unwrap() == *id)

            // build a vector from each of the component
            .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
                (Some(x), Some(y), Some(z))
                    => Some(na::Vec3::new(x as f32, y as f32, z as f32)),
                (Some(x), Some(y), _)
                    => Some(na::Vec3::new(x as f32, y as f32, 0.0)),
                _ => None
            })

            // add all the elements together
            .fold(na::Vec3::new(0.0, 0.0, 0.0), |vec, a| vec + a)
    }

    /// Returns the total movement of an entity.
    pub fn get_entity_movement(state: &EntitiesState, id: &EntityID)
        -> na::Vec3<f32>
    {
        state
            .get_visible_native_components("movement")
            .move_iter()

            // take only the components owned by the entity
            .filter(|c| state.get_owner(c).unwrap() == *id)

            // build a vector from each of the component
            .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
                (Some(x), Some(y), Some(z))
                    => Some(na::Vec3::new(x as f32, y as f32, z as f32)),
                (Some(x), Some(y), _)
                    => Some(na::Vec3::new(x as f32, y as f32, 0.0)),
                _ => None
            })

            // add all the elements together
            .fold(na::Vec3::new(0.0, 0.0, 0.0), |vec, a| vec + a)
    }

    /// returns the total requested movement of an entity
    fn get_requested_movement(state: &EntitiesState, id: &EntityID)
        -> Option<Vec2<f32>>
    {
        state
            .get_visible_native_components("requestedMovement")
            .move_iter()

            // take only the components owned by the entity
            .filter(|c| state.get_owner(c).unwrap() == *id)

            // build a vector from each of the component
            .filter_map(|cmp| match (state.get_as_number(&cmp, "x"), state.get_as_number(&cmp, "y"), state.get_as_number(&cmp, "z")) {
                (Some(x), Some(y), _)
                    => Some(Vec2::new(x as f32, y as f32)),
                _ => None
            })

            // add all the elements together
            .fold(None, |vec: Option<Vec2<f32>>, a| match vec { None => Some(a), Some(v) => Some(v + a) })
    }

    /// changes the position of an entity
    /// TODO: this is wrong
    fn set_position(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
    {
        let list: Vec<ComponentID> = state
            .get_components_iter()
            // take only the components owned by the entity
            .filter(|c| state.get_owner(*c).unwrap() == *id)
            // take only the "position" components
            .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })
            .map(|c| c.clone()).collect();

        for cmp in list.iter()
        {
            state.set(cmp, "x", ::entities::Number(pos.x as f64 / list.len() as f64));
            state.set(cmp, "y", ::entities::Number(pos.y as f64 / list.len() as f64));
        }
    }

    /// changes the movement of an entity
    /// TODO: this is wrong
    fn set_movement(state: &mut EntitiesState, id: &EntityID, pos: &Vec2<f32>)
    {
        let list: Vec<ComponentID> = state
            .get_components_iter()
            // take only the components owned by the entity
            .filter(|c| state.get_owner(*c).unwrap() == *id)
            // take only the "position" components
            .filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "movement", _ => false })
            .map(|c| c.clone()).collect();

        for cmp in list.iter()
        {
            state.set(cmp, "x", ::entities::Number(pos.x as f64 / list.len() as f64));
            state.set(cmp, "y", ::entities::Number(pos.y as f64 / list.len() as f64));
        }
    }
}
<|endoftext|>


<commit_before>use {osc_types as ot,
    errors as oe};

use std::{io, string, mem, error};
use std::io::{Read, BufRead};

use byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg, size)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(oe::OscError::BadOscPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    match read_osc_string(&mut cursor) {
        Ok(s) => {
            let addr: String = s;
            match read_osc_string(&mut cursor) {
                Ok(type_tags) => {
                    if type_tags.len() > 1 {
                        match read_osc_args(&mut cursor, type_tags) {
                            Ok(args) => println!("{}", args.len()),
                            Err(e) => ()
                        };
                    }
                },
                Err(e) => return Err(e)
            }
        }
        Err(e) => return Err(e)
    }

    Ok(ot::OscPacket::Message(ot::OscMessage))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf)
                .map_err(|e| oe::OscError::StringError(e))
                .map(|s| s.trim_matches(0u8 as char).to_string())
        },
        Err(e) => Err(oe::OscError::ReadError(e)),
    }
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> ot::OscResult<Vec<ot::OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
        .skip(1)
        .map(|c| c as char)
        .collect();
    let mut args: Vec<ot::OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        match read_osc_arg(cursor, tag) {
            Ok(arg) => {
                args.push(arg);
            },
            Err(e) => return Err(e)
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> ot::OscResult<ot::OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
            .map(|f| ot::OscType::OscFloat(f))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        'd' => {
            cursor.read_f64::<BigEndian>()
            .map(|d| ot::OscType::OscDouble(d))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
            .map(|i| ot::OscType::OscInt(i))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        'h' => {
            cursor.read_i64::<BigEndian>()
            .map(|l| ot::OscType::OscLong(l))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        's' => {
            read_osc_string(cursor)
            .map(|s| ot::OscType::OscString(s))
        },
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            match cursor.read_u32::<BigEndian>() {
                Ok(size) => {
                    let mut buf: Vec<u8> = Vec::with_capacity(size as usize);
                    match cursor.take(size as u64).read(&mut buf) {
                        Ok(blob_size) => Ok(ot::OscType::OscBlob(buf)),
                        Err(e) => Err(oe::OscError::ReadError(e))
                    }
                },
                Err(e) => return Err(oe::OscError::BadOscBundle)
            }
        },
        _ => Err(oe::OscError::BadOscArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<ot::OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(ot::OscType::OscTime(date, frac)),
                Err(e) => Err(oe::OscError::ByteOrderError(e))
            }
        },
        Err(e) => Err(oe::OscError::ByteOrderError(e))
    }
}

fn decode_bundle(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    Err(oe::OscError::BadOscBundle)
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    match pos % 4 {
        0 => (),
        d => cursor.set_position(pos + (4 - d)),
    }
}<commit_msg>Return OscMessage and remove `println!`<commit_after>use {osc_types as ot,
    errors as oe};

use std::{io, string, mem, error};
use std::io::{Read, BufRead};

use byteorder;
use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg, size)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(oe::OscError::BadOscPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8], size: usize) -> ot::OscResult<ot::OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    match read_osc_string(&mut cursor) {
        Ok(s) => {
            let addr: String = s;
            match read_osc_string(&mut cursor) {
                Ok(type_tags) => {
                    if type_tags.len() > 1 {
                        match read_osc_args(&mut cursor, type_tags) {
                            Ok(args) => {
                                Ok(ot::OscPacket::Message(ot::OscMessage{
                                    addr: addr,
                                    args: Some(args),
                                }))
                            },
                            Err(e) => Err(e),
                        }
                    } else {
                        Ok(ot::OscPacket::Message(ot::OscMessage{
                            addr: addr,
                            args: None
                        }))
                    }
                },
                Err(e) => Err(e),
            }
        }
        Err(e) => Err(e),
    }

    Ok(ot::OscPacket::Message(ot::OscMessage))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    match cursor.read_until(0, &mut str_buf) {
        Ok(_) => {
            pad_cursor(cursor);
            String::from_utf8(str_buf)
                .map_err(|e| oe::OscError::StringError(e))
                .map(|s| s.trim_matches(0u8 as char).to_string())
        },
        Err(e) => Err(oe::OscError::ReadError(e)),
    }
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> ot::OscResult<Vec<ot::OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
        .skip(1)
        .map(|c| c as char)
        .collect();
    let mut args: Vec<ot::OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        match read_osc_arg(cursor, tag) {
            Ok(arg) => {
                args.push(arg);
            },
            Err(e) => return Err(e)
        }
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> ot::OscResult<ot::OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
            .map(|f| ot::OscType::OscFloat(f))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        'd' => {
            cursor.read_f64::<BigEndian>()
            .map(|d| ot::OscType::OscDouble(d))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
            .map(|i| ot::OscType::OscInt(i))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        'h' => {
            cursor.read_i64::<BigEndian>()
            .map(|l| ot::OscType::OscLong(l))
            .map_err(|e| oe::OscError::ByteOrderError(e))
        },
        's' => {
            read_osc_string(cursor)
            .map(|s| ot::OscType::OscString(s))
        },
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            match cursor.read_u32::<BigEndian>() {
                Ok(size) => {
                    let mut buf: Vec<u8> = Vec::with_capacity(size as usize);
                    match cursor.take(size as u64).read(&mut buf) {
                        Ok(blob_size) => Ok(ot::OscType::OscBlob(buf)),
                        Err(e) => Err(oe::OscError::ReadError(e))
                    }
                },
                Err(e) => return Err(oe::OscError::BadOscBundle)
            }
        },
        _ => Err(oe::OscError::BadOscArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> ot::OscResult<ot::OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(ot::OscType::OscTime(date, frac)),
                Err(e) => Err(oe::OscError::ByteOrderError(e))
            }
        },
        Err(e) => Err(oe::OscError::ByteOrderError(e))
    }
}

fn decode_bundle(msg: &[u8]) -> ot::OscResult<ot::OscPacket> {
    Err(oe::OscError::BadOscBundle)
}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    match pos % 4 {
        0 => (),
        d => cursor.set_position(pos + (4 - d)),
    }
}<|endoftext|>


<commit_before>//! Timestamp formatting.

use std::time::{SystemTime, UNIX_EPOCH};

use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece, Month};
use datetime::fmt::DateFormat;

use lazy_static::lazy_static;
use unicode_width::UnicodeWidthStr;

/// Every timestamp in exa needs to be rendered by a **time format**.
/// Formatting times is tricky, because how a timestamp is rendered can
/// depend on one or more of the following:
///
/// - The user’s locale, for printing the month name as “Feb”, or as “fév”,
///   or as “2月”;
/// - The current year, because certain formats will be less precise when
///   dealing with dates far in the past;
/// - The formatting style that the user asked for on the command-line.
///
/// Because not all formatting styles need the same data, they all have their
/// own enum variants. It’s not worth looking the locale up if the formatter
/// prints month names as numbers.
///
/// Currently exa does not support *custom* styles, where the user enters a
/// format string in an environment variable or something. Just these four.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum TimeFormat {

    /// The **default format** uses the user’s locale to print month names,
    /// and specifies the timestamp down to the minute for recent times, and
    /// day for older times.
    DefaultFormat,

    /// Use the **ISO format**, which specifies the timestamp down to the
    /// minute for recent times, and day for older times. It uses a number
    /// for the month so it doesn’t use the locale.
    ISOFormat,

    /// Use the **long ISO format**, which specifies the timestamp down to the
    /// minute using only numbers, without needing the locale or year.
    LongISO,

    /// Use the **full ISO format**, which specifies the timestamp down to the
    /// millisecond and includes its offset down to the minute. This too uses
    /// only numbers so doesn’t require any special consideration.
    FullISO,
}

// There are two different formatting functions because local and zoned
// timestamps are separate types.

impl TimeFormat {
    pub fn format_local(self, time: SystemTime) -> String {
        match self {
            Self::DefaultFormat  => default_local(time),
            Self::ISOFormat      => iso_local(time),
            Self::LongISO        => long_local(time),
            Self::FullISO        => full_local(time),
        }
    }

    pub fn format_zoned(self, time: SystemTime, zone: &TimeZone) -> String {
        match self {
            Self::DefaultFormat  => default_zoned(time, zone),
            Self::ISOFormat      => iso_zoned(time, zone),
            Self::LongISO        => long_zoned(time, zone),
            Self::FullISO        => full_zoned(time, zone),
        }
    }
}

#[allow(trivial_numeric_casts)]
fn default_local(time: SystemTime) -> String {
    let date = LocalDateTime::at(systemtime_epoch(time));

    if date.year() == *CURRENT_YEAR {
        format!("{:2} {} {:02}:{:02}",
                date.day(), month_to_abbrev(date.month()),
                date.hour(), date.minute())
    }
    else {
        let date_format = match *MAXIMUM_MONTH_WIDTH {
            4  => &*FOUR_WIDE_DATE_TIME,
            5  => &*FIVE_WIDE_DATE_TIME,
            _  => &*OTHER_WIDE_DATE_TIME,
        };

        date_format.format(&date, &*LOCALE)
    }
}

#[allow(trivial_numeric_casts)]
fn default_zoned(time: SystemTime, zone: &TimeZone) -> String {
    let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));

    if date.year() == *CURRENT_YEAR {
        format!("{:2} {} {:02}:{:02}",
                date.day(), month_to_abbrev(date.month()),
                date.hour(), date.minute())
    }
    else {
        let date_format = match *MAXIMUM_MONTH_WIDTH {
            4  => &*FOUR_WIDE_DATE_YEAR,
            5  => &*FIVE_WIDE_DATE_YEAR,
            _  => &*OTHER_WIDE_DATE_YEAR,
        };

        date_format.format(&date, &*LOCALE)
    }
}

#[allow(trivial_numeric_casts)]
fn long_local(time: SystemTime) -> String {
    let date = LocalDateTime::at(systemtime_epoch(time));
    format!("{:04}-{:02}-{:02} {:02}:{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute())
}

#[allow(trivial_numeric_casts)]
fn long_zoned(time: SystemTime, zone: &TimeZone) -> String {
    let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
    format!("{:04}-{:02}-{:02} {:02}:{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute())
}

#[allow(trivial_numeric_casts)]
fn full_local(time: SystemTime) -> String {
    let date = LocalDateTime::at(systemtime_epoch(time));
    format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute(), date.second(), systemtime_nanos(time))
}

#[allow(trivial_numeric_casts)]
fn full_zoned(time: SystemTime, zone: &TimeZone) -> String {
    use datetime::Offset;

    let local = LocalDateTime::at(systemtime_epoch(time));
    let date = zone.to_zoned(local);
    let offset = Offset::of_seconds(zone.offset(local) as i32).expect("Offset out of range");
    format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09} {:+03}{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute(), date.second(), systemtime_nanos(time),
            offset.hours(), offset.minutes().abs())
}

#[allow(trivial_numeric_casts)]
fn iso_local(time: SystemTime) -> String {
    let date = LocalDateTime::at(systemtime_epoch(time));

    if is_recent(date) {
        format!("{:02}-{:02} {:02}:{:02}",
                date.month() as usize, date.day(),
                date.hour(), date.minute())
    }
    else {
        format!("{:04}-{:02}-{:02}",
                date.year(), date.month() as usize, date.day())
    }
}

#[allow(trivial_numeric_casts)]
fn iso_zoned(time: SystemTime, zone: &TimeZone) -> String {
    let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));

    if is_recent(date) {
        format!("{:02}-{:02} {:02}:{:02}",
                date.month() as usize, date.day(),
                date.hour(), date.minute())
    }
    else {
        format!("{:04}-{:02}-{:02}",
                date.year(), date.month() as usize, date.day())
    }
}

fn systemtime_epoch(time: SystemTime) -> i64 {
    time.duration_since(UNIX_EPOCH)
        .map(|t| t.as_secs() as i64)
        .unwrap_or_else(|e| {
            let diff = e.duration();
            let mut secs = diff.as_secs();
            if diff.subsec_nanos() > 0 {
                secs += 1;
            }
            -(secs as i64)
        })
}

fn systemtime_nanos(time: SystemTime) -> u32 {
    time.duration_since(UNIX_EPOCH)
        .map(|t| t.subsec_nanos())
        .unwrap_or_else(|e| {
            let nanos = e.duration().subsec_nanos();
            if nanos > 0 {
                1_000_000_000 - nanos
            } else {
                nanos
            }
        })
}

fn is_recent(date: LocalDateTime) -> bool {
    date.year() == *CURRENT_YEAR
}

fn month_to_abbrev(month: Month) -> &'static str {
    match month {
        Month::January    => "Jan",
        Month::February   => "Feb",
        Month::March      => "Mar",
        Month::April      => "Apr",
        Month::May        => "May",
        Month::June       => "Jun",
        Month::July       => "Jul",
        Month::August     => "Aug",
        Month::September  => "Sep",
        Month::October    => "Oct",
        Month::November   => "Nov",
        Month::December   => "Dec",
    }
}

lazy_static! {

    static ref CURRENT_YEAR: i64 = LocalDateTime::now().year();

    static ref LOCALE: locale::Time = {
        locale::Time::load_user_locale()
               .unwrap_or_else(|_| locale::Time::english())
    };

    static ref MAXIMUM_MONTH_WIDTH: usize = {
        // Some locales use a three-character wide month name (Jan to Dec);
        // others vary between three to four (1月 to 12月, juil.). We check each month width
        // to detect the longest and set the output format accordingly.
        let mut maximum_month_width = 0;
        for i in 0..11 {
            let current_month_width = UnicodeWidthStr::width(&*LOCALE.short_month_name(i));
            maximum_month_width = std::cmp::max(maximum_month_width, current_month_width);
        }
        maximum_month_width
    };

    static ref FOUR_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {4<:M} {2>:h}:{02>:m}"
    ).unwrap();

    static ref FIVE_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {5<:M} {2>:h}:{02>:m}"
    ).unwrap();

    static ref OTHER_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {:M} {2>:h}:{02>:m}"
    ).unwrap();

    static ref FOUR_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {4<:M} {5>:Y}"
    ).unwrap();

    static ref FIVE_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {5<:M} {5>:Y}"
    ).unwrap();

    static ref OTHER_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {:M} {5>:Y}"
    ).unwrap();
}
<commit_msg>Fix month name not following locale when date is in current year<commit_after>//! Timestamp formatting.

use std::time::{SystemTime, UNIX_EPOCH};

use datetime::{LocalDateTime, TimeZone, DatePiece, TimePiece};
use datetime::fmt::DateFormat;

use lazy_static::lazy_static;
use unicode_width::UnicodeWidthStr;

/// Every timestamp in exa needs to be rendered by a **time format**.
/// Formatting times is tricky, because how a timestamp is rendered can
/// depend on one or more of the following:
///
/// - The user’s locale, for printing the month name as “Feb”, or as “fév”,
///   or as “2月”;
/// - The current year, because certain formats will be less precise when
///   dealing with dates far in the past;
/// - The formatting style that the user asked for on the command-line.
///
/// Because not all formatting styles need the same data, they all have their
/// own enum variants. It’s not worth looking the locale up if the formatter
/// prints month names as numbers.
///
/// Currently exa does not support *custom* styles, where the user enters a
/// format string in an environment variable or something. Just these four.
#[derive(PartialEq, Debug, Copy, Clone)]
pub enum TimeFormat {

    /// The **default format** uses the user’s locale to print month names,
    /// and specifies the timestamp down to the minute for recent times, and
    /// day for older times.
    DefaultFormat,

    /// Use the **ISO format**, which specifies the timestamp down to the
    /// minute for recent times, and day for older times. It uses a number
    /// for the month so it doesn’t use the locale.
    ISOFormat,

    /// Use the **long ISO format**, which specifies the timestamp down to the
    /// minute using only numbers, without needing the locale or year.
    LongISO,

    /// Use the **full ISO format**, which specifies the timestamp down to the
    /// millisecond and includes its offset down to the minute. This too uses
    /// only numbers so doesn’t require any special consideration.
    FullISO,
}

// There are two different formatting functions because local and zoned
// timestamps are separate types.

impl TimeFormat {
    pub fn format_local(self, time: SystemTime) -> String {
        match self {
            Self::DefaultFormat  => default_local(time),
            Self::ISOFormat      => iso_local(time),
            Self::LongISO        => long_local(time),
            Self::FullISO        => full_local(time),
        }
    }

    pub fn format_zoned(self, time: SystemTime, zone: &TimeZone) -> String {
        match self {
            Self::DefaultFormat  => default_zoned(time, zone),
            Self::ISOFormat      => iso_zoned(time, zone),
            Self::LongISO        => long_zoned(time, zone),
            Self::FullISO        => full_zoned(time, zone),
        }
    }
}

#[allow(trivial_numeric_casts)]
fn default_local(time: SystemTime) -> String {
    let date = LocalDateTime::at(systemtime_epoch(time));
    let date_format = get_dateformat(&date);
    date_format.format(&date, &*LOCALE)
}

#[allow(trivial_numeric_casts)]
fn default_zoned(time: SystemTime, zone: &TimeZone) -> String {
    let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
    let date_format = get_dateformat(&date);
    date_format.format(&date, &*LOCALE)
}

fn get_dateformat(date: &LocalDateTime) -> &'static DateFormat<'static> {
    match (is_recent(&date), *MAXIMUM_MONTH_WIDTH) {
        (true, 4)   => &FOUR_WIDE_DATE_TIME,
        (true, 5)   => &FIVE_WIDE_DATE_TIME,
        (true, _)   => &OTHER_WIDE_DATE_TIME,
        (false, 4)  => &FOUR_WIDE_DATE_YEAR,
        (false, 5)  => &FIVE_WIDE_DATE_YEAR,
        (false, _)  => &OTHER_WIDE_DATE_YEAR,
    }
}

#[allow(trivial_numeric_casts)]
fn long_local(time: SystemTime) -> String {
    let date = LocalDateTime::at(systemtime_epoch(time));
    format!("{:04}-{:02}-{:02} {:02}:{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute())
}

#[allow(trivial_numeric_casts)]
fn long_zoned(time: SystemTime, zone: &TimeZone) -> String {
    let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));
    format!("{:04}-{:02}-{:02} {:02}:{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute())
}

#[allow(trivial_numeric_casts)]
fn full_local(time: SystemTime) -> String {
    let date = LocalDateTime::at(systemtime_epoch(time));
    format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute(), date.second(), systemtime_nanos(time))
}

#[allow(trivial_numeric_casts)]
fn full_zoned(time: SystemTime, zone: &TimeZone) -> String {
    use datetime::Offset;

    let local = LocalDateTime::at(systemtime_epoch(time));
    let date = zone.to_zoned(local);
    let offset = Offset::of_seconds(zone.offset(local) as i32).expect("Offset out of range");
    format!("{:04}-{:02}-{:02} {:02}:{:02}:{:02}.{:09} {:+03}{:02}",
            date.year(), date.month() as usize, date.day(),
            date.hour(), date.minute(), date.second(), systemtime_nanos(time),
            offset.hours(), offset.minutes().abs())
}

#[allow(trivial_numeric_casts)]
fn iso_local(time: SystemTime) -> String {
    let date = LocalDateTime::at(systemtime_epoch(time));

    if is_recent(&date) {
        format!("{:02}-{:02} {:02}:{:02}",
                date.month() as usize, date.day(),
                date.hour(), date.minute())
    }
    else {
        format!("{:04}-{:02}-{:02}",
                date.year(), date.month() as usize, date.day())
    }
}

#[allow(trivial_numeric_casts)]
fn iso_zoned(time: SystemTime, zone: &TimeZone) -> String {
    let date = zone.to_zoned(LocalDateTime::at(systemtime_epoch(time)));

    if is_recent(&date) {
        format!("{:02}-{:02} {:02}:{:02}",
                date.month() as usize, date.day(),
                date.hour(), date.minute())
    }
    else {
        format!("{:04}-{:02}-{:02}",
                date.year(), date.month() as usize, date.day())
    }
}

fn systemtime_epoch(time: SystemTime) -> i64 {
    time.duration_since(UNIX_EPOCH)
        .map(|t| t.as_secs() as i64)
        .unwrap_or_else(|e| {
            let diff = e.duration();
            let mut secs = diff.as_secs();
            if diff.subsec_nanos() > 0 {
                secs += 1;
            }
            -(secs as i64)
        })
}

fn systemtime_nanos(time: SystemTime) -> u32 {
    time.duration_since(UNIX_EPOCH)
        .map(|t| t.subsec_nanos())
        .unwrap_or_else(|e| {
            let nanos = e.duration().subsec_nanos();
            if nanos > 0 {
                1_000_000_000 - nanos
            } else {
                nanos
            }
        })
}

fn is_recent(date: &LocalDateTime) -> bool {
    date.year() == *CURRENT_YEAR
}

lazy_static! {

    static ref CURRENT_YEAR: i64 = LocalDateTime::now().year();

    static ref LOCALE: locale::Time = {
        locale::Time::load_user_locale()
               .unwrap_or_else(|_| locale::Time::english())
    };

    static ref MAXIMUM_MONTH_WIDTH: usize = {
        // Some locales use a three-character wide month name (Jan to Dec);
        // others vary between three to four (1月 to 12月, juil.). We check each month width
        // to detect the longest and set the output format accordingly.
        let mut maximum_month_width = 0;
        for i in 0..11 {
            let current_month_width = UnicodeWidthStr::width(&*LOCALE.short_month_name(i));
            maximum_month_width = std::cmp::max(maximum_month_width, current_month_width);
        }
        maximum_month_width
    };

    static ref FOUR_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {4<:M} {02>:h}:{02>:m}"
    ).unwrap();

    static ref FIVE_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {5<:M} {02>:h}:{02>:m}"
    ).unwrap();

    static ref OTHER_WIDE_DATE_TIME: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {:M} {02>:h}:{02>:m}"
    ).unwrap();

    static ref FOUR_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {4<:M} {5>:Y}"
    ).unwrap();

    static ref FIVE_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {5<:M} {5>:Y}"
    ).unwrap();

    static ref OTHER_WIDE_DATE_YEAR: DateFormat<'static> = DateFormat::parse(
        "{2>:D} {:M} {5>:Y}"
    ).unwrap();
}
<|endoftext|>