<commit_before>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.
//! Hints may be compile time or runtime.

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
pub const unsafe fn unreachable_unchecked() -> ! {
    // SAFETY: the safety contract for `intrinsics::unreachable` must
    // be upheld by the caller.
    unsafe { intrinsics::unreachable() }
}

/// Emits a machine instruction to signal the processor that it is running in
/// a busy-wait spin-loop ("spin lock").
///
/// Upon receiving the spin-loop signal the processor can optimize its behavior by,
/// for example, saving power or switching hyper-threads.
///
/// This function is different from [`thread::yield_now`] which directly
/// yields to the system's scheduler, whereas `spin_loop` does not interact
/// with the operating system.
///
/// A common use case for `spin_loop` is implementing bounded optimistic
/// spinning in a CAS loop in synchronization primitives. To avoid problems
/// like priority inversion, it is strongly recommended that the spin loop is
/// terminated after a finite amount of iterations and an appropriate blocking
/// syscall is made.
///
/// **Note**: On platforms that do not support receiving spin-loop hints this
/// function does not do anything at all.
///
/// # Examples
///
/// ```
/// use std::sync::atomic::{AtomicBool, Ordering};
/// use std::sync::Arc;
/// use std::{hint, thread};
///
/// // A shared atomic value that threads will use to coordinate
/// let live = Arc::new(AtomicBool::new(false));
///
/// // In a background thread we'll eventually set the value
/// let bg_work = {
///     let live = live.clone();
///     thread::spawn(move || {
///         // Do some work, then make the value live
///         do_some_work();
///         live.store(true, Ordering::Release);
///     })
/// };
///
/// // Back on our current thread, we wait for the value to be set
/// while !live.load(Ordering::Acquire) {
///     // The spin loop is a hint to the CPU that we're waiting, but probably
///     // not for very long
///     hint::spin_loop();
/// }
///
/// // The value is now set
/// # fn do_some_work() {}
/// do_some_work();
/// bg_work.join()?;
/// # Ok::<(), Box<dyn core::any::Any + Send + 'static>>(())
/// ```
///
/// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html
#[inline]
#[stable(feature = "renamed_spin_loop", since = "1.49.0")]
pub fn spin_loop() {
    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
    {
        #[cfg(target_arch = "x86")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
    {
        #[cfg(target_arch = "aarch64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
            unsafe { crate::arch::aarch64::__yield() };
        }
        #[cfg(target_arch = "arm")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
            // with support for the v6 feature.
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
///
/// [`std::convert::identity`]: crate::convert::identity
#[cfg_attr(not(miri), inline)]
#[cfg_attr(miri, inline(never))]
#[unstable(feature = "bench_black_box", issue = "64102")]
#[cfg_attr(miri, allow(unused_mut))]
pub fn black_box<T>(mut dummy: T) -> T {
    // We need to "use" the argument in some way LLVM can't introspect, and on
    // targets that support it we can typically leverage inline assembly to do
    // this. LLVM's interpretation of inline assembly is that it's, well, a black
    // box. This isn't the greatest implementation since it probably deoptimizes
    // more than we want, but it's so far good enough.

    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
    // SAFETY: the inline assembly is a no-op.
    unsafe {
        // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
        llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
    }

    dummy
}
<commit_msg>Auto merge of #84725 - sebpop:arm64-isb, r=joshtriplett<commit_after>#![stable(feature = "core_hint", since = "1.27.0")]

//! Hints to compiler that affects how code should be emitted or optimized.
//! Hints may be compile time or runtime.

use crate::intrinsics;

/// Informs the compiler that this point in the code is not reachable, enabling
/// further optimizations.
///
/// # Safety
///
/// Reaching this function is completely *undefined behavior* (UB). In
/// particular, the compiler assumes that all UB must never happen, and
/// therefore will eliminate all branches that reach to a call to
/// `unreachable_unchecked()`.
///
/// Like all instances of UB, if this assumption turns out to be wrong, i.e., the
/// `unreachable_unchecked()` call is actually reachable among all possible
/// control flow, the compiler will apply the wrong optimization strategy, and
/// may sometimes even corrupt seemingly unrelated code, causing
/// difficult-to-debug problems.
///
/// Use this function only when you can prove that the code will never call it.
/// Otherwise, consider using the [`unreachable!`] macro, which does not allow
/// optimizations but will panic when executed.
///
/// # Example
///
/// ```
/// fn div_1(a: u32, b: u32) -> u32 {
///     use std::hint::unreachable_unchecked;
///
///     // `b.saturating_add(1)` is always positive (not zero),
///     // hence `checked_div` will never return `None`.
///     // Therefore, the else branch is unreachable.
///     a.checked_div(b.saturating_add(1))
///         .unwrap_or_else(|| unsafe { unreachable_unchecked() })
/// }
///
/// assert_eq!(div_1(7, 0), 7);
/// assert_eq!(div_1(9, 1), 4);
/// assert_eq!(div_1(11, u32::MAX), 0);
/// ```
#[inline]
#[stable(feature = "unreachable", since = "1.27.0")]
#[rustc_const_unstable(feature = "const_unreachable_unchecked", issue = "53188")]
pub const unsafe fn unreachable_unchecked() -> ! {
    // SAFETY: the safety contract for `intrinsics::unreachable` must
    // be upheld by the caller.
    unsafe { intrinsics::unreachable() }
}

/// Emits a machine instruction to signal the processor that it is running in
/// a busy-wait spin-loop ("spin lock").
///
/// Upon receiving the spin-loop signal the processor can optimize its behavior by,
/// for example, saving power or switching hyper-threads.
///
/// This function is different from [`thread::yield_now`] which directly
/// yields to the system's scheduler, whereas `spin_loop` does not interact
/// with the operating system.
///
/// A common use case for `spin_loop` is implementing bounded optimistic
/// spinning in a CAS loop in synchronization primitives. To avoid problems
/// like priority inversion, it is strongly recommended that the spin loop is
/// terminated after a finite amount of iterations and an appropriate blocking
/// syscall is made.
///
/// **Note**: On platforms that do not support receiving spin-loop hints this
/// function does not do anything at all.
///
/// # Examples
///
/// ```
/// use std::sync::atomic::{AtomicBool, Ordering};
/// use std::sync::Arc;
/// use std::{hint, thread};
///
/// // A shared atomic value that threads will use to coordinate
/// let live = Arc::new(AtomicBool::new(false));
///
/// // In a background thread we'll eventually set the value
/// let bg_work = {
///     let live = live.clone();
///     thread::spawn(move || {
///         // Do some work, then make the value live
///         do_some_work();
///         live.store(true, Ordering::Release);
///     })
/// };
///
/// // Back on our current thread, we wait for the value to be set
/// while !live.load(Ordering::Acquire) {
///     // The spin loop is a hint to the CPU that we're waiting, but probably
///     // not for very long
///     hint::spin_loop();
/// }
///
/// // The value is now set
/// # fn do_some_work() {}
/// do_some_work();
/// bg_work.join()?;
/// # Ok::<(), Box<dyn core::any::Any + Send + 'static>>(())
/// ```
///
/// [`thread::yield_now`]: ../../std/thread/fn.yield_now.html
#[inline]
#[stable(feature = "renamed_spin_loop", since = "1.49.0")]
pub fn spin_loop() {
    #[cfg(all(any(target_arch = "x86", target_arch = "x86_64"), target_feature = "sse2"))]
    {
        #[cfg(target_arch = "x86")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86 targets.
            unsafe { crate::arch::x86::_mm_pause() };
        }

        #[cfg(target_arch = "x86_64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on x86_64 targets.
            unsafe { crate::arch::x86_64::_mm_pause() };
        }
    }

    #[cfg(any(target_arch = "aarch64", all(target_arch = "arm", target_feature = "v6")))]
    {
        #[cfg(target_arch = "aarch64")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on aarch64 targets.
            unsafe { crate::arch::aarch64::__isb(crate::arch::aarch64::SY) };
        }
        #[cfg(target_arch = "arm")]
        {
            // SAFETY: the `cfg` attr ensures that we only execute this on arm targets
            // with support for the v6 feature.
            unsafe { crate::arch::arm::__yield() };
        }
    }
}

/// An identity function that *__hints__* to the compiler to be maximally pessimistic about what
/// `black_box` could do.
///
/// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can
/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined
/// behavior in the calling code. This property makes `black_box` useful for writing code in which
/// certain optimizations are not desired, such as benchmarks.
///
/// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The
/// extent to which it can block optimisations may vary depending upon the platform and code-gen
/// backend used. Programs cannot rely on `black_box` for *correctness* in any way.
///
/// [`std::convert::identity`]: crate::convert::identity
#[cfg_attr(not(miri), inline)]
#[cfg_attr(miri, inline(never))]
#[unstable(feature = "bench_black_box", issue = "64102")]
#[cfg_attr(miri, allow(unused_mut))]
pub fn black_box<T>(mut dummy: T) -> T {
    // We need to "use" the argument in some way LLVM can't introspect, and on
    // targets that support it we can typically leverage inline assembly to do
    // this. LLVM's interpretation of inline assembly is that it's, well, a black
    // box. This isn't the greatest implementation since it probably deoptimizes
    // more than we want, but it's so far good enough.

    #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
    // SAFETY: the inline assembly is a no-op.
    unsafe {
        // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures.
        llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
    }

    dummy
}
<|endoftext|>


<commit_before>use std::ops::Mul;
use std::f32::consts::PI;

use vector::Vector3;
use matrix::*;
use super::{IsZero, Clamp, Dot};

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Quaternion {
    pub w: f32,
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Quaternion {
    /// Creates an identity quaternion.
    ///
    /// The identity quaternion is the quaternion that can be multiplied into any other quaternion
    /// without changing it.
    pub fn identity() -> Quaternion {
        Quaternion {
            w: 1.0,
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }

    /// Creates a quaternion from an axis and a rotation around that axis.
    ///
    /// # Params
    ///
    /// - axis - The axis being used to represent the rotation. This should
    ///   be normalized before being passed into `axis_angle()`.
    pub fn axis_angle(axis: Vector3, angle: f32) -> Quaternion {
        assert!(axis.is_normalized());

        let s = (angle * 0.5).sin();
        Quaternion {
            w: (angle * 0.5).cos(),
            x: s * axis.x,
            y: s * axis.y,
            z: s * axis.z,
        }.normalized()
    }

    /// Creates a quaternion that rotates an object to look in the specified direction.
    pub fn look_rotation(forward: Vector3, up: Vector3) -> Quaternion {
        assert!(!forward.is_zero());
        assert!(!up.is_zero());

        let source = Vector3::forward();
        let forward = forward.normalized();
        let up = up.normalized();

        let dot = source.dot(forward);

        if (dot + 1.0).is_zero() {
            // vector a and b point exactly in the opposite direction,
            // so it is a 180 degrees turn around the up-axis
            return Quaternion::axis_angle(up, PI)
        }

        if (dot - 1.0).is_zero() {
            // Vector a and b point exactly in the same direction
            // so we return the identity quaternion.
            return Quaternion::identity()
        }

        let rot_angle = dot.acos();
        let rot_axis = Vector3::cross(source, forward).normalized();// source.cross(forward).normalized();
        return Quaternion::axis_angle(rot_axis, rot_angle)

        // TODO: Correctly take the up vector into account.
    }

    /// Creates a quaternion from a set of euler angles.
    pub fn from_eulers(x: f32, y: f32, z: f32) -> Quaternion {
        Quaternion::axis_angle(Vector3::new(1.0, 0.0, 0.0), x)
      * Quaternion::axis_angle(Vector3::new(0.0, 1.0, 0.0), y)
      * Quaternion::axis_angle(Vector3::new(0.0, 0.0, 1.0), z)
    }

    pub fn from_vector3(angles: Vector3) -> Quaternion {
        Quaternion::from_eulers(angles.x, angles.y, angles.z)
    }

    /// Converts the quaternion to the corresponding rotation matrix.
    pub fn as_matrix4(self) -> Matrix4 {
        Matrix4::from_quaternion(self)
    }

    pub fn as_matrix3(self) -> Matrix3 {
        Matrix3::from_quaternion(self)
    }

    /// Retrieves the rotation represented by the quaternion as a rotation about an axis.
    ///
    /// The returned axis will always be normalized.
    pub fn as_axis_angle(&self) -> (Vector3, f32) {
        assert!(self.is_normalized());

        let angle = 2.0 * self.w.acos();
        let s = (1.0 - self.w * self.w).sqrt();
        if s.is_zero() {
            // If s is 0, axis is arbitrary.
            (Vector3::new(1.0, 0.0, 0.0), angle)
        } else {
            (Vector3::new(self.x / s, self.y / s, self.z / s).normalized(), angle)
        }
    }

    /// Retrieves the rotation represented by the quaternion as euler angles.
    pub fn as_eulers(&self) -> Vector3 {
        assert!(self.is_normalized());

        let x = f32::atan2(
            2.0 * (self.w * self.x + self.y * self.z),
            1.0 - 2.0 * (self.x * self.x + self.y * self.y));
        let y = (2.0 * (self.w * self.y - self.z * self.x)).asin();
        let z = f32::atan2(
            2.0 * (self.w * self.z + self.x * self.y),
            1.0 - 2.0 * (self.y * self.y + self.z * self.z));

        Vector3::new(x, y, z)
    }

    /// Normalizes the quaternion to unit length.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalize(&mut self) {
        assert!(!self.is_zero());

        let length = (self.w * self.w
                    + self.x * self.x
                    + self.y * self.y
                    + self.z * self.z).sqrt();

        self.w /= length;
        self.x /= length;
        self.y /= length;
        self.z /= length;
    }

    /// Creates a normalized copy of the quaternion.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalized(&self) -> Quaternion {
        let mut temp = *self;
        temp.normalize();
        temp
    }

    /// Determines if the quaternion is normalized (has a length of 1.0).
    pub fn is_normalized(&self) -> bool {
        let mag_sqrd = Quaternion::dot(*self, *self);
        (mag_sqrd - 1.0).is_zero()
    }

    pub fn repeat(&self, repeat: f32) -> Quaternion {
        let (axis, angle) = self.as_axis_angle();
        Quaternion::axis_angle(axis, angle * repeat)
    }

    /// Calculates the dot product of two quaternions.
    pub fn dot(first: Quaternion, second: Quaternion) -> f32 {
        (first.w * second.w
       + first.x * second.x
       + first.y * second.y
       + first.z * second.z)
    }

    /// Interpolates linearly between two quaternions.
    ///
    /// # Remarks
    ///
    /// This method does not necessarily result in a normalized Quaternion, so the result should
    /// not be used directly to represent a rotation. If you would like to lerp two rotation
    /// quaternions use `Quaternion::nlerp()`.
    pub fn lerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        // first + t * (second - first)
        second.sub(first).mul(t).add(first)
    }

    /// Interpolates linearly between two quaternions using a normalized lerp.
    pub fn nlerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        Quaternion::lerp(first, second, t).normalized()
    }

    /// Calculates the spherical linear interpolation between two quaternions.
    ///
    /// # Remarks
    ///
    /// While slerp is generally the go-to method for interpolating quaternions, it's computationaly
    /// expensive and has some undesirable properties. `Quaternion::nlerp()` is often more appropriate unless it's
    /// absolutely necessary that the interpolation have a constant velocity. For a better discussion
    /// of the different methods of interpolating quaternions see [this article by Jonathan Blow]
    /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/).
    pub fn slerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        assert!(first.is_normalized());
        assert!(second.is_normalized());

        // Compute the cosine of the angle between the two vectors.
        let dot = Quaternion::dot(first, second);

        const DOT_THRESHOLD: f32 = 0.9995;
        if dot > DOT_THRESHOLD {
            // If the inputs are too close for comfort, linearly interpolate
            // and normalize the result.
            return Quaternion::nlerp(first, second, t);
        }

        dot.clamp(-1.0, 1.0);     // Robustness: Stay within domain of acos()
        let theta_0 = dot.acos(); // theta_0 = angle between input vectors
        let theta = theta_0 * t;  // theta = angle between first and result

        let normal = (second.sub(first).mul(dot)).normalized(); // { first, normal } is now an orthonormal basis

        // TODO: We shouldn't need to normalize here since both inputs are normalized,
        //       the result was introducing error. Figure out if there's something else we
        //       can do to improve accuracy.
        //      first *   theta.cos()  +   normal *   theta.sin()
        return (first.mul(theta.cos()).add(normal.mul(theta.sin()))).normalized();
    }

    fn mul(self, rhs: f32) -> Quaternion {
        Quaternion {
            w: self.w * rhs,
            x: self.x * rhs,
            y: self.y * rhs,
            z: self.z * rhs,
        }
    }

    fn sub(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w - rhs.w,
            x: self.x - rhs.x,
            y: self.y - rhs.y,
            z: self.z - rhs.z,
        }
    }

    fn add(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w + rhs.w,
            x: self.x + rhs.x,
            y: self.y + rhs.y,
            z: self.z + rhs.z,
        }
    }
}

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

    fn mul(self, rhs: Quaternion) -> Quaternion {
        assert!(self.is_normalized());
        assert!(rhs.is_normalized());

        Quaternion {
            w: (self.w * rhs.w) - (self.x * rhs.x) - (self.y * rhs.y) - (self.z * rhs.z),
            x: (self.w * rhs.x) + (self.x * rhs.w) + (self.y * rhs.z) - (self.z * rhs.y),
            y: (self.w * rhs.y) - (self.x * rhs.z) + (self.y * rhs.w) + (self.z * rhs.x),
            z: (self.w * rhs.z) + (self.x * rhs.y) - (self.y * rhs.x) + (self.z * rhs.w),
        }.normalized()
    }
}

// TODO: impl Mul<Vector3> for Quaternion (or maybe other way around).

impl IsZero for Quaternion {
    fn is_zero(self) -> bool {
        (self.w * self.w
       + self.x * self.x
       + self.y * self.y
       + self.z * self.z).is_zero()
    }
}
<commit_msg>feature(math): implement MulAssign for quaternion multiplication<commit_after>use std::ops::{Mul, MulAssign};
use std::f32::consts::PI;

use vector::Vector3;
use matrix::*;
use super::{IsZero, Clamp, Dot};

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Quaternion {
    pub w: f32,
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Quaternion {
    /// Creates an identity quaternion.
    ///
    /// The identity quaternion is the quaternion that can be multiplied into any other quaternion
    /// without changing it.
    pub fn identity() -> Quaternion {
        Quaternion {
            w: 1.0,
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }

    /// Creates a quaternion from an axis and a rotation around that axis.
    ///
    /// # Params
    ///
    /// - axis - The axis being used to represent the rotation. This should
    ///   be normalized before being passed into `axis_angle()`.
    pub fn axis_angle(axis: Vector3, angle: f32) -> Quaternion {
        assert!(axis.is_normalized());

        let s = (angle * 0.5).sin();
        Quaternion {
            w: (angle * 0.5).cos(),
            x: s * axis.x,
            y: s * axis.y,
            z: s * axis.z,
        }.normalized()
    }

    /// Creates a quaternion that rotates an object to look in the specified direction.
    pub fn look_rotation(forward: Vector3, up: Vector3) -> Quaternion {
        assert!(!forward.is_zero());
        assert!(!up.is_zero());

        let source = Vector3::forward();
        let forward = forward.normalized();
        let up = up.normalized();

        let dot = source.dot(forward);

        if (dot + 1.0).is_zero() {
            // vector a and b point exactly in the opposite direction,
            // so it is a 180 degrees turn around the up-axis
            return Quaternion::axis_angle(up, PI)
        }

        if (dot - 1.0).is_zero() {
            // Vector a and b point exactly in the same direction
            // so we return the identity quaternion.
            return Quaternion::identity()
        }

        let rot_angle = dot.acos();
        let rot_axis = Vector3::cross(source, forward).normalized();// source.cross(forward).normalized();
        return Quaternion::axis_angle(rot_axis, rot_angle)

        // TODO: Correctly take the up vector into account.
    }

    /// Creates a quaternion from a set of euler angles.
    pub fn from_eulers(x: f32, y: f32, z: f32) -> Quaternion {
        Quaternion::axis_angle(Vector3::new(1.0, 0.0, 0.0), x)
      * Quaternion::axis_angle(Vector3::new(0.0, 1.0, 0.0), y)
      * Quaternion::axis_angle(Vector3::new(0.0, 0.0, 1.0), z)
    }

    pub fn from_vector3(angles: Vector3) -> Quaternion {
        Quaternion::from_eulers(angles.x, angles.y, angles.z)
    }

    /// Converts the quaternion to the corresponding rotation matrix.
    pub fn as_matrix4(self) -> Matrix4 {
        Matrix4::from_quaternion(self)
    }

    pub fn as_matrix3(self) -> Matrix3 {
        Matrix3::from_quaternion(self)
    }

    /// Retrieves the rotation represented by the quaternion as a rotation about an axis.
    ///
    /// The returned axis will always be normalized.
    pub fn as_axis_angle(&self) -> (Vector3, f32) {
        assert!(self.is_normalized());

        let angle = 2.0 * self.w.acos();
        let s = (1.0 - self.w * self.w).sqrt();
        if s.is_zero() {
            // If s is 0, axis is arbitrary.
            (Vector3::new(1.0, 0.0, 0.0), angle)
        } else {
            (Vector3::new(self.x / s, self.y / s, self.z / s).normalized(), angle)
        }
    }

    /// Retrieves the rotation represented by the quaternion as euler angles.
    pub fn as_eulers(&self) -> Vector3 {
        assert!(self.is_normalized());

        let x = f32::atan2(
            2.0 * (self.w * self.x + self.y * self.z),
            1.0 - 2.0 * (self.x * self.x + self.y * self.y));
        let y = (2.0 * (self.w * self.y - self.z * self.x)).asin();
        let z = f32::atan2(
            2.0 * (self.w * self.z + self.x * self.y),
            1.0 - 2.0 * (self.y * self.y + self.z * self.z));

        Vector3::new(x, y, z)
    }

    /// Normalizes the quaternion to unit length.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalize(&mut self) {
        assert!(!self.is_zero());

        let length = (self.w * self.w
                    + self.x * self.x
                    + self.y * self.y
                    + self.z * self.z).sqrt();

        self.w /= length;
        self.x /= length;
        self.y /= length;
        self.z /= length;
    }

    /// Creates a normalized copy of the quaternion.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalized(&self) -> Quaternion {
        let mut temp = *self;
        temp.normalize();
        temp
    }

    /// Determines if the quaternion is normalized (has a length of 1.0).
    pub fn is_normalized(&self) -> bool {
        let mag_sqrd = Quaternion::dot(*self, *self);
        (mag_sqrd - 1.0).is_zero()
    }

    pub fn repeat(&self, repeat: f32) -> Quaternion {
        let (axis, angle) = self.as_axis_angle();
        Quaternion::axis_angle(axis, angle * repeat)
    }

    /// Calculates the dot product of two quaternions.
    pub fn dot(first: Quaternion, second: Quaternion) -> f32 {
        (first.w * second.w
       + first.x * second.x
       + first.y * second.y
       + first.z * second.z)
    }

    /// Interpolates linearly between two quaternions.
    ///
    /// # Remarks
    ///
    /// This method does not necessarily result in a normalized Quaternion, so the result should
    /// not be used directly to represent a rotation. If you would like to lerp two rotation
    /// quaternions use `Quaternion::nlerp()`.
    pub fn lerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        // first + t * (second - first)
        second.sub(first).mul(t).add(first)
    }

    /// Interpolates linearly between two quaternions using a normalized lerp.
    pub fn nlerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        Quaternion::lerp(first, second, t).normalized()
    }

    /// Calculates the spherical linear interpolation between two quaternions.
    ///
    /// # Remarks
    ///
    /// While slerp is generally the go-to method for interpolating quaternions, it's computationaly
    /// expensive and has some undesirable properties. `Quaternion::nlerp()` is often more appropriate unless it's
    /// absolutely necessary that the interpolation have a constant velocity. For a better discussion
    /// of the different methods of interpolating quaternions see [this article by Jonathan Blow]
    /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/).
    pub fn slerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        assert!(first.is_normalized());
        assert!(second.is_normalized());

        // Compute the cosine of the angle between the two vectors.
        let dot = Quaternion::dot(first, second);

        const DOT_THRESHOLD: f32 = 0.9995;
        if dot > DOT_THRESHOLD {
            // If the inputs are too close for comfort, linearly interpolate
            // and normalize the result.
            return Quaternion::nlerp(first, second, t);
        }

        dot.clamp(-1.0, 1.0);     // Robustness: Stay within domain of acos()
        let theta_0 = dot.acos(); // theta_0 = angle between input vectors
        let theta = theta_0 * t;  // theta = angle between first and result

        let normal = (second.sub(first).mul(dot)).normalized(); // { first, normal } is now an orthonormal basis

        // TODO: We shouldn't need to normalize here since both inputs are normalized,
        //       the result was introducing error. Figure out if there's something else we
        //       can do to improve accuracy.
        //      first *   theta.cos()  +   normal *   theta.sin()
        return (first.mul(theta.cos()).add(normal.mul(theta.sin()))).normalized();
    }

    fn mul(self, rhs: f32) -> Quaternion {
        Quaternion {
            w: self.w * rhs,
            x: self.x * rhs,
            y: self.y * rhs,
            z: self.z * rhs,
        }
    }

    fn sub(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w - rhs.w,
            x: self.x - rhs.x,
            y: self.y - rhs.y,
            z: self.z - rhs.z,
        }
    }

    fn add(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w + rhs.w,
            x: self.x + rhs.x,
            y: self.y + rhs.y,
            z: self.z + rhs.z,
        }
    }
}

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

    fn mul(self, rhs: Quaternion) -> Quaternion {
        assert!(self.is_normalized());
        assert!(rhs.is_normalized());

        Quaternion {
            w: (self.w * rhs.w) - (self.x * rhs.x) - (self.y * rhs.y) - (self.z * rhs.z),
            x: (self.w * rhs.x) + (self.x * rhs.w) + (self.y * rhs.z) - (self.z * rhs.y),
            y: (self.w * rhs.y) - (self.x * rhs.z) + (self.y * rhs.w) + (self.z * rhs.x),
            z: (self.w * rhs.z) + (self.x * rhs.y) - (self.y * rhs.x) + (self.z * rhs.w),
        }.normalized()
    }
}

impl MulAssign<Quaternion> for Quaternion {
    fn mul_assign(&mut self, rhs: Quaternion) {
        *self = *self * rhs; // TODO: No temp object? We'll have to see if LLVM can optimize it away.
    }
}

// TODO: impl Mul<Vector3> for Quaternion (or maybe other way around).

impl IsZero for Quaternion {
    fn is_zero(self) -> bool {
        (self.w * self.w
       + self.x * self.x
       + self.y * self.y
       + self.z * self.z).is_zero()
    }
}
<|endoftext|>


<commit_before>// Do not remove inline: will result in relocation failure
#[inline(always)]
pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T {
    (image_base() + offset) as *const T
}

// Do not remove inline: will result in relocation failure
#[inline(always)]
pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
    (image_base() + offset) as *mut T
}

extern "C" {
    static ENCLAVE_SIZE: usize;
}

// Do not remove inline: will result in relocation failure
// For the same reason we use inline ASM here instead of an extern static to
// locate the base
/// Returns address at which current enclave is loaded.
#[inline(always)]
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn image_base() -> u64 {
    let base;
    unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) };
    base
}

/// Returns `true` if the specified memory range is in the enclave.
///
/// `p + len` must not overflow.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn is_enclave_range(p: *const u8, len: usize) -> bool {
    let start = p as u64;
    let end = start + (len as u64);
    start >= image_base() && end <= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant
}

/// Returns `true` if the specified memory range is in userspace.
///
/// `p + len` must not overflow.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn is_user_range(p: *const u8, len: usize) -> bool {
    let start = p as u64;
    let end = start + (len as u64);
    end <= image_base() || start >= image_base() + (unsafe { ENCLAVE_SIZE } as u64) // unsafe ok: link-time constant
}
<commit_msg>Add is_enclave_range/is_user_range overflow checks<commit_after>// Do not remove inline: will result in relocation failure
#[inline(always)]
pub(crate) unsafe fn rel_ptr<T>(offset: u64) -> *const T {
    (image_base() + offset) as *const T
}

// Do not remove inline: will result in relocation failure
#[inline(always)]
pub(crate) unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
    (image_base() + offset) as *mut T
}

extern "C" {
    static ENCLAVE_SIZE: usize;
}

// Do not remove inline: will result in relocation failure
// For the same reason we use inline ASM here instead of an extern static to
// locate the base
/// Returns address at which current enclave is loaded.
#[inline(always)]
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn image_base() -> u64 {
    let base;
    unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) };
    base
}

/// Returns `true` if the specified memory range is in the enclave.
///
/// For safety, this function also checks whether the range given overflows,
/// returning `false` if so.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn is_enclave_range(p: *const u8, len: usize) -> bool {
    let start = p as usize;

    // Subtract one from `len` when calculating `end` in case `p + len` is
    // exactly at the end of addressable memory (`p + len` would overflow, but
    // the range is still valid).
    let end = if len == 0 {
        start
    } else if let Some(end) = start.checked_add(len - 1) {
        end
    } else {
        return false;
    };

    let base = image_base() as usize;
    start >= base && end <= base + (unsafe { ENCLAVE_SIZE } - 1) // unsafe ok: link-time constant
}

/// Returns `true` if the specified memory range is in userspace.
///
/// For safety, this function also checks whether the range given overflows,
/// returning `false` if so.
#[unstable(feature = "sgx_platform", issue = "56975")]
pub fn is_user_range(p: *const u8, len: usize) -> bool {
    let start = p as usize;

    // Subtract one from `len` when calculating `end` in case `p + len` is
    // exactly at the end of addressable memory (`p + len` would overflow, but
    // the range is still valid).
    let end = if len == 0 {
        start
    } else if let Some(end) = start.checked_add(len - 1) {
        end
    } else {
        return false;
    };

    let base = image_base() as usize;
    end < base || start > base + (unsafe { ENCLAVE_SIZE } - 1) // unsafe ok: link-time constant
}
<|endoftext|>


<commit_before>mod calc {
    include!(concat!(env!("OUT_DIR"), "/calc.rs"));
}

#[test]
fn test_binary() {
    assert_eq!(calc::expr("0b00"), Ok(0b0));
    assert_eq!(calc::expr("0b01"), Ok(0b1));
    assert_eq!(calc::expr("0b11010"), Ok(0b11010));

    // negative test cases
    assert!(calc::expr("0b5").is_err());
}

#[test]
fn test_decimal() {
    assert_eq!(calc::expr("0"), Ok(0));
    assert_eq!(calc::expr("4"), Ok(4));
    assert_eq!(calc::expr("123456"), Ok(123456));

    // negative test cases
    assert!(calc::expr("1c").is_err());
}

#[test]
fn test_octal() {
    assert_eq!(calc::expr("0o0"), Ok(0o0));
    assert_eq!(calc::expr("0o1"), Ok(0o1));
    assert_eq!(calc::expr("0o755"), Ok(0o755));

    // negative test cases
    assert!(calc::expr("0o789").is_err());
}

#[test]
fn test_infix() {
    assert_eq!(calc::expr("0 + 0"), Ok(0 + 0));
    assert_eq!(calc::expr("0+ 0"), Ok(0 + 0));
    assert_eq!(calc::expr("0 +0"), Ok(0 + 0));
    assert_eq!(calc::expr("0+0"), Ok(0 + 0));

    assert_eq!(calc::expr("5 * 4"), Ok(5 * 4));
    assert_eq!(calc::expr("5 - 4"), Ok(5 - 4));
    assert_eq!(calc::expr("20 / 4"), Ok(20 / 4));
    assert_eq!(calc::expr("20 % 4"), Ok(20 % 4));
    assert_eq!(calc::expr("20 % 3"), Ok(20 % 3));
    assert_eq!(calc::expr("2**5"), Ok(32));
    assert_eq!(calc::expr("2 ** 5"), Ok(32));

    // negative test cases
    assert!(calc::expr("5 $ 6").is_err());
}

#[test]
fn test_unary() {
    assert_eq!(calc::expr("~5"), Ok(!5));
    assert_eq!(calc::expr("-5"), Ok(-5));
}
<commit_msg>add initial weak test for precedence<commit_after>mod calc {
    include!(concat!(env!("OUT_DIR"), "/calc.rs"));
}

#[test]
fn test_binary() {
    assert_eq!(calc::expr("0b00"), Ok(0b0));
    assert_eq!(calc::expr("0b01"), Ok(0b1));
    assert_eq!(calc::expr("0b11010"), Ok(0b11010));

    // negative test cases
    assert!(calc::expr("0b5").is_err());
}

#[test]
fn test_decimal() {
    assert_eq!(calc::expr("0"), Ok(0));
    assert_eq!(calc::expr("4"), Ok(4));
    assert_eq!(calc::expr("123456"), Ok(123456));

    // negative test cases
    assert!(calc::expr("1c").is_err());
}

#[test]
fn test_octal() {
    assert_eq!(calc::expr("0o0"), Ok(0o0));
    assert_eq!(calc::expr("0o1"), Ok(0o1));
    assert_eq!(calc::expr("0o755"), Ok(0o755));

    // negative test cases
    assert!(calc::expr("0o789").is_err());
}

#[test]
fn test_infix() {
    assert_eq!(calc::expr("0 + 0"), Ok(0 + 0));
    assert_eq!(calc::expr("0+ 0"), Ok(0 + 0));
    assert_eq!(calc::expr("0 +0"), Ok(0 + 0));
    assert_eq!(calc::expr("0+0"), Ok(0 + 0));

    assert_eq!(calc::expr("5 * 4"), Ok(5 * 4));
    assert_eq!(calc::expr("5 - 4"), Ok(5 - 4));
    assert_eq!(calc::expr("20 / 4"), Ok(20 / 4));
    assert_eq!(calc::expr("20 % 4"), Ok(20 % 4));
    assert_eq!(calc::expr("20 % 3"), Ok(20 % 3));
    assert_eq!(calc::expr("2**5"), Ok(32));
    assert_eq!(calc::expr("2 ** 5"), Ok(32));

    // negative test cases
    assert!(calc::expr("5 $ 6").is_err());
}

#[test]
fn test_unary() {
    assert_eq!(calc::expr("~5"), Ok(!5));
    assert_eq!(calc::expr("-5"), Ok(-5));
}

#[test]
fn test_precedence() {
    assert_eq!(calc::expr("2 + 5 * 4"), Ok(2 + 5 * 4));
    assert_eq!(calc::expr("-2 + 5 * 4"), Ok(-2 + 5 * 4));
    assert_eq!(calc::expr("~2 + 5 * 4"), Ok(!2 + 5 * 4));
}
<|endoftext|>


<commit_before>// The elements of an array can be accessed by their indices
// arr[4]
#[test]
fn array_index() {
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    assert!(arr[__] == 1);
}

// A new fixed size array can be created by declaring the type of its elements
// along with its length
// [i32; 0] = []
#[test]
fn array_empty() {
    let arr: __;
    assert!(arr.len() == 0);
}

// Attempting to access an array at an index that is
// out of its bounds will cause an error. Let's cause
// that error in this example.
#[test]
#[should_panic]
fn out_of_index() {
    let arr: [&'static str; 5] = ["rust", "is", "mostly", "for", "nerds"];
    arr[__];
}

// Elements can be replaced in an array at a certain index.
// hint: Without the 'mut' keyword, you won't be able to change data.
#[test]
fn insert_at_index() {
    let mut arr: [u8; 5] = [0, 1, 2, 3, 4];
    __ = 0;
    assert!(arr == [0, 1, 2, 3, 0]);
}

// Arrays can be iterated over.
#[test]
fn array_iteration() {
    let arr: [u8; 3] = [3, 2, 1];
    let mut iterator = arr.iter();
    assert!(iterator.next().unwrap() == &__);
    assert!(iterator.next().unwrap() == &__);
    assert!(iterator.next().unwrap() == &__);
}

// Arrays can also be mutated during iteration
#[test]
fn array_map() {
    let arr: [u32; 4] = [2, 5, 7, 4];
    let mut iterator = arr.iter().map(__);
    assert!(iterator.next() == Some(4));
    assert!(iterator.next() == Some(10));
    assert!(iterator.next() == Some(14));
    assert!(iterator.next() == Some(8));
}

// You can filter an array for results that match a given condition
#[test]
fn array_filter() {
    let arr: [u16; 5] = [1, 2, 3, 4, 5];
    let mut iterator = arr.iter().filter(__);
    assert!(iterator.next().unwrap() == &2);
    assert!(iterator.next().unwrap() == &4);
    assert!(iterator.next().is_none());
}

// Filter and map can be combined to do both at once
#[test]
fn array_filter_map() {
    let arr: [u8; 5] = [2, 1, 2, 1, 2];
    let mut iterator = arr.iter().filter_map(|&x| if x == 1 { Some(__) } else { None });
    assert!(iterator.next() == Some(3));
    assert!(iterator.next() == Some(3));
    assert!(iterator.next().is_none());
}

// This can be used for more complex logic as well
#[test]
fn complex_array_filter_map() {
    let arr: [u64; 4] = [4, 8, 16, 32];
    let mut iterator = arr.iter()
        .filter_map(|&x| if (x as f64).sqrt().floor() == (x as f64).sqrt() {
            Some((x as f64).sqrt() as u64)
        } else {
            None
        });
    assert!(iterator.next().unwrap() == __);
    assert!(iterator.next().unwrap() == __);
    assert!(iterator.next().is_none());
}

// Arrays can also be iterated through using a for loop
#[test]
fn for_loops() {
    let arr: [u64; 3] = [1, 2, 3];
    let mut y: u64 = 1;
    for x in &arr {
        assert!(*x == y);
    }
}

// Let's try iterating over an array of strings to build a sentence
#[test]
fn for_loops_two() {
    let words: [&'static str; 3] = ["I", "love", "Rust"];
    let mut sentence: String = String::new();
    for word in words.iter() {
        __
    }
    println!("{:?}", sentence);
    assert!(sentence == "I love Rust".to_string());
}
<commit_msg>Allow `const_err` lint<commit_after>// The elements of an array can be accessed by their indices
// arr[4]
#[test]
fn array_index() {
    let arr: [i32; 5] = [1, 2, 3, 4, 5];
    assert!(arr[__] == 1);
}

// A new fixed size array can be created by declaring the type of its elements
// along with its length
// [i32; 0] = []
#[test]
fn array_empty() {
    let arr: __;
    assert!(arr.len() == 0);
}

// Attempting to access an array at an index that is
// out of its bounds will cause an error. Let's cause
// that error in this example.
#[test]
#[should_panic]
#[allow(const_err)]
fn out_of_index() {
    let arr: [&'static str; 5] = ["rust", "is", "mostly", "for", "nerds"];
    arr[__];
}

// Elements can be replaced in an array at a certain index.
// hint: Without the 'mut' keyword, you won't be able to change data.
#[test]
fn insert_at_index() {
    let mut arr: [u8; 5] = [0, 1, 2, 3, 4];
    __ = 0;
    assert!(arr == [0, 1, 2, 3, 0]);
}

// Arrays can be iterated over.
#[test]
fn array_iteration() {
    let arr: [u8; 3] = [3, 2, 1];
    let mut iterator = arr.iter();
    assert!(iterator.next().unwrap() == &__);
    assert!(iterator.next().unwrap() == &__);
    assert!(iterator.next().unwrap() == &__);
}

// Arrays can also be mutated during iteration
#[test]
fn array_map() {
    let arr: [u32; 4] = [2, 5, 7, 4];
    let mut iterator = arr.iter().map(__);
    assert!(iterator.next() == Some(4));
    assert!(iterator.next() == Some(10));
    assert!(iterator.next() == Some(14));
    assert!(iterator.next() == Some(8));
}

// You can filter an array for results that match a given condition
#[test]
fn array_filter() {
    let arr: [u16; 5] = [1, 2, 3, 4, 5];
    let mut iterator = arr.iter().filter(__);
    assert!(iterator.next().unwrap() == &2);
    assert!(iterator.next().unwrap() == &4);
    assert!(iterator.next().is_none());
}

// Filter and map can be combined to do both at once
#[test]
fn array_filter_map() {
    let arr: [u8; 5] = [2, 1, 2, 1, 2];
    let mut iterator = arr.iter().filter_map(|&x| if x == 1 { Some(__) } else { None });
    assert!(iterator.next() == Some(3));
    assert!(iterator.next() == Some(3));
    assert!(iterator.next().is_none());
}

// This can be used for more complex logic as well
#[test]
fn complex_array_filter_map() {
    let arr: [u64; 4] = [4, 8, 16, 32];
    let mut iterator = arr.iter()
        .filter_map(|&x| if (x as f64).sqrt().floor() == (x as f64).sqrt() {
            Some((x as f64).sqrt() as u64)
        } else {
            None
        });
    assert!(iterator.next().unwrap() == __);
    assert!(iterator.next().unwrap() == __);
    assert!(iterator.next().is_none());
}

// Arrays can also be iterated through using a for loop
#[test]
fn for_loops() {
    let arr: [u64; 3] = [1, 2, 3];
    let mut y: u64 = 1;
    for x in &arr {
        assert!(*x == y);
    }
}

// Let's try iterating over an array of strings to build a sentence
#[test]
fn for_loops_two() {
    let words: [&'static str; 3] = ["I", "love", "Rust"];
    let mut sentence: String = String::new();
    for word in words.iter() {
        __
    }
    println!("{:?}", sentence);
    assert!(sentence == "I love Rust".to_string());
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ascii::AsciiExt;

use header::{Header, Raw, parsing};

/// `Referrer-Policy` header, part of
/// [Referrer Policy](https://www.w3.org/TR/referrer-policy/#referrer-policy-header)
///
/// The `Referrer-Policy` HTTP header specifies the referrer
/// policy that the user agent applies when determining what
/// referrer information should be included with requests made,
/// and with browsing contexts created from the context of the
/// protected resource.
///
/// # ABNF
/// ```plain
/// Referrer-Policy: 1#policy-token
/// policy-token   = "no-referrer" / "no-referrer-when-downgrade"
///                  / "same-origin" / "origin"
///                  / "origin-when-cross-origin" / "unsafe-url"
/// ```
///
/// # Example values
/// * `no-referrer`
///
/// # Example
/// ```
/// use hyper::header::{Headers, ReferrerPolicy};
///
/// let mut headers = Headers::new();
/// headers.set(ReferrerPolicy::NoReferrer);
/// ```
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ReferrerPolicy {
    /// `no-referrer`
    NoReferrer,
    /// `no-referrer-when-downgrade`
    NoReferrerWhenDowngrade,
    /// `same-origin`
    SameOrigin,
    /// `origin`
    Origin,
    /// `origin-when-cross-origin`
    OriginWhenCrossOrigin,
    /// `unsafe-url`
    UnsafeUrl,
}

impl Header for ReferrerPolicy {
    fn header_name() -> &'static str {
        static NAME: &'static str = "Referrer-Policy";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<ReferrerPolicy> {
        use self::ReferrerPolicy::*;
        parsing::from_one_raw_str(raw).and_then(|s: String| {
            let slice = &s.to_ascii_lowercase()[..];
            // See https://www.w3.org/TR/referrer-policy/#determine-policy-for-token
            match slice {
                "no-referrer" | "never" => Ok(NoReferrer),
                "no-referrer-when-downgrade" | "default" => Ok(NoReferrerWhenDowngrade),
                "same-origin" => Ok(SameOrigin),
                "origin" => Ok(Origin),
                "origin-when-cross-origin" => Ok(OriginWhenCrossOrigin),
                "unsafe-url" | "always" => Ok(UnsafeUrl),
                _ => Err(::Error::Header),
            }
        })
    }

    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::ReferrerPolicy::*;
        f.write_str(match *self {
            NoReferrer => "no-referrer",
            NoReferrerWhenDowngrade => "no-referrer-when-downgrade",
            SameOrigin => "same-origin",
            Origin => "origin",
            OriginWhenCrossOrigin => "origin-when-cross-origin",
            UnsafeUrl => "unsafe-url",
        })
    }
}

#[test]
fn test_parse_header() {
    let a: ReferrerPolicy = Header::parse_header(&"origin".into()).unwrap();
    let b = ReferrerPolicy::Origin;
    assert_eq!(a, b);
    let e: ::Result<ReferrerPolicy> = Header::parse_header(&"foobar".into());
    assert!(e.is_err());
}
<commit_msg>feat(headers): support multiple values for Referrer-Policy header<commit_after>use std::fmt;
use std::ascii::AsciiExt;

use header::{Header, Raw, parsing};

/// `Referrer-Policy` header, part of
/// [Referrer Policy](https://www.w3.org/TR/referrer-policy/#referrer-policy-header)
///
/// The `Referrer-Policy` HTTP header specifies the referrer
/// policy that the user agent applies when determining what
/// referrer information should be included with requests made,
/// and with browsing contexts created from the context of the
/// protected resource.
///
/// # ABNF
/// ```plain
/// Referrer-Policy: 1#policy-token
/// policy-token   = "no-referrer" / "no-referrer-when-downgrade"
///                  / "same-origin" / "origin"
///                  / "origin-when-cross-origin" / "unsafe-url"
/// ```
///
/// # Example values
/// * `no-referrer`
///
/// # Example
/// ```
/// use hyper::header::{Headers, ReferrerPolicy};
///
/// let mut headers = Headers::new();
/// headers.set(ReferrerPolicy::NoReferrer);
/// ```
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum ReferrerPolicy {
    /// `no-referrer`
    NoReferrer,
    /// `no-referrer-when-downgrade`
    NoReferrerWhenDowngrade,
    /// `same-origin`
    SameOrigin,
    /// `origin`
    Origin,
    /// `origin-when-cross-origin`
    OriginWhenCrossOrigin,
    /// `unsafe-url`
    UnsafeUrl,
}

impl Header for ReferrerPolicy {
    fn header_name() -> &'static str {
        static NAME: &'static str = "Referrer-Policy";
        NAME
    }

    fn parse_header(raw: &Raw) -> ::Result<ReferrerPolicy> {
        use self::ReferrerPolicy::*;
        // See https://www.w3.org/TR/referrer-policy/#determine-policy-for-token
        let headers: Vec<String> = try!(parsing::from_comma_delimited(raw));

        for h in headers.iter().rev() {
            let slice = &h.to_ascii_lowercase()[..];
            match slice {
                "no-referrer" | "never" => return Ok(NoReferrer),
                "no-referrer-when-downgrade" | "default" => return Ok(NoReferrerWhenDowngrade),
                "same-origin" => return Ok(SameOrigin),
                "origin" => return Ok(Origin),
                "origin-when-cross-origin" => return Ok(OriginWhenCrossOrigin),
                "unsafe-url" | "always" => return Ok(UnsafeUrl),
                _ => continue,
            }
        }

        Err(::Error::Header)
    }

    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::ReferrerPolicy::*;
        f.write_str(match *self {
            NoReferrer => "no-referrer",
            NoReferrerWhenDowngrade => "no-referrer-when-downgrade",
            SameOrigin => "same-origin",
            Origin => "origin",
            OriginWhenCrossOrigin => "origin-when-cross-origin",
            UnsafeUrl => "unsafe-url",
        })
    }
}

#[test]
fn test_parse_header() {
    let a: ReferrerPolicy = Header::parse_header(&"origin".into()).unwrap();
    let b = ReferrerPolicy::Origin;
    assert_eq!(a, b);
    let e: ::Result<ReferrerPolicy> = Header::parse_header(&"foobar".into());
    assert!(e.is_err());
}

#[test]
fn test_rightmost_header() {
    let a: ReferrerPolicy = Header::parse_header(&"same-origin, origin, foobar".into()).unwrap();
    let b = ReferrerPolicy::Origin;
    assert_eq!(a, b);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! This crate contains a GraphQL schema representation.

#![deny(warnings)]
#![deny(rust_2018_idioms)]
#![deny(clippy::all)]

pub mod definitions;
mod errors;
mod flatbuffer;
mod graphql_schema;
mod in_memory;
mod schema;

pub use crate::schema::SDLSchema;
use common::{DiagnosticsResult, SourceLocationKey};
pub use definitions::{
    Argument, ArgumentDefinitions, ArgumentValue, Directive, DirectiveValue, Enum, EnumID,
    EnumValue, Field, FieldID, InputObject, InputObjectID, Interface, InterfaceID, Object,
    ObjectID, Scalar, ScalarID, Type, TypeReference, TypeWithFields, Union, UnionID,
};
pub use errors::{Result, SchemaError};
use flatbuffer::FlatBufferSchema;
pub use graphql_schema::Schema;
pub use graphql_syntax::{DirectiveLocation, TypeSystemDefinition};
pub use in_memory::InMemorySchema;

const BUILTINS: &str = include_str!("./builtins.graphql");

pub use flatbuffer::serialize_as_flatbuffer;

pub fn build_schema(sdl: &str) -> DiagnosticsResult<SDLSchema> {
    build_schema_with_extensions::<_, &str>(&[sdl], &[])
}

pub fn build_schema_with_extensions<T: AsRef<str>, U: AsRef<str>>(
    server_sdls: &[T],
    extension_sdls: &[U],
) -> DiagnosticsResult<SDLSchema> {
    let mut server_definitions = builtins()?;
    let mut combined_sdl: String = String::new();
    for server_sdl in server_sdls {
        combined_sdl.push_str(server_sdl.as_ref());
        combined_sdl.push('\n');
    }
    server_definitions.extend(
        graphql_syntax::parse_schema_document(&combined_sdl, SourceLocationKey::generated())?
            .definitions,
    );

    let mut extension_definitions = Vec::new();
    for extension_sdl in extension_sdls {
        extension_definitions.extend(
            graphql_syntax::parse_schema_document(
                extension_sdl.as_ref(),
                SourceLocationKey::generated(),
            )?
            .definitions,
        );
    }

    SDLSchema::build(&server_definitions, &extension_definitions)
}

pub fn build_schema_from_flat_buffer(bytes: &[u8]) -> DiagnosticsResult<FlatBufferSchema<'_>> {
    Ok(FlatBufferSchema::build(bytes))
}

pub fn builtins() -> DiagnosticsResult<Vec<TypeSystemDefinition>> {
    Ok(
        graphql_syntax::parse_schema_document(BUILTINS, SourceLocationKey::generated())?
            .definitions,
    )
}
<commit_msg>Use flatbuffer schema in native build<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

//! This crate contains a GraphQL schema representation.

#![deny(warnings)]
#![deny(rust_2018_idioms)]
#![deny(clippy::all)]

pub mod definitions;
mod errors;
mod flatbuffer;
mod graphql_schema;
mod in_memory;
mod schema;

pub use crate::schema::SDLSchema;
use common::{DiagnosticsResult, SourceLocationKey};
pub use definitions::{
    Argument, ArgumentDefinitions, ArgumentValue, Directive, DirectiveValue, Enum, EnumID,
    EnumValue, Field, FieldID, InputObject, InputObjectID, Interface, InterfaceID, Object,
    ObjectID, Scalar, ScalarID, Type, TypeReference, TypeWithFields, Union, UnionID,
};
pub use errors::{Result, SchemaError};
use flatbuffer::FlatBufferSchema;
pub use flatbuffer::SchemaWrapper;
pub use graphql_schema::Schema;
pub use graphql_syntax::{DirectiveLocation, TypeSystemDefinition};
pub use in_memory::InMemorySchema;

const BUILTINS: &str = include_str!("./builtins.graphql");

pub use flatbuffer::serialize_as_flatbuffer;

pub fn build_schema(sdl: &str) -> DiagnosticsResult<SDLSchema> {
    build_schema_with_extensions::<_, &str>(&[sdl], &[])
}

pub fn build_schema_with_extensions<T: AsRef<str>, U: AsRef<str>>(
    server_sdls: &[T],
    extension_sdls: &[U],
) -> DiagnosticsResult<SDLSchema> {
    let mut server_definitions = builtins()?;
    let mut combined_sdl: String = String::new();
    for server_sdl in server_sdls {
        combined_sdl.push_str(server_sdl.as_ref());
        combined_sdl.push('\n');
    }
    server_definitions.extend(
        graphql_syntax::parse_schema_document(&combined_sdl, SourceLocationKey::generated())?
            .definitions,
    );

    let mut extension_definitions = Vec::new();
    for extension_sdl in extension_sdls {
        extension_definitions.extend(
            graphql_syntax::parse_schema_document(
                extension_sdl.as_ref(),
                SourceLocationKey::generated(),
            )?
            .definitions,
        );
    }

    SDLSchema::build(&server_definitions, &extension_definitions)
}

pub fn build_schema_with_flat_buffer(bytes: Vec<u8>) -> SDLSchema {
    SDLSchema::FlatBuffer(SchemaWrapper::from_vec(bytes))
}

pub fn build_schema_from_flat_buffer(bytes: &[u8]) -> DiagnosticsResult<FlatBufferSchema<'_>> {
    Ok(FlatBufferSchema::build(bytes))
}

pub fn builtins() -> DiagnosticsResult<Vec<TypeSystemDefinition>> {
    Ok(
        graphql_syntax::parse_schema_document(BUILTINS, SourceLocationKey::generated())?
            .definitions,
    )
}
<|endoftext|>


<commit_before>/// `RouteGraph` defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot, tag, and channel.
/// Edges are also allowed to go to null, in which case they only have a destination slot and
/// channel. These are outputs.
/// Edges can also COME from null, in which case the source has the format (slot, channel)

use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use resman::ResMan;
use super::adjlist::AdjList;
use super::effect;
use super::effect::Effect;
use super::nullable_int::NullableInt;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct EdgeWeight {
    from_slot: u32,
    to_slot: u32,
}

pub type NodeData = Rc<Effect>;

/// None represents the Top-level DAG
type DagHandle = NullableInt<u32>;

/// None represents the Dag's I/O
type PrimNodeHandle = NullableInt<u32>;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct NodeHandle {
    node_handle: PrimNodeHandle,
}

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct Edge {
    from: NodeHandle,
    to: NodeHandle,
    weight: EdgeWeight,
}

#[derive(Debug)]
pub enum Error {
    /// Raised when an attempt to modify the graph would create a dependency cycle.
    WouldCycle,
    /// Raised on attempt to delete a node when it still has edges.
    NodeInUse,
    /// Raised on attempt to create a node with an id that's already in use.
    NodeExists,
    /// Error inside some Effect:: method
    EffectError(effect::Error),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

#[derive(Default)]
pub struct RouteGraph {
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        Default::default()
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=(&NodeHandle, &NodeData)> + 'a {
        self.node_data.iter()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn get_data(&self, handle: &NodeHandle) -> Option<&NodeData> {
        self.node_data.get(handle)
    }
    /// Try to create a node with the given handle/data.
    /// Will error if the handle is already in use.
    pub fn add_node(&mut self, handle: NodeHandle, node_data: NodeData) -> ResultE<()> {
        // Create storage for the node's outgoing edges
        match self.edges.entry(handle) {
            hash_map::Entry::Occupied(_) => Err(Error::NodeExists),
            hash_map::Entry::Vacant(entry) => { entry.insert(EdgeSet::new()); Ok(()) },
        }?;
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data.clone()).is_none());
        Ok(())
    }
    pub fn add_edge(&mut self, edge: Edge) -> ResultE<()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(Error::WouldCycle)
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, target: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        if let Some(_to) = from.to.node_handle.get() {
            // The edge points to a NODE inside a DAG.
            // Consider all (reachable) outgoing edges of the node:
            if let Some(node_data) = self.edges.get(&from.to_full()) {
                for candidate_edge in &node_data.outbound {
                    if self.are_edges_internally_connected(from, candidate_edge) &&
                      self.is_edge_reachable(candidate_edge, target) {
                        return true;
                    }
                }
            }
        }
        false
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, from: &Edge, to: &Edge) -> bool {
        self.node_data[&from.to_full()]
            .are_slots_connected(from.weight.to_slot, to.weight.from_slot)
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, out_slot: u32) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::toplevel();
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> ResultE<()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(Error::NodeInUse)
                }
            }
        };
        if ok_to_delete.is_ok() {
            // delete the data associated with this node
            self.node_data.remove(&node);
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
    }

    pub fn to_adjlist(&self) -> AdjList {
        // Map Effect -> EffectId
        let nodes = self.node_data.iter().map(|(handle, data)| {
            (*handle, data.id())
        }).collect();
        // Doubly-linked edges -> singly-linked
        let edges = self.edges.iter().flat_map(|(_key, edgeset)| {
            edgeset.outbound.clone().into_iter()
        }).collect();

        AdjList {
            nodes: nodes,
            edges: edges,
        }
    }
    pub fn from_adjlist(adj: AdjList, res: &ResMan) -> ResultE<Self> {
        // Unwrap struct fields to local variables
        let (nodes, edges) = (adj.nodes, adj.edges);

        // Map EffectId -> Effect
        let nodes: ResultE<HashMap<NodeHandle, NodeData>> = nodes.into_iter().map(|(handle, id)| {
            let decoded_data = Effect::from_id(id, res)?;
            Ok((handle, decoded_data))
        }).collect();
        // Type deduction isn't smart enough to unwrap nodes in above statement.
        let nodes = nodes?;

        // Build self with only nodes and no edges
        let mut me = Self {
            edges: HashMap::new(),
            node_data: nodes,
        };

        // Add the edges one at a time, enforcing zero cycles
        for edge in &edges {
            me.add_edge(edge.clone())?
        }
        Ok(me)
    }
}

impl NodeHandle {
    pub fn toplevel() -> Self {
        NodeHandle::new(None)
    }
    pub fn new<T>(node_handle: T) -> Self
        where T: Into<PrimNodeHandle>
    {
        Self{ node_handle: node_handle.into() }
    }
    pub fn node_handle(&self) -> &PrimNodeHandle {
        &self.node_handle
    }
}

impl Edge {
    /// Create an edge from `from` to null (i.e. an output)
    pub fn new_to_null(from: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from,
            to: NodeHandle::toplevel(),
            weight,
        }
    }
    pub fn new_from_null(to: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from: NodeHandle::toplevel(),
            to,
            weight
        }
    }
    /// Create an edge between the two nodes.
    pub fn new(from: NodeHandle, to: NodeHandle, weight: EdgeWeight) -> Self {
        Self{ from, to, weight }
    }
    pub fn from_full(&self) -> NodeHandle {
        self.from
    }
    pub fn to_full(&self) -> NodeHandle {
        self.to
    }
    pub fn to_slot(&self) -> u32 {
        self.weight.to_slot
    }
    pub fn from_slot(&self) -> u32 {
        self.weight.from_slot
    }
}

impl EdgeWeight {
    pub fn new(from_slot: u32, to_slot: u32) -> Self {
        Self{ from_slot, to_slot }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}
<commit_msg>Remove unused DagHandle type<commit_after>/// `RouteGraph` defines a Directed Acyclic Graph of Effects.
/// The edges connecting each Effect have a source and destination slot, tag, and channel.
/// Edges are also allowed to go to null, in which case they only have a destination slot and
/// channel. These are outputs.
/// Edges can also COME from null, in which case the source has the format (slot, channel)

use std::collections::hash_map::HashMap;
use std::collections::hash_map;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use resman::ResMan;
use super::adjlist::AdjList;
use super::effect;
use super::effect::Effect;
use super::nullable_int::NullableInt;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct EdgeWeight {
    from_slot: u32,
    to_slot: u32,
}

pub type NodeData = Rc<Effect>;

/// None represents the Dag's I/O
type PrimNodeHandle = NullableInt<u32>;

#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct NodeHandle {
    node_handle: PrimNodeHandle,
}

#[derive(Clone, Debug, Hash, Eq, PartialEq)]
#[derive(Serialize, Deserialize)]
pub struct Edge {
    from: NodeHandle,
    to: NodeHandle,
    weight: EdgeWeight,
}

#[derive(Debug)]
pub enum Error {
    /// Raised when an attempt to modify the graph would create a dependency cycle.
    WouldCycle,
    /// Raised on attempt to delete a node when it still has edges.
    NodeInUse,
    /// Raised on attempt to create a node with an id that's already in use.
    NodeExists,
    /// Error inside some Effect:: method
    EffectError(effect::Error),
}

/// Alias for a `Result` with our error type.
pub type ResultE<T> = Result<T, Error>;

#[derive(Default)]
pub struct RouteGraph {
    edges: HashMap<NodeHandle, EdgeSet>,
    node_data: HashMap<NodeHandle, NodeData>,
}

struct EdgeSet {
    outbound: HashSet<Edge>,
    inbound: HashSet<Edge>,
}

impl RouteGraph {
    pub fn new() -> Self {
        Default::default()
    }
    pub fn iter_nodes<'a>(&'a self) -> impl Iterator<Item=(&NodeHandle, &NodeData)> + 'a {
        self.node_data.iter()
    }
    pub fn iter_edges<'a>(&'a self) -> impl Iterator<Item=&Edge> + 'a {
        self.edges.values().flat_map(|v_set| v_set.outbound.iter())
    }
    pub fn get_data(&self, handle: &NodeHandle) -> Option<&NodeData> {
        self.node_data.get(handle)
    }
    /// Try to create a node with the given handle/data.
    /// Will error if the handle is already in use.
    pub fn add_node(&mut self, handle: NodeHandle, node_data: NodeData) -> ResultE<()> {
        // Create storage for the node's outgoing edges
        match self.edges.entry(handle) {
            hash_map::Entry::Occupied(_) => Err(Error::NodeExists),
            hash_map::Entry::Vacant(entry) => { entry.insert(EdgeSet::new()); Ok(()) },
        }?;
        // Store the node's data
        assert!(self.node_data.insert(handle, node_data.clone()).is_none());
        Ok(())
    }
    pub fn add_edge(&mut self, edge: Edge) -> ResultE<()> {
        // Algorithm:
        //   Assume we currently have a DAG.
        //   Given that, the only way this new edge could introduce a cycle is if it was a part of
        //     that cycle.
        //   Therefore, if no path exists from the edge to itself, then it is safe to add the edge.
        let is_reachable = self.is_edge_reachable(&edge, &edge);
        if is_reachable {
            Err(Error::WouldCycle)
        } else {
            self.add_edge_unchecked(edge);
            Ok(())
        }
    }
    fn add_edge_unchecked(&mut self, edge: Edge) {
        // associate the edge with its origin.
        self.edges.entry(edge.from_full()).or_insert_with(EdgeSet::new).outbound.insert(edge.clone());
        // associate the edge with its destination.
        self.edges.entry(edge.to_full()).or_insert_with(EdgeSet::new).inbound.insert(edge);
    }
    fn is_edge_reachable(&self, from: &Edge, target: &Edge) -> bool {
        // Algorithm:
        //   Try to reach `edge` from `edge`.
        //   If we reach the boundary of the DAG while doing so, consider all reachable outbound
        //     edges of the DAG
        //     For each such edge, try to reach this DAG (recursively), and then resume the search for `edge`.
        if let Some(_to) = from.to.node_handle.get() {
            // The edge points to a NODE inside a DAG.
            // Consider all (reachable) outgoing edges of the node:
            if let Some(node_data) = self.edges.get(&from.to_full()) {
                for candidate_edge in &node_data.outbound {
                    if self.are_edges_internally_connected(from, candidate_edge) &&
                      self.is_edge_reachable(candidate_edge, target) {
                        return true;
                    }
                }
            }
        }
        false
    }
    /// Assuming from.to() == to.from(), will return true if & only if
    /// from and to are internally connected within the node.
    fn are_edges_internally_connected(&self, from: &Edge, to: &Edge) -> bool {
        self.node_data[&from.to_full()]
            .are_slots_connected(from.weight.to_slot, to.weight.from_slot)
    }
    /// Returns true if there's a path from `in` to `out` at the toplevel DAG.
    pub fn are_slots_connected(&self, in_slot: u32, out_slot: u32) -> bool {
        // Consider all edges from None paired with all edges to None:
        let root_dag = NodeHandle::toplevel();
        let edges_from = self.edges[&root_dag].outbound.iter().filter(|&edge| {
            edge.weight.from_slot == in_slot
        });
        for edge_from in edges_from {
            let edges_to = self.edges[&root_dag].inbound.iter().filter(|&edge| {
                edge.weight.to_slot == out_slot
            });
            for edge_to in edges_to {
                if self.is_edge_reachable(edge_from, edge_to) {
                    return true;
                }
            }
        }
        false
    }
    pub fn del_node(&mut self, node: NodeHandle) -> ResultE<()> {
        let ok_to_delete = match self.edges.entry(node) {
            // Already deleted
            hash_map::Entry::Vacant(_) => Ok(()),
            hash_map::Entry::Occupied(entry) => {
                if entry.get().is_empty() {
                    entry.remove();
                    Ok(())
                } else {
                    // Node has edges
                    Err(Error::NodeInUse)
                }
            }
        };
        if ok_to_delete.is_ok() {
            // delete the data associated with this node
            self.node_data.remove(&node);
        }
        ok_to_delete
    }
    pub fn del_edge(&mut self, edge: Edge) {
        // TODO: garbage collect the edge sets.
        if let Some(edge_set) = self.edges.get_mut(&edge.from_full()) {
            edge_set.outbound.remove(&edge);
        }
        if let Some(edge_set) = self.edges.get_mut(&edge.to_full()) {
            edge_set.inbound.remove(&edge);
        }
    }

    pub fn to_adjlist(&self) -> AdjList {
        // Map Effect -> EffectId
        let nodes = self.node_data.iter().map(|(handle, data)| {
            (*handle, data.id())
        }).collect();
        // Doubly-linked edges -> singly-linked
        let edges = self.edges.iter().flat_map(|(_key, edgeset)| {
            edgeset.outbound.clone().into_iter()
        }).collect();

        AdjList {
            nodes: nodes,
            edges: edges,
        }
    }
    pub fn from_adjlist(adj: AdjList, res: &ResMan) -> ResultE<Self> {
        // Unwrap struct fields to local variables
        let (nodes, edges) = (adj.nodes, adj.edges);

        // Map EffectId -> Effect
        let nodes: ResultE<HashMap<NodeHandle, NodeData>> = nodes.into_iter().map(|(handle, id)| {
            let decoded_data = Effect::from_id(id, res)?;
            Ok((handle, decoded_data))
        }).collect();
        // Type deduction isn't smart enough to unwrap nodes in above statement.
        let nodes = nodes?;

        // Build self with only nodes and no edges
        let mut me = Self {
            edges: HashMap::new(),
            node_data: nodes,
        };

        // Add the edges one at a time, enforcing zero cycles
        for edge in &edges {
            me.add_edge(edge.clone())?
        }
        Ok(me)
    }
}

impl NodeHandle {
    pub fn toplevel() -> Self {
        NodeHandle::new(None)
    }
    pub fn new<T>(node_handle: T) -> Self
        where T: Into<PrimNodeHandle>
    {
        Self{ node_handle: node_handle.into() }
    }
    pub fn node_handle(&self) -> &PrimNodeHandle {
        &self.node_handle
    }
}

impl Edge {
    /// Create an edge from `from` to null (i.e. an output)
    pub fn new_to_null(from: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from,
            to: NodeHandle::toplevel(),
            weight,
        }
    }
    pub fn new_from_null(to: NodeHandle, weight: EdgeWeight) -> Self {
        Self {
            from: NodeHandle::toplevel(),
            to,
            weight
        }
    }
    /// Create an edge between the two nodes.
    pub fn new(from: NodeHandle, to: NodeHandle, weight: EdgeWeight) -> Self {
        Self{ from, to, weight }
    }
    pub fn from_full(&self) -> NodeHandle {
        self.from
    }
    pub fn to_full(&self) -> NodeHandle {
        self.to
    }
    pub fn to_slot(&self) -> u32 {
        self.weight.to_slot
    }
    pub fn from_slot(&self) -> u32 {
        self.weight.from_slot
    }
}

impl EdgeWeight {
    pub fn new(from_slot: u32, to_slot: u32) -> Self {
        Self{ from_slot, to_slot }
    }
}

impl EdgeSet {
    fn new() -> Self {
        EdgeSet {
            outbound: HashSet::new(),
            inbound: HashSet::new(),
        }
    }
    fn is_empty(&self) -> bool {
        self.outbound.is_empty() && self.inbound.is_empty()
    }
}

/// Conversion from `effect::Error` for use with the `?` operator
impl From<effect::Error> for Error {
    fn from(e: effect::Error) -> Self {
        Error::EffectError(e)
    }
}
<|endoftext|>


<commit_before>extern crate chrono;
extern crate clap;
extern crate hostname;
#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_async;

mod command_line_arguments;
mod context;
mod execution_timer;
mod qork;

use command_line_arguments::CommandLineArguments;
use context::Context;
use execution_timer::ExecutionTimer;
use slog::Logger;

fn main() {
    let throw_away_logger = create_root_logger();
    let _timer = ExecutionTimer::new(&throw_away_logger, "Main.Start");

    let args = CommandLineArguments::new();
    let main_logger = create_root_logger();
    let context = Context::new(main_logger, args);
    context.log_created_message();
}

fn create_root_logger() -> Logger {

    use slog::Drain;

    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    // TODO: We want dynamic configuration here.
    slog::Logger::root(drain, o!())
}

/*
fn sleep(msec: u64) {
    use std::thread;
    use std::time::Duration;
    thread::sleep(Duration::from_millis(msec));
}
*/
<commit_msg>Remove old sleep function.<commit_after>extern crate chrono;
extern crate clap;
extern crate hostname;
#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_async;

mod command_line_arguments;
mod context;
mod execution_timer;
mod qork;

use command_line_arguments::CommandLineArguments;
use context::Context;
use execution_timer::ExecutionTimer;
use slog::Logger;

fn main() {
    let throw_away_logger = create_root_logger();
    let _timer = ExecutionTimer::new(&throw_away_logger, "Main.Start");

    let args = CommandLineArguments::new();
    let main_logger = create_root_logger();
    let context = Context::new(main_logger, args);
    context.log_created_message();
}

fn create_root_logger() -> Logger {

    use slog::Drain;

    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    // TODO: We want dynamic configuration here.
    slog::Logger::root(drain, o!())
}
<|endoftext|>