<commit_before>// Copyright 2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::ops::*;

use structure::*;

use angle::Rad;
use approx::ApproxEq;
use euler::Euler;
use matrix::{Matrix2, Matrix3};
use num::BaseFloat;
use point::{Point2, Point3};
use quaternion::Quaternion;
use vector::{Vector2, Vector3};

/// A trait for a generic rotation. A rotation is a transformation that
/// creates a circular motion, and preserves at least one point in the space.
pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One where
    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
    Self: ApproxEq<Epsilon = <P as EuclideanSpace>::Scalar>,
    <P as EuclideanSpace>::Scalar: BaseFloat,
{
    /// Create a rotation to a given direction with an 'up' vector
    fn look_at(dir: P::Diff, up: P::Diff) -> Self;

    /// Create a shortest rotation to transform vector 'a' into 'b'.
    /// Both given vectors are assumed to have unit length.
    fn between_vectors(a: P::Diff, b: P::Diff) -> Self;

    /// Rotate a vector using this rotation.
    fn rotate_vector(&self, vec: P::Diff) -> P::Diff;

    /// Rotate a point using this rotation, by converting it to its
    /// representation as a vector.
    #[inline]
    fn rotate_point(&self, point: P) -> P {
        P::from_vec(self.rotate_vector(point.to_vec()))
    }

    /// Create a new rotation which "un-does" this rotation. That is,
    /// `r * r.invert()` is the identity.
    fn invert(&self) -> Self;
}

/// A two-dimensional rotation.
pub trait Rotation2<S: BaseFloat>: Rotation<Point2<S>>
                                 + Into<Matrix2<S>>
                                 + Into<Basis2<S>> {
    /// Create a rotation by a given angle. Thus is a redundant case of both
    /// from_axis_angle() and from_euler() for 2D space.
    fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self;
}

/// A three-dimensional rotation.
pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>>
                                 + Into<Matrix3<S>>
                                 + Into<Basis3<S>>
                                 + Into<Quaternion<S>>
                                 + From<Euler<Rad<S>>> {
    /// Create a rotation using an angle around a given axis.
    ///
    /// The specified axis **must be normalized**, or it represents an invalid rotation.
    fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Self;

    /// Create a rotation from an angle around the `x` axis (pitch).
    #[inline]
    fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Self {
        Rotation3::from_axis_angle(Vector3::unit_x(), theta)
    }

    /// Create a rotation from an angle around the `y` axis (yaw).
    #[inline]
    fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Self {
        Rotation3::from_axis_angle(Vector3::unit_y(), theta)
    }

    /// Create a rotation from an angle around the `z` axis (roll).
    #[inline]
    fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Self {
        Rotation3::from_axis_angle(Vector3::unit_z(), theta)
    }
}

/// A two-dimensional rotation matrix.
///
/// The matrix is guaranteed to be orthogonal, so some operations can be
/// implemented more efficiently than the implementations for `math::Matrix2`. To
/// enforce orthogonality at the type level the operations have been restricted
/// to a subset of those implemented on `Matrix2`.
///
/// ## Example
///
/// Suppose we want to rotate a vector that lies in the x-y plane by some
/// angle. We can accomplish this quite easily with a two-dimensional rotation
/// matrix:
///
/// ```no_run
/// use cgmath::Rad;
/// use cgmath::Vector2;
/// use cgmath::{Matrix, Matrix2};
/// use cgmath::{Rotation, Rotation2, Basis2};
/// use cgmath::ApproxEq;
/// use std::f64;
///
/// // For simplicity, we will rotate the unit x vector to the unit y vector --
/// // so the angle is 90 degrees, or π/2.
/// let unit_x: Vector2<f64> = Vector2::unit_x();
/// let rot: Basis2<f64> = Rotation2::from_angle(Rad(0.5f64 * f64::consts::PI));
///
/// // Rotate the vector using the two-dimensional rotation matrix:
/// let unit_y = rot.rotate_vector(unit_x);
///
/// // Since sin(π/2) may not be exactly zero due to rounding errors, we can
/// // use approx's assert_ulps_eq!() feature to show that it is close enough.
/// // assert_ulps_eq!(&unit_y, &Vector2::unit_y()); // TODO: Figure out how to use this
///
/// // This is exactly equivalent to using the raw matrix itself:
/// let unit_y2: Matrix2<_> = rot.into();
/// let unit_y2 = unit_y2 * unit_x;
/// assert_eq!(unit_y2, unit_y);
///
/// // Note that we can also concatenate rotations:
/// let rot_half: Basis2<f64> = Rotation2::from_angle(Rad(0.25f64 * f64::consts::PI));
/// let unit_y3 = (rot_half * rot_half).rotate_vector(unit_x);
/// // assert_ulps_eq!(&unit_y3, &unit_y2); // TODO: Figure out how to use this
/// ```
#[derive(PartialEq, Copy, Clone)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
pub struct Basis2<S> {
    mat: Matrix2<S>
}

impl<S: BaseFloat> AsRef<Matrix2<S>> for Basis2<S> {
    #[inline]
    fn as_ref(&self) -> &Matrix2<S> {
        &self.mat
    }
}

impl<S: BaseFloat> From<Basis2<S>> for Matrix2<S> {
    #[inline]
    fn from(b: Basis2<S>) -> Matrix2<S> { b.mat }
}

impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
    #[inline]
    fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> {
        Basis2 { mat: Matrix2::look_at(dir, up) }
    }

    #[inline]
    fn between_vectors(a: Vector2<S>, b: Vector2<S>) -> Basis2<S> {
        Rotation2::from_angle(Rad::acos(a.dot(b)) )
    }

    #[inline]
    fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> { self.mat * vec }

    // TODO: we know the matrix is orthogonal, so this could be re-written
    // to be faster
    #[inline]
    fn invert(&self) -> Basis2<S> { Basis2 { mat: self.mat.invert().unwrap() } }
}

impl<S: BaseFloat> One for Basis2<S> {
    #[inline]
    fn one() -> Basis2<S> { Basis2 { mat: Matrix2::one() } }
}

impl_operator!(<S: BaseFloat> Mul<Basis2<S> > for Basis2<S> {
    fn mul(lhs, rhs) -> Basis2<S> { Basis2 { mat: lhs.mat * rhs.mat  } }
});

impl<S: BaseFloat> ApproxEq for Basis2<S> {
    type Epsilon = S::Epsilon;

    #[inline]
    fn default_epsilon() -> S::Epsilon {
        S::default_epsilon()
    }

    #[inline]
    fn default_max_relative() -> S::Epsilon {
        S::default_max_relative()
    }

    #[inline]
    fn default_max_ulps() -> u32 {
        S::default_max_ulps()
    }

    #[inline]
    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
        Matrix2::relative_eq(&self.mat, &other.mat, epsilon, max_relative)
    }

    #[inline]
    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
        Matrix2::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps)
    }
}

impl<S: BaseFloat> Rotation2<S> for Basis2<S> {
    fn from_angle<A: Into<Rad<S>>>(theta: A) -> Basis2<S> { Basis2 { mat: Matrix2::from_angle(theta) } }
}

impl<S: fmt::Debug> fmt::Debug for Basis2<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Basis2 "));
        <[[S; 2]; 2] as fmt::Debug>::fmt(self.mat.as_ref(), f)
    }
}

/// A three-dimensional rotation matrix.
///
/// The matrix is guaranteed to be orthogonal, so some operations, specifically
/// inversion, can be implemented more efficiently than the implementations for
/// `math::Matrix3`. To ensure orthogonality is maintained, the operations have
/// been restricted to a subeset of those implemented on `Matrix3`.
#[derive(PartialEq, Copy, Clone)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
pub struct Basis3<S> {
    mat: Matrix3<S>
}

impl<S: BaseFloat> Basis3<S> {
    /// Create a new rotation matrix from a quaternion.
    #[inline]
    pub fn from_quaternion(quaternion: &Quaternion<S>) -> Basis3<S> {
        Basis3 { mat: quaternion.clone().into() }
    }
}

impl<S> AsRef<Matrix3<S>> for Basis3<S> {
    #[inline]
    fn as_ref(&self) -> &Matrix3<S> {
        &self.mat
    }
}

impl<S: BaseFloat> From<Basis3<S>> for Matrix3<S> {
    #[inline]
    fn from(b: Basis3<S>) -> Matrix3<S> { b.mat }
}

impl<S: BaseFloat> From<Basis3<S>> for Quaternion<S> {
    #[inline]
    fn from(b: Basis3<S>) -> Quaternion<S> { b.mat.into() }
}

impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
    #[inline]
    fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> {
        Basis3 { mat: Matrix3::look_at(dir, up) }
    }

    #[inline]
    fn between_vectors(a: Vector3<S>, b: Vector3<S>) -> Basis3<S> {
        let q: Quaternion<S> = Rotation::between_vectors(a, b);
        q.into()
    }

    #[inline]
    fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self.mat * vec }

    // TODO: we know the matrix is orthogonal, so this could be re-written
    // to be faster
    #[inline]
    fn invert(&self) -> Basis3<S> { Basis3 { mat: self.mat.invert().unwrap() } }
}

impl<S: BaseFloat> One for Basis3<S> {
    #[inline]
    fn one() -> Basis3<S> { Basis3 { mat: Matrix3::one() } }
}

impl_operator!(<S: BaseFloat> Mul<Basis3<S> > for Basis3<S> {
    fn mul(lhs, rhs) -> Basis3<S> { Basis3 { mat: lhs.mat * rhs.mat  } }
});

impl<S: BaseFloat> ApproxEq for Basis3<S> {
    type Epsilon = S::Epsilon;

    #[inline]
    fn default_epsilon() -> S::Epsilon {
        S::default_epsilon()
    }

    #[inline]
    fn default_max_relative() -> S::Epsilon {
        S::default_max_relative()
    }

    #[inline]
    fn default_max_ulps() -> u32 {
        S::default_max_ulps()
    }

    #[inline]
    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
        Matrix3::relative_eq(&self.mat, &other.mat, epsilon, max_relative)
    }

    #[inline]
    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
        Matrix3::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps)
    }
}

impl<S: BaseFloat> Rotation3<S> for Basis3<S> {
    fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Basis3<S> {
        Basis3 { mat: Matrix3::from_axis_angle(axis, angle) }
    }

    fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
        Basis3 { mat: Matrix3::from_angle_x(theta) }
    }

    fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
        Basis3 { mat: Matrix3::from_angle_y(theta) }
    }

    fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
        Basis3 { mat: Matrix3::from_angle_z(theta) }
    }
}

impl<A: Angle> From<Euler<A>> for Basis3<<A as Angle>::Unitless> where
    A: Into<Rad<<A as Angle>::Unitless>>,
{
    /// Create a three-dimensional rotation matrix from a set of euler angles.
    fn from(src: Euler<A>) -> Basis3<A::Unitless> {
        Basis3 {
            mat: Matrix3::from(src),
        }
    }
}

impl<S: fmt::Debug> fmt::Debug for Basis3<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Basis3 "));
        <[[S; 3]; 3] as fmt::Debug>::fmt(self.mat.as_ref(), f)
    }
}
<commit_msg>subeset -> subset.<commit_after>// Copyright 2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::ops::*;

use structure::*;

use angle::Rad;
use approx::ApproxEq;
use euler::Euler;
use matrix::{Matrix2, Matrix3};
use num::BaseFloat;
use point::{Point2, Point3};
use quaternion::Quaternion;
use vector::{Vector2, Vector3};

/// A trait for a generic rotation. A rotation is a transformation that
/// creates a circular motion, and preserves at least one point in the space.
pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One where
    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
    Self: ApproxEq<Epsilon = <P as EuclideanSpace>::Scalar>,
    <P as EuclideanSpace>::Scalar: BaseFloat,
{
    /// Create a rotation to a given direction with an 'up' vector
    fn look_at(dir: P::Diff, up: P::Diff) -> Self;

    /// Create a shortest rotation to transform vector 'a' into 'b'.
    /// Both given vectors are assumed to have unit length.
    fn between_vectors(a: P::Diff, b: P::Diff) -> Self;

    /// Rotate a vector using this rotation.
    fn rotate_vector(&self, vec: P::Diff) -> P::Diff;

    /// Rotate a point using this rotation, by converting it to its
    /// representation as a vector.
    #[inline]
    fn rotate_point(&self, point: P) -> P {
        P::from_vec(self.rotate_vector(point.to_vec()))
    }

    /// Create a new rotation which "un-does" this rotation. That is,
    /// `r * r.invert()` is the identity.
    fn invert(&self) -> Self;
}

/// A two-dimensional rotation.
pub trait Rotation2<S: BaseFloat>: Rotation<Point2<S>>
                                 + Into<Matrix2<S>>
                                 + Into<Basis2<S>> {
    /// Create a rotation by a given angle. Thus is a redundant case of both
    /// from_axis_angle() and from_euler() for 2D space.
    fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self;
}

/// A three-dimensional rotation.
pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>>
                                 + Into<Matrix3<S>>
                                 + Into<Basis3<S>>
                                 + Into<Quaternion<S>>
                                 + From<Euler<Rad<S>>> {
    /// Create a rotation using an angle around a given axis.
    ///
    /// The specified axis **must be normalized**, or it represents an invalid rotation.
    fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Self;

    /// Create a rotation from an angle around the `x` axis (pitch).
    #[inline]
    fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Self {
        Rotation3::from_axis_angle(Vector3::unit_x(), theta)
    }

    /// Create a rotation from an angle around the `y` axis (yaw).
    #[inline]
    fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Self {
        Rotation3::from_axis_angle(Vector3::unit_y(), theta)
    }

    /// Create a rotation from an angle around the `z` axis (roll).
    #[inline]
    fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Self {
        Rotation3::from_axis_angle(Vector3::unit_z(), theta)
    }
}

/// A two-dimensional rotation matrix.
///
/// The matrix is guaranteed to be orthogonal, so some operations can be
/// implemented more efficiently than the implementations for `math::Matrix2`. To
/// enforce orthogonality at the type level the operations have been restricted
/// to a subset of those implemented on `Matrix2`.
///
/// ## Example
///
/// Suppose we want to rotate a vector that lies in the x-y plane by some
/// angle. We can accomplish this quite easily with a two-dimensional rotation
/// matrix:
///
/// ```no_run
/// use cgmath::Rad;
/// use cgmath::Vector2;
/// use cgmath::{Matrix, Matrix2};
/// use cgmath::{Rotation, Rotation2, Basis2};
/// use cgmath::ApproxEq;
/// use std::f64;
///
/// // For simplicity, we will rotate the unit x vector to the unit y vector --
/// // so the angle is 90 degrees, or π/2.
/// let unit_x: Vector2<f64> = Vector2::unit_x();
/// let rot: Basis2<f64> = Rotation2::from_angle(Rad(0.5f64 * f64::consts::PI));
///
/// // Rotate the vector using the two-dimensional rotation matrix:
/// let unit_y = rot.rotate_vector(unit_x);
///
/// // Since sin(π/2) may not be exactly zero due to rounding errors, we can
/// // use approx's assert_ulps_eq!() feature to show that it is close enough.
/// // assert_ulps_eq!(&unit_y, &Vector2::unit_y()); // TODO: Figure out how to use this
///
/// // This is exactly equivalent to using the raw matrix itself:
/// let unit_y2: Matrix2<_> = rot.into();
/// let unit_y2 = unit_y2 * unit_x;
/// assert_eq!(unit_y2, unit_y);
///
/// // Note that we can also concatenate rotations:
/// let rot_half: Basis2<f64> = Rotation2::from_angle(Rad(0.25f64 * f64::consts::PI));
/// let unit_y3 = (rot_half * rot_half).rotate_vector(unit_x);
/// // assert_ulps_eq!(&unit_y3, &unit_y2); // TODO: Figure out how to use this
/// ```
#[derive(PartialEq, Copy, Clone)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
pub struct Basis2<S> {
    mat: Matrix2<S>
}

impl<S: BaseFloat> AsRef<Matrix2<S>> for Basis2<S> {
    #[inline]
    fn as_ref(&self) -> &Matrix2<S> {
        &self.mat
    }
}

impl<S: BaseFloat> From<Basis2<S>> for Matrix2<S> {
    #[inline]
    fn from(b: Basis2<S>) -> Matrix2<S> { b.mat }
}

impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
    #[inline]
    fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> {
        Basis2 { mat: Matrix2::look_at(dir, up) }
    }

    #[inline]
    fn between_vectors(a: Vector2<S>, b: Vector2<S>) -> Basis2<S> {
        Rotation2::from_angle(Rad::acos(a.dot(b)) )
    }

    #[inline]
    fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> { self.mat * vec }

    // TODO: we know the matrix is orthogonal, so this could be re-written
    // to be faster
    #[inline]
    fn invert(&self) -> Basis2<S> { Basis2 { mat: self.mat.invert().unwrap() } }
}

impl<S: BaseFloat> One for Basis2<S> {
    #[inline]
    fn one() -> Basis2<S> { Basis2 { mat: Matrix2::one() } }
}

impl_operator!(<S: BaseFloat> Mul<Basis2<S> > for Basis2<S> {
    fn mul(lhs, rhs) -> Basis2<S> { Basis2 { mat: lhs.mat * rhs.mat  } }
});

impl<S: BaseFloat> ApproxEq for Basis2<S> {
    type Epsilon = S::Epsilon;

    #[inline]
    fn default_epsilon() -> S::Epsilon {
        S::default_epsilon()
    }

    #[inline]
    fn default_max_relative() -> S::Epsilon {
        S::default_max_relative()
    }

    #[inline]
    fn default_max_ulps() -> u32 {
        S::default_max_ulps()
    }

    #[inline]
    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
        Matrix2::relative_eq(&self.mat, &other.mat, epsilon, max_relative)
    }

    #[inline]
    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
        Matrix2::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps)
    }
}

impl<S: BaseFloat> Rotation2<S> for Basis2<S> {
    fn from_angle<A: Into<Rad<S>>>(theta: A) -> Basis2<S> { Basis2 { mat: Matrix2::from_angle(theta) } }
}

impl<S: fmt::Debug> fmt::Debug for Basis2<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Basis2 "));
        <[[S; 2]; 2] as fmt::Debug>::fmt(self.mat.as_ref(), f)
    }
}

/// A three-dimensional rotation matrix.
///
/// The matrix is guaranteed to be orthogonal, so some operations, specifically
/// inversion, can be implemented more efficiently than the implementations for
/// `math::Matrix3`. To ensure orthogonality is maintained, the operations have
/// been restricted to a subset of those implemented on `Matrix3`.
#[derive(PartialEq, Copy, Clone)]
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
#[cfg_attr(feature = "eders", derive(Serialize, Deserialize))]
pub struct Basis3<S> {
    mat: Matrix3<S>
}

impl<S: BaseFloat> Basis3<S> {
    /// Create a new rotation matrix from a quaternion.
    #[inline]
    pub fn from_quaternion(quaternion: &Quaternion<S>) -> Basis3<S> {
        Basis3 { mat: quaternion.clone().into() }
    }
}

impl<S> AsRef<Matrix3<S>> for Basis3<S> {
    #[inline]
    fn as_ref(&self) -> &Matrix3<S> {
        &self.mat
    }
}

impl<S: BaseFloat> From<Basis3<S>> for Matrix3<S> {
    #[inline]
    fn from(b: Basis3<S>) -> Matrix3<S> { b.mat }
}

impl<S: BaseFloat> From<Basis3<S>> for Quaternion<S> {
    #[inline]
    fn from(b: Basis3<S>) -> Quaternion<S> { b.mat.into() }
}

impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
    #[inline]
    fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> {
        Basis3 { mat: Matrix3::look_at(dir, up) }
    }

    #[inline]
    fn between_vectors(a: Vector3<S>, b: Vector3<S>) -> Basis3<S> {
        let q: Quaternion<S> = Rotation::between_vectors(a, b);
        q.into()
    }

    #[inline]
    fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self.mat * vec }

    // TODO: we know the matrix is orthogonal, so this could be re-written
    // to be faster
    #[inline]
    fn invert(&self) -> Basis3<S> { Basis3 { mat: self.mat.invert().unwrap() } }
}

impl<S: BaseFloat> One for Basis3<S> {
    #[inline]
    fn one() -> Basis3<S> { Basis3 { mat: Matrix3::one() } }
}

impl_operator!(<S: BaseFloat> Mul<Basis3<S> > for Basis3<S> {
    fn mul(lhs, rhs) -> Basis3<S> { Basis3 { mat: lhs.mat * rhs.mat  } }
});

impl<S: BaseFloat> ApproxEq for Basis3<S> {
    type Epsilon = S::Epsilon;

    #[inline]
    fn default_epsilon() -> S::Epsilon {
        S::default_epsilon()
    }

    #[inline]
    fn default_max_relative() -> S::Epsilon {
        S::default_max_relative()
    }

    #[inline]
    fn default_max_ulps() -> u32 {
        S::default_max_ulps()
    }

    #[inline]
    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
        Matrix3::relative_eq(&self.mat, &other.mat, epsilon, max_relative)
    }

    #[inline]
    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
        Matrix3::ulps_eq(&self.mat, &other.mat, epsilon, max_ulps)
    }
}

impl<S: BaseFloat> Rotation3<S> for Basis3<S> {
    fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Basis3<S> {
        Basis3 { mat: Matrix3::from_axis_angle(axis, angle) }
    }

    fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
        Basis3 { mat: Matrix3::from_angle_x(theta) }
    }

    fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
        Basis3 { mat: Matrix3::from_angle_y(theta) }
    }

    fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
        Basis3 { mat: Matrix3::from_angle_z(theta) }
    }
}

impl<A: Angle> From<Euler<A>> for Basis3<<A as Angle>::Unitless> where
    A: Into<Rad<<A as Angle>::Unitless>>,
{
    /// Create a three-dimensional rotation matrix from a set of euler angles.
    fn from(src: Euler<A>) -> Basis3<A::Unitless> {
        Basis3 {
            mat: Matrix3::from(src),
        }
    }
}

impl<S: fmt::Debug> fmt::Debug for Basis3<S> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "Basis3 "));
        <[[S; 3]; 3] as fmt::Debug>::fmt(self.mat.as_ref(), f)
    }
}
<|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 cssparser::{Parser, Token, SourcePosition};
use properties::DeclaredValue;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use string_cache::Atom;

#[derive(Clone, PartialEq)]
pub struct Value {
    /// In CSS syntax
    value: String,

    /// Custom property names in var() functions. Do not include the `--` prefix.
    references: HashSet<Atom>,
}

pub struct BorrowedValue<'a> {
    value: &'a str,
    references: Option<&'a HashSet<Atom>>,
}

pub fn parse(input: &mut Parser) -> Result<Value, ()> {
    let start = input.position();
    let mut references = HashSet::new();
    try!(parse_declaration_value(input, &mut references));
    Ok(Value {
        value: input.slice_from(start).to_owned(),
        references: references,
    })
}

/// https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value
fn parse_declaration_value(input: &mut Parser, references: &mut HashSet<Atom>) -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::BadUrl |
            Token::BadString |
            Token::CloseParenthesis |
            Token::CloseSquareBracket |
            Token::CloseCurlyBracket |

            Token::Semicolon |
            Token::Delim('!') => {
                return Err(())
            }

            Token::Function(ref name) if name == "var" => {
                try!(input.parse_nested_block(|input| {
                    parse_var_function(input, references)
                }));
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(input.parse_nested_block(|input| {
                    parse_declaration_value_block(input, references)
                }));
            }

            _ => {}
        }
    }
    Ok(())
}

/// Like parse_declaration_value,
/// but accept `!` and `;` since they are only invalid at the top level
fn parse_declaration_value_block(input: &mut Parser, references: &mut HashSet<Atom>)
                                 -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::BadUrl |
            Token::BadString |
            Token::CloseParenthesis |
            Token::CloseSquareBracket |
            Token::CloseCurlyBracket => {
                return Err(())
            }

            Token::Function(ref name) if name == "var" => {
                try!(input.parse_nested_block(|input| {
                    parse_var_function(input, references)
                }));
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(input.parse_nested_block(|input| {
                    parse_declaration_value_block(input, references)
                }));
            }

            _ => {}
        }
    }
    Ok(())
}

// If the var function is valid, return Ok((custom_property_name, fallback))
fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut HashSet<Atom>)
                              -> Result<(), ()> {
    // https://drafts.csswg.org/css-variables/#typedef-custom-property-name
    let name = try!(input.expect_ident());
    let name = if name.starts_with("--") {
        &name[2..]
    } else {
        return Err(())
    };
    if input.expect_comma().is_ok() {
        try!(parse_declaration_value(input, references));
    }
    references.insert(Atom::from_slice(name));
    Ok(())
}

/// Add one custom property declaration to a map,
/// unless another with the same name was already there.
pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Atom, BorrowedValue<'a>>>,
                   inherited_custom_properties: &'a Option<Arc<HashMap<Atom, String>>>,
                   seen: &mut HashSet<&'a Atom>,
                   name: &'a Atom,
                   value: &'a DeclaredValue<Value>) {
    let was_not_already_present = seen.insert(name);
    if was_not_already_present {
        let map = match *custom_properties {
            Some(ref mut map) => map,
            None => {
                *custom_properties = Some(match *inherited_custom_properties {
                    Some(ref inherited) => inherited.iter().map(|(key, value)| {
                        (key, BorrowedValue { value: &value, references: None })
                    }).collect(),
                    None => HashMap::new(),
                });
                custom_properties.as_mut().unwrap()
            }
        };
        match *value {
            DeclaredValue::Value(ref value) => {
                map.insert(name, BorrowedValue {
                    value: &value.value,
                    references: Some(&value.references),
                });
            }
            DeclaredValue::Initial => {
                map.remove(&name);
            }
            DeclaredValue::Inherit => {}  // The inherited value is what we already have.
        }
    }
}

pub fn finish_cascade(custom_properties: Option<HashMap<&Atom, BorrowedValue>>,
                      inherited_custom_properties: &Option<Arc<HashMap<Atom, String>>>)
                      -> Option<Arc<HashMap<Atom, String>>> {
    if let Some(mut map) = custom_properties {
        remove_cycles(&mut map);
        Some(Arc::new(substitute_all(map)))
    } else {
        inherited_custom_properties.clone()
    }
}

/// https://drafts.csswg.org/css-variables/#cycles
fn remove_cycles(map: &mut HashMap<&Atom, BorrowedValue>) {
    let mut to_remove = HashSet::new();
    {
        let mut visited = HashSet::new();
        let mut stack = Vec::new();
        for name in map.keys() {
            walk(map, name, &mut stack, &mut visited, &mut to_remove);

            fn walk<'a>(map: &HashMap<&'a Atom, BorrowedValue<'a>>,
                        name: &'a Atom,
                        stack: &mut Vec<&'a Atom>,
                        visited: &mut HashSet<&'a Atom>,
                        to_remove: &mut HashSet<Atom>) {
                let was_not_already_present = visited.insert(name);
                if !was_not_already_present {
                    return
                }
                if let Some(value) = map.get(name) {
                    if let Some(references) = value.references {
                        stack.push(name);
                        for next in references {
                            if let Some(position) = stack.position_elem(&next) {
                                // Found a cycle
                                for in_cycle in &stack[position..] {
                                    to_remove.insert((**in_cycle).clone());
                                }
                            } else {
                                walk(map, next, stack, visited, to_remove);
                            }
                        }
                        stack.pop();
                    }
                }
            }
        }
    }
    for name in &to_remove {
        map.remove(name);
    }
}

fn substitute_all(custom_properties: HashMap<&Atom, BorrowedValue>) -> HashMap<Atom, String> {
    custom_properties.iter().filter_map(|(&name, value)| {
        let mut substituted = String::new();
        if substitute_one(value, &mut substituted, &custom_properties).is_ok() {
            Some((name.clone(), substituted))
        } else {
            None
        }
    }).collect()
}

fn substitute_one(value: &BorrowedValue,
                  substituted: &mut String,
                  custom_properties: &HashMap<&Atom, BorrowedValue>)
                  -> Result<(), ()> {
    if let Some(references) = value.references {
        if !references.is_empty() {
            let mut input = Parser::new(&value.value);
            let mut start = input.position();
            try!(substitute_block(&mut input, &mut start, substituted, &custom_properties));
            substituted.push_str(input.slice_from(start));
            return Ok(())
        }
    }
    substituted.push_str(value.value);
    Ok(())
}

fn substitute_block(input: &mut Parser,
                    start: &mut SourcePosition,
                    substituted: &mut String,
                    custom_properties: &HashMap<&Atom, BorrowedValue>)
                    -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::Function(ref name) if name == "var" => {
                substituted.push_str(input.slice_from(*start));
                try!(input.parse_nested_block(|input| {
                    let name = input.expect_ident().unwrap();
                    debug_assert!(name.starts_with("--"));
                    let name = Atom::from_slice(&name[2..]);

                    if let Some(value) = custom_properties.get(&name) {
                        return substitute_one(value, substituted, custom_properties)
                    }
                    try!(input.expect_comma());
                    let mut start = input.position();
                    try!(substitute_block(input, &mut start, substituted, custom_properties));
                    substituted.push_str(input.slice_from(start));
                    Ok(())
                }));
                *start = input.position();
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(input.parse_nested_block(|input| {
                    substitute_block(input, start, substituted, custom_properties)
                }));
            }

            _ => {}
        }
    }
    Ok(())
}
<commit_msg>Make custom property substitution do less work.<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 cssparser::{Parser, Token, SourcePosition};
use properties::DeclaredValue;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use string_cache::Atom;

#[derive(Clone, PartialEq)]
pub struct Value {
    /// In CSS syntax
    value: String,

    /// Custom property names in var() functions. Do not include the `--` prefix.
    references: HashSet<Atom>,
}

pub struct BorrowedValue<'a> {
    value: &'a str,
    references: Option<&'a HashSet<Atom>>,
}

pub fn parse(input: &mut Parser) -> Result<Value, ()> {
    let start = input.position();
    let mut references = HashSet::new();
    try!(parse_declaration_value(input, &mut references));
    Ok(Value {
        value: input.slice_from(start).to_owned(),
        references: references,
    })
}

/// https://drafts.csswg.org/css-syntax-3/#typedef-declaration-value
fn parse_declaration_value(input: &mut Parser, references: &mut HashSet<Atom>) -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::BadUrl |
            Token::BadString |
            Token::CloseParenthesis |
            Token::CloseSquareBracket |
            Token::CloseCurlyBracket |

            Token::Semicolon |
            Token::Delim('!') => {
                return Err(())
            }

            Token::Function(ref name) if name == "var" => {
                try!(input.parse_nested_block(|input| {
                    parse_var_function(input, references)
                }));
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(input.parse_nested_block(|input| {
                    parse_declaration_value_block(input, references)
                }));
            }

            _ => {}
        }
    }
    Ok(())
}

/// Like parse_declaration_value,
/// but accept `!` and `;` since they are only invalid at the top level
fn parse_declaration_value_block(input: &mut Parser, references: &mut HashSet<Atom>)
                                 -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::BadUrl |
            Token::BadString |
            Token::CloseParenthesis |
            Token::CloseSquareBracket |
            Token::CloseCurlyBracket => {
                return Err(())
            }

            Token::Function(ref name) if name == "var" => {
                try!(input.parse_nested_block(|input| {
                    parse_var_function(input, references)
                }));
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(input.parse_nested_block(|input| {
                    parse_declaration_value_block(input, references)
                }));
            }

            _ => {}
        }
    }
    Ok(())
}

// If the var function is valid, return Ok((custom_property_name, fallback))
fn parse_var_function<'i, 't>(input: &mut Parser<'i, 't>, references: &mut HashSet<Atom>)
                              -> Result<(), ()> {
    // https://drafts.csswg.org/css-variables/#typedef-custom-property-name
    let name = try!(input.expect_ident());
    let name = if name.starts_with("--") {
        &name[2..]
    } else {
        return Err(())
    };
    if input.expect_comma().is_ok() {
        try!(parse_declaration_value(input, references));
    }
    references.insert(Atom::from_slice(name));
    Ok(())
}

/// Add one custom property declaration to a map,
/// unless another with the same name was already there.
pub fn cascade<'a>(custom_properties: &mut Option<HashMap<&'a Atom, BorrowedValue<'a>>>,
                   inherited_custom_properties: &'a Option<Arc<HashMap<Atom, String>>>,
                   seen: &mut HashSet<&'a Atom>,
                   name: &'a Atom,
                   value: &'a DeclaredValue<Value>) {
    let was_not_already_present = seen.insert(name);
    if was_not_already_present {
        let map = match *custom_properties {
            Some(ref mut map) => map,
            None => {
                *custom_properties = Some(match *inherited_custom_properties {
                    Some(ref inherited) => inherited.iter().map(|(key, value)| {
                        (key, BorrowedValue { value: &value, references: None })
                    }).collect(),
                    None => HashMap::new(),
                });
                custom_properties.as_mut().unwrap()
            }
        };
        match *value {
            DeclaredValue::Value(ref value) => {
                map.insert(name, BorrowedValue {
                    value: &value.value,
                    references: Some(&value.references),
                });
            }
            DeclaredValue::Initial => {
                map.remove(&name);
            }
            DeclaredValue::Inherit => {}  // The inherited value is what we already have.
        }
    }
}

pub fn finish_cascade(custom_properties: Option<HashMap<&Atom, BorrowedValue>>,
                      inherited_custom_properties: &Option<Arc<HashMap<Atom, String>>>)
                      -> Option<Arc<HashMap<Atom, String>>> {
    if let Some(mut map) = custom_properties {
        remove_cycles(&mut map);
        Some(Arc::new(substitute_all(map)))
    } else {
        inherited_custom_properties.clone()
    }
}

/// https://drafts.csswg.org/css-variables/#cycles
fn remove_cycles(map: &mut HashMap<&Atom, BorrowedValue>) {
    let mut to_remove = HashSet::new();
    {
        let mut visited = HashSet::new();
        let mut stack = Vec::new();
        for name in map.keys() {
            walk(map, name, &mut stack, &mut visited, &mut to_remove);

            fn walk<'a>(map: &HashMap<&'a Atom, BorrowedValue<'a>>,
                        name: &'a Atom,
                        stack: &mut Vec<&'a Atom>,
                        visited: &mut HashSet<&'a Atom>,
                        to_remove: &mut HashSet<Atom>) {
                let was_not_already_present = visited.insert(name);
                if !was_not_already_present {
                    return
                }
                if let Some(value) = map.get(name) {
                    if let Some(references) = value.references {
                        stack.push(name);
                        for next in references {
                            if let Some(position) = stack.position_elem(&next) {
                                // Found a cycle
                                for in_cycle in &stack[position..] {
                                    to_remove.insert((**in_cycle).clone());
                                }
                            } else {
                                walk(map, next, stack, visited, to_remove);
                            }
                        }
                        stack.pop();
                    }
                }
            }
        }
    }
    for name in &to_remove {
        map.remove(name);
    }
}

fn substitute_all(custom_properties: HashMap<&Atom, BorrowedValue>) -> HashMap<Atom, String> {
    let mut substituted_map = HashMap::new();
    let mut invalid = HashSet::new();
    for (&name, value) in &custom_properties {
        // If this value is invalid at computed time it won’t be inserted in substituted_map.
        // Nothing else to do.
        let _ = substitute_one(
            name, value, &custom_properties, None, &mut substituted_map, &mut invalid);
    }
    substituted_map
}

fn substitute_one(name: &Atom,
                  value: &BorrowedValue,
                  custom_properties: &HashMap<&Atom, BorrowedValue>,
                  substituted: Option<&mut String>,
                  substituted_map: &mut HashMap<Atom, String>,
                  invalid: &mut HashSet<Atom>)
                  -> Result<(), ()> {
    if let Some(value) = substituted_map.get(name) {
        if let Some(substituted) = substituted {
            substituted.push_str(value)
        }
        return Ok(())
    }

    if invalid.contains(name) {
        return Err(());
    }
    let value = if let Some(references) = value.references {
        if !references.is_empty() {
            let mut substituted = String::new();
            let mut input = Parser::new(&value.value);
            let mut start = input.position();
            if substitute_block(
                custom_properties, &mut input, &mut start, &mut substituted,
                substituted_map, invalid,
            ).is_err() {
                invalid.insert(name.clone());
                return Err(())
            }
            substituted.push_str(input.slice_from(start));
            substituted
        } else {
            value.value.to_owned()
        }
    } else {
        value.value.to_owned()
    };
    if let Some(substituted) = substituted {
        substituted.push_str(&value)
    }
    substituted_map.insert(name.clone(), value);
    Ok(())
}

fn substitute_block(custom_properties: &HashMap<&Atom, BorrowedValue>,
                    input: &mut Parser,
                    start: &mut SourcePosition,
                    substituted: &mut String,
                    substituted_map: &mut HashMap<Atom, String>,
                    invalid: &mut HashSet<Atom>)
                    -> Result<(), ()> {
    while let Ok(token) = input.next() {
        match token {
            Token::Function(ref name) if name == "var" => {
                substituted.push_str(input.slice_from(*start));
                try!(input.parse_nested_block(|input| {
                    let name = input.expect_ident().unwrap();
                    debug_assert!(name.starts_with("--"));
                    let name = Atom::from_slice(&name[2..]);

                    if let Some(value) = custom_properties.get(&name) {
                        try!(substitute_one(
                            &name, value, custom_properties,
                            Some(substituted), substituted_map, invalid));
                        // Skip over the fallback, as `parse_nested_block` would return `Err`
                        // if we don’t consume all of `input`.
                        // FIXME: Add a specialized method to cssparser to do this with less work.
                        while let Ok(_) = input.next() {}
                    } else {
                        try!(input.expect_comma());
                        let mut start = input.position();
                        try!(substitute_block(
                            custom_properties, input, &mut start, substituted,
                            substituted_map, invalid));
                        substituted.push_str(input.slice_from(start));
                    }
                    Ok(())
                }));
                *start = input.position();
            }

            Token::Function(_) |
            Token::ParenthesisBlock |
            Token::CurlyBracketBlock |
            Token::SquareBracketBlock => {
                try!(input.parse_nested_block(|input| substitute_block(
                    custom_properties, input, start, substituted, substituted_map, invalid)));
            }

            _ => {}
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#[desc = "Bindings for the GeoIP library."];
#[license = "BSD"];
#[link(package_id = "geoip", name = "geoip", vers = "0.1")];
#[crate_type = "lib"];

#[warn(non_camel_case_types,
       non_uppercase_statics,
       unnecessary_qualification,
       managed_heap_memory)];

use std::c_str::CString;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};
use std::libc::{c_void, c_int, c_ulong};
use std::path::Path;

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup {
    netmask: c_int
}

impl GeoIPLookup {
    fn new() -> GeoIPLookup {
        GeoIPLookup {
            netmask: 0
        }
    }
}

#[link_args = "-lGeoIP"]
extern {
    fn GeoIP_open(dbtype: CString, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup) -> CString;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup) -> CString;
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    priv db: GeoIP_
}

pub struct ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

impl ToStr for ASInfo {
    fn to_str(&self) -> ~str {
        format!("{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                    db: db
                })
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description = match cres.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(~Path::new("/opt/geoip/GeoIPASNum.dat"), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}
<commit_msg>Path::new() is gone<commit_after>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#[desc = "Bindings for the GeoIP library."];
#[license = "BSD"];
#[link(package_id = "geoip", name = "geoip", vers = "0.1")];
#[crate_type = "lib"];

#[warn(non_camel_case_types,
       non_uppercase_statics,
       unnecessary_qualification,
       managed_heap_memory)];

use std::c_str::CString;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};
use std::libc::{c_void, c_int, c_ulong};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup {
    netmask: c_int
}

impl GeoIPLookup {
    fn new() -> GeoIPLookup {
        GeoIPLookup {
            netmask: 0
        }
    }
}

#[link_args = "-lGeoIP"]
extern {
    fn GeoIP_open(dbtype: CString, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup) -> CString;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup) -> CString;
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    priv db: GeoIP_
}

pub struct ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

impl ToStr for ASInfo {
    fn to_str(&self) -> ~str {
        format!("{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                    db: db
                })
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description = match cres.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(~from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}
<|endoftext|>


<commit_before>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#[desc = "Bindings for the GeoIP library."];
#[license = "BSD"];
#[crate_id = "geoip#0.1"];
#[crate_type = "rlib"];

#[warn(non_camel_case_types,
       non_uppercase_statics,
       unnecessary_qualification,
       managed_heap_memory)];

use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};
use std::libc::{c_void, c_char, c_int, c_ulong};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup {
    netmask: c_int
}

impl GeoIPLookup {
    fn new() -> GeoIPLookup {
        GeoIPLookup {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup) -> *c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup) -> *c_char;
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    priv db: GeoIP_
}

pub struct ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                    db: db
                })
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}
<commit_msg>Remove unnecessary `priv` visibility<commit_after>// (C)opyleft 2013 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#[desc = "Bindings for the GeoIP library."];
#[license = "BSD"];
#[crate_id = "geoip#0.1"];
#[crate_type = "rlib"];

#[warn(non_camel_case_types,
       non_uppercase_statics,
       unnecessary_qualification,
       managed_heap_memory)];

use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};
use std::libc::{c_void, c_char, c_int, c_ulong};

type GeoIP_ = *c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup {
    netmask: c_int
}

impl GeoIPLookup {
    fn new() -> GeoIPLookup {
        GeoIPLookup {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup) -> *c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup) -> *c_char;
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct ASInfo {
    asn: uint,
    name: ~str,
    netmask: uint
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f.buf, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, ~str> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        match db.is_null() {
            true => Err(format!("Can't open {}", file)),
            false => Ok(GeoIP {
                    db: db
                })
        }
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let asinfo = ASInfo {
            asn: asn,
            name: name.to_owned(),
            netmask: gl.netmask as uint
        };
        Some(asinfo)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.contains("Telefun"));
    assert!(res.netmask == 22);
}
<|endoftext|>


<commit_before>use super::number::Number;
use super::point::Point;

pub enum LineIntersection<T> {
   Point(Point<T>),
   Parallel,
   Overlapping,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Line<T> {
   a: T,
   b: T,
   c: T
}

impl<T> Line<T> where T: Number {
   pub fn new(x1: T, y1: T, x2: T, y2: T) -> Self {
      let (a, b, c) = Self::calc_abc(x1, y1, x2, y2);
      Line {
         a: a,
         b: b,
         c: c
      }
   }

   pub fn update(&mut self, x1: T, y1: T, x2: T, y2: T) {
      let (a, b, c) = Self::calc_abc(x1, y1, x2, y2);
      self.a = a;
      self.b = b;
      self.c = c;
   }

   #[inline]
   fn calc_abc(x1: T, y1: T, x2: T, y2: T) -> (T, T, T) {
      let mut a = y2 - y1;
      let mut b = x1 - x2;
      let mut c = -(x1 * y2 - x2 * y1);

      let mut norm = (T::one() / (a * a + b * b)).sqrt();
      if a != T::zero() {
         if a < T::zero() {
            norm = -norm;
         }
      } else {
         if b < T::zero() {
            norm = -norm;
         }
      }

      a = a * norm;
      b = b * norm;
      c = c * norm;

      (a, b, c)
   }

   pub fn intersect(&self, line: &Self) -> LineIntersection<T> {
      let denominator = self.a * line.b - line.a * self.b;

      if denominator == T::zero() {
         return LineIntersection::Overlapping;
      }

      let x = (line.c * self.b - self.c * line.b) / denominator;
      let y = (line.a * self.c - self.a * line.c) / denominator;

      LineIntersection::Point(Point::new(x, y))
   }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct LineSegment<T> {
   p1: Point<T>,
   p2: Point<T>,
   line: Line<T>
}

impl<T> LineSegment<T> where T: Number {
   pub fn new(x1: T, y1: T, x2: T, y2: T) -> Self {
      let p1 = Point::new(x1, y1);
      let p2 = Point::new(x2, y2);
      let line = Line::new(x1, y1, x2, y2);

      LineSegment {
         p1: p1,
         p2: p2,
         line: line
      }
   }

   pub fn update(&mut self, x1: T, y1: T, x2: T, y2: T) {
      self.p1.x = x1;
      self.p1.y = y1;
      self.p2.x = x2;
      self.p2.y = y2;

      self.line.update(x1, y1, x2, y2);
   }

   #[inline]
   pub fn x1(&self) -> T {
      self.p1.x
   }

   #[inline]
   pub fn y1(&self) -> T {
      self.p1.y
   }

   #[inline]
   pub fn x2(&self) -> T {
      self.p2.x
   }

   #[inline]
   pub fn y2(&self) -> T {
      self.p2.y
   }

   #[inline]
   pub fn line(&self) -> &Line<T> {
      &self.line
   }
}

impl<T> Default for LineSegment<T> where T: Number {
   fn default() -> LineSegment<T> {
      LineSegment::new(T::zero(), T::zero(), T::zero(), T::zero())
   }
}

#[cfg(test)]
mod tests {
   use std::{f32, f64};
   use test::{Bencher, black_box};

   use super::*;

   #[test]
   fn test_segment_new_f64() {
      let ls = LineSegment::new(
         10_f64, 20_f64,
         -100_f64, 0_f64
      );
      assert_eq!(ls.p1.x, 10_f64);
      assert_eq!(ls.p1.y, 20_f64);
      assert_eq!(ls.p2.x, -100_f64);
      assert_eq!(ls.p2.y, 0_f64);
   }

   #[test]
   fn test_segment_new_f32() {
      let ls = LineSegment::new(
         10_f32, 20_f32,
         -100_f32, 0_f32
      );
      assert_eq!(ls.p1.x, 10_f32);
      assert_eq!(ls.p1.y, 20_f32);
      assert_eq!(ls.p2.x, -100_f32);
      assert_eq!(ls.p2.y, 0_f32);
   }

   #[test]
   fn test_line_new_f64() {
      let ln = Line::new(
         10_f64, 20_f64,
         -100_f64, 0_f64
      );
      assert_eq!(ln.a, 0.1788854381999832_f64);
      assert_eq!(ln.b, -0.9838699100999075_f64);
      assert_eq!(ln.c, 17.88854381999832_f64);

      assert!(f64::abs(1_f64 - (ln.a*ln.a+ln.b*ln.b)) <= f64::EPSILON);
   }

   #[test]
   fn test_line_new_f32() {
      let ln = Line::new(
         10_f32, 20_f32,
         -100_f32, 0_f32
      );
      assert_eq!(ln.a, 0.1788854381999832_f32);
      assert_eq!(ln.b, -0.9838699100999075_f32);
      assert_eq!(ln.c, 17.88854381999832_f32);

      assert!(f32::abs(1_f32 - (ln.a*ln.a+ln.b*ln.b)) <= f32::EPSILON);
   }

   #[test]
   fn test_vline_f64() {
      let ln = Line::new(
         50_f64, 100_f64,
         50_f64, 200_f64
      );
      assert_eq!(ln.a, 1_f64);
      assert_eq!(ln.b, 0_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_vline_f32() {
      let ln = Line::new(
         50_f32, 100_f32,
         50_f32, 200_f32
      );
      assert_eq!(ln.a, 1_f32);
      assert_eq!(ln.b, 0_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_vline_one_f64() {
      let ln = Line::new(
         50_f64, 100_f64,
         50_f64, 101_f64
      );
      assert_eq!(ln.a, 1_f64);
      assert_eq!(ln.b, 0_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_vline_one_f32() {
      let ln = Line::new(
         50_f32, 100_f32,
         50_f32, 101_f32
      );
      assert_eq!(ln.a, 1_f32);
      assert_eq!(ln.b, 0_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_vline_one_down_f64() {
      let ln = Line::new(
         50_f64, 101_f64,
         50_f64, 100_f64
      );
      assert_eq!(ln.a, 1_f64);
      assert_eq!(ln.b, 0_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_vline_one_down_f32() {
      let ln = Line::new(
         50_f32, 101_f32,
         50_f32, 100_f32
      );
      assert_eq!(ln.a, 1_f32);
      assert_eq!(ln.b, 0_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_hline_f64() {
      let ln = Line::new(
         100_f64, 50_f64,
         200_f64, 50_f64
      );
      assert_eq!(ln.a, 0_f64);
      assert_eq!(ln.b, 1_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_hline_f32() {
      let ln = Line::new(
         100_f32, 50_f32,
         200_f32, 50_f32
      );
      assert_eq!(ln.a, 0_f32);
      assert_eq!(ln.b, 1_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_hline_one_f64() {
      let ln = Line::new(
         100_f64, 50_f64,
         101_f64, 50_f64
      );
      assert_eq!(ln.a, 0_f64);
      assert_eq!(ln.b, 1_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_hline_one_f32() {
      let ln = Line::new(
         100_f32, 50_f32,
         101_f32, 50_f32
      );
      assert_eq!(ln.a, 0_f32);
      assert_eq!(ln.b, 1_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_hline_one_down_f64() {
      let ln = Line::new(
         101_f64, 50_f64,
         100_f64, 50_f64
      );
      assert_eq!(ln.a, 0_f64);
      assert_eq!(ln.b, 1_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_hline_one_down_f32() {
      let ln = Line::new(
         101_f32, 50_f32,
         100_f32, 50_f32
      );
      assert_eq!(ln.a, 0_f32);
      assert_eq!(ln.b, 1_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[bench]
   fn bench_line_new_f64(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(
               Line::new(
                  black_box(5_f64),
                  black_box(7_f64),
                  black_box(3_f64),
                  black_box(2_f64)
               )
            );
         }
      });
   }

   #[bench]
   fn bench_line_new_f32(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(
               Line::new(
                  black_box(5_f32),
                  black_box(7_f32),
                  black_box(3_f32),
                  black_box(2_f32)
               )
            );
         }
      });
   }
}

<commit_msg>Line intersection supporting both Parallel and Overlapping<commit_after>use super::number::Number;
use super::point::Point;

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum LineIntersection<T> {
   Point(Point<T>),
   Parallel,
   Overlapping,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct Line<T> {
   a: T,
   b: T,
   c: T
}

impl<T> Line<T> where T: Number {
   pub fn new(x1: T, y1: T, x2: T, y2: T) -> Self {
      let (a, b, c) = Self::calc_abc(x1, y1, x2, y2);
      Line {
         a: a,
         b: b,
         c: c
      }
   }

   pub fn update(&mut self, x1: T, y1: T, x2: T, y2: T) {
      let (a, b, c) = Self::calc_abc(x1, y1, x2, y2);
      self.a = a;
      self.b = b;
      self.c = c;
   }

   #[inline]
   fn calc_abc(x1: T, y1: T, x2: T, y2: T) -> (T, T, T) {
      let mut a = y2 - y1;
      let mut b = x1 - x2;
      let mut c = -(x1 * y2 - x2 * y1);

      let mut norm = (T::one() / (a * a + b * b)).sqrt();
      if a != T::zero() {
         if a < T::zero() {
            norm = -norm;
         }
      } else {
         if b < T::zero() {
            norm = -norm;
         }
      }

      a = a * norm;
      b = b * norm;
      c = c * norm;

      (a, b, c)
   }

   pub fn intersect(&self, line: &Self) -> LineIntersection<T> {
      let denominator = self.a * line.b - line.a * self.b;

      if denominator == T::zero() {
         if self == line {
            return LineIntersection::Overlapping;
         } else {
            return LineIntersection::Parallel;
         }
      }

      let x = (line.c * self.b - self.c * line.b) / denominator;
      let y = (line.a * self.c - self.a * line.c) / denominator;

      LineIntersection::Point(Point::new(x, y))
   }
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct LineSegment<T> {
   p1: Point<T>,
   p2: Point<T>,
   line: Line<T>
}

impl<T> LineSegment<T> where T: Number {
   pub fn new(x1: T, y1: T, x2: T, y2: T) -> Self {
      let p1 = Point::new(x1, y1);
      let p2 = Point::new(x2, y2);
      let line = Line::new(x1, y1, x2, y2);

      LineSegment {
         p1: p1,
         p2: p2,
         line: line
      }
   }

   pub fn update(&mut self, x1: T, y1: T, x2: T, y2: T) {
      self.p1.x = x1;
      self.p1.y = y1;
      self.p2.x = x2;
      self.p2.y = y2;

      self.line.update(x1, y1, x2, y2);
   }

   #[inline]
   pub fn x1(&self) -> T {
      self.p1.x
   }

   #[inline]
   pub fn y1(&self) -> T {
      self.p1.y
   }

   #[inline]
   pub fn x2(&self) -> T {
      self.p2.x
   }

   #[inline]
   pub fn y2(&self) -> T {
      self.p2.y
   }

   #[inline]
   pub fn line(&self) -> &Line<T> {
      &self.line
   }
}

impl<T> Default for LineSegment<T> where T: Number {
   fn default() -> LineSegment<T> {
      LineSegment::new(T::zero(), T::zero(), T::zero(), T::zero())
   }
}

#[cfg(test)]
mod tests {
   use std::{f32, f64};
   use test::{Bencher, black_box};

   use super::*;

   #[test]
   fn test_segment_new_f64() {
      let ls = LineSegment::new(
         10_f64, 20_f64,
         -100_f64, 0_f64
      );
      assert_eq!(ls.p1.x, 10_f64);
      assert_eq!(ls.p1.y, 20_f64);
      assert_eq!(ls.p2.x, -100_f64);
      assert_eq!(ls.p2.y, 0_f64);
   }

   #[test]
   fn test_segment_new_f32() {
      let ls = LineSegment::new(
         10_f32, 20_f32,
         -100_f32, 0_f32
      );
      assert_eq!(ls.p1.x, 10_f32);
      assert_eq!(ls.p1.y, 20_f32);
      assert_eq!(ls.p2.x, -100_f32);
      assert_eq!(ls.p2.y, 0_f32);
   }

   #[test]
   fn test_line_new_f64() {
      let ln = Line::new(
         10_f64, 20_f64,
         -100_f64, 0_f64
      );
      assert_eq!(ln.a, 0.1788854381999832_f64);
      assert_eq!(ln.b, -0.9838699100999075_f64);
      assert_eq!(ln.c, 17.88854381999832_f64);

      assert!(f64::abs(1_f64 - (ln.a*ln.a+ln.b*ln.b)) <= f64::EPSILON);
   }

   #[test]
   fn test_line_new_f32() {
      let ln = Line::new(
         10_f32, 20_f32,
         -100_f32, 0_f32
      );
      assert_eq!(ln.a, 0.1788854381999832_f32);
      assert_eq!(ln.b, -0.9838699100999075_f32);
      assert_eq!(ln.c, 17.88854381999832_f32);

      assert!(f32::abs(1_f32 - (ln.a*ln.a+ln.b*ln.b)) <= f32::EPSILON);
   }

   #[test]
   fn test_vline_f64() {
      let ln = Line::new(
         50_f64, 100_f64,
         50_f64, 200_f64
      );
      assert_eq!(ln.a, 1_f64);
      assert_eq!(ln.b, 0_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_vline_f32() {
      let ln = Line::new(
         50_f32, 100_f32,
         50_f32, 200_f32
      );
      assert_eq!(ln.a, 1_f32);
      assert_eq!(ln.b, 0_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_vline_one_f64() {
      let ln = Line::new(
         50_f64, 100_f64,
         50_f64, 101_f64
      );
      assert_eq!(ln.a, 1_f64);
      assert_eq!(ln.b, 0_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_vline_one_f32() {
      let ln = Line::new(
         50_f32, 100_f32,
         50_f32, 101_f32
      );
      assert_eq!(ln.a, 1_f32);
      assert_eq!(ln.b, 0_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_vline_one_down_f64() {
      let ln = Line::new(
         50_f64, 101_f64,
         50_f64, 100_f64
      );
      assert_eq!(ln.a, 1_f64);
      assert_eq!(ln.b, 0_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_vline_one_down_f32() {
      let ln = Line::new(
         50_f32, 101_f32,
         50_f32, 100_f32
      );
      assert_eq!(ln.a, 1_f32);
      assert_eq!(ln.b, 0_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_hline_f64() {
      let ln = Line::new(
         100_f64, 50_f64,
         200_f64, 50_f64
      );
      assert_eq!(ln.a, 0_f64);
      assert_eq!(ln.b, 1_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_hline_f32() {
      let ln = Line::new(
         100_f32, 50_f32,
         200_f32, 50_f32
      );
      assert_eq!(ln.a, 0_f32);
      assert_eq!(ln.b, 1_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_hline_one_f64() {
      let ln = Line::new(
         100_f64, 50_f64,
         101_f64, 50_f64
      );
      assert_eq!(ln.a, 0_f64);
      assert_eq!(ln.b, 1_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_hline_one_f32() {
      let ln = Line::new(
         100_f32, 50_f32,
         101_f32, 50_f32
      );
      assert_eq!(ln.a, 0_f32);
      assert_eq!(ln.b, 1_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_hline_one_down_f64() {
      let ln = Line::new(
         101_f64, 50_f64,
         100_f64, 50_f64
      );
      assert_eq!(ln.a, 0_f64);
      assert_eq!(ln.b, 1_f64);
      assert_eq!(ln.c, -50_f64);
   }

   #[test]
   fn test_hline_one_down_f32() {
      let ln = Line::new(
         101_f32, 50_f32,
         100_f32, 50_f32
      );
      assert_eq!(ln.a, 0_f32);
      assert_eq!(ln.b, 1_f32);
      assert_eq!(ln.c, -50_f32);
   }

   #[test]
   fn test_line_overlapping_f32() {
      let ln1 = Line::new(
         100_f32, 100_f32,
         200_f32, 200_f32
      );

      let ln2 = Line::new(
         150_f32, 150_f32,
         250_f32, 250_f32
      );

      assert_eq!(ln1.intersect(&ln2), LineIntersection::Overlapping);
   }

   #[test]
   fn test_line_parallel_f32() {
      let ln1 = Line::new(
         100_f32, 100_f32,
         200_f32, 200_f32
      );

      let ln2 = Line::new(
         250_f32, 150_f32,
         450_f32, 350_f32
      );

      assert_eq!(ln1.intersect(&ln2), LineIntersection::Parallel);
   }

   #[test]
   fn test_hline_overlapping_f32() {
      let ln1 = Line::new(
         100_f32, 50_f32,
         200_f32, 50_f32
      );

      let ln2 = Line::new(
         150_f32, 50_f32,
         250_f32, 50_f32
      );

      assert_eq!(ln1.intersect(&ln2), LineIntersection::Overlapping);
   }

   #[test]
   fn test_hline_parallel_f32() {
      let ln1 = Line::new(
         100_f32, 50_f32,
         200_f32, 50_f32
      );

      let ln2 = Line::new(
         150_f32, 150_f32,
         250_f32, 150_f32
      );

      assert_eq!(ln1.intersect(&ln2), LineIntersection::Parallel);
   }

   #[test]
   fn test_vline_overlapping_f32() {
      let ln1 = Line::new(
         50_f32, 100_f32,
         50_f32, 200_f32,
      );

      let ln2 = Line::new(
         50_f32, 150_f32,
         50_f32, 250_f32,
      );

      assert_eq!(ln1.intersect(&ln2), LineIntersection::Overlapping);
   }

   #[test]
   fn test_vline_parallel_f32() {
      let ln1 = Line::new(
         50_f32, 100_f32,
         50_f32, 200_f32,
      );

      let ln2 = Line::new(
         150_f32, 150_f32,
         150_f32, 250_f32,
      );

      assert_eq!(ln1.intersect(&ln2), LineIntersection::Parallel);
   }

   #[bench]
   fn bench_line_new_f64(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(
               Line::new(
                  black_box(5_f64),
                  black_box(7_f64),
                  black_box(3_f64),
                  black_box(2_f64)
               )
            );
         }
      });
   }

   #[bench]
   fn bench_line_new_f32(b: &mut Bencher) {
      b.iter(|| {
         for _ in 0..1000 {
            black_box(
               Line::new(
                  black_box(5_f32),
                  black_box(7_f32),
                  black_box(3_f32),
                  black_box(2_f32)
               )
            );
         }
      });
   }
}

<|endoftext|>


<commit_before>pub struct PLPWriter
{
	/// If true, tabs will be used to indent. Else, spaces will be used to indent
	pub use_tabs: bool,

	/// Number of indent characters to prefix each line of code with.
	/// Adjusting this value will not affect code that has already been written
	pub indent_level: u16,

	/// PLP output of this writer
	pub code: String,

	pub annotations_enabled: bool,

	pub mapping_enabled: bool,
}

impl PLPWriter
{
	pub fn new() -> PLPWriter
	{
		PLPWriter {
			use_tabs: true,
			indent_level: 0,
			code: String::new(),
			annotations_enabled: false,
			mapping_enabled: false,
			}
	}

	fn create_indented_string(&self) -> String
	{
		let mut string = String::new();
		let indent = match self.use_tabs {
				true  => "\t",
				false => " ",
			};

		for _ in (0..self.indent_level)
		{
			string.push_str(indent);
		}

		string
	}

	#[allow(dead_code)]
	pub fn reset(&mut self)
	{
		self.indent_level = 0;
		self.code = String::new();
	}

	pub fn println(&mut self)
	{
		self.code.push_str("\n");
	}

	pub fn map(&mut self, comment: &str)
	{
		if self.mapping_enabled
		{
			self.comment(comment);
		}
	}

	pub fn annotate(&mut self, annotation: &str)
	{
		if self.annotations_enabled
		{
			self.comment(annotation);
		}
	}

	pub fn comment(&mut self, comment: &str)
	{
		// TODO: split by "\n" to support multi-line comments
		let mut code = self.create_indented_string();
		code.push_str("# ");
		code.push_str(comment);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn org(&mut self, address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str(".org ");
		code.push_str(address);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn word(&mut self, initial_value: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".word ");
		code.push_str(&*initial_value.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn equ(&mut self, symbol: &str, initial_value: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".equ ");
		code.push_str(symbol);
		code.push_str(" ");
		code.push_str(&*initial_value.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn li(&mut self, register: &str, value: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("li ");
		code.push_str(register);
		code.push_str(", ");
		code.push_str(value);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn mov(&mut self, register_to: &str, register_from: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("move ");
		code.push_str(register_to);
		code.push_str(", ");
		code.push_str(register_from);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn addu(&mut self, register_sum: &str, register_addend1: &str, register_addend2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("addu ");
		code.push_str(register_sum);
		code.push_str(", ");
		code.push_str(register_addend1);
		code.push_str(", ");
		code.push_str(register_addend2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn subu(&mut self, register_difference: &str, register_addend1: &str, register_addend2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("subu ");
		code.push_str(register_difference);
		code.push_str(", ");
		code.push_str(register_addend1);
		code.push_str(", ");
		code.push_str(register_addend2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn mullo(&mut self, register_product: &str, register_multiplicand1: &str, register_multiplicand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("mullo ");
		code.push_str(register_product);
		code.push_str(", ");
		code.push_str(register_multiplicand1);
		code.push_str(", ");
		code.push_str(register_multiplicand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn sw(&mut self, register_target: &str, offset: u16, register_address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("sw ");
		code.push_str(register_target);
		code.push_str(", ");
		code.push_str(&*offset.to_string());
		code.push_str("(");
		code.push_str(register_address);
		code.push_str(")\n");

		self.code.push_str(&*code);
	}

	pub fn lw(&mut self, register_target: &str, offset: u16, register_address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("lw ");
		code.push_str(register_target);
		code.push_str(", ");
		code.push_str(&*offset.to_string());
		code.push_str("(");
		code.push_str(register_address);
		code.push_str(")\n");

		self.code.push_str(&*code);
	}

	pub fn push(&mut self, register_target: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("push ");
		code.push_str(register_target);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn pop(&mut self, register_target: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("pop ");
		code.push_str(register_target);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn call(&mut self, function_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("call ");
		code.push_str(function_label);
		code.push_str("\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn nop(&mut self)
	{
		let mut code = self.create_indented_string();
		code.push_str("nop");
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn label(&mut self, label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str(label);
		code.push_str(":");
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	#[allow(dead_code)]
	pub fn beq(&mut self, register_comparator1: &str, register_comparator2: &str, target_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("beq ");
		code.push_str(register_comparator1);
		code.push_str(", ");
		code.push_str(register_comparator2);
		code.push_str(", ");
		code.push_str(target_label);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	#[allow(dead_code)]
	pub fn bne(&mut self, register_comparator1: &str, register_comparator2: &str, target_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("bne ");
		code.push_str(register_comparator1);
		code.push_str(", ");
		code.push_str(register_comparator2);
		code.push_str(", ");
		code.push_str(target_label);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn ret(&mut self)
	{
		let mut code = self.create_indented_string();
		code.push_str("return\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn j(&mut self, label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("j ");
		code.push_str(label);
		code.push_str("\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn space(&mut self, amount: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".space ");
		code.push_str(&*amount.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}
}
<commit_msg>Expand plp utilities<commit_after>pub struct PLPWriter
{
	/// If true, tabs will be used to indent. Else, spaces will be used to indent
	pub use_tabs: bool,

	/// Number of indent characters to prefix each line of code with.
	/// Adjusting this value will not affect code that has already been written
	pub indent_level: u16,

	/// PLP output of this writer
	pub code: String,

	pub annotations_enabled: bool,

	pub mapping_enabled: bool,
}

impl PLPWriter
{
	pub fn new() -> PLPWriter
	{
		PLPWriter {
			use_tabs: true,
			indent_level: 0,
			code: String::new(),
			annotations_enabled: false,
			mapping_enabled: false,
			}
	}

	pub fn copy(&self) -> PLPWriter
	{
		PLPWriter {
			use_tabs: self.use_tabs,
			indent_level: self.indent_level,
			code: String::new(),
			annotations_enabled: self.annotations_enabled,
			mapping_enabled: self.mapping_enabled,
			}
	}

	fn create_indented_string(&self) -> String
	{
		let mut string = String::new();
		let indent = match self.use_tabs {
				true  => "\t",
				false => "    ",
			};

		for _ in (0..self.indent_level)
		{
			string.push_str(indent);
		}

		string
	}

	#[allow(dead_code)]
	pub fn reset(&mut self)
	{
		self.indent_level = 0;
		self.code = String::new();
	}

	pub fn println(&mut self)
	{
		self.code.push_str("\n");
	}

	pub fn map(&mut self, comment: &str)
	{
		if self.mapping_enabled
		{
			self.comment(comment);
		}
	}

	pub fn annotate(&mut self, annotation: &str)
	{
		if self.annotations_enabled
		{
			self.comment(annotation);
		}
	}

	pub fn annotate_newline(&mut self)
	{
		if self.annotations_enabled
		{
			self.println();
		}
	}

	pub fn comment(&mut self, comment: &str)
	{
		// TODO: split by "\n" to support multi-line comments
		let mut code = self.create_indented_string();
		code.push_str("# ");
		code.push_str(comment);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn org(&mut self, address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str(".org ");
		code.push_str(address);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn word(&mut self, initial_value: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".word ");
		code.push_str(&*initial_value.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn equ(&mut self, symbol: &str, initial_value: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".equ ");
		code.push_str(symbol);
		code.push_str(" ");
		code.push_str(&*initial_value.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn li(&mut self, register: &str, value: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("li ");
		code.push_str(register);
		code.push_str(", ");
		code.push_str(value);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn mov(&mut self, register_to: &str, register_from: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("move ");
		code.push_str(register_to);
		code.push_str(", ");
		code.push_str(register_from);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn addu(&mut self, register_sum: &str, register_addend1: &str, register_addend2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("addu ");
		code.push_str(register_sum);
		code.push_str(", ");
		code.push_str(register_addend1);
		code.push_str(", ");
		code.push_str(register_addend2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn subu(&mut self, register_difference: &str, register_addend1: &str, register_addend2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("subu ");
		code.push_str(register_difference);
		code.push_str(", ");
		code.push_str(register_addend1);
		code.push_str(", ");
		code.push_str(register_addend2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn mullo(&mut self, register_product: &str, register_multiplicand1: &str, register_multiplicand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("mullo ");
		code.push_str(register_product);
		code.push_str(", ");
		code.push_str(register_multiplicand1);
		code.push_str(", ");
		code.push_str(register_multiplicand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn sw(&mut self, register_target: &str, offset: u16, register_address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("sw ");
		code.push_str(register_target);
		code.push_str(", ");
		code.push_str(&*offset.to_string());
		code.push_str("(");
		code.push_str(register_address);
		code.push_str(")\n");

		self.code.push_str(&*code);
	}

	pub fn lw(&mut self, register_target: &str, offset: u16, register_address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("lw ");
		code.push_str(register_target);
		code.push_str(", ");
		code.push_str(&*offset.to_string());
		code.push_str("(");
		code.push_str(register_address);
		code.push_str(")\n");

		self.code.push_str(&*code);
	}

	pub fn push(&mut self, register_target: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("push ");
		code.push_str(register_target);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn pop(&mut self, register_target: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("pop ");
		code.push_str(register_target);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn call(&mut self, function_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("call ");
		code.push_str(function_label);
		code.push_str("\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn nop(&mut self)
	{
		let mut code = self.create_indented_string();
		code.push_str("nop");
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn label(&mut self, label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str(label);
		code.push_str(":");
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	#[allow(dead_code)]
	pub fn beq(&mut self, register_comparator1: &str, register_comparator2: &str, target_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("beq ");
		code.push_str(register_comparator1);
		code.push_str(", ");
		code.push_str(register_comparator2);
		code.push_str(", ");
		code.push_str(target_label);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	#[allow(dead_code)]
	pub fn bne(&mut self, register_comparator1: &str, register_comparator2: &str, target_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("bne ");
		code.push_str(register_comparator1);
		code.push_str(", ");
		code.push_str(register_comparator2);
		code.push_str(", ");
		code.push_str(target_label);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn ret(&mut self)
	{
		let mut code = self.create_indented_string();
		code.push_str("return\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn j(&mut self, label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("j ");
		code.push_str(label);
		code.push_str("\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn space(&mut self, amount: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".space ");
		code.push_str(&*amount.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}
}
<|endoftext|>