<commit_before>//! Geometric types for 2D lattice-shaped puzzles.

use std::ops::{Add, Index, IndexMut, Mul, Neg, Range, Sub};

/// A two-dimensional lattice point.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Point(pub i32, pub i32);

/// A size of a rectangle.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Size(pub i32, pub i32);

/// A difference between two `Point`s.
///
/// `Point(y0, x0)` - `Point(y1, x1) == `Move(y0 - y1, x0 - x1)`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Move(pub i32, pub i32);

/// A 2x2 rotation matrix.
///
/// `Rotation(yy, yx, xy, xx) * Move(y, x) == Move(yy*y + yx*x, xy*y + xx*x)`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Rotation(i32, i32, i32, i32);

/// An upward `Move` vector.
pub const MOVE_UP: Move = Move(-1, 0);

/// A rightward `Move` vector.
pub const MOVE_RIGHT: Move = Move(0, 1);

/// A downward `Move` vector.
pub const MOVE_DOWN: Move = Move(1, 0);

/// A leftward `Move` vector.
pub const MOVE_LEFT: Move = Move(0, -1);

/// `Move` vectors that is toward four adjacent points.
pub const MOVE_ALL_DIRECTIONS: [Move; 4] = [MOVE_UP, MOVE_RIGHT, MOVE_DOWN, MOVE_LEFT];

/// `Move` vectors that is toward eight adjacent points.
pub const MOVE_ALL_ADJACENTS: [Move; 8] = [
    MOVE_UP,
    Move(-1, 1),
    MOVE_RIGHT,
    Move(1, 1),
    MOVE_DOWN,
    Move(1, -1),
    MOVE_LEFT,
    Move(-1, -1),
];

impl Add<Move> for Point {
    type Output = Point;

    #[inline]
    fn add(self, other: Move) -> Point {
        Point(self.0 + other.0, self.1 + other.1)
    }
}

impl Sub<Point> for Point {
    type Output = Move;

    #[inline]
    fn sub(self, other: Point) -> Move {
        Move(self.0 - other.0, self.1 - other.1)
    }
}

impl Add<Move> for Move {
    type Output = Move;

    #[inline]
    fn add(self, other: Move) -> Move {
        Move(self.0 + other.0, self.1 + other.1)
    }
}

impl Sub<Move> for Move {
    type Output = Move;

    #[inline]
    fn sub(self, other: Move) -> Move {
        Move(self.0 - other.0, self.1 - other.1)
    }
}

impl Neg for Move {
    type Output = Move;

    #[inline]
    fn neg(self) -> Move {
        Move(-self.0, -self.1)
    }
}

impl Mul<i32> for Move {
    type Output = Move;

    #[inline]
    fn mul(self, other: i32) -> Move {
        Move(self.0 * other, self.1 * other)
    }
}

/// A 0-degree `Rotation` to the left (counterclockwise).
pub const ROT_CCW0: Rotation = Rotation(1, 0, 0, 1);

/// A 90-degree `Rotation` to the left (counterclockwise).
pub const ROT_CCW90: Rotation = Rotation(0, -1, 1, 0);

/// A 180-degree `Rotation` to the left (counterclockwise).
pub const ROT_CCW180: Rotation = Rotation(-1, 0, 0, -1);

/// A 270-degree `Rotation` to the left (counterclockwise).
pub const ROT_CCW270: Rotation = Rotation(0, 1, -1, 0);

/// Flip horizontal.
pub const ROT_H_FLIP: Rotation = Rotation(1, 0, 0, -1);

/// Flip vertical.
pub const ROT_V_FLIP: Rotation = Rotation(-1, 0, 0, 1);

impl Mul<Rotation> for Rotation {
    type Output = Rotation;

    #[inline]
    fn mul(self, other: Rotation) -> Rotation {
        Rotation(
            self.0 * other.0 + self.1 * other.2,
            self.0 * other.1 + self.1 * other.3,
            self.2 * other.0 + self.3 * other.2,
            self.2 * other.1 + self.3 * other.3,
        )
    }
}

impl Mul<Move> for Rotation {
    type Output = Move;

    #[inline]
    fn mul(self, other: Move) -> Move {
        Move(
            self.0 * other.0 + self.1 * other.1,
            self.2 * other.0 + self.3 * other.1,
        )
    }
}

/// An ID identifying a cell in lattice rectangle.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct CellId(usize);

/// An ID being given to cells on outside the rectangle.
pub const CELL_ID_OUTSIDE: CellId = CellId(0);

impl CellId {
    /// Creates a new `CellId` from an ID.
    #[inline]
    pub fn new(id: usize) -> CellId {
        CellId(id)
    }

    /// Gets an ID of the cell.
    #[inline]
    pub fn id(self) -> usize {
        self.0
    }

    /// Returns if the cell is on outside of the rectangle.
    #[inline]
    pub fn is_outside(self) -> bool {
        self == CELL_ID_OUTSIDE
    }
}

/// A representative `Point` of points on outside the rectangle.
const OUTSIDE_POINT: Point = Point(-1, -1);

/// A rectangle area.
pub trait Geom {
    /// Returns the rectangle's size.
    #[inline]
    fn size(&self) -> Size;

    /// Returns the number of the rectangle's rows.
    #[inline]
    fn row(&self) -> i32 {
        self.size().0
    }

    /// Returns the number of the rectangle's columns.
    #[inline]
    fn column(&self) -> i32 {
        self.size().1
    }

    /// Returns the cell length which is contained in the rectangle.
    #[inline]
    fn cell_len(&self) -> usize {
        (self.row() * self.column() + 1) as usize
    }

    /// Returns true if the point is contained in the rectangle.
    #[inline]
    fn contains(&self, p: Point) -> bool {
        let size = self.size();
        0 <= p.0 && p.0 < size.0 && 0 <= p.1 && p.1 < size.1
    }

    /// Convert a point to a corresponding cell ID.
    #[inline]
    fn point_to_cellid(&self, p: Point) -> CellId {
        if self.contains(p) {
            CellId::new((p.0 * self.column() + p.1 + 1) as usize)
        } else {
            CELL_ID_OUTSIDE
        }
    }

    /// Convert a cell ID to a corresponding point.
    #[inline]
    fn cellid_to_point(&self, id: CellId) -> Point {
        if id.is_outside() {
            OUTSIDE_POINT
        } else {
            let idx = id.id() - 1;
            Point((idx as i32) / self.column(), (idx as i32) % self.column())
        }
    }

    /// Returns an iterator iterating all points.
    #[inline]
    fn points(&self) -> Points {
        if self.row() > 0 && self.column() > 0 {
            Points {
                point: Some(Point(0, 0)),
                size: self.size(),
            }
        } else {
            Points {
                point: None,
                size: self.size(),
            }
        }
    }

    /// Returns an iterator iterating all points in the row.
    #[inline]
    fn points_in_row(&self, row: i32) -> PointsInRow {
        PointsInRow {
            row: row,
            columns: 0..self.column(),
        }
    }

    /// Returns an iterator iterating all points in the column.
    #[inline]
    fn points_in_column(&self, column: i32) -> PointsInColumn {
        PointsInColumn {
            column: column,
            rows: 0..self.row(),
        }
    }
}

/// An iterator iterating all points in the rectangle.
#[derive(Copy, Clone, Debug)]
pub struct Points {
    point: Option<Point>,
    size: Size,
}

impl Iterator for Points {
    type Item = Point;

    #[inline]
    fn next(&mut self) -> Option<Point> {
        if let Some(cur) = self.point {
            let mut next = cur;
            let mut end = false;
            next.1 += 1;
            if next.1 >= self.size.1 {
                next.0 += 1;
                next.1 = 0;
                if next.0 >= self.size.0 {
                    end = true;
                }
            }
            if !end {
                self.point = Some(next);
            } else {
                self.point = None;
            }
            return Some(cur);
        }
        None
    }
}

/// An iterator iterating all points in a row of the rectangle.
#[derive(Clone, Debug)]
pub struct PointsInRow {
    row: i32,
    columns: Range<i32>,
}

impl Iterator for PointsInRow {
    type Item = Point;

    #[inline]
    fn next(&mut self) -> Option<Point> {
        if let Some(c) = self.columns.next() {
            Some(Point(self.row, c))
        } else {
            None
        }
    }
}

/// An iterator iterating all points in a column of the rectangle.
#[derive(Clone, Debug)]
pub struct PointsInColumn {
    rows: Range<i32>,
    column: i32,
}

impl Iterator for PointsInColumn {
    type Item = Point;

    #[inline]
    fn next(&mut self) -> Option<Point> {
        if let Some(r) = self.rows.next() {
            Some(Point(r, self.column))
        } else {
            None
        }
    }
}

/// A table that stores values for each cells.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Table<T> {
    size: Size,
    data: Vec<T>,
}

impl<T> Table<T> {
    /// Creates a new table with data.
    #[inline]
    pub fn new(size: Size, outside: T, mut data: Vec<T>) -> Table<T> {
        assert_eq!((size.0 * size.1) as usize, data.len());
        data.insert(0, outside);
        Table {
            size: size,
            data: data,
        }
    }

    /// Creates a new empty table.
    #[inline]
    pub fn new_empty(size: Size, outside: T, init: T) -> Table<T>
    where
        T: Clone,
    {
        let data = vec![init; (size.0 * size.1) as usize];
        Table::new(size, outside, data)
    }
}

impl<T> Geom for Table<T> {
    #[inline]
    fn size(&self) -> Size {
        self.size
    }
}

impl<T> Index<Point> for Table<T> {
    type Output = T;

    #[inline]
    fn index(&self, p: Point) -> &T {
        let idx = self.point_to_cellid(p).id();
        &self.data[idx]
    }
}

impl<T> IndexMut<Point> for Table<T> {
    #[inline]
    fn index_mut(&mut self, p: Point) -> &mut T {
        let idx = self.point_to_cellid(p).id();
        &mut self.data[idx]
    }
}

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

    struct Rect(Size);
    impl Geom for Rect {
        fn size(&self) -> Size {
            self.0
        }
    }

    #[test]
    fn points() {
        let pts = [
            Point(0, 0),
            Point(0, 1),
            Point(0, 2),
            Point(1, 0),
            Point(1, 1),
            Point(1, 2),
            Point(2, 0),
            Point(2, 1),
            Point(2, 2),
            Point(3, 0),
            Point(3, 1),
            Point(3, 2),
        ];
        let rect = Rect(Size(4, 3));
        assert_eq!(&pts[..], &rect.points().collect::<Vec<_>>()[..]);
    }

    #[test]
    fn rotate_mat() {
        let mat = [ROT_CCW0, ROT_CCW90, ROT_CCW180, ROT_CCW270];
        for i in 0..mat.len() {
            for j in 0..mat.len() {
                assert_eq!(mat[(i + j) % mat.len()], mat[i] * mat[j]);
            }
        }
    }

    #[test]
    fn rotate_point() {
        let mat = [ROT_CCW0, ROT_CCW90, ROT_CCW180, ROT_CCW270];
        let vec = [
            [MOVE_UP, MOVE_LEFT, MOVE_DOWN, MOVE_RIGHT],
            [
                MOVE_UP + MOVE_RIGHT,
                MOVE_LEFT + MOVE_UP,
                MOVE_DOWN + MOVE_LEFT,
                MOVE_RIGHT + MOVE_DOWN,
            ],
        ];
        for i in 0..mat.len() {
            for v in &vec {
                for j in 0..v.len() {
                    assert_eq!(v[(i + j) % v.len()], mat[i] * v[j]);
                }
            }
        }
    }
}
<commit_msg>fix warnings<commit_after>//! Geometric types for 2D lattice-shaped puzzles.

use std::ops::{Add, Index, IndexMut, Mul, Neg, Range, Sub};

/// A two-dimensional lattice point.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Point(pub i32, pub i32);

/// A size of a rectangle.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct Size(pub i32, pub i32);

/// A difference between two `Point`s.
///
/// `Point(y0, x0)` - `Point(y1, x1) == `Move(y0 - y1, x0 - x1)`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Move(pub i32, pub i32);

/// A 2x2 rotation matrix.
///
/// `Rotation(yy, yx, xy, xx) * Move(y, x) == Move(yy*y + yx*x, xy*y + xx*x)`
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub struct Rotation(i32, i32, i32, i32);

/// An upward `Move` vector.
pub const MOVE_UP: Move = Move(-1, 0);

/// A rightward `Move` vector.
pub const MOVE_RIGHT: Move = Move(0, 1);

/// A downward `Move` vector.
pub const MOVE_DOWN: Move = Move(1, 0);

/// A leftward `Move` vector.
pub const MOVE_LEFT: Move = Move(0, -1);

/// `Move` vectors that is toward four adjacent points.
pub const MOVE_ALL_DIRECTIONS: [Move; 4] = [MOVE_UP, MOVE_RIGHT, MOVE_DOWN, MOVE_LEFT];

/// `Move` vectors that is toward eight adjacent points.
pub const MOVE_ALL_ADJACENTS: [Move; 8] = [
    MOVE_UP,
    Move(-1, 1),
    MOVE_RIGHT,
    Move(1, 1),
    MOVE_DOWN,
    Move(1, -1),
    MOVE_LEFT,
    Move(-1, -1),
];

impl Add<Move> for Point {
    type Output = Point;

    #[inline]
    fn add(self, other: Move) -> Point {
        Point(self.0 + other.0, self.1 + other.1)
    }
}

impl Sub<Point> for Point {
    type Output = Move;

    #[inline]
    fn sub(self, other: Point) -> Move {
        Move(self.0 - other.0, self.1 - other.1)
    }
}

impl Add<Move> for Move {
    type Output = Move;

    #[inline]
    fn add(self, other: Move) -> Move {
        Move(self.0 + other.0, self.1 + other.1)
    }
}

impl Sub<Move> for Move {
    type Output = Move;

    #[inline]
    fn sub(self, other: Move) -> Move {
        Move(self.0 - other.0, self.1 - other.1)
    }
}

impl Neg for Move {
    type Output = Move;

    #[inline]
    fn neg(self) -> Move {
        Move(-self.0, -self.1)
    }
}

impl Mul<i32> for Move {
    type Output = Move;

    #[inline]
    fn mul(self, other: i32) -> Move {
        Move(self.0 * other, self.1 * other)
    }
}

/// A 0-degree `Rotation` to the left (counterclockwise).
pub const ROT_CCW0: Rotation = Rotation(1, 0, 0, 1);

/// A 90-degree `Rotation` to the left (counterclockwise).
pub const ROT_CCW90: Rotation = Rotation(0, -1, 1, 0);

/// A 180-degree `Rotation` to the left (counterclockwise).
pub const ROT_CCW180: Rotation = Rotation(-1, 0, 0, -1);

/// A 270-degree `Rotation` to the left (counterclockwise).
pub const ROT_CCW270: Rotation = Rotation(0, 1, -1, 0);

/// Flip horizontal.
pub const ROT_H_FLIP: Rotation = Rotation(1, 0, 0, -1);

/// Flip vertical.
pub const ROT_V_FLIP: Rotation = Rotation(-1, 0, 0, 1);

impl Mul<Rotation> for Rotation {
    type Output = Rotation;

    #[inline]
    fn mul(self, other: Rotation) -> Rotation {
        Rotation(
            self.0 * other.0 + self.1 * other.2,
            self.0 * other.1 + self.1 * other.3,
            self.2 * other.0 + self.3 * other.2,
            self.2 * other.1 + self.3 * other.3,
        )
    }
}

impl Mul<Move> for Rotation {
    type Output = Move;

    #[inline]
    fn mul(self, other: Move) -> Move {
        Move(
            self.0 * other.0 + self.1 * other.1,
            self.2 * other.0 + self.3 * other.1,
        )
    }
}

/// An ID identifying a cell in lattice rectangle.
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct CellId(usize);

/// An ID being given to cells on outside the rectangle.
pub const CELL_ID_OUTSIDE: CellId = CellId(0);

impl CellId {
    /// Creates a new `CellId` from an ID.
    #[inline]
    pub fn new(id: usize) -> CellId {
        CellId(id)
    }

    /// Gets an ID of the cell.
    #[inline]
    pub fn id(self) -> usize {
        self.0
    }

    /// Returns if the cell is on outside of the rectangle.
    #[inline]
    pub fn is_outside(self) -> bool {
        self == CELL_ID_OUTSIDE
    }
}

/// A representative `Point` of points on outside the rectangle.
const OUTSIDE_POINT: Point = Point(-1, -1);

/// A rectangle area.
pub trait Geom {
    /// Returns the rectangle's size.
    fn size(&self) -> Size;

    /// Returns the number of the rectangle's rows.
    #[inline]
    fn row(&self) -> i32 {
        self.size().0
    }

    /// Returns the number of the rectangle's columns.
    #[inline]
    fn column(&self) -> i32 {
        self.size().1
    }

    /// Returns the cell length which is contained in the rectangle.
    #[inline]
    fn cell_len(&self) -> usize {
        (self.row() * self.column() + 1) as usize
    }

    /// Returns true if the point is contained in the rectangle.
    #[inline]
    fn contains(&self, p: Point) -> bool {
        let size = self.size();
        0 <= p.0 && p.0 < size.0 && 0 <= p.1 && p.1 < size.1
    }

    /// Convert a point to a corresponding cell ID.
    #[inline]
    fn point_to_cellid(&self, p: Point) -> CellId {
        if self.contains(p) {
            CellId::new((p.0 * self.column() + p.1 + 1) as usize)
        } else {
            CELL_ID_OUTSIDE
        }
    }

    /// Convert a cell ID to a corresponding point.
    #[inline]
    fn cellid_to_point(&self, id: CellId) -> Point {
        if id.is_outside() {
            OUTSIDE_POINT
        } else {
            let idx = id.id() - 1;
            Point((idx as i32) / self.column(), (idx as i32) % self.column())
        }
    }

    /// Returns an iterator iterating all points.
    #[inline]
    fn points(&self) -> Points {
        if self.row() > 0 && self.column() > 0 {
            Points {
                point: Some(Point(0, 0)),
                size: self.size(),
            }
        } else {
            Points {
                point: None,
                size: self.size(),
            }
        }
    }

    /// Returns an iterator iterating all points in the row.
    #[inline]
    fn points_in_row(&self, row: i32) -> PointsInRow {
        PointsInRow {
            row: row,
            columns: 0..self.column(),
        }
    }

    /// Returns an iterator iterating all points in the column.
    #[inline]
    fn points_in_column(&self, column: i32) -> PointsInColumn {
        PointsInColumn {
            column: column,
            rows: 0..self.row(),
        }
    }
}

/// An iterator iterating all points in the rectangle.
#[derive(Copy, Clone, Debug)]
pub struct Points {
    point: Option<Point>,
    size: Size,
}

impl Iterator for Points {
    type Item = Point;

    #[inline]
    fn next(&mut self) -> Option<Point> {
        if let Some(cur) = self.point {
            let mut next = cur;
            let mut end = false;
            next.1 += 1;
            if next.1 >= self.size.1 {
                next.0 += 1;
                next.1 = 0;
                if next.0 >= self.size.0 {
                    end = true;
                }
            }
            if !end {
                self.point = Some(next);
            } else {
                self.point = None;
            }
            return Some(cur);
        }
        None
    }
}

/// An iterator iterating all points in a row of the rectangle.
#[derive(Clone, Debug)]
pub struct PointsInRow {
    row: i32,
    columns: Range<i32>,
}

impl Iterator for PointsInRow {
    type Item = Point;

    #[inline]
    fn next(&mut self) -> Option<Point> {
        if let Some(c) = self.columns.next() {
            Some(Point(self.row, c))
        } else {
            None
        }
    }
}

/// An iterator iterating all points in a column of the rectangle.
#[derive(Clone, Debug)]
pub struct PointsInColumn {
    rows: Range<i32>,
    column: i32,
}

impl Iterator for PointsInColumn {
    type Item = Point;

    #[inline]
    fn next(&mut self) -> Option<Point> {
        if let Some(r) = self.rows.next() {
            Some(Point(r, self.column))
        } else {
            None
        }
    }
}

/// A table that stores values for each cells.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Table<T> {
    size: Size,
    data: Vec<T>,
}

impl<T> Table<T> {
    /// Creates a new table with data.
    #[inline]
    pub fn new(size: Size, outside: T, mut data: Vec<T>) -> Table<T> {
        assert_eq!((size.0 * size.1) as usize, data.len());
        data.insert(0, outside);
        Table {
            size: size,
            data: data,
        }
    }

    /// Creates a new empty table.
    #[inline]
    pub fn new_empty(size: Size, outside: T, init: T) -> Table<T>
    where
        T: Clone,
    {
        let data = vec![init; (size.0 * size.1) as usize];
        Table::new(size, outside, data)
    }
}

impl<T> Geom for Table<T> {
    #[inline]
    fn size(&self) -> Size {
        self.size
    }
}

impl<T> Index<Point> for Table<T> {
    type Output = T;

    #[inline]
    fn index(&self, p: Point) -> &T {
        let idx = self.point_to_cellid(p).id();
        &self.data[idx]
    }
}

impl<T> IndexMut<Point> for Table<T> {
    #[inline]
    fn index_mut(&mut self, p: Point) -> &mut T {
        let idx = self.point_to_cellid(p).id();
        &mut self.data[idx]
    }
}

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

    struct Rect(Size);
    impl Geom for Rect {
        fn size(&self) -> Size {
            self.0
        }
    }

    #[test]
    fn points() {
        let pts = [
            Point(0, 0),
            Point(0, 1),
            Point(0, 2),
            Point(1, 0),
            Point(1, 1),
            Point(1, 2),
            Point(2, 0),
            Point(2, 1),
            Point(2, 2),
            Point(3, 0),
            Point(3, 1),
            Point(3, 2),
        ];
        let rect = Rect(Size(4, 3));
        assert_eq!(&pts[..], &rect.points().collect::<Vec<_>>()[..]);
    }

    #[test]
    fn rotate_mat() {
        let mat = [ROT_CCW0, ROT_CCW90, ROT_CCW180, ROT_CCW270];
        for i in 0..mat.len() {
            for j in 0..mat.len() {
                assert_eq!(mat[(i + j) % mat.len()], mat[i] * mat[j]);
            }
        }
    }

    #[test]
    fn rotate_point() {
        let mat = [ROT_CCW0, ROT_CCW90, ROT_CCW180, ROT_CCW270];
        let vec = [
            [MOVE_UP, MOVE_LEFT, MOVE_DOWN, MOVE_RIGHT],
            [
                MOVE_UP + MOVE_RIGHT,
                MOVE_LEFT + MOVE_UP,
                MOVE_DOWN + MOVE_LEFT,
                MOVE_RIGHT + MOVE_DOWN,
            ],
        ];
        for i in 0..mat.len() {
            for v in &vec {
                for j in 0..v.len() {
                    assert_eq!(v[(i + j) % v.len()], mat[i] * v[j]);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! This crate is a reimplementation
//! of GNU gettext translation framework in Rust.
//! It allows your Rust programs to parse out GNU MO files
//! containing translations and use them in your user interface.
//!
//! It contains several differences from the official C implementation.
//! Notably, this crate does not in any way depend on a global locale
//! ([2.2](https://www.gnu.org/software/gettext/manual/gettext.html#Setting-the-GUI-Locale))
//! and does not enforce a directory structure
//! for storing your translation catalogs
//! ([11.2.3](https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs)).
//! Instead, the choice of translation catalog to use is explicitly made by the user.
//!
//! This crate is still in-progress
//! and may not be on par with the original implementation feature-wise.
//!
//! For the exact feature parity see the roadmap in the
//! [README](https://github.com/justinas/gettext#readme).
//!
//! # Example
//!
//! ```ignore
//!
//! use std::fs::File;
//! use gettext::Catalog;
//!
//! fn main() {
//!     let f = File::open("french.mo").expect("could not open the catalog");
//!     let catalog = Catalog::parse(f).expect("could not parse the catalog");
//!
//!     // Will print out the French translation
//!     // if it is found in the parsed file
//!     // or "Name" otherwise.
//!     println!("{}", catalog.gettext("Name"));
//! }
//! ```

#![warn(clippy::all)]
// https://pascalhertleif.de/artikel/good-practices-for-writing-rust-libraries/
#![deny(
    missing_docs,
    missing_debug_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unused_import_braces
)]

mod error;
mod metadata;
mod parser;
mod plurals;

use std::collections::HashMap;
use std::io::Read;
use std::ops::Deref;

use crate::parser::default_resolver;
use crate::plurals::*;
pub use crate::{error::Error, parser::ParseOptions};

fn key_with_context(context: &str, key: &str) -> String {
    let mut result = context.to_owned();
    result.push('\x04');
    result.push_str(key);
    result
}

/// Catalog represents a set of translation strings
/// parsed out of one MO file.
#[derive(Clone, Debug)]
pub struct Catalog {
    strings: HashMap<String, Message>,
    resolver: Resolver,
}

impl Catalog {
    /// Creates an empty catalog.
    ///
    /// All the translated strings will be the same as the original ones.
    pub fn empty() -> Self {
        Self::new()
    }

    /// Creates a new, empty gettext catalog.
    fn new() -> Self {
        Catalog {
            strings: HashMap::new(),
            resolver: Resolver::Function(default_resolver),
        }
    }

    /// Parses a gettext catalog from the given binary MO file.
    /// Returns the `Err` variant upon encountering an invalid file format
    /// or invalid byte sequence in strings.
    ///
    /// Calling this method is equivalent to calling
    /// `ParseOptions::new().parse(reader)`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use gettext::Catalog;
    /// use std::fs::File;
    ///
    /// let file = File::open("french.mo").unwrap();
    /// let catalog = Catalog::parse(file).unwrap();
    /// ```
    pub fn parse<R: Read>(reader: R) -> Result<Self, Error> {
        ParseOptions::new().parse(reader)
    }

    fn insert(&mut self, msg: Message) {
        let key = match msg.context {
            Some(ref ctxt) => key_with_context(ctxt, &msg.id),
            None => msg.id.clone(),
        };
        self.strings.insert(key, msg);
    }

    /// Returns the singular translation of `msg_id` from the given catalog
    /// or `msg_id` itself if a translation does not exist.
    pub fn gettext<'a>(&'a self, msg_id: &'a str) -> &'a str {
        self.strings
            .get(msg_id)
            .and_then(|msg| msg.get_translated(0))
            .unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id` from the given catalog
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    pub fn ngettext<'a>(&'a self, msg_id: &'a str, msg_id_plural: &'a str, n: u64) -> &'a str {
        let form_no = self.resolver.resolve(n);
        let message = self.strings.get(msg_id);
        match message.and_then(|m| m.get_translated(form_no)) {
            Some(msg) => msg,
            None if n == 1 => msg_id,
            None if n != 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }

    /// Returns the singular translation of `msg_id`
    /// in the context `msg_context`
    /// or `msg_id` itself if a translation does not exist.
    // TODO: DRY gettext/pgettext
    pub fn pgettext<'a>(&'a self, msg_context: &'a str, msg_id: &'a str) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        self.strings
            .get(&key)
            .and_then(|msg| msg.get_translated(0))
            .unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id`
    /// in the context `msg_context`
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    // TODO: DRY ngettext/npgettext
    pub fn npgettext<'a>(
        &'a self,
        msg_context: &'a str,
        msg_id: &'a str,
        msg_id_plural: &'a str,
        n: u64,
    ) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        let form_no = self.resolver.resolve(n);
        let message = self.strings.get(&key);
        match message.and_then(|m| m.get_translated(form_no)) {
            Some(msg) => msg,
            None if n == 1 => msg_id,
            None if n != 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct Message {
    id: String,
    context: Option<String>,
    translated: Vec<String>,
}

impl Message {
    fn new<T: Into<String>>(id: T, context: Option<T>, translated: Vec<T>) -> Self {
        Message {
            id: id.into(),
            context: context.map(Into::into),
            translated: translated.into_iter().map(Into::into).collect(),
        }
    }

    fn get_translated(&self, form_no: usize) -> Option<&str> {
        self.translated.get(form_no).map(|s| s.deref())
    }
}

#[test]
fn catalog_impls_send_sync() {
    fn check<T: Send + Sync>(_: T) {};
    check(Catalog::new());
}

#[test]
fn catalog_insert() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("thisisid", None, vec![]));
    cat.insert(Message::new("anotherid", Some("context"), vec![]));
    let mut keys = cat.strings.keys().collect::<Vec<_>>();
    keys.sort();
    assert_eq!(keys, &["context\x04anotherid", "thisisid"])
}

#[test]
fn catalog_gettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas"]));
    cat.insert(Message::new("Image", Some("context"), vec!["Paveikslelis"]));
    assert_eq!(cat.gettext("Text"), "Tekstas");
    assert_eq!(cat.gettext("Image"), "Image");
}

#[test]
fn catalog_ngettext() {
    let mut cat = Catalog::new();
    {
        // n == 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Text");
        // n != 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Texts");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
    }
    {
        cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
        // n == 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstas");
        // n != 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstai");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Tekstai");
    }
}

#[test]
fn catalog_ngettext_not_enough_forms_in_message() {
    fn resolver(count: u64) -> usize {
        count as usize
    }

    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
    cat.resolver = Resolver::Function(resolver);
    assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstas");
    assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstai");
    assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
}

#[test]
fn catalog_npgettext_not_enough_forms_in_message() {
    fn resolver(count: u64) -> usize {
        count as usize
    }

    let mut cat = Catalog::new();
    cat.insert(Message::new(
        "Text",
        Some("ctx"),
        vec!["Tekstas", "Tekstai"],
    ));
    cat.resolver = Resolver::Function(resolver);
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 0), "Tekstas");
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 1), "Tekstai");
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 2), "Texts");
}

#[test]
fn catalog_pgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas"]));
    assert_eq!(cat.pgettext("unit test", "Text"), "Tekstas");
    assert_eq!(cat.pgettext("integration test", "Text"), "Text");
}

#[test]
fn catalog_npgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new(
        "Text",
        Some("unit test"),
        vec!["Tekstas", "Tekstai"],
    ));

    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 1), "Tekstas");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 0), "Tekstai");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 2), "Tekstai");

    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 1),
        "Text"
    );
    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 0),
        "Texts"
    );
    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 2),
        "Texts"
    );
}
<commit_msg>Remove explicit lifetimes where unnecessary<commit_after>//! This crate is a reimplementation
//! of GNU gettext translation framework in Rust.
//! It allows your Rust programs to parse out GNU MO files
//! containing translations and use them in your user interface.
//!
//! It contains several differences from the official C implementation.
//! Notably, this crate does not in any way depend on a global locale
//! ([2.2](https://www.gnu.org/software/gettext/manual/gettext.html#Setting-the-GUI-Locale))
//! and does not enforce a directory structure
//! for storing your translation catalogs
//! ([11.2.3](https://www.gnu.org/software/gettext/manual/gettext.html#Locating-Catalogs)).
//! Instead, the choice of translation catalog to use is explicitly made by the user.
//!
//! This crate is still in-progress
//! and may not be on par with the original implementation feature-wise.
//!
//! For the exact feature parity see the roadmap in the
//! [README](https://github.com/justinas/gettext#readme).
//!
//! # Example
//!
//! ```ignore
//!
//! use std::fs::File;
//! use gettext::Catalog;
//!
//! fn main() {
//!     let f = File::open("french.mo").expect("could not open the catalog");
//!     let catalog = Catalog::parse(f).expect("could not parse the catalog");
//!
//!     // Will print out the French translation
//!     // if it is found in the parsed file
//!     // or "Name" otherwise.
//!     println!("{}", catalog.gettext("Name"));
//! }
//! ```

#![warn(clippy::all)]
// https://pascalhertleif.de/artikel/good-practices-for-writing-rust-libraries/
#![deny(
    missing_docs,
    missing_debug_implementations,
    trivial_casts,
    trivial_numeric_casts,
    unused_import_braces
)]

mod error;
mod metadata;
mod parser;
mod plurals;

use std::collections::HashMap;
use std::io::Read;
use std::ops::Deref;

use crate::parser::default_resolver;
use crate::plurals::*;
pub use crate::{error::Error, parser::ParseOptions};

fn key_with_context(context: &str, key: &str) -> String {
    let mut result = context.to_owned();
    result.push('\x04');
    result.push_str(key);
    result
}

/// Catalog represents a set of translation strings
/// parsed out of one MO file.
#[derive(Clone, Debug)]
pub struct Catalog {
    strings: HashMap<String, Message>,
    resolver: Resolver,
}

impl Catalog {
    /// Creates an empty catalog.
    ///
    /// All the translated strings will be the same as the original ones.
    pub fn empty() -> Self {
        Self::new()
    }

    /// Creates a new, empty gettext catalog.
    fn new() -> Self {
        Catalog {
            strings: HashMap::new(),
            resolver: Resolver::Function(default_resolver),
        }
    }

    /// Parses a gettext catalog from the given binary MO file.
    /// Returns the `Err` variant upon encountering an invalid file format
    /// or invalid byte sequence in strings.
    ///
    /// Calling this method is equivalent to calling
    /// `ParseOptions::new().parse(reader)`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use gettext::Catalog;
    /// use std::fs::File;
    ///
    /// let file = File::open("french.mo").unwrap();
    /// let catalog = Catalog::parse(file).unwrap();
    /// ```
    pub fn parse<R: Read>(reader: R) -> Result<Self, Error> {
        ParseOptions::new().parse(reader)
    }

    fn insert(&mut self, msg: Message) {
        let key = match msg.context {
            Some(ref ctxt) => key_with_context(ctxt, &msg.id),
            None => msg.id.clone(),
        };
        self.strings.insert(key, msg);
    }

    /// Returns the singular translation of `msg_id` from the given catalog
    /// or `msg_id` itself if a translation does not exist.
    pub fn gettext<'a>(&'a self, msg_id: &'a str) -> &'a str {
        self.strings
            .get(msg_id)
            .and_then(|msg| msg.get_translated(0))
            .unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id` from the given catalog
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    pub fn ngettext<'a>(&'a self, msg_id: &'a str, msg_id_plural: &'a str, n: u64) -> &'a str {
        let form_no = self.resolver.resolve(n);
        let message = self.strings.get(msg_id);
        match message.and_then(|m| m.get_translated(form_no)) {
            Some(msg) => msg,
            None if n == 1 => msg_id,
            None if n != 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }

    /// Returns the singular translation of `msg_id`
    /// in the context `msg_context`
    /// or `msg_id` itself if a translation does not exist.
    // TODO: DRY gettext/pgettext
    pub fn pgettext<'a>(&'a self, msg_context: &str, msg_id: &'a str) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        self.strings
            .get(&key)
            .and_then(|msg| msg.get_translated(0))
            .unwrap_or(msg_id)
    }

    /// Returns the plural translation of `msg_id`
    /// in the context `msg_context`
    /// with the correct plural form for the number `n` of objects.
    /// Returns msg_id if a translation does not exist and `n == 1`,
    /// msg_id_plural otherwise.
    // TODO: DRY ngettext/npgettext
    pub fn npgettext<'a>(
        &'a self,
        msg_context: &str,
        msg_id: &'a str,
        msg_id_plural: &'a str,
        n: u64,
    ) -> &'a str {
        let key = key_with_context(msg_context, &msg_id);
        let form_no = self.resolver.resolve(n);
        let message = self.strings.get(&key);
        match message.and_then(|m| m.get_translated(form_no)) {
            Some(msg) => msg,
            None if n == 1 => msg_id,
            None if n != 1 => msg_id_plural,
            _ => unreachable!(),
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct Message {
    id: String,
    context: Option<String>,
    translated: Vec<String>,
}

impl Message {
    fn new<T: Into<String>>(id: T, context: Option<T>, translated: Vec<T>) -> Self {
        Message {
            id: id.into(),
            context: context.map(Into::into),
            translated: translated.into_iter().map(Into::into).collect(),
        }
    }

    fn get_translated(&self, form_no: usize) -> Option<&str> {
        self.translated.get(form_no).map(|s| s.deref())
    }
}

#[test]
fn catalog_impls_send_sync() {
    fn check<T: Send + Sync>(_: T) {};
    check(Catalog::new());
}

#[test]
fn catalog_insert() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("thisisid", None, vec![]));
    cat.insert(Message::new("anotherid", Some("context"), vec![]));
    let mut keys = cat.strings.keys().collect::<Vec<_>>();
    keys.sort();
    assert_eq!(keys, &["context\x04anotherid", "thisisid"])
}

#[test]
fn catalog_gettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas"]));
    cat.insert(Message::new("Image", Some("context"), vec!["Paveikslelis"]));
    assert_eq!(cat.gettext("Text"), "Tekstas");
    assert_eq!(cat.gettext("Image"), "Image");
}

#[test]
fn catalog_ngettext() {
    let mut cat = Catalog::new();
    {
        // n == 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Text");
        // n != 1, no translation
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Texts");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
    }
    {
        cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
        // n == 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstas");
        // n != 1, translation available
        assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstai");
        assert_eq!(cat.ngettext("Text", "Texts", 2), "Tekstai");
    }
}

#[test]
fn catalog_ngettext_not_enough_forms_in_message() {
    fn resolver(count: u64) -> usize {
        count as usize
    }

    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", None, vec!["Tekstas", "Tekstai"]));
    cat.resolver = Resolver::Function(resolver);
    assert_eq!(cat.ngettext("Text", "Texts", 0), "Tekstas");
    assert_eq!(cat.ngettext("Text", "Texts", 1), "Tekstai");
    assert_eq!(cat.ngettext("Text", "Texts", 2), "Texts");
}

#[test]
fn catalog_npgettext_not_enough_forms_in_message() {
    fn resolver(count: u64) -> usize {
        count as usize
    }

    let mut cat = Catalog::new();
    cat.insert(Message::new(
        "Text",
        Some("ctx"),
        vec!["Tekstas", "Tekstai"],
    ));
    cat.resolver = Resolver::Function(resolver);
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 0), "Tekstas");
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 1), "Tekstai");
    assert_eq!(cat.npgettext("ctx", "Text", "Texts", 2), "Texts");
}

#[test]
fn catalog_pgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new("Text", Some("unit test"), vec!["Tekstas"]));
    assert_eq!(cat.pgettext("unit test", "Text"), "Tekstas");
    assert_eq!(cat.pgettext("integration test", "Text"), "Text");
}

#[test]
fn catalog_npgettext() {
    let mut cat = Catalog::new();
    cat.insert(Message::new(
        "Text",
        Some("unit test"),
        vec!["Tekstas", "Tekstai"],
    ));

    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 1), "Tekstas");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 0), "Tekstai");
    assert_eq!(cat.npgettext("unit test", "Text", "Texts", 2), "Tekstai");

    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 1),
        "Text"
    );
    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 0),
        "Texts"
    );
    assert_eq!(
        cat.npgettext("integration test", "Text", "Texts", 2),
        "Texts"
    );
}
<|endoftext|>


<commit_before>//! A parser for the [TGFF][1] (Task Graphs For Free) format.
//!
//! [1]: http://www.netlib.org/lapack/explore-html/d7/d2b/dgemm_8f.html

#![feature(macro_rules, if_let)]

use std::iter::Peekable;
use std::str::CharOffsets;

pub use content::Content;
pub use content::{Graph, Task, Arc, Deadline};
pub use content::{Table, Column};

mod content;

static READ_CAPACITY: uint = 20;

/// An outcome of parsing.
pub type Result<T> = std::result::Result<T, Error>;

/// A parsing error.
pub struct Error {
    /// The line on which the error occurred.
    pub line: uint,
    /// The description of the error.
    pub message: String,
}

struct Parser<'a> {
    line: uint,
    cursor: Peekable<(uint, char), CharOffsets<'a>>,
    content: Content,
}

/// Parse a string containing a TGFF file.
///
/// The input string is the content of a TGFF file generated by the `tgff`
/// command-line utility based on the corresponding TGFFOPT file.
pub fn parse(input: &str) -> Result<Content> {
    Parser::new(input).process()
}

macro_rules! raise(
    ($parser:expr, $($arg:tt)*) => (
        return Err(Error { line: $parser.line, message: format!($($arg)*) });
    );
)

macro_rules! some(
    ($parser:expr, $result:expr, $($arg:tt)*) => (
        match $result {
            Some(result) => result,
            None => raise!($parser, $($arg)*),
        }
    );
)

impl std::fmt::Show for Error {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(formatter, "{} on line {}", self.message, self.line)
    }
}

impl<'a> Parser<'a> {
    fn new(input: &'a str) -> Parser<'a> {
        Parser {
            line: 1,
            cursor: input.char_indices().peekable(),
            content: content::new(),
        }
    }

    fn process<'a>(&'a mut self) -> Result<Content> {
        loop {
            match self.peek() {
                Some('@') => try!(self.process_at()),
                Some(_) => raise!(self, "found an unknown statement"),
                None => break,
            }
        }
        Ok(std::mem::replace(&mut self.content, content::new()))
    }

    fn process_at(&mut self) -> Result<()> {
        try!(self.skip_char('@'));

        let name = try!(self.get_token());
        let number = try!(self.get_natural());

        if let Some('{') = self.peek() {
            self.process_block(name, number)
        } else {
            self.content.attributes.insert(name, number);
            Ok(())
        }
    }

    fn process_block(&mut self, name: String, id: uint) -> Result<()> {
        try!(self.skip_char('{'));
        if let Some('#') = self.peek() {
            try!(self.process_table(name, id));
        } else {
            try!(self.process_graph(name, id));
        }
        try!(self.skip_char('}'));
        Ok(())
    }

    fn process_graph(&mut self, name: String, id: uint) -> Result<()> {
        let mut graph = content::new_graph(name, id);

        loop {
            match self.read_token() {
                Some(ref token) => match token.as_slice() {
                    "TASK" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("TYPE"));
                        let kind = try!(self.get_natural());
                        graph.tasks.push(content::new_task(id, kind));
                    },
                    "ARC" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("FROM"));
                        let from = try!(self.get_id());
                        try!(self.skip_str("TO"));
                        let to = try!(self.get_id());
                        try!(self.skip_str("TYPE"));
                        let kind = try!(self.get_natural());
                        graph.arcs.push(content::new_arc(id, from, to, kind));
                    },
                    "HARD_DEADLINE" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("ON"));
                        let on = try!(self.get_id());
                        try!(self.skip_str("AT"));
                        let at = try!(self.get_natural());
                        graph.deadlines.push(content::new_deadline(id, on, at));
                    },
                    _ => {
                        let value = try!(self.get_natural());
                        graph.attributes.insert(token.clone(), value);
                    },
                },
                None => break,
            }
        }

        self.content.graphs.push(graph);
        Ok(())
    }

    fn process_table(&mut self, name: String, id: uint) -> Result<()> {
        let mut table = content::new_table(name, id);

        try!(self.skip_char('#'));

        let mut names = vec![];
        loop {
            match self.read_token() {
                Some(token) => names.push(token),
                None => break,
            }
        }
        for name in names.into_iter() {
            table.attributes.insert(name, try!(self.get_real()));
        }

        try!(self.skip_comment());
        try!(self.skip_char('#'));

        loop {
            match self.read_token() {
                Some(name) => table.columns.push(content::new_column(name)),
                None => break,
            }
        }
        let cols = table.columns.len();
        loop {
            match self.peek() {
                Some('}') | None => break,
                _ => {},
            }
            for i in range(0u, cols) {
                table.columns[i].data.push(try!(self.get_real()));
            }
        }

        self.content.tables.push(table);
        Ok(())
    }

    #[inline]
    fn peek(&mut self) -> Option<char> {
        match self.cursor.peek() {
            Some(&(_, c)) => Some(c),
            None => None,
        }
    }

    fn skip(&mut self, accept: |uint, char| -> bool) -> uint {
        let mut count = 0;

        loop {
            match self.peek() {
                Some(c) => {
                    if !accept(count, c) { break; }
                    self.next();
                    count += 1;
                },
                None => break,
            }
        }

        count
    }

    fn skip_char(&mut self, expected: char) -> Result<()> {
        match self.next() {
            Some(c) => {
                if c == expected {
                    self.skip_void();
                    return Ok(());
                }
            },
            None => {},
        }
        raise!(self, "expected `{}`", expected);
    }

    fn skip_str(&mut self, expected: &str) -> Result<()> {
        let len = expected.len();
        if self.skip(|i, c| i < len && c == expected.char_at(i)) != len {
            raise!(self, "expected `{}`", expected);
        }
        self.skip_void();
        Ok(())
    }

    #[inline]
    fn skip_void(&mut self) {
        self.skip(|_, c| c == ' ' || c == '\t' || c == '\n');
    }

    fn skip_comment(&mut self) -> Result<()> {
        if self.skip(|i, c| i == 0 && c == '#' || (i > 0) && c == '-') < 2 {
            raise!(self, "expected a comment line");
        }
        self.skip_void();
        Ok(())
    }

    fn read(&mut self, accept: |uint, char| -> bool) -> Option<String> {
        let mut result = std::string::String::with_capacity(READ_CAPACITY);
        let mut count = 0;

        loop {
            match self.peek() {
                Some(c) => {
                    if !accept(count, c) { break; }
                    result.push(c);
                    self.next();
                    count += 1;
                },
                None => break,
            }
        }

        if count == 0 {
            None
        } else {
            Some(result)
        }
    }

    fn read_token(&mut self) -> Option<String> {
        let result = self.read(|i, c| {
            match c {
                'A'...'Z' | 'a'...'z' if i == 0 => true,
                'A'...'Z' | 'a'...'z' | '_' | '0'...'9' if i > 0 => true,
                _ => false,
            }
        });
        self.skip_void();
        result
    }

    fn read_id(&mut self) -> Option<uint> {
        match self.read_token() {
            Some(ref token) => match token.as_slice().split('_').nth(1) {
                Some(id) => std::num::from_str_radix(id, 10),
                None => None,
            },
            None => None,
        }
    }

    fn read_natural(&mut self) -> Option<uint> {
        let result = match self.read(|_, c| c >= '0' && c <= '9') {
            Some(ref number) => std::num::from_str_radix(number.as_slice(), 10),
            None => None,
        };
        self.skip_void();
        result
    }

    fn read_real(&mut self) -> Option<f64> {
        let result = match self.read(|_, c| {
            match c {
                '+' | '-' | '.' | '0'...'9' | 'e' | 'E' => true,
                _ => false,
            }
        }) {
            Some(ref number) => from_str(number.as_slice()),
            None => None,
        };
        self.skip_void();
        result
    }

    fn get_token(&mut self) -> Result<String> {
        match self.read_token() {
            Some(token) => Ok(token),
            None => raise!(self, "expected a token"),
        }
    }

    fn get_id(&mut self) -> Result<uint> {
        match self.read_id() {
            Some(id) => Ok(id),
            None => raise!(self, "expected an id"),
        }
    }

    fn get_natural(&mut self) -> Result<uint> {
        match self.read_natural() {
            Some(number) => Ok(number),
            None => raise!(self, "expected a natural number"),
        }
    }

    fn get_real(&mut self) -> Result<f64> {
        match self.read_real() {
            Some(number) => Ok(number),
            None => raise!(self, "expected a real number"),
        }
    }
}

impl<'a> std::iter::Iterator<char> for Parser<'a> {
    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some((_, '\n')) => {
                self.line += 1;
                Some('\n')
            },
            Some((_, c)) => Some(c),
            None => None,
        }
    }
}

#[cfg(test)]
mod tests {
    macro_rules! assert_ok(
        ($result: expr) => (
            if let Err(err) = $result {
                assert!(false, "{}", err);
            }
        );
    )

    macro_rules! assert_error(
        ($result: expr) => (
            if let Ok(_) = $result {
                assert!(false, "expected an error");
            }
        );
    )

    macro_rules! parser(
        ($input:expr) => (super::Parser::new($input));
    )

    #[test]
    fn process_at() {
        assert_ok!(parser!("@abc 12").process_at());
        assert_error!(parser!("@ ").process_at());
        assert_error!(parser!("@abc").process_at());
    }

    #[test]
    fn process_block() {
        assert_ok!(parser!("{}").process_block(String::new(), 0));
    }

    #[test]
    fn process_graph() {
        let mut parser = parser!("TASK t0_0\tTYPE 2   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref task = parser.content.graphs[0].tasks[0];
            assert_eq!(task.id, 0);
            assert_eq!(task.kind, 2);
        }

        parser = parser!("ARC a0_42 \tFROM t0_0  TO  t0_1 TYPE 35   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref arc = parser.content.graphs[0].arcs[0];
            assert_eq!(arc.id, 42);
            assert_eq!(arc.from, 0);
            assert_eq!(arc.to, 1);
            assert_eq!(arc.kind, 35);
        }

        parser = parser!("HARD_DEADLINE d0_9 ON t0_12 AT 1000   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref deadline = parser.content.graphs[0].deadlines[0];
            assert_eq!(deadline.id, 9);
            assert_eq!(deadline.on, 12);
            assert_eq!(deadline.at, 1000);
        }
    }

    #[test]
    fn process_table() {
        let mut parser = parser!("# foo\n 70.07\n#--\n# bar baz\n1 2 3 4 ");
        assert_ok!(parser.process_table(String::new(), 0));
        let ref table = parser.content.tables[0];
        assert_eq!(table.attributes["foo".to_string()], 70.07);
        assert_eq!(table.columns[0].name, "bar".to_string());
        assert_eq!(table.columns[1].name, "baz".to_string());
        assert_eq!(table.columns[0].data, vec![1.0, 3.0]);
        assert_eq!(table.columns[1].data, vec![2.0, 4.0]);
    }

    #[test]
    fn skip_char() {
        let mut parser = parser!("#  \t\n  abc");
        assert_ok!(parser.skip_char('#'));
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn skip_str() {
        let mut parser = parser!("abc  \t\n  xyz");
        assert_ok!(parser.skip_str("abc"));
        assert_eq!(parser.next().unwrap(), 'x');
    }

    #[test]
    fn skip_void() {
        let mut parser = parser!("  \t  abc");
        parser.skip_void();
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn skip_comment() {
        let mut parser = parser!("#--------------   \n abc");
        assert_ok!(parser.skip_comment());
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn get_token() {
        macro_rules! test(
            ($input:expr, $output:expr) => (
                assert_eq!(parser!($input).get_token().unwrap(),
                           String::from_str($output))
            );
        )
        test!("AZ xyz", "AZ");
        test!("az xyz", "az");
        test!("AZ_az_09 xyz", "AZ_az_09");
    }

    #[test]
    fn get_id() {
        assert_eq!(parser!("t0_42").get_id().unwrap(), 42);
    }

    #[test]
    fn get_natural() {
        assert_eq!(parser!("09").get_natural().unwrap(), 9);
    }

    #[test]
    fn get_real() {
        macro_rules! test(
            ($input:expr, $output:expr) => (
                assert_eq!(parser!($input).get_real().unwrap(), $output)
            );
        )
        test!("-1", -1.0);
        test!("0.1", 0.1);
        test!("1.2e3", 1.2e3);
        test!("1.2e+3", 1.2e3);
        test!("-1.2e-3", -1.2e-3);
    }
}
<commit_msg>Removed a deprecation<commit_after>//! A parser for the [TGFF][1] (Task Graphs For Free) format.
//!
//! [1]: http://www.netlib.org/lapack/explore-html/d7/d2b/dgemm_8f.html

#![feature(macro_rules)]

use std::iter::Peekable;
use std::str::CharOffsets;

pub use content::Content;
pub use content::{Graph, Task, Arc, Deadline};
pub use content::{Table, Column};

mod content;

static READ_CAPACITY: uint = 20;

/// An outcome of parsing.
pub type Result<T> = std::result::Result<T, Error>;

/// A parsing error.
pub struct Error {
    /// The line on which the error occurred.
    pub line: uint,
    /// The description of the error.
    pub message: String,
}

struct Parser<'a> {
    line: uint,
    cursor: Peekable<(uint, char), CharOffsets<'a>>,
    content: Content,
}

/// Parse a string containing a TGFF file.
///
/// The input string is the content of a TGFF file generated by the `tgff`
/// command-line utility based on the corresponding TGFFOPT file.
pub fn parse(input: &str) -> Result<Content> {
    Parser::new(input).process()
}

macro_rules! raise(
    ($parser:expr, $($arg:tt)*) => (
        return Err(Error { line: $parser.line, message: format!($($arg)*) });
    );
)

macro_rules! some(
    ($parser:expr, $result:expr, $($arg:tt)*) => (
        match $result {
            Some(result) => result,
            None => raise!($parser, $($arg)*),
        }
    );
)

impl std::fmt::Show for Error {
    fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(formatter, "{} on line {}", self.message, self.line)
    }
}

impl<'a> Parser<'a> {
    fn new(input: &'a str) -> Parser<'a> {
        Parser {
            line: 1,
            cursor: input.char_indices().peekable(),
            content: content::new(),
        }
    }

    fn process<'a>(&'a mut self) -> Result<Content> {
        loop {
            match self.peek() {
                Some('@') => try!(self.process_at()),
                Some(_) => raise!(self, "found an unknown statement"),
                None => break,
            }
        }
        Ok(std::mem::replace(&mut self.content, content::new()))
    }

    fn process_at(&mut self) -> Result<()> {
        try!(self.skip_char('@'));

        let name = try!(self.get_token());
        let number = try!(self.get_natural());

        if let Some('{') = self.peek() {
            self.process_block(name, number)
        } else {
            self.content.attributes.insert(name, number);
            Ok(())
        }
    }

    fn process_block(&mut self, name: String, id: uint) -> Result<()> {
        try!(self.skip_char('{'));
        if let Some('#') = self.peek() {
            try!(self.process_table(name, id));
        } else {
            try!(self.process_graph(name, id));
        }
        try!(self.skip_char('}'));
        Ok(())
    }

    fn process_graph(&mut self, name: String, id: uint) -> Result<()> {
        let mut graph = content::new_graph(name, id);

        loop {
            match self.read_token() {
                Some(ref token) => match token.as_slice() {
                    "TASK" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("TYPE"));
                        let kind = try!(self.get_natural());
                        graph.tasks.push(content::new_task(id, kind));
                    },
                    "ARC" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("FROM"));
                        let from = try!(self.get_id());
                        try!(self.skip_str("TO"));
                        let to = try!(self.get_id());
                        try!(self.skip_str("TYPE"));
                        let kind = try!(self.get_natural());
                        graph.arcs.push(content::new_arc(id, from, to, kind));
                    },
                    "HARD_DEADLINE" => {
                        let id = try!(self.get_id());
                        try!(self.skip_str("ON"));
                        let on = try!(self.get_id());
                        try!(self.skip_str("AT"));
                        let at = try!(self.get_natural());
                        graph.deadlines.push(content::new_deadline(id, on, at));
                    },
                    _ => {
                        let value = try!(self.get_natural());
                        graph.attributes.insert(token.clone(), value);
                    },
                },
                None => break,
            }
        }

        self.content.graphs.push(graph);
        Ok(())
    }

    fn process_table(&mut self, name: String, id: uint) -> Result<()> {
        let mut table = content::new_table(name, id);

        try!(self.skip_char('#'));

        let mut names = vec![];
        loop {
            match self.read_token() {
                Some(token) => names.push(token),
                None => break,
            }
        }
        for name in names.into_iter() {
            table.attributes.insert(name, try!(self.get_real()));
        }

        try!(self.skip_comment());
        try!(self.skip_char('#'));

        loop {
            match self.read_token() {
                Some(name) => table.columns.push(content::new_column(name)),
                None => break,
            }
        }
        let cols = table.columns.len();
        loop {
            match self.peek() {
                Some('}') | None => break,
                _ => {},
            }
            for i in range(0u, cols) {
                table.columns[i].data.push(try!(self.get_real()));
            }
        }

        self.content.tables.push(table);
        Ok(())
    }

    #[inline]
    fn peek(&mut self) -> Option<char> {
        match self.cursor.peek() {
            Some(&(_, c)) => Some(c),
            None => None,
        }
    }

    fn skip(&mut self, accept: |uint, char| -> bool) -> uint {
        let mut count = 0;

        loop {
            match self.peek() {
                Some(c) => {
                    if !accept(count, c) { break; }
                    self.next();
                    count += 1;
                },
                None => break,
            }
        }

        count
    }

    fn skip_char(&mut self, expected: char) -> Result<()> {
        match self.next() {
            Some(c) => {
                if c == expected {
                    self.skip_void();
                    return Ok(());
                }
            },
            None => {},
        }
        raise!(self, "expected `{}`", expected);
    }

    fn skip_str(&mut self, expected: &str) -> Result<()> {
        let len = expected.len();
        if self.skip(|i, c| i < len && c == expected.char_at(i)) != len {
            raise!(self, "expected `{}`", expected);
        }
        self.skip_void();
        Ok(())
    }

    #[inline]
    fn skip_void(&mut self) {
        self.skip(|_, c| c == ' ' || c == '\t' || c == '\n');
    }

    fn skip_comment(&mut self) -> Result<()> {
        if self.skip(|i, c| i == 0 && c == '#' || (i > 0) && c == '-') < 2 {
            raise!(self, "expected a comment line");
        }
        self.skip_void();
        Ok(())
    }

    fn read(&mut self, accept: |uint, char| -> bool) -> Option<String> {
        let mut result = std::string::String::with_capacity(READ_CAPACITY);
        let mut count = 0;

        loop {
            match self.peek() {
                Some(c) => {
                    if !accept(count, c) { break; }
                    result.push(c);
                    self.next();
                    count += 1;
                },
                None => break,
            }
        }

        if count == 0 {
            None
        } else {
            Some(result)
        }
    }

    fn read_token(&mut self) -> Option<String> {
        let result = self.read(|i, c| {
            match c {
                'A'...'Z' | 'a'...'z' if i == 0 => true,
                'A'...'Z' | 'a'...'z' | '_' | '0'...'9' if i > 0 => true,
                _ => false,
            }
        });
        self.skip_void();
        result
    }

    fn read_id(&mut self) -> Option<uint> {
        match self.read_token() {
            Some(ref token) => match token.as_slice().split('_').nth(1) {
                Some(id) => std::num::from_str_radix(id, 10),
                None => None,
            },
            None => None,
        }
    }

    fn read_natural(&mut self) -> Option<uint> {
        let result = match self.read(|_, c| c >= '0' && c <= '9') {
            Some(ref number) => std::num::from_str_radix(number.as_slice(), 10),
            None => None,
        };
        self.skip_void();
        result
    }

    fn read_real(&mut self) -> Option<f64> {
        let result = match self.read(|_, c| {
            match c {
                '+' | '-' | '.' | '0'...'9' | 'e' | 'E' => true,
                _ => false,
            }
        }) {
            Some(ref number) => from_str(number.as_slice()),
            None => None,
        };
        self.skip_void();
        result
    }

    fn get_token(&mut self) -> Result<String> {
        match self.read_token() {
            Some(token) => Ok(token),
            None => raise!(self, "expected a token"),
        }
    }

    fn get_id(&mut self) -> Result<uint> {
        match self.read_id() {
            Some(id) => Ok(id),
            None => raise!(self, "expected an id"),
        }
    }

    fn get_natural(&mut self) -> Result<uint> {
        match self.read_natural() {
            Some(number) => Ok(number),
            None => raise!(self, "expected a natural number"),
        }
    }

    fn get_real(&mut self) -> Result<f64> {
        match self.read_real() {
            Some(number) => Ok(number),
            None => raise!(self, "expected a real number"),
        }
    }
}

impl<'a> std::iter::Iterator<char> for Parser<'a> {
    fn next(&mut self) -> Option<char> {
        match self.cursor.next() {
            Some((_, '\n')) => {
                self.line += 1;
                Some('\n')
            },
            Some((_, c)) => Some(c),
            None => None,
        }
    }
}

#[cfg(test)]
mod tests {
    macro_rules! assert_ok(
        ($result: expr) => (
            if let Err(err) = $result {
                assert!(false, "{}", err);
            }
        );
    )

    macro_rules! assert_error(
        ($result: expr) => (
            if let Ok(_) = $result {
                assert!(false, "expected an error");
            }
        );
    )

    macro_rules! parser(
        ($input:expr) => (super::Parser::new($input));
    )

    #[test]
    fn process_at() {
        assert_ok!(parser!("@abc 12").process_at());
        assert_error!(parser!("@ ").process_at());
        assert_error!(parser!("@abc").process_at());
    }

    #[test]
    fn process_block() {
        assert_ok!(parser!("{}").process_block(String::new(), 0));
    }

    #[test]
    fn process_graph() {
        let mut parser = parser!("TASK t0_0\tTYPE 2   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref task = parser.content.graphs[0].tasks[0];
            assert_eq!(task.id, 0);
            assert_eq!(task.kind, 2);
        }

        parser = parser!("ARC a0_42 \tFROM t0_0  TO  t0_1 TYPE 35   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref arc = parser.content.graphs[0].arcs[0];
            assert_eq!(arc.id, 42);
            assert_eq!(arc.from, 0);
            assert_eq!(arc.to, 1);
            assert_eq!(arc.kind, 35);
        }

        parser = parser!("HARD_DEADLINE d0_9 ON t0_12 AT 1000   ");
        assert_ok!(parser.process_graph(String::new(), 0));
        {
            let ref deadline = parser.content.graphs[0].deadlines[0];
            assert_eq!(deadline.id, 9);
            assert_eq!(deadline.on, 12);
            assert_eq!(deadline.at, 1000);
        }
    }

    #[test]
    fn process_table() {
        let mut parser = parser!("# foo\n 70.07\n#--\n# bar baz\n1 2 3 4 ");
        assert_ok!(parser.process_table(String::new(), 0));
        let ref table = parser.content.tables[0];
        assert_eq!(table.attributes["foo".to_string()], 70.07);
        assert_eq!(table.columns[0].name, "bar".to_string());
        assert_eq!(table.columns[1].name, "baz".to_string());
        assert_eq!(table.columns[0].data, vec![1.0, 3.0]);
        assert_eq!(table.columns[1].data, vec![2.0, 4.0]);
    }

    #[test]
    fn skip_char() {
        let mut parser = parser!("#  \t\n  abc");
        assert_ok!(parser.skip_char('#'));
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn skip_str() {
        let mut parser = parser!("abc  \t\n  xyz");
        assert_ok!(parser.skip_str("abc"));
        assert_eq!(parser.next().unwrap(), 'x');
    }

    #[test]
    fn skip_void() {
        let mut parser = parser!("  \t  abc");
        parser.skip_void();
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn skip_comment() {
        let mut parser = parser!("#--------------   \n abc");
        assert_ok!(parser.skip_comment());
        assert_eq!(parser.next().unwrap(), 'a');
    }

    #[test]
    fn get_token() {
        macro_rules! test(
            ($input:expr, $output:expr) => (
                assert_eq!(parser!($input).get_token().unwrap(),
                           String::from_str($output))
            );
        )
        test!("AZ xyz", "AZ");
        test!("az xyz", "az");
        test!("AZ_az_09 xyz", "AZ_az_09");
    }

    #[test]
    fn get_id() {
        assert_eq!(parser!("t0_42").get_id().unwrap(), 42);
    }

    #[test]
    fn get_natural() {
        assert_eq!(parser!("09").get_natural().unwrap(), 9);
    }

    #[test]
    fn get_real() {
        macro_rules! test(
            ($input:expr, $output:expr) => (
                assert_eq!(parser!($input).get_real().unwrap(), $output)
            );
        )
        test!("-1", -1.0);
        test!("0.1", 0.1);
        test!("1.2e3", 1.2e3);
        test!("1.2e+3", 1.2e3);
        test!("-1.2e-3", -1.2e-3);
    }
}
<|endoftext|>


<commit_before>//extern crate libc;
//
//use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t};
//use std::mem;
//use std::ptr;

#[link(name = "isl")]
extern {
    //fn isl_ctx_alloc() -> Box<Ctx>;
    fn isl_ctx_alloc() -> *mut i64;
}

// safe wrapper
//fn getCtx() -> Box<Ctx>  {
fn getCtx() -> *mut i64  {
    unsafe {
        let ptr = isl_ctx_alloc();
        println!("ptr: {:?} {:?}", ptr, *ptr);
        ptr
    }
}

//isl_ctx *ctx = isl_ctx_alloc();

#[repr(C)]
#[derive(Clone, Copy)]
// TODO align with isl/include/isl/isl_ctx_private.h
struct Ctx {
    ref_: i32,
}

#[test]
fn it_works() {
    // see https://github.com/rust-lang/rust/issues/20204
    // used to have with boxed values: rust je_arena_dalloc_bin_locked
    let ctx = getCtx();
    unsafe {
      assert!((ctx as i64) != 0);
    }
}

fn main()
{
    let mut ptr = getCtx();
}
<commit_msg>do it right: use is_null() for ptr.<commit_after>//extern crate libc;
//
//use libc::{c_void, c_int, c_char, c_ulong, c_long, c_uint, c_uchar, size_t};
//use std::mem;
//use std::ptr;

#[link(name = "isl")]
extern {
    //fn isl_ctx_alloc() -> Box<Ctx>;
    fn isl_ctx_alloc() -> *mut i64;
}

// safe wrapper
//fn getCtx() -> Box<Ctx>  {
fn getCtx() -> *mut i64  {
    unsafe {
        let ptr = isl_ctx_alloc();
        println!("ptr: {:?} {:?}", ptr, *ptr);
        ptr
    }
}

#[repr(C)]
#[derive(Clone, Copy)]
// TODO align with isl/include/isl/isl_ctx_private.h
struct Ctx {
    ref_: i32,
}

#[test]
fn it_works() {
    // see https://github.com/rust-lang/rust/issues/20204
    // used to have with boxed values: rust je_arena_dalloc_bin_locked
    let ctx = getCtx();
    // see here for std::ptr https://doc.rust-lang.org/std/ptr/
    assert!(!ctx.is_null())
}

fn main()
{
    let mut ptr = getCtx();
}
<|endoftext|>


<commit_before>//! Rust friendly bindings to the various *nix system functions.
//!
//! Modules are structured according to the C header file that they would be
//! defined in.
#![crate_name = "nix"]
#![cfg(unix)]
#![allow(non_camel_case_types)]
// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
// warnings even though the macro expands into something with allow(dead_code)
#![allow(dead_code)]
#![deny(warnings)]

#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate cfg_if;
extern crate void;

#[cfg(test)]
extern crate nix_test as nixtest;

#[macro_use] mod macros;

// In rust 1.8+ this should be `pub extern crate libc` but prior
// to https://github.com/rust-lang/rust/issues/26775 being resolved
// it is necessary to get a little creative.
pub mod libc {
    extern crate libc;
    pub use self::libc::*;
}

pub use libc::{c_int, c_void};
pub use errno::Errno;

pub mod errno;
pub mod features;
pub mod fcntl;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod mount;

#[cfg(any(target_os = "linux"))]
pub mod mqueue;

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub mod poll;

pub mod net;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod sched;

pub mod sys;

// This can be implemented for other platforms as soon as libc
// provides bindings for them.
#[cfg(all(target_os = "linux",
          any(target_arch = "x86", target_arch = "x86_64")))]
pub mod ucontext;

pub mod unistd;

/*
 *
 * ===== Result / Error =====
 *
 */

use libc::c_char;
use std::{ptr, result};
use std::ffi::{CStr, OsStr};
use std::path::{Path, PathBuf};
use std::os::unix::ffi::OsStrExt;
use std::io;
use std::fmt;
use std::error;
use libc::PATH_MAX;

pub type Result<T> = result::Result<T, Error>;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Error {
    Sys(errno::Errno),
    InvalidPath,
}

impl Error {
    pub fn from_errno(errno: errno::Errno) -> Error {
        Error::Sys(errno)
    }

    pub fn last() -> Error {
        Error::Sys(errno::Errno::last())
    }

    pub fn invalid_argument() -> Error {
        Error::Sys(errno::EINVAL)
    }

    pub fn errno(&self) -> errno::Errno {
        match *self {
            Error::Sys(errno) => errno,
            Error::InvalidPath => errno::Errno::EINVAL,
        }
    }
}

impl From<errno::Errno> for Error {
    fn from(errno: errno::Errno) -> Error { Error::from_errno(errno) }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::InvalidPath => "Invalid path",
            &Error::Sys(ref errno) => errno.desc(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::InvalidPath => write!(f, "Invalid path"),
            &Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
        }
    }
}

impl From<Error> for io::Error {
    fn from(err: Error) -> Self {
        match err {
            Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err),
            Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32),
        }
    }
}

pub trait NixPath {
    fn len(&self) -> usize;

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T;
}

impl NixPath for str {
    fn len(&self) -> usize {
        NixPath::len(OsStr::new(self))
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T {
            OsStr::new(self).with_nix_path(f)
        }
}

impl NixPath for OsStr {
    fn len(&self) -> usize {
        self.as_bytes().len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T {
            self.as_bytes().with_nix_path(f)
        }
}

impl NixPath for CStr {
    fn len(&self) -> usize {
        self.to_bytes().len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&CStr) -> T {
        // Equivalence with the [u8] impl.
        if self.len() >= PATH_MAX as usize {
            return Err(Error::InvalidPath);
        }

        Ok(f(self))
    }
}

impl NixPath for [u8] {
    fn len(&self) -> usize {
        self.len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&CStr) -> T {
        let mut buf = [0u8; PATH_MAX as usize];

        if self.len() >= PATH_MAX as usize {
            return Err(Error::InvalidPath);
        }

        match self.iter().position(|b| *b == 0) {
            Some(_) => Err(Error::InvalidPath),
            None => {
                unsafe {
                    // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
                    ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
                    Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
                }

            }
        }
    }
}

impl NixPath for Path {
    fn len(&self) -> usize {
        NixPath::len(self.as_os_str())
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        self.as_os_str().with_nix_path(f)
    }
}

impl NixPath for PathBuf {
    fn len(&self) -> usize {
        NixPath::len(self.as_os_str())
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        self.as_os_str().with_nix_path(f)
    }
}

/// Treats `None` as an empty string.
impl<'a, NP: ?Sized + NixPath>  NixPath for Option<&'a NP> {
    fn len(&self) -> usize {
        self.map_or(0, NixPath::len)
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        if let Some(nix_path) = *self {
            nix_path.with_nix_path(f)
        } else {
            unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
        }
    }
}
<commit_msg>Auto merge of #376 - kamalmarhubi:warnings-in-test, r=utkarshkukreti<commit_after>//! Rust friendly bindings to the various *nix system functions.
//!
//! Modules are structured according to the C header file that they would be
//! defined in.
#![crate_name = "nix"]
#![cfg(unix)]
#![allow(non_camel_case_types)]
// latest bitflags triggers a rustc bug with cross-crate macro expansions causing dead_code
// warnings even though the macro expands into something with allow(dead_code)
#![allow(dead_code)]
#![cfg_attr(test, deny(warnings))]

#[macro_use]
extern crate bitflags;

#[macro_use]
extern crate cfg_if;
extern crate void;

#[cfg(test)]
extern crate nix_test as nixtest;

#[macro_use] mod macros;

// In rust 1.8+ this should be `pub extern crate libc` but prior
// to https://github.com/rust-lang/rust/issues/26775 being resolved
// it is necessary to get a little creative.
pub mod libc {
    extern crate libc;
    pub use self::libc::*;
}

pub use libc::{c_int, c_void};
pub use errno::Errno;

pub mod errno;
pub mod features;
pub mod fcntl;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod mount;

#[cfg(any(target_os = "linux"))]
pub mod mqueue;

#[cfg(any(target_os = "linux", target_os = "macos"))]
pub mod poll;

pub mod net;

#[cfg(any(target_os = "linux", target_os = "android"))]
pub mod sched;

pub mod sys;

// This can be implemented for other platforms as soon as libc
// provides bindings for them.
#[cfg(all(target_os = "linux",
          any(target_arch = "x86", target_arch = "x86_64")))]
pub mod ucontext;

pub mod unistd;

/*
 *
 * ===== Result / Error =====
 *
 */

use libc::c_char;
use std::{ptr, result};
use std::ffi::{CStr, OsStr};
use std::path::{Path, PathBuf};
use std::os::unix::ffi::OsStrExt;
use std::io;
use std::fmt;
use std::error;
use libc::PATH_MAX;

pub type Result<T> = result::Result<T, Error>;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Error {
    Sys(errno::Errno),
    InvalidPath,
}

impl Error {
    pub fn from_errno(errno: errno::Errno) -> Error {
        Error::Sys(errno)
    }

    pub fn last() -> Error {
        Error::Sys(errno::Errno::last())
    }

    pub fn invalid_argument() -> Error {
        Error::Sys(errno::EINVAL)
    }

    pub fn errno(&self) -> errno::Errno {
        match *self {
            Error::Sys(errno) => errno,
            Error::InvalidPath => errno::Errno::EINVAL,
        }
    }
}

impl From<errno::Errno> for Error {
    fn from(errno: errno::Errno) -> Error { Error::from_errno(errno) }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            &Error::InvalidPath => "Invalid path",
            &Error::Sys(ref errno) => errno.desc(),
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::InvalidPath => write!(f, "Invalid path"),
            &Error::Sys(errno) => write!(f, "{:?}: {}", errno, errno.desc()),
        }
    }
}

impl From<Error> for io::Error {
    fn from(err: Error) -> Self {
        match err {
            Error::InvalidPath => io::Error::new(io::ErrorKind::InvalidInput, err),
            Error::Sys(errno) => io::Error::from_raw_os_error(errno as i32),
        }
    }
}

pub trait NixPath {
    fn len(&self) -> usize;

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T;
}

impl NixPath for str {
    fn len(&self) -> usize {
        NixPath::len(OsStr::new(self))
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T {
            OsStr::new(self).with_nix_path(f)
        }
}

impl NixPath for OsStr {
    fn len(&self) -> usize {
        self.as_bytes().len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
        where F: FnOnce(&CStr) -> T {
            self.as_bytes().with_nix_path(f)
        }
}

impl NixPath for CStr {
    fn len(&self) -> usize {
        self.to_bytes().len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&CStr) -> T {
        // Equivalence with the [u8] impl.
        if self.len() >= PATH_MAX as usize {
            return Err(Error::InvalidPath);
        }

        Ok(f(self))
    }
}

impl NixPath for [u8] {
    fn len(&self) -> usize {
        self.len()
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T>
            where F: FnOnce(&CStr) -> T {
        let mut buf = [0u8; PATH_MAX as usize];

        if self.len() >= PATH_MAX as usize {
            return Err(Error::InvalidPath);
        }

        match self.iter().position(|b| *b == 0) {
            Some(_) => Err(Error::InvalidPath),
            None => {
                unsafe {
                    // TODO: Replace with bytes::copy_memory. rust-lang/rust#24028
                    ptr::copy_nonoverlapping(self.as_ptr(), buf.as_mut_ptr(), self.len());
                    Ok(f(CStr::from_ptr(buf.as_ptr() as *const c_char)))
                }

            }
        }
    }
}

impl NixPath for Path {
    fn len(&self) -> usize {
        NixPath::len(self.as_os_str())
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        self.as_os_str().with_nix_path(f)
    }
}

impl NixPath for PathBuf {
    fn len(&self) -> usize {
        NixPath::len(self.as_os_str())
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        self.as_os_str().with_nix_path(f)
    }
}

/// Treats `None` as an empty string.
impl<'a, NP: ?Sized + NixPath>  NixPath for Option<&'a NP> {
    fn len(&self) -> usize {
        self.map_or(0, NixPath::len)
    }

    fn with_nix_path<T, F>(&self, f: F) -> Result<T> where F: FnOnce(&CStr) -> T {
        if let Some(nix_path) = *self {
            nix_path.with_nix_path(f)
        } else {
            unsafe { CStr::from_ptr("\0".as_ptr() as *const _).with_nix_path(f) }
        }
    }
}
<|endoftext|>


<commit_before>#[derive(Debug, Clone, Copy)]
enum StateMachine {
    Normal,
    Separator,
    Text,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SplitFormat {
    Anime,
    Commands,
}

pub struct Splitter<'a> {
    start: usize,
    state: StateMachine,
    string: &'a str,
    fmt: SplitFormat,
}

impl<'a> Splitter<'a> {
    pub fn new(string: &'a str, fmt: SplitFormat) -> Splitter {
        Splitter {
            start: 0,
            state: StateMachine::Normal,
            string: string,
            fmt: fmt,
        }
    }

    fn anime_cycle(state: StateMachine, character: char) -> (StateMachine, Option<char>) {
        use self::StateMachine::*;

        match (state, character) {
            (Normal, '"') => (Text, None),
            (Normal, ' ') => (Separator, None),
            (Normal, _) => (Normal, Some(character)),
            (Separator, ' ') => (Separator, None),
            (Separator, '"') => (Text, None),
            (Separator, _) => (Normal, Some(character)),
            (Text, '"') => (Normal, None),
            (Text, _) => (Text, Some(character)),
        }
    }

    fn command_cycle(state: StateMachine, character: char) -> (StateMachine, Option<char>) {
        use self::StateMachine::*;

        match (state, character) {
            (Normal, '"') => (Text, None),
            (Normal, '/') => (Separator, None),
            (Normal, _) => (Normal, Some(character)),
            (Separator, '/') => (Separator, None),
            (Separator, '"') => (Text, None),
            (Separator, _) => (Normal, Some(character)),
            (Text, '"') => (Normal, None),
            (Text, _) => (Text, Some(character)),
        }
    }
}

impl<'a> Iterator for Splitter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        for (index, character) in self.string[self.start..].chars().enumerate() {
            let (new_state, new_char) = match self.fmt {
                SplitFormat::Anime => Splitter::anime_cycle(self.state, character),
                SplitFormat::Commands => Splitter::command_cycle(self.state, character),
            };
            let index = index + self.start;
            self.state = new_state;
            match (new_state, new_char) {
                (StateMachine::Separator, None) => {
                    let last_start = self.start;
                    self.start = index + 1;
                    if index - last_start > 0 {
                        return Some(&self.string[last_start..index]);
                    }
                }
                (StateMachine::Text, None) => self.start = index + 1,
                (StateMachine::Normal, None) => {
                    let result = &self.string[self.start..index - 1];
                    self.start = index + 1;
                    return Some(result);
                }
                _ => {}
            };
        }
        if self.start < self.string.len() {
            let result = &self.string[self.start..];
            self.start = self.string.len();
            Some(result)
        } else {
            None
        }
    }
}
<commit_msg>[fix] substr slicing<commit_after>#[derive(Debug, Clone, Copy)]
enum StateMachine {
    Normal,
    Separator,
    Text,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SplitFormat {
    Anime,
    Commands,
}

pub struct Splitter<'a> {
    start: usize,
    state: StateMachine,
    string: &'a str,
    fmt: SplitFormat,
}

impl<'a> Splitter<'a> {
    pub fn new(string: &'a str, fmt: SplitFormat) -> Splitter {
        Splitter {
            start: 0,
            state: StateMachine::Normal,
            string: string,
            fmt: fmt,
        }
    }

    fn anime_cycle(state: StateMachine, character: char) -> (StateMachine, Option<char>) {
        use self::StateMachine::*;

        match (state, character) {
            (Normal, '"') => (Text, None),
            (Normal, ' ') => (Separator, None),
            (Normal, _) => (Normal, Some(character)),
            (Separator, ' ') => (Separator, None),
            (Separator, '"') => (Text, None),
            (Separator, _) => (Normal, Some(character)),
            (Text, '"') => (Normal, None),
            (Text, _) => (Text, Some(character)),
        }
    }

    fn command_cycle(state: StateMachine, character: char) -> (StateMachine, Option<char>) {
        use self::StateMachine::*;

        match (state, character) {
            (Normal, '"') => (Text, None),
            (Normal, '/') => (Separator, None),
            (Normal, _) => (Normal, Some(character)),
            (Separator, '/') => (Separator, None),
            (Separator, '"') => (Text, None),
            (Separator, _) => (Normal, Some(character)),
            (Text, '"') => (Normal, None),
            (Text, _) => (Text, Some(character)),
        }
    }
}

impl<'a> Iterator for Splitter<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        fn substr(str: &str, start: usize, stop: usize) -> &str {
            let (s, _) = str.char_indices().nth(start).unwrap();
            let (e, _) = str.char_indices().nth(stop).unwrap();
            &str[s..e]
        }
        for (index, character) in self.string.chars().skip(self.start).enumerate() {
            let (new_state, new_char) = match self.fmt {
                SplitFormat::Anime => Splitter::anime_cycle(self.state, character),
                SplitFormat::Commands => Splitter::command_cycle(self.state, character),
            };
            let index = index + self.start;
            self.state = new_state;
            match (new_state, new_char) {
                (StateMachine::Separator, None) => {
                    let last_start = self.start;
                    self.start = index + 1;
                    if index - last_start > 0 {
                        return Some(substr(self.string, last_start, index))
                    }
                }
                (StateMachine::Text, None) => self.start = index + 1,
                (StateMachine::Normal, None) => {
                    let result = substr(self.string, self.start, index - 1);
                    self.start = index + 1;
                    return Some(result);
                }
                _ => {}
            };
        }
        if self.start < self.string.len() {
            let (s, _) = self.string.char_indices().nth(self.start).unwrap();
            self.start = self.string.len();
            Some(&self.string[s..])
        } else {
            None
        }
    }
}
<|endoftext|>