<commit_before>use radians::{self, Radians};
use turtle_window::TurtleWindow;
use event::MouseButton;
use {Speed, Color, Event};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum AngleUnit {
    Degrees,
    Radians,
}

impl AngleUnit {
    fn to_radians(&self, angle: Angle) -> Radians {
        match *self {
            AngleUnit::Degrees => Radians::from_degrees_value(angle),
            AngleUnit::Radians => Radians::from_radians_value(angle),
        }
    }

    fn to_angle(&self, angle: Radians) -> Angle {
        match *self {
            AngleUnit::Degrees => angle.to_degrees(),
            AngleUnit::Radians => angle.to_radians(),
        }
    }
}

/// A point in 2D space: [x, y]
///
/// ```rust
/// # extern crate turtle;
/// # use turtle::Point;
/// # fn main() {
/// let p: Point = [100., 120.];
/// // get x coordinate
/// let x = p[0];
/// assert_eq!(x, 100.);
/// // get y coordinate
/// let y = p[1];
/// assert_eq!(y, 120.);
/// # }
pub type Point = [f64; 2];

/// Any distance value
pub type Distance = f64;

/// An angle value without a unit
///
/// The unit of the angle represented by this value depends on what
/// unit the Turtle was set to when this angle was retrieved
pub type Angle = f64;

/// A turtle with a pen attached to its tail.
///
/// **The idea:** You control a turtle with a pen tied to its tail. As it moves
/// across the screen, it draws the path that it follows. You can use this to draw
/// any picture you want just by moving the turtle across the screen.
///
/// ![turtle moving forward](https://github.com/sunjay/turtle/raw/master/forward.gif)
///
/// See the documentation for the methods below to learn about the different drawing commands you
/// can use with the turtle.
pub struct Turtle {
    window: TurtleWindow,
    angle_unit: AngleUnit,
}

impl Turtle {
    /// Create a new turtle.
    ///
    /// This will immediately open a new window with the turtle at the center. As each line in
    /// your program runs, the turtle shown in the window will update.
    ///
    /// ```rust
    /// # #![allow(unused_variables, unused_mut)]
    /// extern crate turtle;
    /// use turtle::Turtle;
    ///
    /// fn main() {
    ///     let mut turtle = Turtle::new();
    ///     // Do things with the turtle...
    /// }
    /// ```
    pub fn new() -> Turtle {
        Turtle {
            window: TurtleWindow::new(),
            angle_unit: AngleUnit::Degrees,
        }
    }

    /// Returns the current speed of the turtle
    ///
    /// ```rust
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// # let mut turtle = Turtle::new();
    /// turtle.set_speed(8);
    /// assert_eq!(turtle.speed(), Speed::Eight);
    /// # }
    /// ```
    pub fn speed(&self) -> Speed {
        self.window.turtle().speed
    }

    /// Returns the turtle's current location (x, y)
    ///
    /// ```rust
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// # let mut turtle = Turtle::new();
    /// turtle.forward(100.0);
    /// let pos = turtle.position();
    /// # // Cheating a bit here for rounding...
    /// # let pos = [pos[0].round(), pos[1].round()];
    /// assert_eq!(pos, [0.0, 100.0]);
    /// # }
    /// ```
    pub fn position(&self) -> Point {
        self.window.turtle().position
    }

    /// Returns the turtle's current heading
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn heading(&self) -> Angle {
        let heading = self.window.turtle().heading;
        self.angle_unit.to_angle(heading)
    }

    /// Returns true if the turtle is visible
    pub fn is_visible(&self) -> bool {
        self.window.turtle().visible
    }

    /// Returns true if Angle values will be interpreted as degrees
    pub fn is_using_degrees(&self) -> bool {
        self.angle_unit == AngleUnit::Degrees
    }

    /// Returns true if Angle values will be interpreted as radians
    pub fn is_using_radians(&self) -> bool {
        self.angle_unit == AngleUnit::Radians
    }

    /// Return true if pen is down, false if it’s up.
    pub fn is_pen_down(&self) -> bool {
        self.window.drawing().pen.enabled
    }

    /// Returns the size (thickness) of the pen
    pub fn pen_size(&self) -> f64 {
        self.window.drawing().pen.thickness
    }

    /// Returns the color of the pen
    pub fn pen_color(&self) -> Color {
        self.window.drawing().pen.color
    }

    /// Returns the color of the background
    pub fn background_color(&self) -> Color {
        self.window.drawing().background
    }

    /// Returns the current fill color
    ///
    /// This will be used to fill the shape when `begin_fill()` and `end_fill()` are called.
    //TODO: Hyperlink begin_fill() and end_fill() methods to their docs
    pub fn fill_color(&self) -> Color {
        self.window.drawing().fill_color
    }

    /// Begin filling the shape drawn by the turtle's movements
    pub fn begin_fill(&mut self) {
        self.window.begin_fill();
    }

    /// Stop filling the shape drawn by the turtle's movements
    pub fn end_fill(&mut self) {
        self.window.end_fill();
    }

    /// Pull the pen down so that the turtle draws while moving
    pub fn pen_down(&mut self) {
        self.window.drawing_mut().pen.enabled = true;
    }

    /// Pick the pen up so that the turtle does not draw while moving
    pub fn pen_up(&mut self) {
        self.window.drawing_mut().pen.enabled = false;
    }

    /// Sets the thickness of the pen to the given size
    //TODO: Document this more like set_speed
    pub fn set_pen_size(&mut self, thickness: f64) {
        self.window.drawing_mut().pen.thickness = thickness;
    }

    /// Sets the color of the pen to the given color
    //TODO: Document this more like set_speed
    pub fn set_pen_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().pen.color = color.into();
    }

    /// Sets the color of the background to the given color
    //TODO: Document this more like set_speed
    pub fn set_background_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().background = color.into();
    }

    /// Sets the fill color to the given color
    ///
    /// **Note:** Only the fill color set **before** `begin_fill()` is called will be used to fill
    /// the shape.
    //TODO: Document this more like set_speed
    pub fn set_fill_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().fill_color = color.into();
    }

    /// Set the turtle's movement speed to the given setting. This speed affects the animation of
    /// the turtle's movement and rotation.
    ///
    /// This method's types make it so that it can be called in a number of different ways:
    ///
    /// ```rust,no_run
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// # let mut turtle = Turtle::new();
    /// turtle.set_speed("normal");
    /// turtle.set_speed("fast");
    /// turtle.set_speed(2);
    /// turtle.set_speed(10);
    /// // Directly using a Speed variant works, but the methods above are usually more convenient.
    /// turtle.set_speed(Speed::Six);
    /// # }
    /// ```
    ///
    /// If input is a number greater than 10 or smaller than 1,
    /// speed is set to 0 (`Speed::Instant`). Strings are converted as follows:
    ///
    /// | String      | Value          |
    /// | ----------- | -------------- |
    /// | `"slowest"` | `Speed::One`     |
    /// | `"slow"`    | `Speed::Three`   |
    /// | `"normal"`  | `Speed::Six`     |
    /// | `"fast"`    | `Speed::Eight`   |
    /// | `"fastest"` | `Speed::Ten`     |
    /// | `"instant"` | `Speed::Instant` |
    ///
    /// Anything else will cause the program to `panic!` at runtime.
    ///
    /// ## Moving Instantly
    ///
    /// A speed of zero (`Speed::Instant`) results in no animation. The turtle moves instantly
    /// and turns instantly. This is very useful for moving the turtle from its "home" position
    /// before you start drawing. By setting the speed to instant, you don't have to wait for
    /// the turtle to move into position.
    ///
    /// ## Learning About Conversion Traits
    ///
    /// Using this method is an excellent way to learn about conversion
    /// traits `From` and `Into`. This method takes a *generic type* as its speed parameter. That type
    /// is specified to implement the `Into` trait for the type `Speed`. That means that *any* type
    /// that can be converted into a `Speed` can be passed to this method.
    ///
    /// We have implemented that trait for several types like strings and 32-bit integers so that
    /// those values can be passed into this method.
    /// Rather than calling this function and passing `Speed::Six` directly, you can use just `6`.
    /// Rust will then allow us to call `.into()` as provided by the `Into<Speed>` trait to get the
    /// corresponding `Speed` value.
    ///
    /// You can pass in strings, 32-bit integers, and even `Speed` enum variants because they all
    /// implement the `Into<Speed>` trait.
    pub fn set_speed<S: Into<Speed>>(&mut self, speed: S) {
        self.window.turtle_mut().speed = speed.into();
    }

    /// Delete the turtle's drawings from the screen.
    ///
    /// Do not move turtle. Position and heading of the turtle are not affected.
    pub fn clear(&mut self) {
        self.window.clear();
    }

    /// Makes the turtle invisible. The shell will not be shown, but drawings will continue.
    ///
    /// Useful for some complex drawings.
    pub fn hide(&mut self) {
        self.window.turtle_mut().visible = false;
    }

    /// Makes the turtle visible.
    pub fn show(&mut self) {
        self.window.turtle_mut().visible = true;
    }

    /// Change the angle unit to degrees.
    pub fn use_degrees(&mut self) {
        self.angle_unit = AngleUnit::Degrees;
    }

    /// Change the angle unit to radians.
    pub fn use_radians(&mut self) {
        self.angle_unit = AngleUnit::Radians;
    }

    /// Move the turtle forward by the given amount of `distance`.
    ///
    /// `distance` is given in "pixels" which are like really small turtle steps.
    /// `distance` can be negative in which case the turtle can move backward
    /// using this method.
    pub fn forward(&mut self, distance: Distance) {
        self.window.forward(distance);
    }

    /// Move the turtle backward by the given amount of `distance`.
    ///
    /// `distance` is given in "pixels" which are like really small turtle steps.
    /// `distance` can be negative in which case the turtle can move forwards
    /// using this method.
    pub fn backward(&mut self, distance: Distance) {
        // Moving backwards is essentially moving forwards with a negative distance
        self.window.forward(-distance);
    }

    /// Rotate the turtle right (clockwise) by the given angle.
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn right(&mut self, angle: Angle) {
        let angle = self.angle_unit.to_radians(angle);
        self.window.rotate(angle, true);
    }

    /// Rotate the turtle left (counterclockwise) by the given angle.
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn left(&mut self, angle: Angle) {
        let angle = self.angle_unit.to_radians(angle);
        self.window.rotate(angle, false);
    }

    /// Rotates the turtle to face the given coordinates.
    /// Coordinates are relative to the center of the window.
    ///
    /// If the coordinates are the same as the turtle's current position, no rotation takes place.
    /// Always rotates the least amount necessary in order to face the given point.
    ///
    /// ## UNSTABLE
    /// This feature is currently unstable and completely buggy. Do not use it until it is fixed.
    pub fn turn_towards(&mut self, target: Point) {
        let target_x = target[0];
        let target_y = target[1];

        let position = self.position();
        let x = position[0];
        let y = position[1];

        if (target_x - x).abs() < 0.1 && (target_y - y).abs() < 0.1 {
            return;
        }

        let heading = self.window.turtle().heading;

        let angle = (target_y - y).atan2(target_x - x);
        let angle = Radians::from_radians_value(angle);
        let angle = (angle - heading) % radians::TWO_PI;
        // Try to rotate as little as possible
        let angle = if angle.abs() > radians::PI {
            // Using signum to deal with negative angles properly
            angle.signum()*(radians::TWO_PI - angle.abs())
        }
        else {
            angle
        };
        self.window.rotate(angle, false);
    }

    /// Returns the next event (if any).
    //TODO: Example of usage with an event loop
    pub fn poll_event(&mut self) -> Option<Event> {
        self.window.poll_event()
    }

    /// Convenience function that waits for a click to occur before returning.
    ///
    /// Useful for when you want your program to wait for the user to click before continuing so
    /// that it doesn't start right away.
    pub fn wait_for_click(&mut self) {
        loop {
            if let Some(Event::MouseButtonReleased(MouseButton::Left)) = self.poll_event() {
                break;
            }
        }
    }
}
<commit_msg>Added documentation and tests for heading()<commit_after>use radians::{self, Radians};
use turtle_window::TurtleWindow;
use event::MouseButton;
use {Speed, Color, Event};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum AngleUnit {
    Degrees,
    Radians,
}

impl AngleUnit {
    fn to_radians(&self, angle: Angle) -> Radians {
        match *self {
            AngleUnit::Degrees => Radians::from_degrees_value(angle),
            AngleUnit::Radians => Radians::from_radians_value(angle),
        }
    }

    fn to_angle(&self, angle: Radians) -> Angle {
        match *self {
            AngleUnit::Degrees => angle.to_degrees(),
            AngleUnit::Radians => angle.to_radians(),
        }
    }
}

/// A point in 2D space: [x, y]
///
/// ```rust
/// # extern crate turtle;
/// # use turtle::Point;
/// # fn main() {
/// let p: Point = [100., 120.];
/// // get x coordinate
/// let x = p[0];
/// assert_eq!(x, 100.);
/// // get y coordinate
/// let y = p[1];
/// assert_eq!(y, 120.);
/// # }
pub type Point = [f64; 2];

/// Any distance value
pub type Distance = f64;

/// An angle value without a unit
///
/// The unit of the angle represented by this value depends on what
/// unit the Turtle was set to when this angle was retrieved
pub type Angle = f64;

/// A turtle with a pen attached to its tail.
///
/// **The idea:** You control a turtle with a pen tied to its tail. As it moves
/// across the screen, it draws the path that it follows. You can use this to draw
/// any picture you want just by moving the turtle across the screen.
///
/// ![turtle moving forward](https://github.com/sunjay/turtle/raw/master/forward.gif)
///
/// See the documentation for the methods below to learn about the different drawing commands you
/// can use with the turtle.
pub struct Turtle {
    window: TurtleWindow,
    angle_unit: AngleUnit,
}

impl Turtle {
    /// Create a new turtle.
    ///
    /// This will immediately open a new window with the turtle at the center. As each line in
    /// your program runs, the turtle shown in the window will update.
    ///
    /// ```rust
    /// # #![allow(unused_variables, unused_mut)]
    /// extern crate turtle;
    /// use turtle::Turtle;
    ///
    /// fn main() {
    ///     let mut turtle = Turtle::new();
    ///     // Do things with the turtle...
    /// }
    /// ```
    pub fn new() -> Turtle {
        Turtle {
            window: TurtleWindow::new(),
            angle_unit: AngleUnit::Degrees,
        }
    }

    /// Returns the current speed of the turtle
    ///
    /// ```rust
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// # let mut turtle = Turtle::new();
    /// turtle.set_speed(8);
    /// assert_eq!(turtle.speed(), Speed::Eight);
    /// # }
    /// ```
    pub fn speed(&self) -> Speed {
        self.window.turtle().speed
    }

    /// Returns the turtle's current location (x, y)
    ///
    /// ```rust
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// # let mut turtle = Turtle::new();
    /// turtle.forward(100.0);
    /// let pos = turtle.position();
    /// # // Cheating a bit here for rounding...
    /// # let pos = [pos[0].round(), pos[1].round()];
    /// assert_eq!(pos, [0.0, 100.0]);
    /// # }
    /// ```
    pub fn position(&self) -> Point {
        self.window.turtle().position
    }

    /// Returns the turtle's current heading.
    ///
    /// Units are by default degrees, but can be set using the
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians) methods.
    ///
    /// The heading is relative to the positive x axis (east). When first created, the turtle
    /// starts facing north. That means that its heading is 90.0 degrees. The following chart
    /// contains many common directions and their angles.
    ///
    /// | Cardinal Direction | Heading (degrees) | Heading (radians) |
    /// | ------------------ | ----------------- | ----------------- |
    /// | East               | 0.0°          | `0.0`             |
    /// | North              | 90.0°         | `PI/2`            |
    /// | West               | 180.0°        | `PI`              |
    /// | South              | 270.0°        | `3*PI/2`          |
    ///
    /// You can test the result of `heading()` with these values to see if the turtle is facing
    /// a certain direction.
    ///
    /// ```rust
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// // Turtles start facing north
    /// let mut turtle = Turtle::new();
    /// // The rounding is to account for floating-point error
    /// assert_eq!(turtle.heading().round(), 90.0);
    /// turtle.right(31.0);
    /// assert_eq!(turtle.heading().round(), 59.0);
    /// turtle.left(193.0);
    /// assert_eq!(turtle.heading().round(), 252.0);
    /// turtle.left(130.0);
    /// // Angles should not exceed 360.0
    /// assert_eq!(turtle.heading().round(), 22.0);
    /// # }
    /// ```
    pub fn heading(&self) -> Angle {
        let heading = self.window.turtle().heading;
        self.angle_unit.to_angle(heading)
    }

    /// Returns true if the turtle is visible
    pub fn is_visible(&self) -> bool {
        self.window.turtle().visible
    }

    /// Returns true if Angle values will be interpreted as degrees
    pub fn is_using_degrees(&self) -> bool {
        self.angle_unit == AngleUnit::Degrees
    }

    /// Returns true if Angle values will be interpreted as radians
    pub fn is_using_radians(&self) -> bool {
        self.angle_unit == AngleUnit::Radians
    }

    /// Return true if pen is down, false if it’s up.
    pub fn is_pen_down(&self) -> bool {
        self.window.drawing().pen.enabled
    }

    /// Returns the size (thickness) of the pen
    pub fn pen_size(&self) -> f64 {
        self.window.drawing().pen.thickness
    }

    /// Returns the color of the pen
    pub fn pen_color(&self) -> Color {
        self.window.drawing().pen.color
    }

    /// Returns the color of the background
    pub fn background_color(&self) -> Color {
        self.window.drawing().background
    }

    /// Returns the current fill color
    ///
    /// This will be used to fill the shape when `begin_fill()` and `end_fill()` are called.
    //TODO: Hyperlink begin_fill() and end_fill() methods to their docs
    pub fn fill_color(&self) -> Color {
        self.window.drawing().fill_color
    }

    /// Begin filling the shape drawn by the turtle's movements
    pub fn begin_fill(&mut self) {
        self.window.begin_fill();
    }

    /// Stop filling the shape drawn by the turtle's movements
    pub fn end_fill(&mut self) {
        self.window.end_fill();
    }

    /// Pull the pen down so that the turtle draws while moving
    pub fn pen_down(&mut self) {
        self.window.drawing_mut().pen.enabled = true;
    }

    /// Pick the pen up so that the turtle does not draw while moving
    pub fn pen_up(&mut self) {
        self.window.drawing_mut().pen.enabled = false;
    }

    /// Sets the thickness of the pen to the given size
    //TODO: Document this more like set_speed
    pub fn set_pen_size(&mut self, thickness: f64) {
        self.window.drawing_mut().pen.thickness = thickness;
    }

    /// Sets the color of the pen to the given color
    //TODO: Document this more like set_speed
    pub fn set_pen_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().pen.color = color.into();
    }

    /// Sets the color of the background to the given color
    //TODO: Document this more like set_speed
    pub fn set_background_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().background = color.into();
    }

    /// Sets the fill color to the given color
    ///
    /// **Note:** Only the fill color set **before** `begin_fill()` is called will be used to fill
    /// the shape.
    //TODO: Document this more like set_speed
    pub fn set_fill_color<C: Into<Color>>(&mut self, color: C) {
        self.window.drawing_mut().fill_color = color.into();
    }

    /// Set the turtle's movement speed to the given setting. This speed affects the animation of
    /// the turtle's movement and rotation.
    ///
    /// This method's types make it so that it can be called in a number of different ways:
    ///
    /// ```rust,no_run
    /// # extern crate turtle;
    /// # use turtle::*;
    /// # fn main() {
    /// # let mut turtle = Turtle::new();
    /// turtle.set_speed("normal");
    /// turtle.set_speed("fast");
    /// turtle.set_speed(2);
    /// turtle.set_speed(10);
    /// // Directly using a Speed variant works, but the methods above are usually more convenient.
    /// turtle.set_speed(Speed::Six);
    /// # }
    /// ```
    ///
    /// If input is a number greater than 10 or smaller than 1,
    /// speed is set to 0 (`Speed::Instant`). Strings are converted as follows:
    ///
    /// | String      | Value          |
    /// | ----------- | -------------- |
    /// | `"slowest"` | `Speed::One`     |
    /// | `"slow"`    | `Speed::Three`   |
    /// | `"normal"`  | `Speed::Six`     |
    /// | `"fast"`    | `Speed::Eight`   |
    /// | `"fastest"` | `Speed::Ten`     |
    /// | `"instant"` | `Speed::Instant` |
    ///
    /// Anything else will cause the program to `panic!` at runtime.
    ///
    /// ## Moving Instantly
    ///
    /// A speed of zero (`Speed::Instant`) results in no animation. The turtle moves instantly
    /// and turns instantly. This is very useful for moving the turtle from its "home" position
    /// before you start drawing. By setting the speed to instant, you don't have to wait for
    /// the turtle to move into position.
    ///
    /// ## Learning About Conversion Traits
    ///
    /// Using this method is an excellent way to learn about conversion
    /// traits `From` and `Into`. This method takes a *generic type* as its speed parameter. That type
    /// is specified to implement the `Into` trait for the type `Speed`. That means that *any* type
    /// that can be converted into a `Speed` can be passed to this method.
    ///
    /// We have implemented that trait for several types like strings and 32-bit integers so that
    /// those values can be passed into this method.
    /// Rather than calling this function and passing `Speed::Six` directly, you can use just `6`.
    /// Rust will then allow us to call `.into()` as provided by the `Into<Speed>` trait to get the
    /// corresponding `Speed` value.
    ///
    /// You can pass in strings, 32-bit integers, and even `Speed` enum variants because they all
    /// implement the `Into<Speed>` trait.
    pub fn set_speed<S: Into<Speed>>(&mut self, speed: S) {
        self.window.turtle_mut().speed = speed.into();
    }

    /// Delete the turtle's drawings from the screen.
    ///
    /// Do not move turtle. Position and heading of the turtle are not affected.
    pub fn clear(&mut self) {
        self.window.clear();
    }

    /// Makes the turtle invisible. The shell will not be shown, but drawings will continue.
    ///
    /// Useful for some complex drawings.
    pub fn hide(&mut self) {
        self.window.turtle_mut().visible = false;
    }

    /// Makes the turtle visible.
    pub fn show(&mut self) {
        self.window.turtle_mut().visible = true;
    }

    /// Change the angle unit to degrees.
    pub fn use_degrees(&mut self) {
        self.angle_unit = AngleUnit::Degrees;
    }

    /// Change the angle unit to radians.
    pub fn use_radians(&mut self) {
        self.angle_unit = AngleUnit::Radians;
    }

    /// Move the turtle forward by the given amount of `distance`.
    ///
    /// `distance` is given in "pixels" which are like really small turtle steps.
    /// `distance` can be negative in which case the turtle can move backward
    /// using this method.
    pub fn forward(&mut self, distance: Distance) {
        self.window.forward(distance);
    }

    /// Move the turtle backward by the given amount of `distance`.
    ///
    /// `distance` is given in "pixels" which are like really small turtle steps.
    /// `distance` can be negative in which case the turtle can move forwards
    /// using this method.
    pub fn backward(&mut self, distance: Distance) {
        // Moving backwards is essentially moving forwards with a negative distance
        self.window.forward(-distance);
    }

    /// Rotate the turtle right (clockwise) by the given angle.
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn right(&mut self, angle: Angle) {
        let angle = self.angle_unit.to_radians(angle);
        self.window.rotate(angle, true);
    }

    /// Rotate the turtle left (counterclockwise) by the given angle.
    ///
    /// Units are by default degrees, but can be set using the methods
    /// [`Turtle::use_degrees`](struct.Turtle.html#method.use_degrees) or
    /// [`Turtle::use_radians`](struct.Turtle.html#method.use_radians).
    pub fn left(&mut self, angle: Angle) {
        let angle = self.angle_unit.to_radians(angle);
        self.window.rotate(angle, false);
    }

    /// Rotates the turtle to face the given coordinates.
    /// Coordinates are relative to the center of the window.
    ///
    /// If the coordinates are the same as the turtle's current position, no rotation takes place.
    /// Always rotates the least amount necessary in order to face the given point.
    ///
    /// ## UNSTABLE
    /// This feature is currently unstable and completely buggy. Do not use it until it is fixed.
    pub fn turn_towards(&mut self, target: Point) {
        let target_x = target[0];
        let target_y = target[1];

        let position = self.position();
        let x = position[0];
        let y = position[1];

        if (target_x - x).abs() < 0.1 && (target_y - y).abs() < 0.1 {
            return;
        }

        let heading = self.window.turtle().heading;

        let angle = (target_y - y).atan2(target_x - x);
        let angle = Radians::from_radians_value(angle);
        let angle = (angle - heading) % radians::TWO_PI;
        // Try to rotate as little as possible
        let angle = if angle.abs() > radians::PI {
            // Using signum to deal with negative angles properly
            angle.signum()*(radians::TWO_PI - angle.abs())
        }
        else {
            angle
        };
        self.window.rotate(angle, false);
    }

    /// Returns the next event (if any).
    //TODO: Example of usage with an event loop
    pub fn poll_event(&mut self) -> Option<Event> {
        self.window.poll_event()
    }

    /// Convenience function that waits for a click to occur before returning.
    ///
    /// Useful for when you want your program to wait for the user to click before continuing so
    /// that it doesn't start right away.
    pub fn wait_for_click(&mut self) {
        loop {
            if let Some(Event::MouseButtonReleased(MouseButton::Left)) = self.poll_event() {
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Default shaders.

use luminance::Sem;
use luminance_gl::gl33::Uniform;
use std::ops::Deref;

use id::Id;
use shader::Program;
use scene::Scene;

pub type ColorUniform = Uniform<[f32; 4]>;
pub const DEFAULT_2D_COLOR: ColorUniform = Uniform::new(0);

struct DefaultProgram<'a>(Id<'a, Program>);

impl<'a> Deref for DefaultProgram<'a> {
  type Target = Id<'a, Program>;

  fn deref(&self) -> &Self::Target {
    &self.0
  }
}

impl<'a> DefaultProgram<'a> {
  pub fn get_id(scene: &'a mut Scene) -> Option<Self> {
    get_id!(scene, "default.glsl", vec![ColorUniform::sem("color")]).map(DefaultProgram)
  }
}
<commit_msg>Fixed DefaultProgram::get_from; pub DefaultProgram.<commit_after>//! Default shaders.

use luminance::Sem;
use luminance_gl::gl33::Uniform;
use std::ops::Deref;

use id::Id;
use shader::Program;
use scene::Scene;

pub type ColorUniform = Uniform<[f32; 4]>;
pub const DEFAULT_2D_COLOR: ColorUniform = Uniform::new(0);

pub struct DefaultProgram<'a>(Id<'a, Program>);

impl<'a> Deref for DefaultProgram<'a> {
  type Target = Id<'a, Program>;

  fn deref(&self) -> &Self::Target {
    &self.0
  }
}

impl<'a> DefaultProgram<'a> {
  pub fn get_from(scene: &mut Scene<'a>) -> Option<Self> {
    get_id!(scene, "default.glsl", vec![ColorUniform::sem("color")]).map(DefaultProgram)
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;

extern crate reqwest;
extern crate hyper_native_tls;
extern crate regex;
extern crate hyper;
extern crate blake2_rfc;
extern crate twox_hash;
extern crate chrono;
extern crate zip;
extern crate serde;
extern crate serde_json;
extern crate libc;
extern crate backtrace;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate openssl;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate hyper_openssl;

pub mod identifier_styles;
pub mod preludes;
pub mod filesystem;
pub mod fetching;
pub mod caching;
pub mod hashing;
pub mod process_testing;
pub mod process_capture;
pub mod colors;
pub mod debug;

pub mod timeywimey{
    pub fn time_bucket(seconds_per_bucket: u64, bucket_count: u64) -> u64{
        ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_secs() / seconds_per_bucket % bucket_count
    }
    pub use chrono::UTC;
}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Make imageflow_helpers run tests under system alloc<commit_after>#![feature(alloc_system)]

extern crate alloc_system;

#[macro_use]
extern crate lazy_static;

extern crate reqwest;
extern crate hyper_native_tls;
extern crate regex;
extern crate hyper;
extern crate blake2_rfc;
extern crate twox_hash;
extern crate chrono;
extern crate zip;
extern crate serde;
extern crate serde_json;
extern crate libc;
extern crate backtrace;

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate openssl;
#[cfg(not(any(target_os = "windows", target_os = "macos")))]
extern crate hyper_openssl;

pub mod identifier_styles;
pub mod preludes;
pub mod filesystem;
pub mod fetching;
pub mod caching;
pub mod hashing;
pub mod process_testing;
pub mod process_capture;
pub mod colors;
pub mod debug;

pub mod timeywimey{
    pub fn time_bucket(seconds_per_bucket: u64, bucket_count: u64) -> u64{
        ::std::time::SystemTime::now().duration_since(::std::time::UNIX_EPOCH).unwrap().as_secs() / seconds_per_bucket % bucket_count
    }
    pub use chrono::UTC;
}

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


<commit_before>use bit_set::Bitset;
use diag::Diagnostic;
use nameck::Atom;
use parser::Comparer;
use parser::NO_STATEMENT;
use parser::SegmentId;
use parser::SegmentOrder;
use parser::StatementAddress;
use parser::StatementRef;
use parser::StatementType;
use parser::TokenPtr;
use scopeck::ExprFragment;
use scopeck::Frame;
use scopeck::ScopeReader;
use scopeck::ScopeResult;
use segment_set::SegmentSet;
use std::cmp::Ordering;
use std::ops::Range;
use std::sync::Arc;
use std::u32;
use std::usize;
use util::fast_clear;
use util::fast_extend;
use util::fast_truncate;
use util::HashMap;
use util::new_map;

enum PreparedStep<'a> {
    Hyp(Bitset, Atom, Range<usize>),
    Assert(&'a Frame),
}

struct StackSlot {
    vars: Bitset,
    code: Atom,
    expr: Range<usize>,
}

struct VerifyState<'a> {
    order: &'a SegmentOrder,
    scoper: ScopeReader<'a>,
    cur_frame: &'a Frame,
    prepared: Vec<PreparedStep<'a>>,
    prep_buffer: Vec<u8>,
    stack: Vec<StackSlot>,
    stack_buffer: Vec<u8>,
    temp_buffer: Vec<u8>,
    subst_info: Vec<(Range<usize>, Bitset)>,
    var2bit: HashMap<TokenPtr<'a>, usize>,
    dv_map: &'a [Bitset],
}

fn map_var<'a>(state: &mut VerifyState<'a>, token: TokenPtr<'a>) -> usize {
    let nbit = state.var2bit.len();
    *state.var2bit.entry(token).or_insert(nbit)
}

// the initial hypotheses are accessed directly to avoid having to look up their names
fn prepare_hypotheses(state: &mut VerifyState) {
    for hyp in &state.cur_frame.hypotheses {
        let mut vars = Bitset::new();
        let tos = state.prep_buffer.len();

        for part in &hyp.expr.tail {
            match *part {
                ExprFragment::Var(ix) => {
                    fast_extend(&mut state.prep_buffer, &state.cur_frame.var_list[ix]);
                    vars.set_bit(ix); // and we have prior knowledge it's identity mapped
                    state.prep_buffer.push(b' ');
                }
                ExprFragment::Constant(ref string) => {
                    fast_extend(&mut state.prep_buffer, &state.cur_frame.const_pool[string.clone()]);
                }
            }
        }

        let ntos = state.prep_buffer.len();
        state.prepared.push(PreparedStep::Hyp(vars, hyp.expr.typecode, tos..ntos));
    }
}

fn prepare_step(state: &mut VerifyState, label: TokenPtr) -> Option<Diagnostic> {
    let frame = match state.scoper.get(label) {
        Some(fp) => fp,
        None => return Some(Diagnostic::StepMissing(label.to_owned())),
    };

    let valid = frame.valid;
    let pos = state.cur_frame.valid.start;
    if state.order.cmp(&pos, &valid.start) != Ordering::Greater {
        return Some(Diagnostic::StepUsedBeforeDefinition(label.to_owned()));
    }

    if valid.end != NO_STATEMENT {
        if pos.segment_id != valid.start.segment_id || pos.index >= valid.end {
            return Some(Diagnostic::StepUsedAfterScope(label.to_owned()));
        }
    }

    if frame.stype == StatementType::Axiom || frame.stype == StatementType::Provable {
        state.prepared.push(PreparedStep::Assert(frame));
    } else {
        let mut vars = Bitset::new();

        for var in &frame.var_list {
            vars.set_bit(map_var(state, var));
        }

        let tos = state.prep_buffer.len();
        fast_extend(&mut state.prep_buffer, &frame.stub_expr);
        let ntos = state.prep_buffer.len();
        state.prepared
            .push(PreparedStep::Hyp(vars, frame.target.typecode, tos..ntos));
    }

    return None;
}

fn do_substitute(target: &mut Vec<u8>,
                 frame: &Frame,
                 expr: &[ExprFragment],
                 vars: &[(Range<usize>, Bitset)],
                 var_buffer: &[u8]) {
    for part in expr {
        match *part {
            ExprFragment::Var(ix) => {
                fast_extend(target, &var_buffer[vars[ix].0.clone()]);
            }
            ExprFragment::Constant(ref string) => {
                fast_extend(target, &frame.const_pool[string.clone()]);
            }
        }
    }
}

fn do_substitute_raw(target: &mut Vec<u8>, frame: &Frame) {
    for part in &frame.target.tail {
        match *part {
            ExprFragment::Var(ix) => {
                fast_extend(target, &frame.var_list[ix]);
                target.push(b' ');
            }
            ExprFragment::Constant(ref string) => {
                fast_extend(target, &frame.const_pool[string.clone()]);
            }
        }
    }
}

fn do_substitute_vars(expr: &[ExprFragment], vars: &[(Range<usize>, Bitset)]) -> Bitset {
    let mut out = Bitset::new();
    for part in expr {
        match *part {
            ExprFragment::Var(ix) => out |= &vars[ix].1,
            ExprFragment::Constant(_) => {}
        }
    }
    out
}

fn execute_step(state: &mut VerifyState, index: usize) -> Option<Diagnostic> {
    if index >= state.prepared.len() {
        return Some(Diagnostic::StepOutOfRange);
    }

    let fref = match state.prepared[index] {
        PreparedStep::Hyp(ref vars, code, ref expr) => {
            let tos = state.stack_buffer.len();
            fast_extend(&mut state.stack_buffer, &state.prep_buffer[expr.clone()]);
            let ntos = state.stack_buffer.len();
            state.stack.push(StackSlot {
                vars: vars.clone(),
                code: code,
                expr: tos..ntos,
            });
            return None;
        }
        PreparedStep::Assert(fref) => fref,
    };

    if state.stack.len() < fref.hypotheses.len() {
        return Some(Diagnostic::ProofUnderflow);
    }
    let sbase = state.stack.len() - fref.hypotheses.len();

    state.subst_info.clear();
    state.subst_info.resize(fref.mandatory_count, (0..0, Bitset::new()));

    // check $f, build substitution
    for (ix, hyp) in fref.hypotheses.iter().enumerate() {
        if hyp.is_float {
            let slot = &state.stack[sbase + ix];
            if slot.code != hyp.expr.typecode {
                return Some(Diagnostic::StepFloatWrongType);
            }
            state.subst_info[hyp.variable_index] = (slot.expr.clone(), slot.vars.clone());
        }
    }

    // check $e
    for (ix, hyp) in fref.hypotheses.iter().enumerate() {
        if !hyp.is_float {
            let slot = &state.stack[sbase + ix];
            if slot.code != hyp.expr.typecode {
                return Some(Diagnostic::StepEssenWrongType);
            }
            fast_clear(&mut state.temp_buffer);
            do_substitute(&mut state.temp_buffer,
                          fref,
                          &hyp.expr.tail,
                          &state.subst_info,
                          &state.stack_buffer);
            if state.stack_buffer[slot.expr.clone()] != state.temp_buffer[..] {
                return Some(Diagnostic::StepEssenWrong);
            }
        }
    }

    fast_clear(&mut state.temp_buffer);
    do_substitute(&mut state.temp_buffer,
                  fref,
                  &fref.target.tail,
                  &state.subst_info,
                  &state.stack_buffer);

    state.stack.truncate(sbase);
    fast_truncate(&mut state.stack_buffer,
                  if sbase == 0 {
                      0
                  } else {
                      state.stack[sbase - 1].expr.end
                  });
    let tos = state.stack_buffer.len();
    fast_extend(&mut state.stack_buffer, &state.temp_buffer);
    let ntos = state.stack_buffer.len();

    state.stack.push(StackSlot {
        code: fref.target.typecode,
        vars: do_substitute_vars(&fref.target.tail, &state.subst_info),
        expr: tos..ntos,
    });

    // check $d
    for &(ix1, ix2) in &fref.mandatory_dv {
        for var1 in &state.subst_info[ix1].1 {
            for var2 in &state.subst_info[ix2].1 {
                if var1 >= state.dv_map.len() || !state.dv_map[var1].has_bit(var2) {
                    return Some(Diagnostic::ProofDvViolation);
                }
            }
        }
    }

    return None;
}

fn finalize_step(state: &mut VerifyState) -> Option<Diagnostic> {
    if state.stack.len() == 0 {
        return Some(Diagnostic::ProofNoSteps);
    }
    if state.stack.len() > 1 {
        return Some(Diagnostic::ProofExcessEnd);
    }
    let tos = state.stack.last().unwrap();

    if tos.code != state.cur_frame.target.typecode {
        return Some(Diagnostic::ProofWrongTypeEnd);
    }

    fast_clear(&mut state.temp_buffer);
    do_substitute_raw(&mut state.temp_buffer,
                      &state.cur_frame);

    if state.stack_buffer[tos.expr.clone()] != state.temp_buffer[..] {
        return Some(Diagnostic::ProofWrongExprEnd);
    }

    None
}

fn save_step(state: &mut VerifyState) {
    let top = state.stack.last().expect("can_save should prevent getting here");
    let tos = state.prep_buffer.len();
    fast_extend(&mut state.prep_buffer,
                &state.stack_buffer[top.expr.clone()]);
    let ntos = state.prep_buffer.len();
    state.prepared.push(PreparedStep::Hyp(top.vars.clone(), top.code, tos..ntos));
}

// proofs are not self-synchronizing, so it's not likely to get >1 usable error
fn verify_proof(sset: &SegmentSet, scopes: ScopeReader, stmt: StatementRef) -> Option<Diagnostic> {
    // only intend to check $p statements
    if stmt.statement.stype != StatementType::Provable {
        return None;
    }

    // no valid frame -> no use checking
    // may wish to record a secondary error?
    let cur_frame = match scopes.get(stmt.label()) {
        None => return None,
        Some(x) => x,
    };
    let mut state = VerifyState {
        scoper: scopes,
        order: &sset.order,
        cur_frame: cur_frame,
        stack: Vec::new(),
        stack_buffer: Vec::new(),
        prepared: Vec::new(),
        prep_buffer: Vec::new(),
        temp_buffer: Vec::new(),
        subst_info: Vec::new(),
        var2bit: new_map(),
        dv_map: &cur_frame.optional_dv,
    };

    for (index, tokr) in cur_frame.var_list.iter().enumerate() {
        state.var2bit.insert(tokr, index);
    }

    if stmt.proof_slice_at(0) == b"(" {
        let mut i = 1;

        prepare_hypotheses(&mut state);

        loop {
            if i >= stmt.proof_len() {
                return Some(Diagnostic::ProofUnterminatedRoster);
            }
            let chunk = stmt.proof_slice_at(i);
            i += 1;

            if chunk == b")" {
                break;
            }

            if let Some(err) = prepare_step(&mut state, chunk) {
                return Some(err);
            }
        }

        let mut k = 0usize;
        let mut can_save = false;
        while i < stmt.proof_len() {
            let chunk = stmt.proof_slice_at(i);
            for &ch in chunk {
                if ch >= b'A' && ch <= b'T' {
                    k = k * 20 + (ch - b'A') as usize;
                    if let Some(err) = execute_step(&mut state, k) {
                        return Some(err);
                    }
                    k = 0;
                    can_save = true;
                } else if ch >= b'U' && ch <= b'Y' {
                    k = k * 5 + 1 + (ch - b'U') as usize;
                    if k >= (u32::max_value() as usize / 20) - 1 {
                        return Some(Diagnostic::ProofMalformedVarint);
                    }
                    can_save = false;
                } else if ch == b'Z' {
                    if !can_save {
                        return Some(Diagnostic::ProofInvalidSave);
                    }
                    save_step(&mut state);
                    can_save = false;
                } else if ch == b'?' {
                    if k > 0 {
                        return Some(Diagnostic::ProofMalformedVarint);
                    }
                    return Some(Diagnostic::ProofIncomplete);
                }
            }
            i += 1;
        }

        if k > 0 {
            return Some(Diagnostic::ProofMalformedVarint);
        }
    } else {
        let mut count = 0;
        for i in 0..stmt.proof_len() {
            let chunk = stmt.proof_slice_at(i);
            if chunk == b"?" {
                return Some(Diagnostic::ProofIncomplete);
            } else {
                if let Some(err) = prepare_step(&mut state, chunk) {
                    return Some(err);
                }
                if let Some(err) = execute_step(&mut state, count) {
                    return Some(err);
                }
                count += 1;
            }
        }
    }

    if let Some(err) = finalize_step(&mut state) {
        return Some(err);
    }

    return None;
}

struct VerifySegment {
    diagnostics: HashMap<StatementAddress, Diagnostic>,
}

pub struct VerifyResult {
    segments: HashMap<SegmentId, Arc<VerifySegment>>,
}

impl VerifyResult {
    pub fn diagnostics(&self) -> Vec<(StatementAddress, Diagnostic)> {
        let mut out = Vec::new();
        for vsr in self.segments.values() {
            for (&sa, &ref diag) in &vsr.diagnostics {
                out.push((sa, diag.clone()));
            }
        }
        out
    }
}

fn verify_segment(sset: &SegmentSet, scopes: &ScopeResult, sid: SegmentId) -> VerifySegment {
    let reader = ScopeReader::new(scopes);
    let mut out = VerifySegment { diagnostics: new_map() };
    for stmt in sset.segment(sid).statement_iter() {
        if let Some(diag) = verify_proof(sset, reader, stmt) {
            out.diagnostics.insert(stmt.address(), diag);
        }
    }
    out
}

pub fn verify(segments: &SegmentSet, scope: &ScopeResult) -> VerifyResult {
    let mut out = VerifyResult { segments: new_map() };
    for sref in segments.segments() {
        out.segments.insert(sref.id, Arc::new(verify_segment(segments, scope, sref.id)));
    }
    out
}
<commit_msg>opt: reuse verification buffers between proofs<commit_after>use bit_set::Bitset;
use diag::Diagnostic;
use nameck::Atom;
use parser::Comparer;
use parser::NO_STATEMENT;
use parser::SegmentId;
use parser::SegmentOrder;
use parser::StatementAddress;
use parser::StatementRef;
use parser::StatementType;
use parser::TokenPtr;
use scopeck::ExprFragment;
use scopeck::Frame;
use scopeck::ScopeReader;
use scopeck::ScopeResult;
use segment_set::SegmentSet;
use std::cmp::Ordering;
use std::ops::Range;
use std::sync::Arc;
use std::u32;
use std::usize;
use util::fast_clear;
use util::fast_extend;
use util::fast_truncate;
use util::HashMap;
use util::new_map;

enum PreparedStep<'a> {
    Hyp(Bitset, Atom, Range<usize>),
    Assert(&'a Frame),
}

struct StackSlot {
    vars: Bitset,
    code: Atom,
    expr: Range<usize>,
}

struct VerifyState<'a> {
    order: &'a SegmentOrder,
    scoper: ScopeReader<'a>,
    cur_frame: &'a Frame,
    prepared: Vec<PreparedStep<'a>>,
    prep_buffer: Vec<u8>,
    stack: Vec<StackSlot>,
    stack_buffer: Vec<u8>,
    temp_buffer: Vec<u8>,
    subst_info: Vec<(Range<usize>, Bitset)>,
    var2bit: HashMap<TokenPtr<'a>, usize>,
    dv_map: &'a [Bitset],
}

fn map_var<'a>(state: &mut VerifyState<'a>, token: TokenPtr<'a>) -> usize {
    let nbit = state.var2bit.len();
    *state.var2bit.entry(token).or_insert(nbit)
}

// the initial hypotheses are accessed directly to avoid having to look up their names
fn prepare_hypotheses(state: &mut VerifyState) {
    for hyp in &state.cur_frame.hypotheses {
        let mut vars = Bitset::new();
        let tos = state.prep_buffer.len();

        for part in &hyp.expr.tail {
            match *part {
                ExprFragment::Var(ix) => {
                    fast_extend(&mut state.prep_buffer, &state.cur_frame.var_list[ix]);
                    vars.set_bit(ix); // and we have prior knowledge it's identity mapped
                    state.prep_buffer.push(b' ');
                }
                ExprFragment::Constant(ref string) => {
                    fast_extend(&mut state.prep_buffer, &state.cur_frame.const_pool[string.clone()]);
                }
            }
        }

        let ntos = state.prep_buffer.len();
        state.prepared.push(PreparedStep::Hyp(vars, hyp.expr.typecode, tos..ntos));
    }
}

fn prepare_step(state: &mut VerifyState, label: TokenPtr) -> Option<Diagnostic> {
    let frame = match state.scoper.get(label) {
        Some(fp) => fp,
        None => return Some(Diagnostic::StepMissing(label.to_owned())),
    };

    let valid = frame.valid;
    let pos = state.cur_frame.valid.start;
    if state.order.cmp(&pos, &valid.start) != Ordering::Greater {
        return Some(Diagnostic::StepUsedBeforeDefinition(label.to_owned()));
    }

    if valid.end != NO_STATEMENT {
        if pos.segment_id != valid.start.segment_id || pos.index >= valid.end {
            return Some(Diagnostic::StepUsedAfterScope(label.to_owned()));
        }
    }

    if frame.stype == StatementType::Axiom || frame.stype == StatementType::Provable {
        state.prepared.push(PreparedStep::Assert(frame));
    } else {
        let mut vars = Bitset::new();

        for var in &frame.var_list {
            vars.set_bit(map_var(state, var));
        }

        let tos = state.prep_buffer.len();
        fast_extend(&mut state.prep_buffer, &frame.stub_expr);
        let ntos = state.prep_buffer.len();
        state.prepared
            .push(PreparedStep::Hyp(vars, frame.target.typecode, tos..ntos));
    }

    return None;
}

fn do_substitute(target: &mut Vec<u8>,
                 frame: &Frame,
                 expr: &[ExprFragment],
                 vars: &[(Range<usize>, Bitset)],
                 var_buffer: &[u8]) {
    for part in expr {
        match *part {
            ExprFragment::Var(ix) => {
                fast_extend(target, &var_buffer[vars[ix].0.clone()]);
            }
            ExprFragment::Constant(ref string) => {
                fast_extend(target, &frame.const_pool[string.clone()]);
            }
        }
    }
}

fn do_substitute_raw(target: &mut Vec<u8>, frame: &Frame) {
    for part in &frame.target.tail {
        match *part {
            ExprFragment::Var(ix) => {
                fast_extend(target, &frame.var_list[ix]);
                target.push(b' ');
            }
            ExprFragment::Constant(ref string) => {
                fast_extend(target, &frame.const_pool[string.clone()]);
            }
        }
    }
}

fn do_substitute_vars(expr: &[ExprFragment], vars: &[(Range<usize>, Bitset)]) -> Bitset {
    let mut out = Bitset::new();
    for part in expr {
        match *part {
            ExprFragment::Var(ix) => out |= &vars[ix].1,
            ExprFragment::Constant(_) => {}
        }
    }
    out
}

fn execute_step(state: &mut VerifyState, index: usize) -> Option<Diagnostic> {
    if index >= state.prepared.len() {
        return Some(Diagnostic::StepOutOfRange);
    }

    let fref = match state.prepared[index] {
        PreparedStep::Hyp(ref vars, code, ref expr) => {
            let tos = state.stack_buffer.len();
            fast_extend(&mut state.stack_buffer, &state.prep_buffer[expr.clone()]);
            let ntos = state.stack_buffer.len();
            state.stack.push(StackSlot {
                vars: vars.clone(),
                code: code,
                expr: tos..ntos,
            });
            return None;
        }
        PreparedStep::Assert(fref) => fref,
    };

    if state.stack.len() < fref.hypotheses.len() {
        return Some(Diagnostic::ProofUnderflow);
    }
    let sbase = state.stack.len() - fref.hypotheses.len();

    state.subst_info.clear();
    state.subst_info.resize(fref.mandatory_count, (0..0, Bitset::new()));

    // check $f, build substitution
    for (ix, hyp) in fref.hypotheses.iter().enumerate() {
        if hyp.is_float {
            let slot = &state.stack[sbase + ix];
            if slot.code != hyp.expr.typecode {
                return Some(Diagnostic::StepFloatWrongType);
            }
            state.subst_info[hyp.variable_index] = (slot.expr.clone(), slot.vars.clone());
        }
    }

    // check $e
    for (ix, hyp) in fref.hypotheses.iter().enumerate() {
        if !hyp.is_float {
            let slot = &state.stack[sbase + ix];
            if slot.code != hyp.expr.typecode {
                return Some(Diagnostic::StepEssenWrongType);
            }
            fast_clear(&mut state.temp_buffer);
            do_substitute(&mut state.temp_buffer,
                          fref,
                          &hyp.expr.tail,
                          &state.subst_info,
                          &state.stack_buffer);
            if state.stack_buffer[slot.expr.clone()] != state.temp_buffer[..] {
                return Some(Diagnostic::StepEssenWrong);
            }
        }
    }

    fast_clear(&mut state.temp_buffer);
    do_substitute(&mut state.temp_buffer,
                  fref,
                  &fref.target.tail,
                  &state.subst_info,
                  &state.stack_buffer);

    state.stack.truncate(sbase);
    fast_truncate(&mut state.stack_buffer,
                  if sbase == 0 {
                      0
                  } else {
                      state.stack[sbase - 1].expr.end
                  });
    let tos = state.stack_buffer.len();
    fast_extend(&mut state.stack_buffer, &state.temp_buffer);
    let ntos = state.stack_buffer.len();

    state.stack.push(StackSlot {
        code: fref.target.typecode,
        vars: do_substitute_vars(&fref.target.tail, &state.subst_info),
        expr: tos..ntos,
    });

    // check $d
    for &(ix1, ix2) in &fref.mandatory_dv {
        for var1 in &state.subst_info[ix1].1 {
            for var2 in &state.subst_info[ix2].1 {
                if var1 >= state.dv_map.len() || !state.dv_map[var1].has_bit(var2) {
                    return Some(Diagnostic::ProofDvViolation);
                }
            }
        }
    }

    return None;
}

fn finalize_step(state: &mut VerifyState) -> Option<Diagnostic> {
    if state.stack.len() == 0 {
        return Some(Diagnostic::ProofNoSteps);
    }
    if state.stack.len() > 1 {
        return Some(Diagnostic::ProofExcessEnd);
    }
    let tos = state.stack.last().unwrap();

    if tos.code != state.cur_frame.target.typecode {
        return Some(Diagnostic::ProofWrongTypeEnd);
    }

    fast_clear(&mut state.temp_buffer);
    do_substitute_raw(&mut state.temp_buffer,
                      &state.cur_frame);

    if state.stack_buffer[tos.expr.clone()] != state.temp_buffer[..] {
        return Some(Diagnostic::ProofWrongExprEnd);
    }

    None
}

fn save_step(state: &mut VerifyState) {
    let top = state.stack.last().expect("can_save should prevent getting here");
    let tos = state.prep_buffer.len();
    fast_extend(&mut state.prep_buffer,
                &state.stack_buffer[top.expr.clone()]);
    let ntos = state.prep_buffer.len();
    state.prepared.push(PreparedStep::Hyp(top.vars.clone(), top.code, tos..ntos));
}

// proofs are not self-synchronizing, so it's not likely to get >1 usable error
fn verify_proof<'a>(statepp: &mut Option<VerifyState<'a>>, sset: &'a SegmentSet, scopes: ScopeReader<'a>, stmt: StatementRef<'a>) -> Option<Diagnostic> {
    // only intend to check $p statements
    if stmt.statement.stype != StatementType::Provable {
        return None;
    }

    // no valid frame -> no use checking
    // may wish to record a secondary error?
    let cur_frame = match scopes.get(stmt.label()) {
        None => return None,
        Some(x) => x,
    };

    if statepp.is_none() {
        *statepp = Some(VerifyState {
            scoper: scopes,
            order: &sset.order,
            cur_frame: cur_frame,
            stack: Vec::new(),
            stack_buffer: Vec::new(),
            prepared: Vec::new(),
            prep_buffer: Vec::new(),
            temp_buffer: Vec::new(),
            subst_info: Vec::new(),
            var2bit: new_map(),
            dv_map: &cur_frame.optional_dv,
        });
    }
    let state = statepp.as_mut().unwrap();
    state.cur_frame = cur_frame;
    state.stack.clear();
    fast_clear(&mut state.stack_buffer);
    state.prepared.clear();
    fast_clear(&mut state.prep_buffer);
    state.var2bit.clear();
    state.dv_map = &cur_frame.optional_dv;
    // temp_buffer and subst_info are cleared before use

    for (index, tokr) in cur_frame.var_list.iter().enumerate() {
        state.var2bit.insert(tokr, index);
    }

    if stmt.proof_slice_at(0) == b"(" {
        let mut i = 1;

        prepare_hypotheses(state);

        loop {
            if i >= stmt.proof_len() {
                return Some(Diagnostic::ProofUnterminatedRoster);
            }
            let chunk = stmt.proof_slice_at(i);
            i += 1;

            if chunk == b")" {
                break;
            }

            if let Some(err) = prepare_step(state, chunk) {
                return Some(err);
            }
        }

        let mut k = 0usize;
        let mut can_save = false;
        while i < stmt.proof_len() {
            let chunk = stmt.proof_slice_at(i);
            for &ch in chunk {
                if ch >= b'A' && ch <= b'T' {
                    k = k * 20 + (ch - b'A') as usize;
                    if let Some(err) = execute_step(state, k) {
                        return Some(err);
                    }
                    k = 0;
                    can_save = true;
                } else if ch >= b'U' && ch <= b'Y' {
                    k = k * 5 + 1 + (ch - b'U') as usize;
                    if k >= (u32::max_value() as usize / 20) - 1 {
                        return Some(Diagnostic::ProofMalformedVarint);
                    }
                    can_save = false;
                } else if ch == b'Z' {
                    if !can_save {
                        return Some(Diagnostic::ProofInvalidSave);
                    }
                    save_step(state);
                    can_save = false;
                } else if ch == b'?' {
                    if k > 0 {
                        return Some(Diagnostic::ProofMalformedVarint);
                    }
                    return Some(Diagnostic::ProofIncomplete);
                }
            }
            i += 1;
        }

        if k > 0 {
            return Some(Diagnostic::ProofMalformedVarint);
        }
    } else {
        let mut count = 0;
        for i in 0..stmt.proof_len() {
            let chunk = stmt.proof_slice_at(i);
            if chunk == b"?" {
                return Some(Diagnostic::ProofIncomplete);
            } else {
                if let Some(err) = prepare_step(state, chunk) {
                    return Some(err);
                }
                if let Some(err) = execute_step(state, count) {
                    return Some(err);
                }
                count += 1;
            }
        }
    }

    if let Some(err) = finalize_step(state) {
        return Some(err);
    }

    return None;
}

struct VerifySegment {
    diagnostics: HashMap<StatementAddress, Diagnostic>,
}

pub struct VerifyResult {
    segments: HashMap<SegmentId, Arc<VerifySegment>>,
}

impl VerifyResult {
    pub fn diagnostics(&self) -> Vec<(StatementAddress, Diagnostic)> {
        let mut out = Vec::new();
        for vsr in self.segments.values() {
            for (&sa, &ref diag) in &vsr.diagnostics {
                out.push((sa, diag.clone()));
            }
        }
        out
    }
}

fn verify_segment(sset: &SegmentSet, scopes: &ScopeResult, sid: SegmentId) -> VerifySegment {
    let reader = ScopeReader::new(scopes);
    let mut out = VerifySegment { diagnostics: new_map() };
    let mut state = None;
    for stmt in sset.segment(sid).statement_iter() {
        if let Some(diag) = verify_proof(&mut state, sset, reader, stmt) {
            out.diagnostics.insert(stmt.address(), diag);
        }
    }
    out
}

pub fn verify(segments: &SegmentSet, scope: &ScopeResult) -> VerifyResult {
    let mut out = VerifyResult { segments: new_map() };
    for sref in segments.segments() {
        out.segments.insert(sref.id, Arc::new(verify_segment(segments, scope, sref.id)));
    }
    out
}
<|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/. */

#[macro_use] #[no_link]
extern crate cfg_if;
extern crate gecko_bindings;
extern crate heapsize;
extern crate selectors;
extern crate serde;

use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use heapsize::HeapSizeOf;
use selectors::bloom::BloomHash;
use selectors::parser::FromCowStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;

#[macro_use]
pub mod atom_macro;
pub mod namespace;

pub use namespace::{Namespace, WeakNamespace};

/// A strong reference to a Gecko atom.
#[derive(PartialEq, Eq)]
pub struct Atom(*mut WeakAtom);

/// An atom *without* a strong reference.
///
/// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsIAtom);

pub type BorrowedAtom<'a> = &'a WeakAtom;

impl Deref for Atom {
    type Target = WeakAtom;

    #[inline]
    fn deref(&self) -> &WeakAtom {
        unsafe {
            &*self.0
        }
    }
}

impl Borrow<WeakAtom> for Atom {
    #[inline]
    fn borrow(&self) -> &WeakAtom {
        self
    }
}

impl Eq for WeakAtom {}
impl PartialEq for WeakAtom {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let weak: *const WeakAtom = self;
        let other: *const WeakAtom = other;
        weak == other
    }
}

unsafe impl Send for Atom {}
unsafe impl Sync for Atom {}
unsafe impl Sync for WeakAtom {}

impl WeakAtom {
    #[inline]
    pub unsafe fn new<'a>(atom: *mut nsIAtom) -> &'a mut Self {
        &mut *(atom as *mut WeakAtom)
    }

    #[inline]
    pub fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }

    #[inline]
    pub fn get_hash(&self) -> u32 {
        self.0.mHash
    }

    pub fn as_slice(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
        }
    }

    // NOTE: don't expose this, since it's slow, and easy to be misused.
    fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
        char::decode_utf16(self.as_slice().iter().cloned())
    }

    pub fn with_str<F, Output>(&self, cb: F) -> Output
        where F: FnOnce(&str) -> Output
    {
        // FIXME(bholley): We should measure whether it makes more sense to
        // cache the UTF-8 version in the Gecko atom table somehow.
        let owned = String::from_utf16(self.as_slice()).unwrap();
        cb(&owned)
    }

    #[inline]
    pub fn eq_str_ignore_ascii_case(&self, s: &str) -> bool {
        self.chars().map(|r| match r {
            Ok(c) => c.to_ascii_lowercase() as u32,
            Err(e) => e.unpaired_surrogate() as u32,
        }).eq(s.chars().map(|c| c.to_ascii_lowercase() as u32))
    }

    #[inline]
    pub fn to_string(&self) -> String {
        String::from_utf16(self.as_slice()).unwrap()
    }

    #[inline]
    pub fn is_static(&self) -> bool {
        unsafe {
            (*self.as_ptr()).mIsStatic() != 0
        }
    }

    #[inline]
    pub fn len(&self) -> u32 {
        unsafe {
            (*self.as_ptr()).mLength()
        }
    }

    #[inline]
    pub fn as_ptr(&self) -> *mut nsIAtom {
        let const_ptr: *const nsIAtom = &self.0;
        const_ptr as *mut nsIAtom
    }
}

impl fmt::Debug for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko WeakAtom({:p}, {})", self, self)
    }
}

impl fmt::Display for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        for c in self.chars() {
            try!(write!(w, "{}", c.unwrap_or(char::REPLACEMENT_CHARACTER)))
        }
        Ok(())
    }
}

impl Atom {
    pub unsafe fn with<F>(ptr: *mut nsIAtom, callback: &mut F) where F: FnMut(&Atom) {
        let atom = Atom(WeakAtom::new(ptr));
        callback(&atom);
        mem::forget(atom);
    }

    /// Creates an atom from an static atom pointer without checking in release
    /// builds.
    ///
    /// Right now it's only used by the atom macro, and ideally it should keep
    /// that way, now we have sugar for is_static, creating atoms using
    /// Atom::from should involve almost no overhead.
    #[inline]
    unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
        let atom = Atom(ptr as *mut WeakAtom);
        debug_assert!(atom.is_static(),
                      "Called from_static for a non-static atom!");
        atom
    }
}

impl BloomHash for Atom {
    #[inline]
    fn bloom_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl BloomHash for WeakAtom {
    #[inline]
    fn bloom_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl Hash for Atom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Hash for WeakAtom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Clone for Atom {
    #[inline(always)]
    fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }
}

impl Drop for Atom {
    #[inline]
    fn drop(&mut self) {
        if !self.is_static() {
            unsafe {
                Gecko_ReleaseAtom(self.as_ptr());
            }
        }
    }
}

impl Default for Atom {
    #[inline]
    fn default() -> Self {
        atom!("")
    }
}

impl HeapSizeOf for Atom {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}

impl Serialize for Atom {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        self.with_str(|s| s.serialize(serializer))
    }
}

impl Deserialize for Atom {
    fn deserialize<D>(deserializer: &mut D) -> Result<Atom, D::Error> where D: Deserializer {
        let string: String = try!(Deserialize::deserialize(deserializer));
        Ok(Atom::from(&*string))
    }
}

impl fmt::Debug for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko Atom({:p}, {})", self.0, self)
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            (&*self.0).fmt(w)
        }
    }
}

impl<'a> From<&'a str> for Atom {
    #[inline]
    fn from(string: &str) -> Atom {
        debug_assert!(string.len() <= u32::max_value() as usize);
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
            ))
        }
    }
}

impl<'a> From<Cow<'a, str>> for Atom {
    #[inline]
    fn from(string: Cow<'a, str>) -> Atom {
        Atom::from(&*string)
    }
}

impl FromCowStr for Atom {
    #[inline]
    fn from_cow_str(string: Cow<str>) -> Atom {
        Atom::from(&*string)
    }
}

impl From<String> for Atom {
    #[inline]
    fn from(string: String) -> Atom {
        Atom::from(&*string)
    }
}

impl From<*mut nsIAtom> for Atom {
    #[inline]
    fn from(ptr: *mut nsIAtom) -> Atom {
        debug_assert!(!ptr.is_null());
        unsafe {
            if (*ptr).mIsStatic() == 0 {
                Gecko_AddRefAtom(ptr);
            }
            Atom(WeakAtom::new(ptr))
        }
    }
}
<commit_msg>Allow improper_ctypes in atom_macro.<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/. */

#[macro_use] #[no_link]
extern crate cfg_if;
extern crate gecko_bindings;
extern crate heapsize;
extern crate selectors;
extern crate serde;

use gecko_bindings::bindings::Gecko_AddRefAtom;
use gecko_bindings::bindings::Gecko_Atomize;
use gecko_bindings::bindings::Gecko_ReleaseAtom;
use gecko_bindings::structs::nsIAtom;
use heapsize::HeapSizeOf;
use selectors::bloom::BloomHash;
use selectors::parser::FromCowStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::ascii::AsciiExt;
use std::borrow::{Cow, Borrow};
use std::char::{self, DecodeUtf16};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::Cloned;
use std::mem;
use std::ops::Deref;
use std::slice;

#[macro_use]
#[allow(improper_ctypes)]
pub mod atom_macro;
pub mod namespace;

pub use namespace::{Namespace, WeakNamespace};

/// A strong reference to a Gecko atom.
#[derive(PartialEq, Eq)]
pub struct Atom(*mut WeakAtom);

/// An atom *without* a strong reference.
///
/// Only usable as `&'a WeakAtom`,
/// where `'a` is the lifetime of something that holds a strong reference to that atom.
pub struct WeakAtom(nsIAtom);

pub type BorrowedAtom<'a> = &'a WeakAtom;

impl Deref for Atom {
    type Target = WeakAtom;

    #[inline]
    fn deref(&self) -> &WeakAtom {
        unsafe {
            &*self.0
        }
    }
}

impl Borrow<WeakAtom> for Atom {
    #[inline]
    fn borrow(&self) -> &WeakAtom {
        self
    }
}

impl Eq for WeakAtom {}
impl PartialEq for WeakAtom {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        let weak: *const WeakAtom = self;
        let other: *const WeakAtom = other;
        weak == other
    }
}

unsafe impl Send for Atom {}
unsafe impl Sync for Atom {}
unsafe impl Sync for WeakAtom {}

impl WeakAtom {
    #[inline]
    pub unsafe fn new<'a>(atom: *mut nsIAtom) -> &'a mut Self {
        &mut *(atom as *mut WeakAtom)
    }

    #[inline]
    pub fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }

    #[inline]
    pub fn get_hash(&self) -> u32 {
        self.0.mHash
    }

    pub fn as_slice(&self) -> &[u16] {
        unsafe {
            slice::from_raw_parts((*self.as_ptr()).mString, self.len() as usize)
        }
    }

    // NOTE: don't expose this, since it's slow, and easy to be misused.
    fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
        char::decode_utf16(self.as_slice().iter().cloned())
    }

    pub fn with_str<F, Output>(&self, cb: F) -> Output
        where F: FnOnce(&str) -> Output
    {
        // FIXME(bholley): We should measure whether it makes more sense to
        // cache the UTF-8 version in the Gecko atom table somehow.
        let owned = String::from_utf16(self.as_slice()).unwrap();
        cb(&owned)
    }

    #[inline]
    pub fn eq_str_ignore_ascii_case(&self, s: &str) -> bool {
        self.chars().map(|r| match r {
            Ok(c) => c.to_ascii_lowercase() as u32,
            Err(e) => e.unpaired_surrogate() as u32,
        }).eq(s.chars().map(|c| c.to_ascii_lowercase() as u32))
    }

    #[inline]
    pub fn to_string(&self) -> String {
        String::from_utf16(self.as_slice()).unwrap()
    }

    #[inline]
    pub fn is_static(&self) -> bool {
        unsafe {
            (*self.as_ptr()).mIsStatic() != 0
        }
    }

    #[inline]
    pub fn len(&self) -> u32 {
        unsafe {
            (*self.as_ptr()).mLength()
        }
    }

    #[inline]
    pub fn as_ptr(&self) -> *mut nsIAtom {
        let const_ptr: *const nsIAtom = &self.0;
        const_ptr as *mut nsIAtom
    }
}

impl fmt::Debug for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko WeakAtom({:p}, {})", self, self)
    }
}

impl fmt::Display for WeakAtom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        for c in self.chars() {
            try!(write!(w, "{}", c.unwrap_or(char::REPLACEMENT_CHARACTER)))
        }
        Ok(())
    }
}

impl Atom {
    pub unsafe fn with<F>(ptr: *mut nsIAtom, callback: &mut F) where F: FnMut(&Atom) {
        let atom = Atom(WeakAtom::new(ptr));
        callback(&atom);
        mem::forget(atom);
    }

    /// Creates an atom from an static atom pointer without checking in release
    /// builds.
    ///
    /// Right now it's only used by the atom macro, and ideally it should keep
    /// that way, now we have sugar for is_static, creating atoms using
    /// Atom::from should involve almost no overhead.
    #[inline]
    unsafe fn from_static(ptr: *mut nsIAtom) -> Self {
        let atom = Atom(ptr as *mut WeakAtom);
        debug_assert!(atom.is_static(),
                      "Called from_static for a non-static atom!");
        atom
    }
}

impl BloomHash for Atom {
    #[inline]
    fn bloom_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl BloomHash for WeakAtom {
    #[inline]
    fn bloom_hash(&self) -> u32 {
        self.get_hash()
    }
}

impl Hash for Atom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Hash for WeakAtom {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        state.write_u32(self.get_hash());
    }
}

impl Clone for Atom {
    #[inline(always)]
    fn clone(&self) -> Atom {
        Atom::from(self.as_ptr())
    }
}

impl Drop for Atom {
    #[inline]
    fn drop(&mut self) {
        if !self.is_static() {
            unsafe {
                Gecko_ReleaseAtom(self.as_ptr());
            }
        }
    }
}

impl Default for Atom {
    #[inline]
    fn default() -> Self {
        atom!("")
    }
}

impl HeapSizeOf for Atom {
    fn heap_size_of_children(&self) -> usize {
        0
    }
}

impl Serialize for Atom {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        self.with_str(|s| s.serialize(serializer))
    }
}

impl Deserialize for Atom {
    fn deserialize<D>(deserializer: &mut D) -> Result<Atom, D::Error> where D: Deserializer {
        let string: String = try!(Deserialize::deserialize(deserializer));
        Ok(Atom::from(&*string))
    }
}

impl fmt::Debug for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        write!(w, "Gecko Atom({:p}, {})", self.0, self)
    }
}

impl fmt::Display for Atom {
    fn fmt(&self, w: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            (&*self.0).fmt(w)
        }
    }
}

impl<'a> From<&'a str> for Atom {
    #[inline]
    fn from(string: &str) -> Atom {
        debug_assert!(string.len() <= u32::max_value() as usize);
        unsafe {
            Atom(WeakAtom::new(
                Gecko_Atomize(string.as_ptr() as *const _, string.len() as u32)
            ))
        }
    }
}

impl<'a> From<Cow<'a, str>> for Atom {
    #[inline]
    fn from(string: Cow<'a, str>) -> Atom {
        Atom::from(&*string)
    }
}

impl FromCowStr for Atom {
    #[inline]
    fn from_cow_str(string: Cow<str>) -> Atom {
        Atom::from(&*string)
    }
}

impl From<String> for Atom {
    #[inline]
    fn from(string: String) -> Atom {
        Atom::from(&*string)
    }
}

impl From<*mut nsIAtom> for Atom {
    #[inline]
    fn from(ptr: *mut nsIAtom) -> Atom {
        debug_assert!(!ptr.is_null());
        unsafe {
            if (*ptr).mIsStatic() == 0 {
                Gecko_AddRefAtom(ptr);
            }
            Atom(WeakAtom::new(ptr))
        }
    }
}
<|endoftext|>


<commit_before>#[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
use serialize::json::Json;
#[cfg(feature = "serde_type")]
use serde_json::value::Value as Json;

use helpers::HelperDef;
use registry::Registry;
use context::{Context, JsonRender};
use render::{RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct LookupHelper;

impl HelperDef for LookupHelper {
    #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
    fn call(&self,
            _: &Context,
            h: &Helper,
            _: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let collection_value = try!(h.param(0).ok_or_else(|| {
            RenderError::new("Param not found for helper \"lookup\"")
        }));
        let index = try!(h.param(1).ok_or_else(|| {
            RenderError::new("Insufficient params for helper \"lookup\"")
        }));

        let null = Json::Null;
        let value = match collection_value.value() {
            &Json::Array(ref v) => {
                index.value()
                     .as_u64()
                     .and_then(|u| Some(u as usize))
                     .and_then(|u| v.get(u))
                     .unwrap_or(&null)
            }
            &Json::Object(ref m) => {
                index.value()
                     .as_string()
                     .and_then(|k| m.get(k))
                     .unwrap_or(&null)
            }
            _ => &null,
        };
        let r = value.render();
        try!(rc.writer.write(r.into_bytes().as_ref()));
        Ok(())
    }

    #[cfg(feature = "serde_type")]
    fn call(&self,
            _: &Context,
            h: &Helper,
            _: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let collection_value = try!(h.param(0).ok_or_else(|| {
            RenderError::new("Param not found for helper \"lookup\"")
        }));
        let index = try!(h.param(1).ok_or_else(|| {
            RenderError::new("Insufficient params for helper \"lookup\"")
        }));

        let null = Json::Null;
        let value = match collection_value.value() {
            &Json::Array(ref v) => {
                index.value()
                     .as_u64()
                     .and_then(|u| Some(u as usize))
                     .and_then(|u| v.get(u))
                     .unwrap_or(&null)
            }
            &Json::Object(ref m) => {
                index.value()
                     .as_str()
                     .and_then(|k| m.get(k))
                     .unwrap_or(&null)
            }
            _ => &null,
        };
        let r = value.render();
        try!(rc.writer.write(r.into_bytes().as_ref()));
        Ok(())
    }
}

pub static LOOKUP_HELPER: LookupHelper = LookupHelper;

#[cfg(test)]
mod test {
    use template::Template;
    use registry::Registry;

    use std::collections::BTreeMap;

    #[test]
    fn test_lookup() {
        let t0 = Template::compile("{{#each v1}}{{lookup ../../v2 @index}}{{/each}}".to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#each v1}}{{lookup ../../v2 1}}{{/each}}".to_string())
                     .ok()
                     .unwrap();
        let t2 = Template::compile("{{lookup kk \"a\"}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);
        handlebars.register_template("t2", t2);

        let mut m: BTreeMap<String, Vec<u16>> = BTreeMap::new();
        m.insert("v1".to_string(), vec![1u16, 2u16, 3u16]);
        m.insert("v2".to_string(), vec![9u16, 8u16, 7u16]);

        let m2 = btreemap!{
            "kk".to_string() => btreemap!{"a".to_string() => "world".to_string()}
        };

        let r0 = handlebars.render("t0", &m);
        assert_eq!(r0.ok().unwrap(), "987".to_string());

        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "888".to_string());

        let r2 = handlebars.render("t2", &m2);
        assert_eq!(r2.ok().unwrap(), "world".to_string());
    }
}
<commit_msg>(refactor) remove duplicate code between features<commit_after>#[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
use serialize::json::Json;
#[cfg(feature = "serde_type")]
use serde_json::value::Value as Json;

use helpers::HelperDef;
use registry::Registry;
use context::{Context, JsonRender};
use render::{RenderContext, RenderError, Helper};

#[derive(Clone, Copy)]
pub struct LookupHelper;

impl HelperDef for LookupHelper {
    fn call(&self,
            _: &Context,
            h: &Helper,
            _: &Registry,
            rc: &mut RenderContext)
            -> Result<(), RenderError> {
        let collection_value = try!(h.param(0).ok_or_else(|| {
            RenderError::new("Param not found for helper \"lookup\"")
        }));
        let index = try!(h.param(1).ok_or_else(|| {
            RenderError::new("Insufficient params for helper \"lookup\"")
        }));

        let null = Json::Null;
        let value = match collection_value.value() {
            &Json::Array(ref v) => {
                index.value()
                     .as_u64()
                     .and_then(|u| Some(u as usize))
                     .and_then(|u| v.get(u))
                     .unwrap_or(&null)
            }
            #[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
            &Json::Object(ref m) => {
                index.value()
                     .as_string()
                     .and_then(|k| m.get(k))
                     .unwrap_or(&null)
            }
            #[cfg(feature = "serde_type")]
            &Json::Object(ref m) => {
                index.value()
                     .as_str()
                     .and_then(|k| m.get(k))
                     .unwrap_or(&null)
            }
            _ => &null,
        };
        let r = value.render();
        try!(rc.writer.write(r.into_bytes().as_ref()));
        Ok(())
    }
}

pub static LOOKUP_HELPER: LookupHelper = LookupHelper;

#[cfg(test)]
mod test {
    use template::Template;
    use registry::Registry;

    use std::collections::BTreeMap;

    #[test]
    fn test_lookup() {
        let t0 = Template::compile("{{#each v1}}{{lookup ../../v2 @index}}{{/each}}".to_string())
                     .ok()
                     .unwrap();
        let t1 = Template::compile("{{#each v1}}{{lookup ../../v2 1}}{{/each}}".to_string())
                     .ok()
                     .unwrap();
        let t2 = Template::compile("{{lookup kk \"a\"}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);
        handlebars.register_template("t2", t2);

        let mut m: BTreeMap<String, Vec<u16>> = BTreeMap::new();
        m.insert("v1".to_string(), vec![1u16, 2u16, 3u16]);
        m.insert("v2".to_string(), vec![9u16, 8u16, 7u16]);

        let m2 = btreemap!{
            "kk".to_string() => btreemap!{"a".to_string() => "world".to_string()}
        };

        let r0 = handlebars.render("t0", &m);
        assert_eq!(r0.ok().unwrap(), "987".to_string());

        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "888".to_string());

        let r2 = handlebars.render("t2", &m2);
        assert_eq!(r2.ok().unwrap(), "world".to_string());
    }
}
<|endoftext|>


<commit_before>#![allow(clippy::needless_borrow, clippy::non_ascii_literal)]

use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
use std::iter::FromIterator;
use syn::parse::{discouraged::Speculative, Parse, ParseStream, Parser, Result};
use syn::{parenthesized, Token};

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_sources() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input1: ParseStream) -> Result<Self> {
            let nested = |input2: ParseStream| {
                input1.advance_to(&input2);
                Ok(Self)
            };
            nested.parse_str("")
        }
    }

    syn::parse_str::<BreakRules>("").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            let b;
            parenthesized!(a in input);
            parenthesized!(b in input);
            a.advance_to(&b);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()()").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_into_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            parenthesized!(a in input);
            input.advance_to(&a);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()").unwrap();
}

#[test]
fn trailing_empty_none_group() {
    fn parse(input: ParseStream) -> Result<()> {
        input.parse::<Token![+]>()?;

        let content;
        parenthesized!(content in input);
        content.parse::<Token![+]>()?;

        Ok(())
    }

    // `+ ( + <Ø Ø> ) <Ø <Ø Ø> Ø>`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('+', Spacing::Alone)),
        TokenTree::Group(Group::new(
            Delimiter::Parenthesis,
            TokenStream::from_iter(vec![
                TokenTree::Punct(Punct::new('+', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
            ]),
        )),
        TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
        TokenTree::Group(Group::new(
            Delimiter::None,
            TokenStream::from_iter(vec![TokenTree::Group(Group::new(
                Delimiter::None,
                TokenStream::new(),
            ))]),
        )),
    ]);

    parse.parse2(tokens).unwrap();
}
<commit_msg>Resolve needless_borrow clippy lint<commit_after>#![allow(clippy::non_ascii_literal)]

use proc_macro2::{Delimiter, Group, Punct, Spacing, TokenStream, TokenTree};
use std::iter::FromIterator;
use syn::parse::{discouraged::Speculative, Parse, ParseStream, Parser, Result};
use syn::{parenthesized, Token};

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_sources() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input1: ParseStream) -> Result<Self> {
            let nested = |input2: ParseStream| {
                input1.advance_to(input2);
                Ok(Self)
            };
            nested.parse_str("")
        }
    }

    syn::parse_str::<BreakRules>("").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            let b;
            parenthesized!(a in input);
            parenthesized!(b in input);
            a.advance_to(&b);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()()").unwrap();
}

#[test]
#[should_panic(expected = "Fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_into_brackets() {
    struct BreakRules;
    impl Parse for BreakRules {
        fn parse(input: ParseStream) -> Result<Self> {
            let a;
            parenthesized!(a in input);
            input.advance_to(&a);
            Ok(Self)
        }
    }

    syn::parse_str::<BreakRules>("()").unwrap();
}

#[test]
fn trailing_empty_none_group() {
    fn parse(input: ParseStream) -> Result<()> {
        input.parse::<Token![+]>()?;

        let content;
        parenthesized!(content in input);
        content.parse::<Token![+]>()?;

        Ok(())
    }

    // `+ ( + <Ø Ø> ) <Ø <Ø Ø> Ø>`
    let tokens = TokenStream::from_iter(vec![
        TokenTree::Punct(Punct::new('+', Spacing::Alone)),
        TokenTree::Group(Group::new(
            Delimiter::Parenthesis,
            TokenStream::from_iter(vec![
                TokenTree::Punct(Punct::new('+', Spacing::Alone)),
                TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
            ]),
        )),
        TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
        TokenTree::Group(Group::new(
            Delimiter::None,
            TokenStream::from_iter(vec![TokenTree::Group(Group::new(
                Delimiter::None,
                TokenStream::new(),
            ))]),
        )),
    ]);

    parse.parse2(tokens).unwrap();
}
<|endoftext|>