<commit_before>use core::ops;

#[cfg(all(feature = "libm-math", not(feature = "std")))]
use crate::nostd_float::FloatExt;

/// A point in 2-dimensional space, with each dimension of type `N`.
///
/// Legal operations on points are addition and subtraction by vectors, and
/// subtraction between points, to give a vector representing the offset between
/// the two points. Combined with the legal operations on vectors, meaningful
/// manipulations of vectors and points can be performed.
///
/// For example, to interpolate between two points by a factor `t`:
///
/// ```
/// # use rusttype::*;
/// # let t = 0.5; let p0 = point(0.0, 0.0); let p1 = point(0.0, 0.0);
/// let interpolated_point = p0 + (p1 - p0) * t;
/// ```
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Point<N> {
    pub x: N,
    pub y: N,
}

/// A vector in 2-dimensional space, with each dimension of type `N`.
///
/// Legal operations on vectors are addition and subtraction by vectors,
/// addition by points (to give points), and multiplication and division by
/// scalars.
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Vector<N> {
    pub x: N,
    pub y: N,
}
/// A convenience function for generating `Point`s.
#[inline]
pub fn point<N>(x: N, y: N) -> Point<N> {
    Point { x, y }
}
/// A convenience function for generating `Vector`s.
#[inline]
pub fn vector<N>(x: N, y: N) -> Vector<N> {
    Vector { x, y }
}

impl<N: ops::Sub<Output = N>> ops::Sub for Point<N> {
    type Output = Vector<N>;
    fn sub(self, rhs: Point<N>) -> Vector<N> {
        vector(self.x - rhs.x, self.y - rhs.y)
    }
}

impl<N: ops::Add<Output = N>> ops::Add for Vector<N> {
    type Output = Vector<N>;
    fn add(self, rhs: Vector<N>) -> Vector<N> {
        vector(self.x + rhs.x, self.y + rhs.y)
    }
}

impl<N: ops::Sub<Output = N>> ops::Sub for Vector<N> {
    type Output = Vector<N>;
    fn sub(self, rhs: Vector<N>) -> Vector<N> {
        vector(self.x - rhs.x, self.y - rhs.y)
    }
}

impl ops::Mul<f32> for Vector<f32> {
    type Output = Vector<f32>;
    fn mul(self, rhs: f32) -> Vector<f32> {
        vector(self.x * rhs, self.y * rhs)
    }
}

impl ops::Mul<Vector<f32>> for f32 {
    type Output = Vector<f32>;
    fn mul(self, rhs: Vector<f32>) -> Vector<f32> {
        vector(self * rhs.x, self * rhs.y)
    }
}

impl ops::Mul<f64> for Vector<f64> {
    type Output = Vector<f64>;
    fn mul(self, rhs: f64) -> Vector<f64> {
        vector(self.x * rhs, self.y * rhs)
    }
}

impl ops::Mul<Vector<f64>> for f64 {
    type Output = Vector<f64>;
    fn mul(self, rhs: Vector<f64>) -> Vector<f64> {
        vector(self * rhs.x, self * rhs.y)
    }
}

impl ops::Div<f32> for Vector<f32> {
    type Output = Vector<f32>;
    fn div(self, rhs: f32) -> Vector<f32> {
        vector(self.x / rhs, self.y / rhs)
    }
}

impl ops::Div<Vector<f32>> for f32 {
    type Output = Vector<f32>;
    fn div(self, rhs: Vector<f32>) -> Vector<f32> {
        vector(self / rhs.x, self / rhs.y)
    }
}

impl ops::Div<f64> for Vector<f64> {
    type Output = Vector<f64>;
    fn div(self, rhs: f64) -> Vector<f64> {
        vector(self.x / rhs, self.y / rhs)
    }
}

impl ops::Div<Vector<f64>> for f64 {
    type Output = Vector<f64>;
    fn div(self, rhs: Vector<f64>) -> Vector<f64> {
        vector(self / rhs.x, self / rhs.y)
    }
}

impl<N: ops::Add<Output = N>> ops::Add<Vector<N>> for Point<N> {
    type Output = Point<N>;
    fn add(self, rhs: Vector<N>) -> Point<N> {
        point(self.x + rhs.x, self.y + rhs.y)
    }
}

impl<N: ops::Sub<Output = N>> ops::Sub<Vector<N>> for Point<N> {
    type Output = Point<N>;
    fn sub(self, rhs: Vector<N>) -> Point<N> {
        point(self.x - rhs.x, self.y - rhs.y)
    }
}

impl<N: ops::Add<Output = N>> ops::Add<Point<N>> for Vector<N> {
    type Output = Point<N>;
    fn add(self, rhs: Point<N>) -> Point<N> {
        point(self.x + rhs.x, self.y + rhs.y)
    }
}

/// A straight line between two points, `p[0]` and `p[1]`
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Line {
    pub p: [Point<f32>; 2],
}
/// A quadratic Bezier curve, starting at `p[0]`, ending at `p[2]`, with control
/// point `p[1]`.
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub struct Curve {
    pub p: [Point<f32>; 3],
}
/// A rectangle, with top-left corner at `min`, and bottom-right corner at
/// `max`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Rect<N> {
    pub min: Point<N>,
    pub max: Point<N>,
}
impl<N: ops::Sub<Output = N> + Copy> Rect<N> {
    pub fn width(&self) -> N {
        self.max.x - self.min.x
    }
    pub fn height(&self) -> N {
        self.max.y - self.min.y
    }
}

pub trait BoundingBox<N> {
    fn bounding_box(&self) -> Rect<N> {
        let (min_x, max_x) = self.x_bounds();
        let (min_y, max_y) = self.y_bounds();
        Rect {
            min: point(min_x, min_y),
            max: point(max_x, max_y),
        }
    }
    fn x_bounds(&self) -> (N, N);
    fn y_bounds(&self) -> (N, N);
}

impl BoundingBox<f32> for Line {
    fn x_bounds(&self) -> (f32, f32) {
        let p = &self.p;
        if p[0].x < p[1].x {
            (p[0].x, p[1].x)
        } else {
            (p[1].x, p[0].x)
        }
    }
    fn y_bounds(&self) -> (f32, f32) {
        let p = &self.p;
        if p[0].y < p[1].y {
            (p[0].y, p[1].y)
        } else {
            (p[1].y, p[0].y)
        }
    }
}

impl BoundingBox<f32> for Curve {
    fn x_bounds(&self) -> (f32, f32) {
        let p = &self.p;
        if p[0].x <= p[1].x && p[1].x <= p[2].x {
            (p[0].x, p[2].x)
        } else if p[0].x >= p[1].x && p[1].x >= p[2].x {
            (p[2].x, p[0].x)
        } else {
            let t = (p[0].x - p[1].x) / (p[0].x - 2.0 * p[1].x + p[2].x);
            let _1mt = 1.0 - t;
            let inflection = _1mt * _1mt * p[0].x + 2.0 * _1mt * t * p[1].x + t * t * p[2].x;
            if p[1].x < p[0].x {
                (inflection, p[0].x.max(p[2].x))
            } else {
                (p[0].x.min(p[2].x), inflection)
            }
        }
    }

    fn y_bounds(&self) -> (f32, f32) {
        let p = &self.p;
        if p[0].y <= p[1].y && p[1].y <= p[2].y {
            (p[0].y, p[2].y)
        } else if p[0].y >= p[1].y && p[1].y >= p[2].y {
            (p[2].y, p[0].y)
        } else {
            let t = (p[0].y - p[1].y) / (p[0].y - 2.0 * p[1].y + p[2].y);
            let _1mt = 1.0 - t;
            let inflection = _1mt * _1mt * p[0].y + 2.0 * _1mt * t * p[1].y + t * t * p[2].y;
            if p[1].y < p[0].y {
                (inflection, p[0].y.max(p[2].y))
            } else {
                (p[0].y.min(p[2].y), inflection)
            }
        }
    }
}

pub trait Cut: Sized {
    fn cut_to(self, t: f32) -> Self;
    fn cut_from(self, t: f32) -> Self;
    fn cut_from_to(self, t0: f32, t1: f32) -> Self {
        self.cut_from(t0).cut_to((t1 - t0) / (1.0 - t0))
    }
}

impl Cut for Curve {
    fn cut_to(self, t: f32) -> Curve {
        let p = self.p;
        let a = p[0] + t * (p[1] - p[0]);
        let b = p[1] + t * (p[2] - p[1]);
        let c = a + t * (b - a);
        Curve { p: [p[0], a, c] }
    }
    fn cut_from(self, t: f32) -> Curve {
        let p = self.p;
        let a = p[0] + t * (p[1] - p[0]);
        let b = p[1] + t * (p[2] - p[1]);
        let c = a + t * (b - a);
        Curve { p: [c, b, p[2]] }
    }
}

impl Cut for Line {
    fn cut_to(self, t: f32) -> Line {
        let p = self.p;
        Line {
            p: [p[0], p[0] + t * (p[1] - p[0])],
        }
    }
    fn cut_from(self, t: f32) -> Line {
        let p = self.p;
        Line {
            p: [p[0] + t * (p[1] - p[0]), p[1]],
        }
    }
    fn cut_from_to(self, t0: f32, t1: f32) -> Line {
        let p = self.p;
        let v = p[1] - p[0];
        Line {
            p: [p[0] + t0 * v, p[0] + t1 * v],
        }
    }
}

/// The real valued solutions to a real quadratic equation.
#[derive(Copy, Clone, Debug)]
pub enum RealQuadraticSolution {
    /// Two zero-crossing solutions
    Two(f32, f32),
    /// One zero-crossing solution (equation is a straight line)
    One(f32),
    /// One zero-touching solution
    Touch(f32),
    /// No solutions
    None,
    /// All real numbers are solutions since a == b == c == 0.0
    All,
}

impl RealQuadraticSolution {
    /// If there are two solutions, this function ensures that they are in order
    /// (first < second)
    pub fn in_order(self) -> RealQuadraticSolution {
        use self::RealQuadraticSolution::*;
        match self {
            Two(x, y) => {
                if x < y {
                    Two(x, y)
                } else {
                    Two(y, x)
                }
            }
            other => other,
        }
    }
}

/// Solve a real quadratic equation, giving all real solutions, if any.
pub fn solve_quadratic_real(a: f32, b: f32, c: f32) -> RealQuadraticSolution {
    let discriminant = b * b - 4.0 * a * c;
    if discriminant > 0.0 {
        let sqrt_d = discriminant.sqrt();
        let common = -b + if b >= 0.0 { -sqrt_d } else { sqrt_d };
        let x1 = 2.0 * c / common;
        if a == 0.0 {
            RealQuadraticSolution::One(x1)
        } else {
            let x2 = common / (2.0 * a);
            RealQuadraticSolution::Two(x1, x2)
        }
    } else if discriminant < 0.0 {
        RealQuadraticSolution::None
    } else if b == 0.0 {
        if a == 0.0 {
            if c == 0.0 {
                RealQuadraticSolution::All
            } else {
                RealQuadraticSolution::None
            }
        } else {
            RealQuadraticSolution::Touch(0.0)
        }
    } else {
        RealQuadraticSolution::Touch(2.0 * c / -b)
    }
}

#[test]
fn quadratic_test() {
    solve_quadratic_real(-0.000_000_1, -2.0, 10.0);
}
<commit_msg>Implement Default for the geometry structs<commit_after>use core::ops;

#[cfg(all(feature = "libm-math", not(feature = "std")))]
use crate::nostd_float::FloatExt;

/// A point in 2-dimensional space, with each dimension of type `N`.
///
/// Legal operations on points are addition and subtraction by vectors, and
/// subtraction between points, to give a vector representing the offset between
/// the two points. Combined with the legal operations on vectors, meaningful
/// manipulations of vectors and points can be performed.
///
/// For example, to interpolate between two points by a factor `t`:
///
/// ```
/// # use rusttype::*;
/// # let t = 0.5; let p0 = point(0.0, 0.0); let p1 = point(0.0, 0.0);
/// let interpolated_point = p0 + (p1 - p0) * t;
/// ```
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Point<N> {
    pub x: N,
    pub y: N,
}

impl <N: Default> Default for Point<N> {
    fn default() -> Self {
        Point {
            x: N::default(),
            y: N::default()
        }
    }
}

/// A vector in 2-dimensional space, with each dimension of type `N`.
///
/// Legal operations on vectors are addition and subtraction by vectors,
/// addition by points (to give points), and multiplication and division by
/// scalars.
#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
pub struct Vector<N> {
    pub x: N,
    pub y: N,
}

impl <N: Default> Default for Vector<N> {
    fn default() -> Self {
        Vector {
            x: N::default(),
            y: N::default()
        }
    }
}

/// A convenience function for generating `Point`s.
#[inline]
pub fn point<N>(x: N, y: N) -> Point<N> {
    Point { x, y }
}
/// A convenience function for generating `Vector`s.
#[inline]
pub fn vector<N>(x: N, y: N) -> Vector<N> {
    Vector { x, y }
}

impl<N: ops::Sub<Output = N>> ops::Sub for Point<N> {
    type Output = Vector<N>;
    fn sub(self, rhs: Point<N>) -> Vector<N> {
        vector(self.x - rhs.x, self.y - rhs.y)
    }
}

impl<N: ops::Add<Output = N>> ops::Add for Vector<N> {
    type Output = Vector<N>;
    fn add(self, rhs: Vector<N>) -> Vector<N> {
        vector(self.x + rhs.x, self.y + rhs.y)
    }
}

impl<N: ops::Sub<Output = N>> ops::Sub for Vector<N> {
    type Output = Vector<N>;
    fn sub(self, rhs: Vector<N>) -> Vector<N> {
        vector(self.x - rhs.x, self.y - rhs.y)
    }
}

impl ops::Mul<f32> for Vector<f32> {
    type Output = Vector<f32>;
    fn mul(self, rhs: f32) -> Vector<f32> {
        vector(self.x * rhs, self.y * rhs)
    }
}

impl ops::Mul<Vector<f32>> for f32 {
    type Output = Vector<f32>;
    fn mul(self, rhs: Vector<f32>) -> Vector<f32> {
        vector(self * rhs.x, self * rhs.y)
    }
}

impl ops::Mul<f64> for Vector<f64> {
    type Output = Vector<f64>;
    fn mul(self, rhs: f64) -> Vector<f64> {
        vector(self.x * rhs, self.y * rhs)
    }
}

impl ops::Mul<Vector<f64>> for f64 {
    type Output = Vector<f64>;
    fn mul(self, rhs: Vector<f64>) -> Vector<f64> {
        vector(self * rhs.x, self * rhs.y)
    }
}

impl ops::Div<f32> for Vector<f32> {
    type Output = Vector<f32>;
    fn div(self, rhs: f32) -> Vector<f32> {
        vector(self.x / rhs, self.y / rhs)
    }
}

impl ops::Div<Vector<f32>> for f32 {
    type Output = Vector<f32>;
    fn div(self, rhs: Vector<f32>) -> Vector<f32> {
        vector(self / rhs.x, self / rhs.y)
    }
}

impl ops::Div<f64> for Vector<f64> {
    type Output = Vector<f64>;
    fn div(self, rhs: f64) -> Vector<f64> {
        vector(self.x / rhs, self.y / rhs)
    }
}

impl ops::Div<Vector<f64>> for f64 {
    type Output = Vector<f64>;
    fn div(self, rhs: Vector<f64>) -> Vector<f64> {
        vector(self / rhs.x, self / rhs.y)
    }
}

impl<N: ops::Add<Output = N>> ops::Add<Vector<N>> for Point<N> {
    type Output = Point<N>;
    fn add(self, rhs: Vector<N>) -> Point<N> {
        point(self.x + rhs.x, self.y + rhs.y)
    }
}

impl<N: ops::Sub<Output = N>> ops::Sub<Vector<N>> for Point<N> {
    type Output = Point<N>;
    fn sub(self, rhs: Vector<N>) -> Point<N> {
        point(self.x - rhs.x, self.y - rhs.y)
    }
}

impl<N: ops::Add<Output = N>> ops::Add<Point<N>> for Vector<N> {
    type Output = Point<N>;
    fn add(self, rhs: Point<N>) -> Point<N> {
        point(self.x + rhs.x, self.y + rhs.y)
    }
}

/// A straight line between two points, `p[0]` and `p[1]`
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
pub struct Line {
    pub p: [Point<f32>; 2],
}
/// A quadratic Bezier curve, starting at `p[0]`, ending at `p[2]`, with control
/// point `p[1]`.
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd)]
pub struct Curve {
    pub p: [Point<f32>; 3],
}
/// A rectangle, with top-left corner at `min`, and bottom-right corner at
/// `max`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct Rect<N> {
    pub min: Point<N>,
    pub max: Point<N>,
}

impl <N: Default> Default for Rect<N> {
    fn default() -> Self {
        Rect {
            min: Point::default(),
            max: Point::default()
        }
    }
}

impl<N: ops::Sub<Output = N> + Copy> Rect<N> {
    pub fn width(&self) -> N {
        self.max.x - self.min.x
    }
    pub fn height(&self) -> N {
        self.max.y - self.min.y
    }
}

pub trait BoundingBox<N> {
    fn bounding_box(&self) -> Rect<N> {
        let (min_x, max_x) = self.x_bounds();
        let (min_y, max_y) = self.y_bounds();
        Rect {
            min: point(min_x, min_y),
            max: point(max_x, max_y),
        }
    }
    fn x_bounds(&self) -> (N, N);
    fn y_bounds(&self) -> (N, N);
}

impl BoundingBox<f32> for Line {
    fn x_bounds(&self) -> (f32, f32) {
        let p = &self.p;
        if p[0].x < p[1].x {
            (p[0].x, p[1].x)
        } else {
            (p[1].x, p[0].x)
        }
    }
    fn y_bounds(&self) -> (f32, f32) {
        let p = &self.p;
        if p[0].y < p[1].y {
            (p[0].y, p[1].y)
        } else {
            (p[1].y, p[0].y)
        }
    }
}

impl BoundingBox<f32> for Curve {
    fn x_bounds(&self) -> (f32, f32) {
        let p = &self.p;
        if p[0].x <= p[1].x && p[1].x <= p[2].x {
            (p[0].x, p[2].x)
        } else if p[0].x >= p[1].x && p[1].x >= p[2].x {
            (p[2].x, p[0].x)
        } else {
            let t = (p[0].x - p[1].x) / (p[0].x - 2.0 * p[1].x + p[2].x);
            let _1mt = 1.0 - t;
            let inflection = _1mt * _1mt * p[0].x + 2.0 * _1mt * t * p[1].x + t * t * p[2].x;
            if p[1].x < p[0].x {
                (inflection, p[0].x.max(p[2].x))
            } else {
                (p[0].x.min(p[2].x), inflection)
            }
        }
    }

    fn y_bounds(&self) -> (f32, f32) {
        let p = &self.p;
        if p[0].y <= p[1].y && p[1].y <= p[2].y {
            (p[0].y, p[2].y)
        } else if p[0].y >= p[1].y && p[1].y >= p[2].y {
            (p[2].y, p[0].y)
        } else {
            let t = (p[0].y - p[1].y) / (p[0].y - 2.0 * p[1].y + p[2].y);
            let _1mt = 1.0 - t;
            let inflection = _1mt * _1mt * p[0].y + 2.0 * _1mt * t * p[1].y + t * t * p[2].y;
            if p[1].y < p[0].y {
                (inflection, p[0].y.max(p[2].y))
            } else {
                (p[0].y.min(p[2].y), inflection)
            }
        }
    }
}

pub trait Cut: Sized {
    fn cut_to(self, t: f32) -> Self;
    fn cut_from(self, t: f32) -> Self;
    fn cut_from_to(self, t0: f32, t1: f32) -> Self {
        self.cut_from(t0).cut_to((t1 - t0) / (1.0 - t0))
    }
}

impl Cut for Curve {
    fn cut_to(self, t: f32) -> Curve {
        let p = self.p;
        let a = p[0] + t * (p[1] - p[0]);
        let b = p[1] + t * (p[2] - p[1]);
        let c = a + t * (b - a);
        Curve { p: [p[0], a, c] }
    }
    fn cut_from(self, t: f32) -> Curve {
        let p = self.p;
        let a = p[0] + t * (p[1] - p[0]);
        let b = p[1] + t * (p[2] - p[1]);
        let c = a + t * (b - a);
        Curve { p: [c, b, p[2]] }
    }
}

impl Cut for Line {
    fn cut_to(self, t: f32) -> Line {
        let p = self.p;
        Line {
            p: [p[0], p[0] + t * (p[1] - p[0])],
        }
    }
    fn cut_from(self, t: f32) -> Line {
        let p = self.p;
        Line {
            p: [p[0] + t * (p[1] - p[0]), p[1]],
        }
    }
    fn cut_from_to(self, t0: f32, t1: f32) -> Line {
        let p = self.p;
        let v = p[1] - p[0];
        Line {
            p: [p[0] + t0 * v, p[0] + t1 * v],
        }
    }
}

/// The real valued solutions to a real quadratic equation.
#[derive(Copy, Clone, Debug)]
pub enum RealQuadraticSolution {
    /// Two zero-crossing solutions
    Two(f32, f32),
    /// One zero-crossing solution (equation is a straight line)
    One(f32),
    /// One zero-touching solution
    Touch(f32),
    /// No solutions
    None,
    /// All real numbers are solutions since a == b == c == 0.0
    All,
}

impl RealQuadraticSolution {
    /// If there are two solutions, this function ensures that they are in order
    /// (first < second)
    pub fn in_order(self) -> RealQuadraticSolution {
        use self::RealQuadraticSolution::*;
        match self {
            Two(x, y) => {
                if x < y {
                    Two(x, y)
                } else {
                    Two(y, x)
                }
            }
            other => other,
        }
    }
}

/// Solve a real quadratic equation, giving all real solutions, if any.
pub fn solve_quadratic_real(a: f32, b: f32, c: f32) -> RealQuadraticSolution {
    let discriminant = b * b - 4.0 * a * c;
    if discriminant > 0.0 {
        let sqrt_d = discriminant.sqrt();
        let common = -b + if b >= 0.0 { -sqrt_d } else { sqrt_d };
        let x1 = 2.0 * c / common;
        if a == 0.0 {
            RealQuadraticSolution::One(x1)
        } else {
            let x2 = common / (2.0 * a);
            RealQuadraticSolution::Two(x1, x2)
        }
    } else if discriminant < 0.0 {
        RealQuadraticSolution::None
    } else if b == 0.0 {
        if a == 0.0 {
            if c == 0.0 {
                RealQuadraticSolution::All
            } else {
                RealQuadraticSolution::None
            }
        } else {
            RealQuadraticSolution::Touch(0.0)
        }
    } else {
        RealQuadraticSolution::Touch(2.0 * c / -b)
    }
}

#[test]
fn quadratic_test() {
    solve_quadratic_real(-0.000_000_1, -2.0, 10.0);
}
<|endoftext|>


<commit_before>//! **GraphMap\<N, E\>** is an undirected graph where node values are mapping keys.

use std::hash::{Hash};
use std::collections::HashMap;
use std::collections::hash_map::Hasher;
use std::iter::Map;
use std::collections::hash_map::{
    Keys,
};
use std::collections::hash_map::Entry::{
    Occupied,
    Vacant,
};
use std::slice::{
    Iter,
};
use std::fmt;
use std::ops::{Index, IndexMut};

/// **GraphMap\<N, E\>** is an undirected graph, with generic node values **N** and edge weights **E**.
///
/// It uses an combined adjacency list and sparse adjacency matrix representation, using **O(|V|
/// + |E|)** space, and allows testing for edge existance in constant time.
///
/// The node type **N** must implement **Copy** and will be used as node identifier, duplicated
/// into several places in the data structure.
/// It must be suitable as a hash table key (implementing **Eq + Hash**).
/// The node type must also implement **Ord** so that the implementation can
/// order the pair (**a**, **b**) for an edge connecting any two nodes **a** and **b**.
///
/// **GraphMap** does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct GraphMap<N: Eq + Hash<Hasher>, E> {
    nodes: HashMap<N, Vec<N>>,
    edges: HashMap<(N, N), E>,
}

impl<N: Eq + Hash<Hasher> + fmt::Debug, E: fmt::Debug> fmt::Debug for GraphMap<N, E>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.nodes.fmt(f)
    }
}

#[inline]
fn edge_key<N: Copy + Ord>(a: N, b: N) -> (N, N)
{
    if a <= b { (a, b) } else { (b, a) }
}

#[inline]
fn copy<N: Copy>(n: &N) -> N { *n }

/// A trait group for **GraphMap**'s node identifier.
pub trait NodeTrait : Copy + Ord + Eq + Hash<Hasher> {}
impl<N> NodeTrait for N where N: Copy + Ord + Eq + Hash<Hasher> {}

impl<N, E> GraphMap<N, E> where N: NodeTrait
{
    /// Create a new **GraphMap**.
    pub fn new() -> Self
    {
        GraphMap {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    /// Create a new **GraphMap** with estimated capacity.
    pub fn with_capacity(nodes: usize, edges: usize) -> Self
    {
        GraphMap {
            nodes: HashMap::with_capacity(nodes),
            edges: HashMap::with_capacity(edges),
        }
    }

    /// Return the number of nodes in the graph.
    pub fn node_count(&self) -> usize
    {
        self.nodes.len()
    }

    /// Return the number of edges in the graph.
    pub fn edge_count(&self) -> usize
    {
        self.edges.len()
    }

    /// Add node **n** to the graph.
    pub fn add_node(&mut self, n: N) -> N {
        match self.nodes.entry(n) {
            Occupied(_) => {}
            Vacant(ent) => { ent.insert(Vec::new()); }
        }
        n
    }

    /// Return **true** if node **n** was removed.
    pub fn remove_node(&mut self, n: N) -> bool {
        let successors = match self.nodes.remove(&n) {
            None => return false,
            Some(sus) => sus,
        };
        for succ in successors.into_iter() {
            // remove all successor links
            self.remove_single_edge(&succ, &n);
            // Remove all edge values
            self.edges.remove(&edge_key(n, succ));
        }
        true
    }

    /// Return **true** if the node is contained in the graph.
    pub fn contains_node(&self, n: N) -> bool {
        self.nodes.contains_key(&n)
    }

    /// Add an edge connecting **a** and **b** to the graph.
    ///
    /// Inserts nodes **a** and/or **b** if they aren't already part of the graph.
    ///
    /// Return **true** if edge did not previously exist.
    ///
    /// ## Example
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    /// assert_eq!(g.node_count(), 2);
    /// assert_eq!(g.edge_count(), 1);
    /// ```
    pub fn add_edge(&mut self, a: N, b: N, edge: E) -> bool
    {
        // Use Ord to order the edges
        match self.nodes.entry(a) {
            Occupied(ent) => { ent.into_mut().push(b); }
            Vacant(ent) => { ent.insert(vec![b]); }
        }
        match self.nodes.entry(b) {
            Occupied(ent) => { ent.into_mut().push(a); }
            Vacant(ent) => { ent.insert(vec![a]); }
        }
        self.edges.insert(edge_key(a, b), edge).is_none()
    }

    /// Remove successor relation from a to b
    ///
    /// Return **true** if it did exist.
    fn remove_single_edge(&mut self, a: &N, b: &N) -> bool
    {
        match self.nodes.get_mut(a) {
            None => false,
            Some(sus) => {
                match sus.iter().position(|elt| elt == b) {
                    Some(index) => { sus.swap_remove(index); true }
                    None => false,
                }
            }
        }
    }

    /// Remove edge from **a** to **b** from the graph and return the edge weight.
    ///
    /// Return **None** if the edge didn't exist.
    ///
    /// ## Example
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_node(1);
    /// g.add_node(2);
    /// g.add_edge(1, 2, -1);
    ///
    /// let edge = g.remove_edge(2, 1);
    /// assert_eq!(edge, Some(-1));
    /// assert_eq!(g.edge_count(), 0);
    /// ```
    pub fn remove_edge(&mut self, a: N, b: N) -> Option<E>
    {
        let exist1 = self.remove_single_edge(&a, &b);
        let exist2 = self.remove_single_edge(&b, &a);
        let weight = self.edges.remove(&edge_key(a, b));
        debug_assert!(exist1 == exist2 && exist1 == weight.is_some());
        weight
    }

    /// Return **true** if the edge connecting **a** with **b** is contained in the graph.
    pub fn contains_edge(&self, a: N, b: N) -> bool {
        self.edges.contains_key(&edge_key(a, b))
    }

    /// Return an iterator over the nodes of the graph.
    ///
    /// Iterator element type is **N**.
    pub fn nodes<'a>(&'a self) -> Nodes<'a, N>
    {
        Nodes{iter: self.nodes.keys().map(copy)}
    }

    /// Return an iterator over the nodes that are connected with **from** by edges.
    ///
    /// If the node **from** does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is **N**.
    pub fn neighbors<'a>(&'a self, from: N) -> Neighbors<'a, N>
    {
        Neighbors{iter:
            match self.nodes.get(&from) {
                Some(neigh) => neigh.iter(),
                None => [].iter(),
            }.map(copy)
        }
    }

    /// Return an iterator over the nodes that are connected with **from** by edges,
    /// paired with the edge weight.
    ///
    /// If the node **from** does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is **(N, &'a E)**.
    pub fn edges<'a>(&'a self, from: N) -> Edges<'a, N, E>
    {
        Edges {
            from: from,
            iter: self.neighbors(from),
            edges: &self.edges,
        }
    }

    /// Return a reference to the edge weight connecting **a** with **b**, or
    /// **None** if the edge does not exist in the graph.
    pub fn edge_weight<'a>(&'a self, a: N, b: N) -> Option<&'a E>
    {
        self.edges.get(&edge_key(a, b))
    }

    /// Return a mutable reference to the edge weight connecting **a** with **b**, or
    /// **None** if the edge does not exist in the graph.
    pub fn edge_weight_mut<'a>(&'a mut self, a: N, b: N) -> Option<&'a mut E>
    {
        self.edges.get_mut(&edge_key(a, b))
    }
}

macro_rules! iterator_methods {
    () => (
        #[inline]
        fn next(&mut self) -> Option<<Self as Iterator>::Item>
        {
            self.iter.next()
        }

        #[inline]
        fn size_hint(&self) -> (usize, Option<usize>)
        {
            self.iter.size_hint()
        }
    )
}

pub struct Nodes<'a, N: 'a> {
    iter: Map<&'a N, N, Keys<'a, N, Vec<N>>, fn(&N) -> N>,
}

impl<'a, N> Iterator for Nodes<'a, N>
{
    type Item = N;
    iterator_methods!();
}

pub struct Neighbors<'a, N: 'a> {
    iter: Map<&'a N, N, Iter<'a, N>, fn(&N) -> N>,
}

impl<'a, N> Iterator for Neighbors<'a, N>
{
    type Item = N;
    iterator_methods!();
}

pub struct Edges<'a, N, E: 'a> where N: 'a + NodeTrait
{
    pub from: N,
    pub edges: &'a HashMap<(N, N), E>,
    pub iter: Neighbors<'a, N>,
}

impl<'a, N, E> Iterator for Edges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, &'a E);
    fn next(&mut self) -> Option<(N, &'a E)>
    {
        match self.iter.next() {
            None => None,
            Some(b) => {
                let a = self.from;
                match self.edges.get(&edge_key(a, b)) {
                    None => unreachable!(),
                    Some(edge) => {
                        Some((b, edge))
                    }
                }
            }
        }
    }
}

impl<N, E> Index<(N, N)> for GraphMap<N, E> where N: NodeTrait
{
    type Output = E;
    /// Index **GraphMap** by node pairs to access edge weights.
    fn index(&self, index: &(N, N)) -> &E
    {
        self.edge_weight(index.0, index.1).unwrap()
    }
}

impl<N, E> IndexMut<(N, N)> for GraphMap<N, E> where N: NodeTrait
{
    type Output = E;
    /// Index **GraphMap** by node pairs to access edge weights.
    fn index_mut(&mut self, index: &(N, N)) -> &mut E
    {
        self.edge_weight_mut(index.0, index.1).unwrap()
    }
}
<commit_msg>Fix unwrap without message<commit_after>//! **GraphMap\<N, E\>** is an undirected graph where node values are mapping keys.

use std::hash::{Hash};
use std::collections::HashMap;
use std::collections::hash_map::Hasher;
use std::iter::Map;
use std::collections::hash_map::{
    Keys,
};
use std::collections::hash_map::Entry::{
    Occupied,
    Vacant,
};
use std::slice::{
    Iter,
};
use std::fmt;
use std::ops::{Index, IndexMut};

/// **GraphMap\<N, E\>** is an undirected graph, with generic node values **N** and edge weights **E**.
///
/// It uses an combined adjacency list and sparse adjacency matrix representation, using **O(|V|
/// + |E|)** space, and allows testing for edge existance in constant time.
///
/// The node type **N** must implement **Copy** and will be used as node identifier, duplicated
/// into several places in the data structure.
/// It must be suitable as a hash table key (implementing **Eq + Hash**).
/// The node type must also implement **Ord** so that the implementation can
/// order the pair (**a**, **b**) for an edge connecting any two nodes **a** and **b**.
///
/// **GraphMap** does not allow parallel edges, but self loops are allowed.
#[derive(Clone)]
pub struct GraphMap<N: Eq + Hash<Hasher>, E> {
    nodes: HashMap<N, Vec<N>>,
    edges: HashMap<(N, N), E>,
}

impl<N: Eq + Hash<Hasher> + fmt::Debug, E: fmt::Debug> fmt::Debug for GraphMap<N, E>
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.nodes.fmt(f)
    }
}

#[inline]
fn edge_key<N: Copy + Ord>(a: N, b: N) -> (N, N)
{
    if a <= b { (a, b) } else { (b, a) }
}

#[inline]
fn copy<N: Copy>(n: &N) -> N { *n }

/// A trait group for **GraphMap**'s node identifier.
pub trait NodeTrait : Copy + Ord + Eq + Hash<Hasher> {}
impl<N> NodeTrait for N where N: Copy + Ord + Eq + Hash<Hasher> {}

impl<N, E> GraphMap<N, E> where N: NodeTrait
{
    /// Create a new **GraphMap**.
    pub fn new() -> Self
    {
        GraphMap {
            nodes: HashMap::new(),
            edges: HashMap::new(),
        }
    }

    /// Create a new **GraphMap** with estimated capacity.
    pub fn with_capacity(nodes: usize, edges: usize) -> Self
    {
        GraphMap {
            nodes: HashMap::with_capacity(nodes),
            edges: HashMap::with_capacity(edges),
        }
    }

    /// Return the number of nodes in the graph.
    pub fn node_count(&self) -> usize
    {
        self.nodes.len()
    }

    /// Return the number of edges in the graph.
    pub fn edge_count(&self) -> usize
    {
        self.edges.len()
    }

    /// Add node **n** to the graph.
    pub fn add_node(&mut self, n: N) -> N {
        match self.nodes.entry(n) {
            Occupied(_) => {}
            Vacant(ent) => { ent.insert(Vec::new()); }
        }
        n
    }

    /// Return **true** if node **n** was removed.
    pub fn remove_node(&mut self, n: N) -> bool {
        let successors = match self.nodes.remove(&n) {
            None => return false,
            Some(sus) => sus,
        };
        for succ in successors.into_iter() {
            // remove all successor links
            self.remove_single_edge(&succ, &n);
            // Remove all edge values
            self.edges.remove(&edge_key(n, succ));
        }
        true
    }

    /// Return **true** if the node is contained in the graph.
    pub fn contains_node(&self, n: N) -> bool {
        self.nodes.contains_key(&n)
    }

    /// Add an edge connecting **a** and **b** to the graph.
    ///
    /// Inserts nodes **a** and/or **b** if they aren't already part of the graph.
    ///
    /// Return **true** if edge did not previously exist.
    ///
    /// ## Example
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_edge(1, 2, -1);
    /// assert_eq!(g.node_count(), 2);
    /// assert_eq!(g.edge_count(), 1);
    /// ```
    pub fn add_edge(&mut self, a: N, b: N, edge: E) -> bool
    {
        // Use Ord to order the edges
        match self.nodes.entry(a) {
            Occupied(ent) => { ent.into_mut().push(b); }
            Vacant(ent) => { ent.insert(vec![b]); }
        }
        match self.nodes.entry(b) {
            Occupied(ent) => { ent.into_mut().push(a); }
            Vacant(ent) => { ent.insert(vec![a]); }
        }
        self.edges.insert(edge_key(a, b), edge).is_none()
    }

    /// Remove successor relation from a to b
    ///
    /// Return **true** if it did exist.
    fn remove_single_edge(&mut self, a: &N, b: &N) -> bool
    {
        match self.nodes.get_mut(a) {
            None => false,
            Some(sus) => {
                match sus.iter().position(|elt| elt == b) {
                    Some(index) => { sus.swap_remove(index); true }
                    None => false,
                }
            }
        }
    }

    /// Remove edge from **a** to **b** from the graph and return the edge weight.
    ///
    /// Return **None** if the edge didn't exist.
    ///
    /// ## Example
    ///
    /// ```
    /// use petgraph::GraphMap;
    ///
    /// let mut g = GraphMap::new();
    /// g.add_node(1);
    /// g.add_node(2);
    /// g.add_edge(1, 2, -1);
    ///
    /// let edge = g.remove_edge(2, 1);
    /// assert_eq!(edge, Some(-1));
    /// assert_eq!(g.edge_count(), 0);
    /// ```
    pub fn remove_edge(&mut self, a: N, b: N) -> Option<E>
    {
        let exist1 = self.remove_single_edge(&a, &b);
        let exist2 = self.remove_single_edge(&b, &a);
        let weight = self.edges.remove(&edge_key(a, b));
        debug_assert!(exist1 == exist2 && exist1 == weight.is_some());
        weight
    }

    /// Return **true** if the edge connecting **a** with **b** is contained in the graph.
    pub fn contains_edge(&self, a: N, b: N) -> bool {
        self.edges.contains_key(&edge_key(a, b))
    }

    /// Return an iterator over the nodes of the graph.
    ///
    /// Iterator element type is **N**.
    pub fn nodes<'a>(&'a self) -> Nodes<'a, N>
    {
        Nodes{iter: self.nodes.keys().map(copy)}
    }

    /// Return an iterator over the nodes that are connected with **from** by edges.
    ///
    /// If the node **from** does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is **N**.
    pub fn neighbors<'a>(&'a self, from: N) -> Neighbors<'a, N>
    {
        Neighbors{iter:
            match self.nodes.get(&from) {
                Some(neigh) => neigh.iter(),
                None => [].iter(),
            }.map(copy)
        }
    }

    /// Return an iterator over the nodes that are connected with **from** by edges,
    /// paired with the edge weight.
    ///
    /// If the node **from** does not exist in the graph, return an empty iterator.
    ///
    /// Iterator element type is **(N, &'a E)**.
    pub fn edges<'a>(&'a self, from: N) -> Edges<'a, N, E>
    {
        Edges {
            from: from,
            iter: self.neighbors(from),
            edges: &self.edges,
        }
    }

    /// Return a reference to the edge weight connecting **a** with **b**, or
    /// **None** if the edge does not exist in the graph.
    pub fn edge_weight<'a>(&'a self, a: N, b: N) -> Option<&'a E>
    {
        self.edges.get(&edge_key(a, b))
    }

    /// Return a mutable reference to the edge weight connecting **a** with **b**, or
    /// **None** if the edge does not exist in the graph.
    pub fn edge_weight_mut<'a>(&'a mut self, a: N, b: N) -> Option<&'a mut E>
    {
        self.edges.get_mut(&edge_key(a, b))
    }
}

macro_rules! iterator_methods {
    () => (
        #[inline]
        fn next(&mut self) -> Option<<Self as Iterator>::Item>
        {
            self.iter.next()
        }

        #[inline]
        fn size_hint(&self) -> (usize, Option<usize>)
        {
            self.iter.size_hint()
        }
    )
}

pub struct Nodes<'a, N: 'a> {
    iter: Map<&'a N, N, Keys<'a, N, Vec<N>>, fn(&N) -> N>,
}

impl<'a, N> Iterator for Nodes<'a, N>
{
    type Item = N;
    iterator_methods!();
}

pub struct Neighbors<'a, N: 'a> {
    iter: Map<&'a N, N, Iter<'a, N>, fn(&N) -> N>,
}

impl<'a, N> Iterator for Neighbors<'a, N>
{
    type Item = N;
    iterator_methods!();
}

pub struct Edges<'a, N, E: 'a> where N: 'a + NodeTrait
{
    pub from: N,
    pub edges: &'a HashMap<(N, N), E>,
    pub iter: Neighbors<'a, N>,
}

impl<'a, N, E> Iterator for Edges<'a, N, E>
    where N: 'a + NodeTrait, E: 'a
{
    type Item = (N, &'a E);
    fn next(&mut self) -> Option<(N, &'a E)>
    {
        match self.iter.next() {
            None => None,
            Some(b) => {
                let a = self.from;
                match self.edges.get(&edge_key(a, b)) {
                    None => unreachable!(),
                    Some(edge) => {
                        Some((b, edge))
                    }
                }
            }
        }
    }
}

impl<N, E> Index<(N, N)> for GraphMap<N, E> where N: NodeTrait
{
    type Output = E;
    /// Index **GraphMap** by node pairs to access edge weights.
    fn index(&self, index: &(N, N)) -> &E
    {
        self.edge_weight(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}

impl<N, E> IndexMut<(N, N)> for GraphMap<N, E> where N: NodeTrait
{
    type Output = E;
    /// Index **GraphMap** by node pairs to access edge weights.
    fn index_mut(&mut self, index: &(N, N)) -> &mut E
    {
        self.edge_weight_mut(index.0, index.1).expect("GraphMap::index: no such edge")
    }
}
<|endoftext|>


<commit_before>//! The HTTP module which provides functions for performing requests to
//! endpoints in Discord's API.
//!
//! An important function of the REST API is ratelimiting. Requests to endpoints
//! are ratelimited to prevent spam, and once ratelimited Discord will stop
//! performing requests. The library implements protection to pre-emptively
//! ratelimit, to ensure that no wasted requests are made.
//!
//! The HTTP module comprises of two types of requests:
//!
//! - REST API requests, which require an authorization token;
//! - Other requests, which do not require an authorization token.
//!
//! The former require a [`Client`] to have logged in, while the latter may be
//! made regardless of any other usage of the library.
//!
//! If a request spuriously fails, it will be retried once.
//!
//! Note that you may want to perform requests through a [model]s'
//! instance methods where possible, as they each offer different
//! levels of a high-level interface to the HTTP module.
//!
//! [`Client`]: ../client/struct.Client.html
//! [model]: ../model/index.html

pub mod ratelimiting;
pub mod raw;
pub mod request;
pub mod routing;

mod error;

pub use reqwest::StatusCode;
pub use self::error::Error as HttpError;
pub use self::raw::*;

use reqwest::{
    Method,
};
use crate::model::prelude::*;
use self::{request::Request};
use std::{
    fs::File,
    path::{Path, PathBuf},
};

#[cfg(feature = "cache")]
use crate::cache::CacheRwLock;
#[cfg(feature = "client")]
use crate::client::Context;

/// This trait will be required by functions that need [`Http`] and can
/// optionally use a [`CacheRwLock`] to potentially avoid REST-requests.
///
/// The types [`Context`], [`CacheRwLock`], and [`Http`] implement this trait
/// and thus passing these to functions expecting `impl CacheHttp` is possible.
///
/// In a situation where you have the `cache`-feature enabled but you do not
/// pass a cache, the function will behave as if no `cache`-feature is active.
///
/// If you are calling a function that expects `impl CacheHttp` as argument
/// and you wish to utilise the `cache`-feature but you got no access to a
/// [`Context`], you can pass a tuple of `(CacheRwLock, Http)`.
///
/// [`CacheRwLock`]: ../cache/struct.CacheRwLock.html
/// [`Http`]: raw/struct.Http.html
/// [`Context`]: ../client/struct.Context.html
pub trait CacheHttp {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http;
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { None }
}

#[cfg(feature = "client")]
impl CacheHttp for &Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &mut Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(all(feature = "cache", feature = "http"))]
impl CacheHttp for (&CacheRwLock, &Http) {
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.0) }
    fn http(&self) -> &Http { &self.1 }
}

impl CacheHttp for &Http {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { *self }
}

#[cfg(all(feature = "cache", feature = "http"))]
impl AsRef<CacheRwLock> for (&CacheRwLock, &Http) {
    fn as_ref(&self) -> &CacheRwLock {
        self.0
    }
}

#[cfg(feature = "cache")]
impl AsRef<Http> for (&CacheRwLock, &Http) {
    fn as_ref(&self) -> &Http {
        self.1
    }
}

/// An method used for ratelimiting special routes.
///
/// This is needed because `reqwest`'s `Method` enum does not derive Copy.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LightMethod {
    /// Indicates that a route is for the `DELETE` method only.
    Delete,
    /// Indicates that a route is for the `GET` method only.
    Get,
    /// Indicates that a route is for the `PATCH` method only.
    Patch,
    /// Indicates that a route is for the `POST` method only.
    Post,
    /// Indicates that a route is for the `PUT` method only.
    Put,
}

impl LightMethod {
    pub fn reqwest_method(self) -> Method {
        match self {
            LightMethod::Delete => Method::DELETE,
            LightMethod::Get => Method::GET,
            LightMethod::Patch => Method::PATCH,
            LightMethod::Post => Method::POST,
            LightMethod::Put => Method::PUT,
        }
    }
}

/// Enum that allows a user to pass a `Path` or a `File` type to `send_files`
#[derive(Clone, Debug)]
pub enum AttachmentType<'a> {
    /// Indicates that the `AttachmentType` is a byte slice with a filename.
    Bytes((&'a [u8], &'a str)),
    /// Indicates that the `AttachmentType` is a `File`
    File((&'a File, &'a str)),
    /// Indicates that the `AttachmentType` is a `Path`
    Path(&'a Path),
    #[doc(hidden)]
    __Nonexhaustive,
}

impl<'a> From<(&'a [u8], &'a str)> for AttachmentType<'a> {
    fn from(params: (&'a [u8], &'a str)) -> AttachmentType<'_> { AttachmentType::Bytes(params) }
}

impl<'a> From<&'a str> for AttachmentType<'a> {
    fn from(s: &'a str) -> AttachmentType<'_> { AttachmentType::Path(Path::new(s)) }
}

impl<'a> From<&'a Path> for AttachmentType<'a> {
    fn from(path: &'a Path) -> AttachmentType<'_> {
        AttachmentType::Path(path)
    }
}

impl<'a> From<&'a PathBuf> for AttachmentType<'a> {
    fn from(pathbuf: &'a PathBuf) -> AttachmentType<'_> { AttachmentType::Path(pathbuf.as_path()) }
}

impl<'a> From<(&'a File, &'a str)> for AttachmentType<'a> {
    fn from(f: (&'a File, &'a str)) -> AttachmentType<'a> { AttachmentType::File((f.0, f.1)) }
}

/// Representation of the method of a query to send for the [`get_guilds`]
/// function.
///
/// [`get_guilds`]: fn.get_guilds.html
pub enum GuildPagination {
    /// The Id to get the guilds after.
    After(GuildId),
    /// The Id to get the guilds before.
    Before(GuildId),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[cfg(test)]
mod test {
    use super::AttachmentType;
    use std::path::Path;

    #[test]
    fn test_attachment_type() {
        assert!(match AttachmentType::from(Path::new("./dogs/corgis/kona.png")) {
            AttachmentType::Path(_) => true,
            _ => false,
        });
        assert!(match AttachmentType::from("./cats/copycat.png") {
            AttachmentType::Path(_) => true,
            _ => false,
        });
    }
}
<commit_msg>Implement `CacheHttp` for more types.<commit_after>//! The HTTP module which provides functions for performing requests to
//! endpoints in Discord's API.
//!
//! An important function of the REST API is ratelimiting. Requests to endpoints
//! are ratelimited to prevent spam, and once ratelimited Discord will stop
//! performing requests. The library implements protection to pre-emptively
//! ratelimit, to ensure that no wasted requests are made.
//!
//! The HTTP module comprises of two types of requests:
//!
//! - REST API requests, which require an authorization token;
//! - Other requests, which do not require an authorization token.
//!
//! The former require a [`Client`] to have logged in, while the latter may be
//! made regardless of any other usage of the library.
//!
//! If a request spuriously fails, it will be retried once.
//!
//! Note that you may want to perform requests through a [model]s'
//! instance methods where possible, as they each offer different
//! levels of a high-level interface to the HTTP module.
//!
//! [`Client`]: ../client/struct.Client.html
//! [model]: ../model/index.html

pub mod ratelimiting;
pub mod raw;
pub mod request;
pub mod routing;

mod error;

pub use reqwest::StatusCode;
pub use self::error::Error as HttpError;
pub use self::raw::*;

use reqwest::{
    Method,
};
use crate::model::prelude::*;
use self::{request::Request};
use std::{
    fs::File,
    path::{Path, PathBuf},
};

#[cfg(feature = "cache")]
use crate::cache::CacheRwLock;
#[cfg(feature = "client")]
use crate::client::Context;

/// This trait will be required by functions that need [`Http`] and can
/// optionally use a [`CacheRwLock`] to potentially avoid REST-requests.
///
/// The types [`Context`], [`CacheRwLock`], and [`Http`] implement this trait
/// and thus passing these to functions expecting `impl CacheHttp` is possible.
///
/// In a situation where you have the `cache`-feature enabled but you do not
/// pass a cache, the function will behave as if no `cache`-feature is active.
///
/// If you are calling a function that expects `impl CacheHttp` as argument
/// and you wish to utilise the `cache`-feature but you got no access to a
/// [`Context`], you can pass a tuple of `(CacheRwLock, Http)`.
///
/// [`CacheRwLock`]: ../cache/struct.CacheRwLock.html
/// [`Http`]: raw/struct.Http.html
/// [`Context`]: ../client/struct.Context.html
pub trait CacheHttp {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http;
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { None }
}

#[cfg(feature = "client")]
impl CacheHttp for Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &mut Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(feature = "client")]
impl CacheHttp for &&mut Context {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { &self.http }
    #[cfg(feature = "cache")]
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.cache) }
}

#[cfg(all(feature = "cache", feature = "http"))]
impl CacheHttp for (&CacheRwLock, &Http) {
    fn cache(&self) -> Option<&CacheRwLock> { Some(&self.0) }
    fn http(&self) -> &Http { &self.1 }
}

impl CacheHttp for &Http {
    #[cfg(feature = "http")]
    fn http(&self) -> &Http { *self }
}

#[cfg(all(feature = "cache", feature = "http"))]
impl AsRef<CacheRwLock> for (&CacheRwLock, &Http) {
    fn as_ref(&self) -> &CacheRwLock {
        self.0
    }
}

#[cfg(feature = "cache")]
impl AsRef<Http> for (&CacheRwLock, &Http) {
    fn as_ref(&self) -> &Http {
        self.1
    }
}

/// An method used for ratelimiting special routes.
///
/// This is needed because `reqwest`'s `Method` enum does not derive Copy.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum LightMethod {
    /// Indicates that a route is for the `DELETE` method only.
    Delete,
    /// Indicates that a route is for the `GET` method only.
    Get,
    /// Indicates that a route is for the `PATCH` method only.
    Patch,
    /// Indicates that a route is for the `POST` method only.
    Post,
    /// Indicates that a route is for the `PUT` method only.
    Put,
}

impl LightMethod {
    pub fn reqwest_method(self) -> Method {
        match self {
            LightMethod::Delete => Method::DELETE,
            LightMethod::Get => Method::GET,
            LightMethod::Patch => Method::PATCH,
            LightMethod::Post => Method::POST,
            LightMethod::Put => Method::PUT,
        }
    }
}

/// Enum that allows a user to pass a `Path` or a `File` type to `send_files`
#[derive(Clone, Debug)]
pub enum AttachmentType<'a> {
    /// Indicates that the `AttachmentType` is a byte slice with a filename.
    Bytes((&'a [u8], &'a str)),
    /// Indicates that the `AttachmentType` is a `File`
    File((&'a File, &'a str)),
    /// Indicates that the `AttachmentType` is a `Path`
    Path(&'a Path),
    #[doc(hidden)]
    __Nonexhaustive,
}

impl<'a> From<(&'a [u8], &'a str)> for AttachmentType<'a> {
    fn from(params: (&'a [u8], &'a str)) -> AttachmentType<'_> { AttachmentType::Bytes(params) }
}

impl<'a> From<&'a str> for AttachmentType<'a> {
    fn from(s: &'a str) -> AttachmentType<'_> { AttachmentType::Path(Path::new(s)) }
}

impl<'a> From<&'a Path> for AttachmentType<'a> {
    fn from(path: &'a Path) -> AttachmentType<'_> {
        AttachmentType::Path(path)
    }
}

impl<'a> From<&'a PathBuf> for AttachmentType<'a> {
    fn from(pathbuf: &'a PathBuf) -> AttachmentType<'_> { AttachmentType::Path(pathbuf.as_path()) }
}

impl<'a> From<(&'a File, &'a str)> for AttachmentType<'a> {
    fn from(f: (&'a File, &'a str)) -> AttachmentType<'a> { AttachmentType::File((f.0, f.1)) }
}

/// Representation of the method of a query to send for the [`get_guilds`]
/// function.
///
/// [`get_guilds`]: fn.get_guilds.html
pub enum GuildPagination {
    /// The Id to get the guilds after.
    After(GuildId),
    /// The Id to get the guilds before.
    Before(GuildId),
    #[doc(hidden)]
    __Nonexhaustive,
}

#[cfg(test)]
mod test {
    use super::AttachmentType;
    use std::path::Path;

    #[test]
    fn test_attachment_type() {
        assert!(match AttachmentType::from(Path::new("./dogs/corgis/kona.png")) {
            AttachmentType::Path(_) => true,
            _ => false,
        });
        assert!(match AttachmentType::from("./cats/copycat.png") {
            AttachmentType::Path(_) => true,
            _ => false,
        });
    }
}
<|endoftext|>


<commit_before>///!
///! Standard plugin is of the type of view plugins and backend plugins
///! which follows the same structure in the shared libs
///!

use dynamic_reload::Lib;
use libc::{c_char, c_void};
use std::rc::Rc;
use std::mem::transmute;
use std::ffi::CStr;

#[repr(C)]
pub struct CBasePlugin {
    pub name: *const c_char,
}

pub struct Plugin {
    pub lib: Rc<Lib>,
    pub name: String,
    pub type_name: String,
    pub plugin_funcs: *mut CBasePlugin,
}

impl Plugin {
    pub fn new(lib: &Rc<Lib>, plugin_type: *const c_char, plugin: *mut c_void) -> Plugin {
        unsafe {
            let plugin_funcs: *mut CBasePlugin = transmute(plugin);

            Plugin {
                lib: lib.clone(),
                type_name: CStr::from_ptr(plugin_type).to_string_lossy().into_owned(),
                name: CStr::from_ptr((*plugin_funcs).name).to_string_lossy().into_owned(),
                plugin_funcs: plugin_funcs,
            }
        }
    }
}

#[cfg(test)]
mod tests {
}
<commit_msg>Move construction of names to local vars first<commit_after>///!
///! Standard plugin is of the type of view plugins and backend plugins
///! which follows the same structure in the shared libs
///!

use dynamic_reload::Lib;
use libc::{c_char, c_void};
use std::rc::Rc;
use std::mem::transmute;
use std::ffi::CStr;

#[repr(C)]
pub struct CBasePlugin {
    pub name: *const c_char,
}

pub struct Plugin {
    pub lib: Rc<Lib>,
    pub name: String,
    pub type_name: String,
    pub plugin_funcs: *mut CBasePlugin,
}

impl Plugin {
    pub fn new(lib: &Rc<Lib>, plugin_type: *const c_char, plugin: *mut c_void) -> Plugin {
        unsafe {
            let plugin_funcs: *mut CBasePlugin = transmute(plugin);

            let type_name = CStr::from_ptr(plugin_type);
            let name = CStr::from_ptr((*plugin_funcs).name);

            Plugin {
                lib: lib.clone(),
                type_name: type_name.to_string_lossy().into_owned(),
                name: name.to_string_lossy().into_owned(),
                plugin_funcs: plugin_funcs,
            }
        }
    }
}

#[cfg(test)]
mod tests {
}
<|endoftext|>


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

use dom::bindings::codegen::Bindings::HTMLStyleElementBinding;
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLStyleElementDerived, NodeCast};
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::Document;
use dom::element::HTMLStyleElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeMethods, NodeHelpers, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use html::cssparse::parse_inline_css;
use layout_interface::{AddStylesheetMsg, LayoutChan};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLStyleElement {
    pub htmlelement: HTMLElement,
}

impl HTMLStyleElementDerived for EventTarget {
    fn is_htmlstyleelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLStyleElementTypeId))
    }
}

impl HTMLStyleElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLStyleElement {
        HTMLStyleElement {
            htmlelement: HTMLElement::new_inherited(HTMLStyleElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLStyleElement> {
        let element = HTMLStyleElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLStyleElementBinding::Wrap)
    }
}

pub trait HTMLStyleElementMethods {
}

pub trait StyleElementHelpers {
    fn parse_own_css(&self);
}

impl<'a> StyleElementHelpers for JSRef<'a, HTMLStyleElement> {
    fn parse_own_css(&self) {
        let node: &JSRef<Node> = NodeCast::from_ref(self);

        if !node.is_in_doc() {
            return;
        }

        let win = window_from_node(node).root();
        let url = win.deref().page().get_url();

        let data = node.GetTextContent().expect("Element.textContent must be a string");
        let sheet = parse_inline_css(url, data);
        let LayoutChan(ref layout_chan) = *win.deref().page().layout_chan;
        layout_chan.send(AddStylesheetMsg(sheet));
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLStyleElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods+> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_ref(self);
        Some(htmlelement as &VirtualMethods+)
    }

    fn child_inserted(&self, child: &JSRef<Node>) {
        match self.super_type() {
            Some(ref s) => s.child_inserted(child),
            _ => (),
        }
        self.parse_own_css();
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => ()
        }
        self.parse_own_css();
    }
}

impl Reflectable for HTMLStyleElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<commit_msg>Use tree_in_doc on Style elem to parse its own CSS, if needed<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::HTMLStyleElementBinding;
use dom::bindings::codegen::InheritTypes::{HTMLElementCast, HTMLStyleElementDerived, NodeCast};
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::document::Document;
use dom::element::HTMLStyleElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, NodeMethods, NodeHelpers, ElementNodeTypeId, window_from_node};
use dom::virtualmethods::VirtualMethods;
use html::cssparse::parse_inline_css;
use layout_interface::{AddStylesheetMsg, LayoutChan};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLStyleElement {
    pub htmlelement: HTMLElement,
}

impl HTMLStyleElementDerived for EventTarget {
    fn is_htmlstyleelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLStyleElementTypeId))
    }
}

impl HTMLStyleElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLStyleElement {
        HTMLStyleElement {
            htmlelement: HTMLElement::new_inherited(HTMLStyleElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLStyleElement> {
        let element = HTMLStyleElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLStyleElementBinding::Wrap)
    }
}

pub trait HTMLStyleElementMethods {
}

pub trait StyleElementHelpers {
    fn parse_own_css(&self);
}

impl<'a> StyleElementHelpers for JSRef<'a, HTMLStyleElement> {
    fn parse_own_css(&self) {
        let node: &JSRef<Node> = NodeCast::from_ref(self);
        assert!(node.is_in_doc());

        let win = window_from_node(node).root();
        let url = win.deref().page().get_url();

        let data = node.GetTextContent().expect("Element.textContent must be a string");
        let sheet = parse_inline_css(url, data);
        let LayoutChan(ref layout_chan) = *win.deref().page().layout_chan;
        layout_chan.send(AddStylesheetMsg(sheet));
    }
}

impl<'a> VirtualMethods for JSRef<'a, HTMLStyleElement> {
    fn super_type<'a>(&'a self) -> Option<&'a VirtualMethods+> {
        let htmlelement: &JSRef<HTMLElement> = HTMLElementCast::from_ref(self);
        Some(htmlelement as &VirtualMethods+)
    }

    fn child_inserted(&self, child: &JSRef<Node>) {
        match self.super_type() {
            Some(ref s) => s.child_inserted(child),
            _ => (),
        }

        let node: &JSRef<Node> = NodeCast::from_ref(self);
        if node.is_in_doc() {
            self.parse_own_css();
        }
    }

    fn bind_to_tree(&self, tree_in_doc: bool) {
        match self.super_type() {
            Some(ref s) => s.bind_to_tree(tree_in_doc),
            _ => ()
        }

        if tree_in_doc {
            self.parse_own_css();
        }
    }
}

impl Reflectable for HTMLStyleElement {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.htmlelement.reflector()
    }
}
<|endoftext|>


<commit_before>use std::rc::*;
use std::result::Result;
use serde_json::*;

use super::script::*;
use super::bound_script::*;
use super::script_interpreter::*;

///
/// Creates an unquoted version of a string
///
fn unquote_string(string: &str) -> String {
    let chars: Vec<char>    = string.chars().collect();
    let mut result          = String::new();
    let mut index           = 1;
    while index < chars.len()-1 {
        // Push character
        let chr = chars[index];

        match chr {
            '\\' => {
                let quoted = chars[index+1];
                index += 1;
                match quoted {
                    'n' => result.push('\n'),
                    'r' => result.push('\r'),
                    't' => result.push('\t'),
                    quoted => result.push(quoted)
                }
            },
            chr => result.push(chr)
        }

        // Next character
        index += 1;
    }

    result
}

///
/// Parses a number string
///
fn parse_number(number: &str) -> Value {
    if number.contains('.') || number.contains('e') || number.contains('E') {
        json![ number.parse::<f64>().unwrap() ]
    } else if number.starts_with("0x") {
        json![ i64::from_str_radix(&number[2..], 16).unwrap() ]
    } else {
        json![ number.parse::<i64>().unwrap() ]
    }
}

///
/// Creates an execution error relating to an expression
///
fn generate_expression_error(error: ScriptEvaluationError, expr: &Expression) -> Value {
    json![{
        "error":                error,
        "failed-expression":    expr
    }]
}

///
/// Generates a tool binding
///
pub fn bind_tool(tool_name: &ScriptToken, expr: &Expression, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    if let Ok(tool) = execution_environment.get_json_tool(&tool_name.matched) {
        Ok(BoundExpression::Tool(Rc::new(tool), tool_name.clone()))
    } else {
        Err(generate_expression_error(ScriptEvaluationError::ExpressionDoesNotEvaluateToTool, expr))
    }
}

///
/// Binds a sequence of elements
///
fn bind_sequence(items: &Vec<Expression>, execution_environment: &ScriptExecutionEnvironment) -> Result<Vec<BoundExpression>, Value> {
    let mut result = vec![];

    for expr in items {
        result.push(bind_expression(expr, execution_environment)?);
    }

    Ok(result)
}

///
/// Generates an array binding
///
pub fn bind_array(items: &Vec<Expression>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    bind_sequence(items, execution_environment)
        .map(|array_items| BoundExpression::Array(array_items))
}

///
/// Generates a tuple binding
///
pub fn bind_tuple(items: &Vec<Expression>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    bind_sequence(items, execution_environment)
        .map(|tuple_items| BoundExpression::Tuple(tuple_items))
}

///
/// Generates a map binding
///
pub fn bind_map(items: &Vec<(Expression, Expression)>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    let mut result = vec![];

    for &(ref lexpr, ref rexpr) in items {
        let lbound = bind_expression(lexpr, execution_environment)?;
        let rbound = bind_expression(rexpr, execution_environment)?;

        result.push((lbound, rbound));
    }

    Ok(BoundExpression::Map(result))
}

///
/// Binds an index expression (a[b])
///
pub fn bind_index(index: &Box<(Expression, Expression)>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    unimplemented!();
}

///
/// Binds a field access expression (a.b)
///
pub fn bind_field_access(field_access: &Box<(Expression, Expression)>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    unimplemented!();
}

///
/// Binds an apply expression (a(parameters))
///
pub fn bind_apply(apply: &Box<(Expression, Expression)>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    let (ref tool, ref parameters) = **apply;

    let bound_tool          = bind_expression(tool, execution_environment)?;
    let bound_parameters    = bind_expression(parameters, execution_environment)?;

    Ok(BoundExpression::Apply(Box::new((bound_tool, bound_parameters))))
}

///
/// Binds an expression to an environment
///
pub fn bind_expression(expr: &Expression, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    match expr {
        &Expression::String(ref s)              => Ok(BoundExpression::Value(Value::String(unquote_string(&s.matched)), s.clone())),
        &Expression::Number(ref n)              => Ok(BoundExpression::Value(parse_number(&n.matched), n.clone())),

        &Expression::Array(ref items)           => bind_array(items, execution_environment),
        &Expression::Tuple(ref items)           => bind_tuple(items, execution_environment),
        &Expression::Map(ref items)             => bind_map(items, execution_environment),

        &Expression::Identifier(ref id)         => bind_tool(id, expr, execution_environment),
        &Expression::Index(ref indexer)         => bind_index(indexer, execution_environment),
        &Expression::FieldAccess(ref accessor)  => bind_field_access(accessor, execution_environment),
        &Expression::Apply(ref application)     => bind_apply(application, execution_environment),
    }
}

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

    #[test]
    fn can_bind_string() {
        let string_expr         = Expression::string("\"Foo\"");
        let empty_environment   = EmptyEnvironment::new();
        let mut env             = ScriptExecutionEnvironment::new(&empty_environment);

        assert!(match bind_expression(&string_expr, &mut env) { Ok(BoundExpression::Value(Value::String(s), _)) => s == "Foo", _ => false });
    }

    #[test]
    fn can_bind_number() {
        let string_expr         = Expression::number("42");
        let empty_environment   = EmptyEnvironment::new();
        let mut env             = ScriptExecutionEnvironment::new(&empty_environment);

        assert!(match bind_expression(&string_expr, &mut env) { Ok(BoundExpression::Value(num, _)) => num == json![ 42 ], _ => false });
    }

    #[test]
    fn can_bind_tool() {
        let tool_expr           = Expression::identifier("test");
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&tool_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Tool(_, _)) => true, _ => false });
    }

    #[test]
    fn can_bind_array() {
        let array_expr          = Expression::Array(vec![Expression::identifier("test"), Expression::number("1")]);
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&array_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Array(_)) => true, _ => false });

        let array = match result { Ok(BoundExpression::Array(x)) => x, _ => vec![] };
        assert!(match array[0] { BoundExpression::Tool(_, _) => true, _ => false });
        assert!(match array[1] { BoundExpression::Value(_, _) => true, _ => false });
    }

    #[test]
    fn can_bind_tuple() {
        let tuple_expr          = Expression::Tuple(vec![Expression::identifier("test"), Expression::number("1")]);
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&tuple_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Tuple(_)) => true, _ => false });

        let tuple = match result { Ok(BoundExpression::Tuple(x)) => x, _ => vec![] };
        assert!(match tuple[0] { BoundExpression::Tool(_, _) => true, _ => false });
        assert!(match tuple[1] { BoundExpression::Value(_, _) => true, _ => false });
    }

    #[test]
    fn can_bind_map() {
        let map_expr            = Expression::Map(vec![(Expression::string("\"test\""), Expression::identifier("test"))]);
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&map_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Map(_)) => true, _ => false });

        let map = match result { Ok(BoundExpression::Map(x)) => x, _ => vec![] };
        assert!(match map[0] { (BoundExpression::Value(_, _), BoundExpression::Tool(_, _)) => true, _ => false });
    }

    #[test]
    fn can_bind_apply() {
        let apply_expr          = Expression::Apply(Box::new((Expression::string("\"test\""), Expression::identifier("test"))));
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&apply_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Apply(_)) => true, _ => false });
    }
}
<commit_msg>Bind indexers<commit_after>use std::rc::*;
use std::result::Result;
use serde_json::*;

use super::script::*;
use super::bound_script::*;
use super::script_interpreter::*;

///
/// Creates an unquoted version of a string
///
fn unquote_string(string: &str) -> String {
    let chars: Vec<char>    = string.chars().collect();
    let mut result          = String::new();
    let mut index           = 1;
    while index < chars.len()-1 {
        // Push character
        let chr = chars[index];

        match chr {
            '\\' => {
                let quoted = chars[index+1];
                index += 1;
                match quoted {
                    'n' => result.push('\n'),
                    'r' => result.push('\r'),
                    't' => result.push('\t'),
                    quoted => result.push(quoted)
                }
            },
            chr => result.push(chr)
        }

        // Next character
        index += 1;
    }

    result
}

///
/// Parses a number string
///
fn parse_number(number: &str) -> Value {
    if number.contains('.') || number.contains('e') || number.contains('E') {
        json![ number.parse::<f64>().unwrap() ]
    } else if number.starts_with("0x") {
        json![ i64::from_str_radix(&number[2..], 16).unwrap() ]
    } else {
        json![ number.parse::<i64>().unwrap() ]
    }
}

///
/// Creates an execution error relating to an expression
///
fn generate_expression_error(error: ScriptEvaluationError, expr: &Expression) -> Value {
    json![{
        "error":                error,
        "failed-expression":    expr
    }]
}

///
/// Generates a tool binding
///
pub fn bind_tool(tool_name: &ScriptToken, expr: &Expression, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    if let Ok(tool) = execution_environment.get_json_tool(&tool_name.matched) {
        Ok(BoundExpression::Tool(Rc::new(tool), tool_name.clone()))
    } else {
        Err(generate_expression_error(ScriptEvaluationError::ExpressionDoesNotEvaluateToTool, expr))
    }
}

///
/// Binds a sequence of elements
///
fn bind_sequence(items: &Vec<Expression>, execution_environment: &ScriptExecutionEnvironment) -> Result<Vec<BoundExpression>, Value> {
    let mut result = vec![];

    for expr in items {
        result.push(bind_expression(expr, execution_environment)?);
    }

    Ok(result)
}

///
/// Generates an array binding
///
pub fn bind_array(items: &Vec<Expression>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    bind_sequence(items, execution_environment)
        .map(|array_items| BoundExpression::Array(array_items))
}

///
/// Generates a tuple binding
///
pub fn bind_tuple(items: &Vec<Expression>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    bind_sequence(items, execution_environment)
        .map(|tuple_items| BoundExpression::Tuple(tuple_items))
}

///
/// Generates a map binding
///
pub fn bind_map(items: &Vec<(Expression, Expression)>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    let mut result = vec![];

    for &(ref lexpr, ref rexpr) in items {
        let lbound = bind_expression(lexpr, execution_environment)?;
        let rbound = bind_expression(rexpr, execution_environment)?;

        result.push((lbound, rbound));
    }

    Ok(BoundExpression::Map(result))
}

///
/// Binds an index expression (a[b])
///
pub fn bind_index(index: &Box<(Expression, Expression)>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    let (ref tool, ref indexer) = **index;

    let bound_tool      = bind_expression(tool, execution_environment)?;
    let bound_indexer   = bind_expression(indexer, execution_environment)?;

    Ok(BoundExpression::Index(Box::new((bound_tool, bound_indexer))))
}

///
/// Binds a field access expression (a.b)
///
pub fn bind_field_access(field_access: &Box<(Expression, Expression)>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    unimplemented!();
}

///
/// Binds an apply expression (a(parameters))
///
pub fn bind_apply(apply: &Box<(Expression, Expression)>, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    let (ref tool, ref parameters) = **apply;

    let bound_tool          = bind_expression(tool, execution_environment)?;
    let bound_parameters    = bind_expression(parameters, execution_environment)?;

    Ok(BoundExpression::Apply(Box::new((bound_tool, bound_parameters))))
}

///
/// Binds an expression to an environment
///
pub fn bind_expression(expr: &Expression, execution_environment: &ScriptExecutionEnvironment) -> Result<BoundExpression, Value> {
    match expr {
        &Expression::String(ref s)              => Ok(BoundExpression::Value(Value::String(unquote_string(&s.matched)), s.clone())),
        &Expression::Number(ref n)              => Ok(BoundExpression::Value(parse_number(&n.matched), n.clone())),

        &Expression::Array(ref items)           => bind_array(items, execution_environment),
        &Expression::Tuple(ref items)           => bind_tuple(items, execution_environment),
        &Expression::Map(ref items)             => bind_map(items, execution_environment),

        &Expression::Identifier(ref id)         => bind_tool(id, expr, execution_environment),
        &Expression::Index(ref indexer)         => bind_index(indexer, execution_environment),
        &Expression::FieldAccess(ref accessor)  => bind_field_access(accessor, execution_environment),
        &Expression::Apply(ref application)     => bind_apply(application, execution_environment),
    }
}

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

    #[test]
    fn can_bind_string() {
        let string_expr         = Expression::string("\"Foo\"");
        let empty_environment   = EmptyEnvironment::new();
        let mut env             = ScriptExecutionEnvironment::new(&empty_environment);

        assert!(match bind_expression(&string_expr, &mut env) { Ok(BoundExpression::Value(Value::String(s), _)) => s == "Foo", _ => false });
    }

    #[test]
    fn can_bind_number() {
        let string_expr         = Expression::number("42");
        let empty_environment   = EmptyEnvironment::new();
        let mut env             = ScriptExecutionEnvironment::new(&empty_environment);

        assert!(match bind_expression(&string_expr, &mut env) { Ok(BoundExpression::Value(num, _)) => num == json![ 42 ], _ => false });
    }

    #[test]
    fn can_bind_tool() {
        let tool_expr           = Expression::identifier("test");
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&tool_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Tool(_, _)) => true, _ => false });
    }

    #[test]
    fn can_bind_array() {
        let array_expr          = Expression::Array(vec![Expression::identifier("test"), Expression::number("1")]);
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&array_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Array(_)) => true, _ => false });

        let array = match result { Ok(BoundExpression::Array(x)) => x, _ => vec![] };
        assert!(match array[0] { BoundExpression::Tool(_, _) => true, _ => false });
        assert!(match array[1] { BoundExpression::Value(_, _) => true, _ => false });
    }

    #[test]
    fn can_bind_tuple() {
        let tuple_expr          = Expression::Tuple(vec![Expression::identifier("test"), Expression::number("1")]);
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&tuple_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Tuple(_)) => true, _ => false });

        let tuple = match result { Ok(BoundExpression::Tuple(x)) => x, _ => vec![] };
        assert!(match tuple[0] { BoundExpression::Tool(_, _) => true, _ => false });
        assert!(match tuple[1] { BoundExpression::Value(_, _) => true, _ => false });
    }

    #[test]
    fn can_bind_map() {
        let map_expr            = Expression::Map(vec![(Expression::string("\"test\""), Expression::identifier("test"))]);
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&map_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Map(_)) => true, _ => false });

        let map = match result { Ok(BoundExpression::Map(x)) => x, _ => vec![] };
        assert!(match map[0] { (BoundExpression::Value(_, _), BoundExpression::Tool(_, _)) => true, _ => false });
    }

    #[test]
    fn can_bind_apply() {
        let apply_expr          = Expression::Apply(Box::new((Expression::string("\"test\""), Expression::identifier("test"))));
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&apply_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Apply(_)) => true, _ => false });
    }

    #[test]
    fn can_bind_index() {
        let index_expr          = Expression::Index(Box::new((Expression::string("\"test\""), Expression::identifier("test"))));
        let tool_environment    = DynamicEnvironment::new();

        tool_environment.define("test", Box::new(make_pure_tool(|_: ()| "Success")));

        let mut env             = ScriptExecutionEnvironment::new(&tool_environment);
        let result              = bind_expression(&index_expr, &mut env);

        assert!(match result { Ok(BoundExpression::Index(_)) => true, _ => false });
    }
}
<|endoftext|>


<commit_before>#[doc = "Code to lex and tokenize css files."]

import comm::{port, chan};
import dom::style;
import option::is_none;
import str::from_bytes;
import vec::push;

import lexer_util::*;

enum ParserState {
    CssElement,
    CssRelation,
    CssDescription,
    CssAttribute
}

type CssLexer = {
    input_state: InputState,
    mut parser_state: ParserState
};

enum Token {
    StartDescription,
    EndDescription,
    Descendant,
    Child,
    Sibling,
    Comma,
    Element(~str),
    Attr(style::Attr),
    Description(~str, ~str),
    Eof
}

trait css_methods {
    fn parse_css() -> Token;
    fn parse_css_relation(c : u8) -> Token;
    fn parse_css_element(c : u8) -> Token;
    fn parse_css_attribute(c : u8) -> Token;
    fn parse_css_description(c: u8) -> Token;
}

impl css_methods of css_methods for CssLexer {
    fn parse_css() -> Token {
        let mut ch: u8;
        alt self.input_state.get() {
            CoeChar(c) { ch = c; }
            CoeEof { ret Eof; }
        }

        let token = alt self.parser_state {
          CssDescription { self.parse_css_description(ch) }
          CssAttribute   { self.parse_css_attribute(ch) }
          CssElement     { self.parse_css_element(ch) }
          CssRelation    { self.parse_css_relation(ch) }
        };

        #debug["token=%?", token];
        ret token;
    }

    fn parse_css_relation(c : u8) -> Token {
        self.parser_state = CssElement;

        let token = alt c {
          '{' as u8  { self.parser_state = CssDescription; StartDescription }
          '>' as u8  { Child }
          '+' as u8  { Sibling }
          ',' as u8  { Comma }
          _          { self.input_state.unget(c); Descendant }
        };

        self.input_state.eat_whitespace();

        ret token;
    }

    fn parse_css_element(c : u8) -> Token {
        assert is_none(self.input_state.lookahead);

        /* Check for special attributes with an implied element,
        or a wildcard which is not a alphabet character.*/
        if c == '.' as u8 || c == '#' as u8 {
            self.parser_state = CssAttribute;
            self.input_state.unget(c);
            ret Element(~"*");
        } else if c == '*' as u8 {
            self.parser_state = CssAttribute;
            ret Element(~"*");
        }

        self.input_state.unget(c);
        let element = self.input_state.parse_ident();

        self.parser_state = CssAttribute;

        ret Element(element);
    }

    fn parse_css_attribute(c : u8) -> Token {
        let mut ch = c;

        /* If we've reached the end of this list of attributes,
        look for the relation to the next element.*/
        if c.is_whitespace() {
            self.parser_state = CssRelation;
            self.input_state.eat_whitespace();

            alt self.input_state.get() {
              CoeChar(c)  { ch = c }
              CoeEof      { fail ~"File ended before description of style" }
            }

            ret self.parse_css_relation(ch);
        }

        alt ch {
          '.' as u8 { ret Attr(style::Includes(~"class", self.input_state.parse_ident())); }
          '#' as u8 { ret Attr(style::Includes(~"id", self.input_state.parse_ident())); }
          '[' as u8 {
            let attr_name = self.input_state.parse_ident();

            alt self.input_state.get() {
              CoeChar(c)    { ch = c; }
              CoeEof        { fail ~"File ended before description finished"; }
            }

            if ch == ']' as u8 {
                ret Attr(style::Exists(attr_name));
            } else if ch == '=' as u8 {
                let attr_val = self.input_state.parse_ident();
                self.input_state.expect(']' as u8);
                ret Attr(style::Exact(attr_name, attr_val));
            } else if ch == '~' as u8 {
                self.input_state.expect('=' as u8);
                let attr_val = self.input_state.parse_ident();
                self.input_state.expect(']' as u8);
                ret Attr(style::Includes(attr_name, attr_val));
            } else if ch == '|' as u8 {
                self.input_state.expect('=' as u8);
                let attr_val = self.input_state.parse_ident();
                self.input_state.expect(']' as u8);
                ret Attr(style::StartsWith(attr_name, attr_val));
            }

            fail #fmt("Unexpected symbol %c in attribute", ch as char);
          }
          _   { fail #fmt("Unexpected symbol %c in attribute", ch as char); }
        }
    }

    fn parse_css_description(c: u8) -> Token {
        let mut ch = c;

        if ch == '}' as u8 {
            self.parser_state = CssElement;
            self.input_state.eat_whitespace();
            ret EndDescription;
        } else if ch.is_whitespace() {
            self.input_state.eat_whitespace();

            alt self.input_state.get() {
              CoeChar(c)  { ch = c }
              CoeEof      { fail ~"Reached end of file in CSS description" }
            }
        }

        let mut desc_name = ~[];

        // Get the name of the descriptor
        loop {
            if ch.is_whitespace() {
                self.input_state.eat_whitespace();
            } else if ch == ':' as u8 {
                if desc_name.len() == 0u {
                    fail ~"Expected descriptor name";
                } else {
                    break;
                }
            } else {
                push(desc_name, ch);
            }

            alt self.input_state.get() {
              CoeChar(c)  { ch = c }
              CoeEof      { fail ~"Reached end of file in CSS description" }
            }
        }

        self.input_state.eat_whitespace();
        let mut desc_val = ~[];

        // Get the value of the descriptor
        loop {
            alt self.input_state.get() {
              CoeChar(c)  { ch = c }
              CoeEof      { fail ~"Reached end of file in CSS description" }
            }

            if ch.is_whitespace() {
                self.input_state.eat_whitespace();
            } else if ch == '}' as u8 {
                if desc_val.len() == 0u {
                    fail ~"Expected descriptor value";
                } else {
                    self.input_state.unget('}' as u8);
                    break;
                }
            } else if ch == ';' as u8 {
                if desc_val.len() == 0u {
                    fail ~"Expected descriptor value";
                } else {
                    break;
                }
            } else {
                push(desc_val, ch);
            }
        }

        ret Description(from_bytes(desc_name), from_bytes(desc_val));
    }
}

fn parser(reader: io::reader, state : ParserState) -> CssLexer {
    ret { input_state: {mut lookahead: none, reader: reader}, mut parser_state: state };
}

fn lex_css_from_bytes(-content : ~[u8], result_chan : chan<Token>) {
    let reader = io::bytes_reader(content);
    let lexer = parser(reader, CssElement);

    loop {
        let token = lexer.parse_css();
        let should_break = (token == Eof);

        result_chan.send(token);

        if should_break {
            break;
        }
    }
}

fn spawn_css_lexer_from_string(-content : ~str) -> port<Token> {
    let result_port = port();
    let result_chan = chan(result_port);

    task::spawn(|| lex_css_from_bytes(str::bytes(content), result_chan));

    ret result_port;
}

#[warn(no_non_implicitly_copyable_typarams)]
fn spawn_css_lexer_from_file(-filename: ~str) -> port<Token> {
    let result_port = port();
    let result_chan = chan(result_port);

    task::spawn(|| {
        assert (copy filename).ends_with(~".css");
        let file_try = io::read_whole_file(filename);

        // Check if the given css file existed, if it does, parse it,
        // otherwise just send an eof.
        if file_try.is_ok() {
            #debug["Lexing css sheet %s", copy filename];
            let file_data = file_try.get();
            lex_css_from_bytes(file_data, result_chan);
        } else {
            #debug["Failed to open css sheet %s", copy filename];
            result_chan.send(Eof);
        }
    });

    ret result_port;
}
<commit_msg>We don't have to copy strings anymore, since we can log slices.<commit_after>#[doc = "Code to lex and tokenize css files."]

import comm::{port, chan};
import dom::style;
import option::is_none;
import str::from_bytes;
import vec::push;

import lexer_util::*;

enum ParserState {
    CssElement,
    CssRelation,
    CssDescription,
    CssAttribute
}

type CssLexer = {
    input_state: InputState,
    mut parser_state: ParserState
};

enum Token {
    StartDescription,
    EndDescription,
    Descendant,
    Child,
    Sibling,
    Comma,
    Element(~str),
    Attr(style::Attr),
    Description(~str, ~str),
    Eof
}

trait css_methods {
    fn parse_css() -> Token;
    fn parse_css_relation(c : u8) -> Token;
    fn parse_css_element(c : u8) -> Token;
    fn parse_css_attribute(c : u8) -> Token;
    fn parse_css_description(c: u8) -> Token;
}

impl css_methods of css_methods for CssLexer {
    fn parse_css() -> Token {
        let mut ch: u8;
        alt self.input_state.get() {
            CoeChar(c) { ch = c; }
            CoeEof { ret Eof; }
        }

        let token = alt self.parser_state {
          CssDescription { self.parse_css_description(ch) }
          CssAttribute   { self.parse_css_attribute(ch) }
          CssElement     { self.parse_css_element(ch) }
          CssRelation    { self.parse_css_relation(ch) }
        };

        #debug["token=%?", token];
        ret token;
    }

    fn parse_css_relation(c : u8) -> Token {
        self.parser_state = CssElement;

        let token = alt c {
          '{' as u8  { self.parser_state = CssDescription; StartDescription }
          '>' as u8  { Child }
          '+' as u8  { Sibling }
          ',' as u8  { Comma }
          _          { self.input_state.unget(c); Descendant }
        };

        self.input_state.eat_whitespace();

        ret token;
    }

    fn parse_css_element(c : u8) -> Token {
        assert is_none(self.input_state.lookahead);

        /* Check for special attributes with an implied element,
        or a wildcard which is not a alphabet character.*/
        if c == '.' as u8 || c == '#' as u8 {
            self.parser_state = CssAttribute;
            self.input_state.unget(c);
            ret Element(~"*");
        } else if c == '*' as u8 {
            self.parser_state = CssAttribute;
            ret Element(~"*");
        }

        self.input_state.unget(c);
        let element = self.input_state.parse_ident();

        self.parser_state = CssAttribute;

        ret Element(element);
    }

    fn parse_css_attribute(c : u8) -> Token {
        let mut ch = c;

        /* If we've reached the end of this list of attributes,
        look for the relation to the next element.*/
        if c.is_whitespace() {
            self.parser_state = CssRelation;
            self.input_state.eat_whitespace();

            alt self.input_state.get() {
              CoeChar(c)  { ch = c }
              CoeEof      { fail ~"File ended before description of style" }
            }

            ret self.parse_css_relation(ch);
        }

        alt ch {
          '.' as u8 { ret Attr(style::Includes(~"class", self.input_state.parse_ident())); }
          '#' as u8 { ret Attr(style::Includes(~"id", self.input_state.parse_ident())); }
          '[' as u8 {
            let attr_name = self.input_state.parse_ident();

            alt self.input_state.get() {
              CoeChar(c)    { ch = c; }
              CoeEof        { fail ~"File ended before description finished"; }
            }

            if ch == ']' as u8 {
                ret Attr(style::Exists(attr_name));
            } else if ch == '=' as u8 {
                let attr_val = self.input_state.parse_ident();
                self.input_state.expect(']' as u8);
                ret Attr(style::Exact(attr_name, attr_val));
            } else if ch == '~' as u8 {
                self.input_state.expect('=' as u8);
                let attr_val = self.input_state.parse_ident();
                self.input_state.expect(']' as u8);
                ret Attr(style::Includes(attr_name, attr_val));
            } else if ch == '|' as u8 {
                self.input_state.expect('=' as u8);
                let attr_val = self.input_state.parse_ident();
                self.input_state.expect(']' as u8);
                ret Attr(style::StartsWith(attr_name, attr_val));
            }

            fail #fmt("Unexpected symbol %c in attribute", ch as char);
          }
          _   { fail #fmt("Unexpected symbol %c in attribute", ch as char); }
        }
    }

    fn parse_css_description(c: u8) -> Token {
        let mut ch = c;

        if ch == '}' as u8 {
            self.parser_state = CssElement;
            self.input_state.eat_whitespace();
            ret EndDescription;
        } else if ch.is_whitespace() {
            self.input_state.eat_whitespace();

            alt self.input_state.get() {
              CoeChar(c)  { ch = c }
              CoeEof      { fail ~"Reached end of file in CSS description" }
            }
        }

        let mut desc_name = ~[];

        // Get the name of the descriptor
        loop {
            if ch.is_whitespace() {
                self.input_state.eat_whitespace();
            } else if ch == ':' as u8 {
                if desc_name.len() == 0u {
                    fail ~"Expected descriptor name";
                } else {
                    break;
                }
            } else {
                push(desc_name, ch);
            }

            alt self.input_state.get() {
              CoeChar(c)  { ch = c }
              CoeEof      { fail ~"Reached end of file in CSS description" }
            }
        }

        self.input_state.eat_whitespace();
        let mut desc_val = ~[];

        // Get the value of the descriptor
        loop {
            alt self.input_state.get() {
              CoeChar(c)  { ch = c }
              CoeEof      { fail ~"Reached end of file in CSS description" }
            }

            if ch.is_whitespace() {
                self.input_state.eat_whitespace();
            } else if ch == '}' as u8 {
                if desc_val.len() == 0u {
                    fail ~"Expected descriptor value";
                } else {
                    self.input_state.unget('}' as u8);
                    break;
                }
            } else if ch == ';' as u8 {
                if desc_val.len() == 0u {
                    fail ~"Expected descriptor value";
                } else {
                    break;
                }
            } else {
                push(desc_val, ch);
            }
        }

        ret Description(from_bytes(desc_name), from_bytes(desc_val));
    }
}

fn parser(reader: io::reader, state : ParserState) -> CssLexer {
    ret { input_state: {mut lookahead: none, reader: reader}, mut parser_state: state };
}

fn lex_css_from_bytes(-content : ~[u8], result_chan : chan<Token>) {
    let reader = io::bytes_reader(content);
    let lexer = parser(reader, CssElement);

    loop {
        let token = lexer.parse_css();
        let should_break = (token == Eof);

        result_chan.send(token);

        if should_break {
            break;
        }
    }
}

fn spawn_css_lexer_from_string(-content : ~str) -> port<Token> {
    let result_port = port();
    let result_chan = chan(result_port);

    task::spawn(|| lex_css_from_bytes(str::bytes(content), result_chan));

    ret result_port;
}

#[warn(no_non_implicitly_copyable_typarams)]
fn spawn_css_lexer_from_file(-filename: ~str) -> port<Token> {
    let result_port = port();
    let result_chan = chan(result_port);

    task::spawn(|| {
        assert (copy filename).ends_with(~".css");
        let file_try = io::read_whole_file(filename);

        // Check if the given css file existed, if it does, parse it,
        // otherwise just send an eof.
        if file_try.is_ok() {
            #debug["Lexing css sheet %s", filename];
            let file_data = file_try.get();
            lex_css_from_bytes(file_data, result_chan);
        } else {
            #debug["Failed to open css sheet %s", filename];
            result_chan.send(Eof);
        }
    });

    ret result_port;
}
<|endoftext|>