<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/. */

//! Animated values.
//!
//! Some values, notably colors, cannot be interpolated directly with their
//! computed values and need yet another intermediate representation. This
//! module's raison d'être is to ultimately contain all these types.

use app_units::Au;
use euclid::{Point2D, Size2D};
use smallvec::SmallVec;
use values::computed::length::CalcLengthOrPercentage;
use values::computed::Angle as ComputedAngle;
use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use values::computed::MaxLength as ComputedMaxLength;
use values::computed::MozLength as ComputedMozLength;
use values::computed::url::ComputedUrl;

pub mod color;
pub mod effects;

/// Animate from one value to another.
///
/// This trait is derivable with `#[derive(Animate)]`. The derived
/// implementation uses a `match` expression with identical patterns for both
/// `self` and `other`, calling `Animate::animate` on each fields of the values.
/// If a field is annotated with `#[animation(constant)]`, the two values should
/// be equal or an error is returned.
///
/// If a variant is annotated with `#[animation(error)]`, the corresponding
/// `match` arm is not generated.
///
/// If the two values are not similar, an error is returned unless a fallback
/// function has been specified through `#[animate(fallback)]`.
///
/// Trait bounds for type parameter `Foo` can be opted out of with
/// `#[animation(no_bound(Foo))]` on the type definition.
pub trait Animate: Sized {
    /// Animate a value towards another one, given an animation procedure.
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
}

/// An animation procedure.
///
/// <https://drafts.csswg.org/web-animations/#procedures-for-animating-properties>
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Procedure {
    /// <https://drafts.csswg.org/web-animations/#animation-interpolation>
    Interpolate { progress: f64 },
    /// <https://drafts.csswg.org/web-animations/#animation-addition>
    Add,
    /// <https://drafts.csswg.org/web-animations/#animation-accumulation>
    Accumulate { count: u64 },
}

/// Conversion between computed values and intermediate values for animations.
///
/// Notably, colors are represented as four floats during animations.
///
/// This trait is derivable with `#[derive(ToAnimatedValue)]`.
pub trait ToAnimatedValue {
    /// The type of the animated value.
    type AnimatedValue;

    /// Converts this value to an animated value.
    fn to_animated_value(self) -> Self::AnimatedValue;

    /// Converts back an animated value into a computed value.
    fn from_animated_value(animated: Self::AnimatedValue) -> Self;
}

/// Returns a value similar to `self` that represents zero.
///
/// This trait is derivable with `#[derive(ToAnimatedValue)]`. If a field is
/// annotated with `#[animation(constant)]`, a clone of its value will be used
/// instead of calling `ToAnimatedZero::to_animated_zero` on it.
///
/// If a variant is annotated with `#[animation(error)]`, the corresponding
/// `match` arm is not generated.
///
/// Trait bounds for type parameter `Foo` can be opted out of with
/// `#[animation(no_bound(Foo))]` on the type definition.
pub trait ToAnimatedZero: Sized {
    /// Returns a value that, when added with an underlying value, will produce the underlying
    /// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
    /// the zero value to the 'by' value, and then adds the result to the underlying value.
    ///
    /// This is not the necessarily the same as the initial value of a property. For example, the
    /// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
    /// underlying value will not produce the underlying value.
    fn to_animated_zero(&self) -> Result<Self, ()>;
}

impl Procedure {
    /// Returns this procedure as a pair of weights.
    ///
    /// This is useful for animations that don't animate differently
    /// depending on the used procedure.
    #[inline]
    pub fn weights(self) -> (f64, f64) {
        match self {
            Procedure::Interpolate { progress } => (1. - progress, progress),
            Procedure::Add => (1., 1.),
            Procedure::Accumulate { count } => (count as f64, 1.),
        }
    }
}

/// <https://drafts.csswg.org/css-transitions/#animtype-number>
impl Animate for i32 {
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        Ok(((*self as f64).animate(&(*other as f64), procedure)? + 0.5).floor() as i32)
    }
}

/// <https://drafts.csswg.org/css-transitions/#animtype-number>
impl Animate for f32 {
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        use std::f32;

        let ret = (*self as f64).animate(&(*other as f64), procedure)?;
        Ok(ret.min(f32::MAX as f64).max(f32::MIN as f64) as f32)
    }
}

/// <https://drafts.csswg.org/css-transitions/#animtype-number>
impl Animate for f64 {
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        use std::f64;

        let (self_weight, other_weight) = procedure.weights();

        let ret = *self * self_weight + *other * other_weight;
        Ok(ret.min(f64::MAX).max(f64::MIN))
    }
}

impl<T> Animate for Option<T>
where
    T: Animate,
{
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        match (self.as_ref(), other.as_ref()) {
            (Some(ref this), Some(ref other)) => Ok(Some(this.animate(other, procedure)?)),
            (None, None) => Ok(None),
            _ => Err(()),
        }
    }
}

impl Animate for Au {
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        Ok(Au::new(self.0.animate(&other.0, procedure)?))
    }
}

impl<T> Animate for Size2D<T>
where
    T: Animate,
{
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        Ok(Size2D::new(
            self.width.animate(&other.width, procedure)?,
            self.height.animate(&other.height, procedure)?,
        ))
    }
}

impl<T> Animate for Point2D<T>
where
    T: Animate,
{
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        Ok(Point2D::new(
            self.x.animate(&other.x, procedure)?,
            self.y.animate(&other.y, procedure)?,
        ))
    }
}

impl<T> ToAnimatedValue for Option<T>
where
    T: ToAnimatedValue,
{
    type AnimatedValue = Option<<T as ToAnimatedValue>::AnimatedValue>;

    #[inline]
    fn to_animated_value(self) -> Self::AnimatedValue {
        self.map(T::to_animated_value)
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        animated.map(T::from_animated_value)
    }
}

impl<T> ToAnimatedValue for Vec<T>
where
    T: ToAnimatedValue,
{
    type AnimatedValue = Vec<<T as ToAnimatedValue>::AnimatedValue>;

    #[inline]
    fn to_animated_value(self) -> Self::AnimatedValue {
        self.into_iter().map(T::to_animated_value).collect()
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        animated.into_iter().map(T::from_animated_value).collect()
    }
}

impl<T> ToAnimatedValue for SmallVec<[T; 1]>
where
    T: ToAnimatedValue,
{
    type AnimatedValue = SmallVec<[T::AnimatedValue; 1]>;

    #[inline]
    fn to_animated_value(self) -> Self::AnimatedValue {
        self.into_iter().map(T::to_animated_value).collect()
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        animated.into_iter().map(T::from_animated_value).collect()
    }
}

macro_rules! trivial_to_animated_value {
    ($ty:ty) => {
        impl $crate::values::animated::ToAnimatedValue for $ty {
            type AnimatedValue = Self;

            #[inline]
            fn to_animated_value(self) -> Self {
                self
            }

            #[inline]
            fn from_animated_value(animated: Self::AnimatedValue) -> Self {
                animated
            }
        }
    };
}

trivial_to_animated_value!(Au);
trivial_to_animated_value!(CalcLengthOrPercentage);
trivial_to_animated_value!(ComputedAngle);
trivial_to_animated_value!(ComputedUrl);
trivial_to_animated_value!(bool);
trivial_to_animated_value!(f32);

impl ToAnimatedValue for ComputedBorderCornerRadius {
    type AnimatedValue = Self;

    #[inline]
    fn to_animated_value(self) -> Self {
        self
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        ComputedBorderCornerRadius::new(
            (animated.0).0.width.clamp_to_non_negative(),
            (animated.0).0.height.clamp_to_non_negative(),
        )
    }
}

impl ToAnimatedValue for ComputedMaxLength {
    type AnimatedValue = Self;

    #[inline]
    fn to_animated_value(self) -> Self {
        self
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        use values::computed::{Length, LengthOrPercentageOrNone, Percentage};
        match animated {
            ComputedMaxLength::LengthOrPercentageOrNone(lopn) => {
                let result = match lopn {
                    LengthOrPercentageOrNone::Length(px) => {
                        LengthOrPercentageOrNone::Length(Length::new(px.px().max(0.)))
                    },
                    LengthOrPercentageOrNone::Percentage(percentage) => {
                        LengthOrPercentageOrNone::Percentage(Percentage(percentage.0.max(0.)))
                    },
                    _ => lopn,
                };
                ComputedMaxLength::LengthOrPercentageOrNone(result)
            },
            _ => animated,
        }
    }
}

impl ToAnimatedValue for ComputedMozLength {
    type AnimatedValue = Self;

    #[inline]
    fn to_animated_value(self) -> Self {
        self
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        use values::computed::{Length, LengthOrPercentageOrAuto, Percentage};
        match animated {
            ComputedMozLength::LengthOrPercentageOrAuto(lopa) => {
                let result = match lopa {
                    LengthOrPercentageOrAuto::Length(px) => {
                        LengthOrPercentageOrAuto::Length(Length::new(px.px().max(0.)))
                    },
                    LengthOrPercentageOrAuto::Percentage(percentage) => {
                        LengthOrPercentageOrAuto::Percentage(Percentage(percentage.0.max(0.)))
                    },
                    _ => lopa,
                };
                ComputedMozLength::LengthOrPercentageOrAuto(result)
            },
            _ => animated,
        }
    }
}

impl ToAnimatedZero for Au {
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(Au(0))
    }
}

impl ToAnimatedZero for f32 {
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(0.)
    }
}

impl ToAnimatedZero for f64 {
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(0.)
    }
}

impl ToAnimatedZero for i32 {
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(0)
    }
}

impl<T> ToAnimatedZero for Option<T>
where
    T: ToAnimatedZero,
{
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        match *self {
            Some(ref value) => Ok(Some(value.to_animated_zero()?)),
            None => Ok(None),
        }
    }
}

impl<T> ToAnimatedZero for Size2D<T>
where
    T: ToAnimatedZero,
{
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(Size2D::new(
            self.width.to_animated_zero()?,
            self.height.to_animated_zero()?,
        ))
    }
}
<commit_msg>style: Appease tidy.<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/. */

//! Animated values.
//!
//! Some values, notably colors, cannot be interpolated directly with their
//! computed values and need yet another intermediate representation. This
//! module's raison d'être is to ultimately contain all these types.

use app_units::Au;
use euclid::{Point2D, Size2D};
use smallvec::SmallVec;
use values::computed::Angle as ComputedAngle;
use values::computed::BorderCornerRadius as ComputedBorderCornerRadius;
use values::computed::MaxLength as ComputedMaxLength;
use values::computed::MozLength as ComputedMozLength;
use values::computed::length::CalcLengthOrPercentage;
use values::computed::url::ComputedUrl;

pub mod color;
pub mod effects;

/// Animate from one value to another.
///
/// This trait is derivable with `#[derive(Animate)]`. The derived
/// implementation uses a `match` expression with identical patterns for both
/// `self` and `other`, calling `Animate::animate` on each fields of the values.
/// If a field is annotated with `#[animation(constant)]`, the two values should
/// be equal or an error is returned.
///
/// If a variant is annotated with `#[animation(error)]`, the corresponding
/// `match` arm is not generated.
///
/// If the two values are not similar, an error is returned unless a fallback
/// function has been specified through `#[animate(fallback)]`.
///
/// Trait bounds for type parameter `Foo` can be opted out of with
/// `#[animation(no_bound(Foo))]` on the type definition.
pub trait Animate: Sized {
    /// Animate a value towards another one, given an animation procedure.
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()>;
}

/// An animation procedure.
///
/// <https://drafts.csswg.org/web-animations/#procedures-for-animating-properties>
#[allow(missing_docs)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Procedure {
    /// <https://drafts.csswg.org/web-animations/#animation-interpolation>
    Interpolate { progress: f64 },
    /// <https://drafts.csswg.org/web-animations/#animation-addition>
    Add,
    /// <https://drafts.csswg.org/web-animations/#animation-accumulation>
    Accumulate { count: u64 },
}

/// Conversion between computed values and intermediate values for animations.
///
/// Notably, colors are represented as four floats during animations.
///
/// This trait is derivable with `#[derive(ToAnimatedValue)]`.
pub trait ToAnimatedValue {
    /// The type of the animated value.
    type AnimatedValue;

    /// Converts this value to an animated value.
    fn to_animated_value(self) -> Self::AnimatedValue;

    /// Converts back an animated value into a computed value.
    fn from_animated_value(animated: Self::AnimatedValue) -> Self;
}

/// Returns a value similar to `self` that represents zero.
///
/// This trait is derivable with `#[derive(ToAnimatedValue)]`. If a field is
/// annotated with `#[animation(constant)]`, a clone of its value will be used
/// instead of calling `ToAnimatedZero::to_animated_zero` on it.
///
/// If a variant is annotated with `#[animation(error)]`, the corresponding
/// `match` arm is not generated.
///
/// Trait bounds for type parameter `Foo` can be opted out of with
/// `#[animation(no_bound(Foo))]` on the type definition.
pub trait ToAnimatedZero: Sized {
    /// Returns a value that, when added with an underlying value, will produce the underlying
    /// value. This is used for SMIL animation's "by-animation" where SMIL first interpolates from
    /// the zero value to the 'by' value, and then adds the result to the underlying value.
    ///
    /// This is not the necessarily the same as the initial value of a property. For example, the
    /// initial value of 'stroke-width' is 1, but the zero value is 0, since adding 1 to the
    /// underlying value will not produce the underlying value.
    fn to_animated_zero(&self) -> Result<Self, ()>;
}

impl Procedure {
    /// Returns this procedure as a pair of weights.
    ///
    /// This is useful for animations that don't animate differently
    /// depending on the used procedure.
    #[inline]
    pub fn weights(self) -> (f64, f64) {
        match self {
            Procedure::Interpolate { progress } => (1. - progress, progress),
            Procedure::Add => (1., 1.),
            Procedure::Accumulate { count } => (count as f64, 1.),
        }
    }
}

/// <https://drafts.csswg.org/css-transitions/#animtype-number>
impl Animate for i32 {
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        Ok(((*self as f64).animate(&(*other as f64), procedure)? + 0.5).floor() as i32)
    }
}

/// <https://drafts.csswg.org/css-transitions/#animtype-number>
impl Animate for f32 {
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        use std::f32;

        let ret = (*self as f64).animate(&(*other as f64), procedure)?;
        Ok(ret.min(f32::MAX as f64).max(f32::MIN as f64) as f32)
    }
}

/// <https://drafts.csswg.org/css-transitions/#animtype-number>
impl Animate for f64 {
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        use std::f64;

        let (self_weight, other_weight) = procedure.weights();

        let ret = *self * self_weight + *other * other_weight;
        Ok(ret.min(f64::MAX).max(f64::MIN))
    }
}

impl<T> Animate for Option<T>
where
    T: Animate,
{
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        match (self.as_ref(), other.as_ref()) {
            (Some(ref this), Some(ref other)) => Ok(Some(this.animate(other, procedure)?)),
            (None, None) => Ok(None),
            _ => Err(()),
        }
    }
}

impl Animate for Au {
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        Ok(Au::new(self.0.animate(&other.0, procedure)?))
    }
}

impl<T> Animate for Size2D<T>
where
    T: Animate,
{
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        Ok(Size2D::new(
            self.width.animate(&other.width, procedure)?,
            self.height.animate(&other.height, procedure)?,
        ))
    }
}

impl<T> Animate for Point2D<T>
where
    T: Animate,
{
    #[inline]
    fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
        Ok(Point2D::new(
            self.x.animate(&other.x, procedure)?,
            self.y.animate(&other.y, procedure)?,
        ))
    }
}

impl<T> ToAnimatedValue for Option<T>
where
    T: ToAnimatedValue,
{
    type AnimatedValue = Option<<T as ToAnimatedValue>::AnimatedValue>;

    #[inline]
    fn to_animated_value(self) -> Self::AnimatedValue {
        self.map(T::to_animated_value)
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        animated.map(T::from_animated_value)
    }
}

impl<T> ToAnimatedValue for Vec<T>
where
    T: ToAnimatedValue,
{
    type AnimatedValue = Vec<<T as ToAnimatedValue>::AnimatedValue>;

    #[inline]
    fn to_animated_value(self) -> Self::AnimatedValue {
        self.into_iter().map(T::to_animated_value).collect()
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        animated.into_iter().map(T::from_animated_value).collect()
    }
}

impl<T> ToAnimatedValue for SmallVec<[T; 1]>
where
    T: ToAnimatedValue,
{
    type AnimatedValue = SmallVec<[T::AnimatedValue; 1]>;

    #[inline]
    fn to_animated_value(self) -> Self::AnimatedValue {
        self.into_iter().map(T::to_animated_value).collect()
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        animated.into_iter().map(T::from_animated_value).collect()
    }
}

macro_rules! trivial_to_animated_value {
    ($ty:ty) => {
        impl $crate::values::animated::ToAnimatedValue for $ty {
            type AnimatedValue = Self;

            #[inline]
            fn to_animated_value(self) -> Self {
                self
            }

            #[inline]
            fn from_animated_value(animated: Self::AnimatedValue) -> Self {
                animated
            }
        }
    };
}

trivial_to_animated_value!(Au);
trivial_to_animated_value!(CalcLengthOrPercentage);
trivial_to_animated_value!(ComputedAngle);
trivial_to_animated_value!(ComputedUrl);
trivial_to_animated_value!(bool);
trivial_to_animated_value!(f32);

impl ToAnimatedValue for ComputedBorderCornerRadius {
    type AnimatedValue = Self;

    #[inline]
    fn to_animated_value(self) -> Self {
        self
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        ComputedBorderCornerRadius::new(
            (animated.0).0.width.clamp_to_non_negative(),
            (animated.0).0.height.clamp_to_non_negative(),
        )
    }
}

impl ToAnimatedValue for ComputedMaxLength {
    type AnimatedValue = Self;

    #[inline]
    fn to_animated_value(self) -> Self {
        self
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        use values::computed::{Length, LengthOrPercentageOrNone, Percentage};
        match animated {
            ComputedMaxLength::LengthOrPercentageOrNone(lopn) => {
                let result = match lopn {
                    LengthOrPercentageOrNone::Length(px) => {
                        LengthOrPercentageOrNone::Length(Length::new(px.px().max(0.)))
                    },
                    LengthOrPercentageOrNone::Percentage(percentage) => {
                        LengthOrPercentageOrNone::Percentage(Percentage(percentage.0.max(0.)))
                    },
                    _ => lopn,
                };
                ComputedMaxLength::LengthOrPercentageOrNone(result)
            },
            _ => animated,
        }
    }
}

impl ToAnimatedValue for ComputedMozLength {
    type AnimatedValue = Self;

    #[inline]
    fn to_animated_value(self) -> Self {
        self
    }

    #[inline]
    fn from_animated_value(animated: Self::AnimatedValue) -> Self {
        use values::computed::{Length, LengthOrPercentageOrAuto, Percentage};
        match animated {
            ComputedMozLength::LengthOrPercentageOrAuto(lopa) => {
                let result = match lopa {
                    LengthOrPercentageOrAuto::Length(px) => {
                        LengthOrPercentageOrAuto::Length(Length::new(px.px().max(0.)))
                    },
                    LengthOrPercentageOrAuto::Percentage(percentage) => {
                        LengthOrPercentageOrAuto::Percentage(Percentage(percentage.0.max(0.)))
                    },
                    _ => lopa,
                };
                ComputedMozLength::LengthOrPercentageOrAuto(result)
            },
            _ => animated,
        }
    }
}

impl ToAnimatedZero for Au {
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(Au(0))
    }
}

impl ToAnimatedZero for f32 {
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(0.)
    }
}

impl ToAnimatedZero for f64 {
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(0.)
    }
}

impl ToAnimatedZero for i32 {
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(0)
    }
}

impl<T> ToAnimatedZero for Option<T>
where
    T: ToAnimatedZero,
{
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        match *self {
            Some(ref value) => Ok(Some(value.to_animated_zero()?)),
            None => Ok(None),
        }
    }
}

impl<T> ToAnimatedZero for Size2D<T>
where
    T: ToAnimatedZero,
{
    #[inline]
    fn to_animated_zero(&self) -> Result<Self, ()> {
        Ok(Size2D::new(
            self.width.to_animated_zero()?,
            self.height.to_animated_zero()?,
        ))
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use std::mem;
use std::ptr::copy;

const PAGE_SIZE: usize = 4096;

fn main() {
    let size = 9;
    let bytes: [u8; 9] = [0x8b, 0x44, 0x24, 0x04, 0x03, 0x44, 0x24, 0x08, 0xc3];
    let f: fn(u8, u8) -> u8 = unsafe {
        let mut page: *mut libc::c_void = mem::uninitialized();
        libc::posix_memalign(&mut page, PAGE_SIZE, size);
        libc::mprotect(
            page,
            size,
            libc::PROT_EXEC | libc::PROT_READ | libc::PROT_WRITE,
        );
        let contents: *mut u8 = mem::transmute(page);
        copy(bytes.as_ptr(), contents, 9);
        mem::transmute(contents)
    };

    println!("{}", f(7, 12));
}
<commit_msg>Added support for 64-bits arch<commit_after>extern crate libc;

#[cfg(all(
    target_os = "linux",
    any(target_pointer_width = "32", target_pointer_width = "64")
))]
fn main() {
    use std::mem;
    use std::ptr;

    let page_size: usize = 4096;
    let (bytes, size): (Vec<u8>, usize) = if cfg!(target_pointer_width = "32") {
        (
            vec![0x8b, 0x44, 0x24, 0x04, 0x03, 0x44, 0x24, 0x08, 0xc3],
            9,
        )
    } else {
        (vec![0x48, 0x89, 0xf8, 0x48, 0x01, 0xf0, 0xc3], 7)
    };
    let f: fn(u8, u8) -> u8 = unsafe {
        let mut page: *mut libc::c_void = ptr::null_mut();
        libc::posix_memalign(&mut page, page_size, size);
        libc::mprotect(
            page,
            size,
            libc::PROT_EXEC | libc::PROT_READ | libc::PROT_WRITE,
        );
        let contents: *mut u8 = page as *mut u8;
        ptr::copy(bytes.as_ptr(), contents, 9);
        mem::transmute(contents)
    };

    let return_value = f(7, 12);
    println!("Returned value: {}", return_value);
    assert_eq!(return_value, 19);
}

#[cfg(any(
    not(target_os = "linux"),
    not(any(target_pointer_width = "32", target_pointer_width = "64"))
))]
fn main() {
    println!("Not supported on this platform.");
}
<|endoftext|>


<commit_before>//! A midi sequence describes an expected sequence to be played.

use editdistancewf;
use Result;
use note::Note;

/// A vector of notes that are expected to be played linearly.  The notes can be played legato.
/// The inner vector holds notes that should be played simultaneously, such as with both hands.
#[derive(Debug)]
pub struct ScaleSeq(Vec<Vec<Note>>);

impl ScaleSeq {
    /// Generate the sequence for the described scale.
    pub fn from_scale(scale: &Scale) -> Result<ScaleSeq> {
        let base = Note::from_str(&scale.base)?;
        // println!("base: {:?}", base);

        // Build up the notes based on the interval.
        let mut first = base;
        let mut last = base;
        let mut notes = vec![base];
        for _ in 0 .. scale.octaves {
            for ch in scale.intervals.chars() {
                let next = match ch {
                    'H' => 1,
                    'W' => 2,
                    'm' => 3,
                    'M' => 4,
                    '4' => 5,
                    _ => return Err(format!("Invalid interval: {:?}", scale.intervals).into()),
                };
                let next = last + next;
                notes.push(next);
                last = next;
            }
            if first + 12 != last {
                return Err(format!("Scale is not exactly one octave: {:?}", scale.intervals).into());
            }
            first = last;
        }

        // Generate the appropriate scale type.
        match scale.style.as_str() {
            "updown" => {
                // Reflect the scale back on itself, except eliminate the duplicate note.
                let mut other = notes.clone();
                other.reverse();
                notes.extend(other.iter().skip(1));
            }
            style => return Err(format!("Unknown scale style: {:?}", style).into()),
        }

        // Build the note vectors out of the notes.
        let notes: Vec<_> = notes.iter().map(|&n| {
            let mut each = vec![n];
            for i in 1..scale.hands {
                each.push(n + (12 * i) as i8);
            }
            each
        }).collect();

        Ok(ScaleSeq(notes))
    }

    /// Convert an input voicing into a sequence.  This is very straightforward, as the voicing
    /// exercises are generated before entering into the database.
    pub fn from_voicing(voicing: &Voicing) -> Result<ScaleSeq> {
        Ok(ScaleSeq(voicing.chords.iter().map(|chord| {
            chord.iter().map(|note| Note(*note)).collect()
        }).collect()))
    }

    /// Scales can be played in a different octave than requested.  Compare the first note the user
    /// played with the note given.  If they are off by some number of octaves, adjust all of the
    /// notes in the ScaleSeq.  Returns true if the first note matches and a possible adjustment
    /// has been made.  Return false if there are either no notes, or the first not is not the
    /// right note.
    pub fn adjust_octave(&mut self, played: &[Vec<Note>]) -> bool {
        let my_first = match self.0.first() {
            None => return false,
            Some(v) => {
                match v.first() {
                    None => return false,
                    Some(&v) => v,
                }
            }
        };
        let played_first = match played.first() {
            None => return false,
            Some(v) => {
                match v.first() {
                    None => return false,
                    Some(&v) => v,
                }
            }
        };

        if my_first == played_first {
            return true;
        }

        let shift = played_first.0 as i32 - my_first.0 as i32;
        if shift % 12 == 0 {
            for me in &mut self.0 {
                for n in me.iter_mut() {
                    *n = *n + shift as i8;
                }
            }
            true
        } else {
            false
        }
    }

    /// Determine how different what the user played is from what is given.
    pub fn differences(&self, played: &[Vec<Note>]) -> usize {
        // println!("Compare: {:?} and\n         {:?}", self.0, played);
        editdistancewf::distance(self.0.iter(), played.iter())
    }
}

/// A structure mapping to the json data that is the input for a scale.
#[derive(Debug, Deserialize)]
pub struct Scale {
    pub base: String,
    pub intervals: String,
    pub hands: u32,
    pub octaves: u32,
    pub style: String,
}

/// A structure mapping to the json data that is the input for a voicing.
#[derive(Debug, Deserialize)]
pub struct Voicing {
    chords: Vec<Vec<u8>>,
}
<commit_msg>midilearn: Better count errors in chords<commit_after>//! A midi sequence describes an expected sequence to be played.

use editdistancewf;
use Result;
use note::Note;

/// A vector of notes that are expected to be played linearly.  The notes can be played legato.
/// The inner vector holds notes that should be played simultaneously, such as with both hands.
#[derive(Debug)]
pub struct ScaleSeq(Vec<Vec<Note>>);

impl ScaleSeq {
    /// Generate the sequence for the described scale.
    pub fn from_scale(scale: &Scale) -> Result<ScaleSeq> {
        let base = Note::from_str(&scale.base)?;
        // println!("base: {:?}", base);

        // Build up the notes based on the interval.
        let mut first = base;
        let mut last = base;
        let mut notes = vec![base];
        for _ in 0 .. scale.octaves {
            for ch in scale.intervals.chars() {
                let next = match ch {
                    'H' => 1,
                    'W' => 2,
                    'm' => 3,
                    'M' => 4,
                    '4' => 5,
                    _ => return Err(format!("Invalid interval: {:?}", scale.intervals).into()),
                };
                let next = last + next;
                notes.push(next);
                last = next;
            }
            if first + 12 != last {
                return Err(format!("Scale is not exactly one octave: {:?}", scale.intervals).into());
            }
            first = last;
        }

        // Generate the appropriate scale type.
        match scale.style.as_str() {
            "updown" => {
                // Reflect the scale back on itself, except eliminate the duplicate note.
                let mut other = notes.clone();
                other.reverse();
                notes.extend(other.iter().skip(1));
            }
            style => return Err(format!("Unknown scale style: {:?}", style).into()),
        }

        // Build the note vectors out of the notes.
        let notes: Vec<_> = notes.iter().map(|&n| {
            let mut each = vec![n];
            for i in 1..scale.hands {
                each.push(n + (12 * i) as i8);
            }
            each
        }).collect();

        Ok(ScaleSeq(notes))
    }

    /// Convert an input voicing into a sequence.  This is very straightforward, as the voicing
    /// exercises are generated before entering into the database.
    pub fn from_voicing(voicing: &Voicing) -> Result<ScaleSeq> {
        Ok(ScaleSeq(voicing.chords.iter().map(|chord| {
            chord.iter().map(|note| Note(*note)).collect()
        }).collect()))
    }

    /// Scales can be played in a different octave than requested.  Compare the first note the user
    /// played with the note given.  If they are off by some number of octaves, adjust all of the
    /// notes in the ScaleSeq.  Returns true if the first note matches and a possible adjustment
    /// has been made.  Return false if there are either no notes, or the first not is not the
    /// right note.
    pub fn adjust_octave(&mut self, played: &[Vec<Note>]) -> bool {
        let my_first = match self.0.first() {
            None => return false,
            Some(v) => {
                match v.first() {
                    None => return false,
                    Some(&v) => v,
                }
            }
        };
        let played_first = match played.first() {
            None => return false,
            Some(v) => {
                match v.first() {
                    None => return false,
                    Some(&v) => v,
                }
            }
        };

        if my_first == played_first {
            return true;
        }

        let shift = played_first.0 as i32 - my_first.0 as i32;
        if shift % 12 == 0 {
            for me in &mut self.0 {
                for n in me.iter_mut() {
                    *n = *n + shift as i8;
                }
            }
            true
        } else {
            false
        }
    }

    /// Determine how different what the user played is from what is given.
    pub fn differences(&self, played: &[Vec<Note>]) -> usize {
        // println!("Compare: {:?} and\n         {:?}", self.0, played);
        editdistancewf::distance(ChordNoteIter::new(&self.0),
            ChordNoteIter::new(played))
    }
}

// An iterator that spreads the notes out of a chord, and inserts a separator between them.  Since
// MIDI notes can only have the value 0-127, we can just use something like 128 as the chord
// marker.
struct ChordNoteIter<'a> {
    // The chords we're iterating over.  If the slice is empty, we're done.
    chords: &'a [Vec<Note>],
    // The position within the first chord.  If this is past the end of the chords, we're
    // generating the separator.
    pos: usize,
}

impl<'a> ChordNoteIter<'a> {
    fn new(chords: &[Vec<Note>]) -> ChordNoteIter {
        ChordNoteIter {
            chords: chords,
            pos: 0,
        }
    }
}

impl<'a> Iterator for ChordNoteIter<'a> {
    type Item = Note;

    fn next(&mut self) -> Option<Self::Item> {
        let chord = match self.chords.first() {
            None => return None,
            Some(ch) => ch,
        };

        if self.pos >= chord.len() {
            self.chords = &self.chords[1..];
            self.pos = 0;
            Some(Note(128))
        } else {
            let result = chord[self.pos];
            self.pos += 1;
            Some(result)
        }
    }
}

/// A structure mapping to the json data that is the input for a scale.
#[derive(Debug, Deserialize)]
pub struct Scale {
    pub base: String,
    pub intervals: String,
    pub hands: u32,
    pub octaves: u32,
    pub style: String,
}

/// A structure mapping to the json data that is the input for a voicing.
#[derive(Debug, Deserialize)]
pub struct Voicing {
    chords: Vec<Vec<u8>>,
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Sunrin SHIMURA
// Collaborator: Jian Zeng
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (paths) GPGHome

use clap::{crate_version, Arg, Command};
use uucore::display::{println_verbatim, Quotable};
use uucore::error::{FromIo, UError, UResult};
use uucore::format_usage;

use std::env;
use std::error::Error;
use std::fmt::Display;
use std::iter;
use std::path::{is_separator, Path, PathBuf};

use rand::Rng;
use tempfile::Builder;

static ABOUT: &str = "create a temporary file or directory.";
const USAGE: &str = "{} [OPTION]... [TEMPLATE]";

static DEFAULT_TEMPLATE: &str = "tmp.XXXXXXXXXX";

static OPT_DIRECTORY: &str = "directory";
static OPT_DRY_RUN: &str = "dry-run";
static OPT_QUIET: &str = "quiet";
static OPT_SUFFIX: &str = "suffix";
static OPT_TMPDIR: &str = "tmpdir";
static OPT_T: &str = "t";

static ARG_TEMPLATE: &str = "template";

#[derive(Debug)]
enum MkTempError {
    PersistError(PathBuf),
    MustEndInX(String),
    TooFewXs(String),
    ContainsDirSeparator(String),
    InvalidTemplate(String),
}

impl UError for MkTempError {}

impl Error for MkTempError {}

impl Display for MkTempError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        use MkTempError::*;
        match self {
            PersistError(p) => write!(f, "could not persist file {}", p.quote()),
            MustEndInX(s) => write!(f, "with --suffix, template {} must end in X", s.quote()),
            TooFewXs(s) => write!(f, "too few X's in template {}", s.quote()),
            ContainsDirSeparator(s) => {
                write!(
                    f,
                    "invalid suffix {}, contains directory separator",
                    s.quote()
                )
            }
            InvalidTemplate(s) => write!(
                f,
                "invalid template, {}; with --tmpdir, it may not be absolute",
                s.quote()
            ),
        }
    }
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().get_matches_from(args);

    let template = matches.value_of(ARG_TEMPLATE).unwrap();
    let tmpdir = matches.value_of(OPT_TMPDIR).unwrap_or_default();

    let (template, mut tmpdir) = if matches.is_present(OPT_TMPDIR)
        && !PathBuf::from(tmpdir).is_dir() // if a temp dir is provided, it must be an actual path
        && tmpdir.contains("XXX")
    // If this is a template, it has to contain at least 3 X
        && template == DEFAULT_TEMPLATE
    // That means that clap does not think we provided a template
    {
        // Special case to workaround a limitation of clap when doing
        // mktemp --tmpdir apt-key-gpghome.XXX
        // The behavior should be
        // mktemp --tmpdir $TMPDIR apt-key-gpghome.XX
        // As --tmpdir is empty
        //
        // Fixed in clap 3
        // See https://github.com/clap-rs/clap/pull/1587
        let tmp = env::temp_dir();
        (tmpdir, tmp)
    } else if !matches.is_present(OPT_TMPDIR) {
        let tmp = env::temp_dir();
        (template, tmp)
    } else {
        (template, PathBuf::from(tmpdir))
    };

    let make_dir = matches.is_present(OPT_DIRECTORY);
    let dry_run = matches.is_present(OPT_DRY_RUN);
    let suppress_file_err = matches.is_present(OPT_QUIET);

    let (prefix, rand, suffix) = parse_template(template, matches.value_of(OPT_SUFFIX))?;

    if matches.is_present(OPT_TMPDIR) && PathBuf::from(prefix).is_absolute() {
        return Err(MkTempError::InvalidTemplate(template.into()).into());
    }

    if matches.is_present(OPT_T) {
        tmpdir = env::temp_dir();
    }

    let res = if dry_run {
        dry_exec(tmpdir, prefix, rand, suffix)
    } else {
        exec(&tmpdir, prefix, rand, suffix, make_dir)
    };

    if suppress_file_err {
        // Mapping all UErrors to ExitCodes prevents the errors from being printed
        res.map_err(|e| e.code().into())
    } else {
        res
    }
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(OPT_DIRECTORY)
                .short('d')
                .long(OPT_DIRECTORY)
                .help("Make a directory instead of a file"),
        )
        .arg(
            Arg::new(OPT_DRY_RUN)
                .short('u')
                .long(OPT_DRY_RUN)
                .help("do not create anything; merely print a name (unsafe)"),
        )
        .arg(
            Arg::new(OPT_QUIET)
                .short('q')
                .long("quiet")
                .help("Fail silently if an error occurs."),
        )
        .arg(
            Arg::new(OPT_SUFFIX)
                .long(OPT_SUFFIX)
                .help(
                    "append SUFFIX to TEMPLATE; SUFFIX must not contain a path separator. \
                     This option is implied if TEMPLATE does not end with X.",
                )
                .value_name("SUFFIX"),
        )
        .arg(
            Arg::new(OPT_TMPDIR)
                .short('p')
                .long(OPT_TMPDIR)
                .help(
                    "interpret TEMPLATE relative to DIR; if DIR is not specified, use \
                     $TMPDIR ($TMP on windows) if set, else /tmp. With this option, TEMPLATE must not \
                     be an absolute name; unlike with -t, TEMPLATE may contain \
                     slashes, but mktemp creates only the final component",
                )
                .value_name("DIR"),
        )
        .arg(Arg::new(OPT_T).short('t').help(
            "Generate a template (using the supplied prefix and TMPDIR (TMP on windows) if set) \
             to create a filename template [deprecated]",
        ))
        .arg(
            Arg::new(ARG_TEMPLATE)
                .multiple_occurrences(false)
                .takes_value(true)
                .max_values(1)
                .default_value(DEFAULT_TEMPLATE),
        )
}

fn parse_template<'a>(
    temp: &'a str,
    suffix: Option<&'a str>,
) -> UResult<(&'a str, usize, &'a str)> {
    let right = match temp.rfind('X') {
        Some(r) => r + 1,
        None => return Err(MkTempError::TooFewXs(temp.into()).into()),
    };
    let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1);
    let prefix = &temp[..left];
    let rand = right - left;

    if rand < 3 {
        return Err(MkTempError::TooFewXs(temp.into()).into());
    }

    let mut suf = &temp[right..];

    if let Some(s) = suffix {
        if suf.is_empty() {
            suf = s;
        } else {
            return Err(MkTempError::MustEndInX(temp.into()).into());
        }
    };

    if suf.chars().any(is_separator) {
        return Err(MkTempError::ContainsDirSeparator(suf.into()).into());
    }

    Ok((prefix, rand, suf))
}

pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) -> UResult<()> {
    let len = prefix.len() + suffix.len() + rand;
    let mut buf = Vec::with_capacity(len);
    buf.extend(prefix.as_bytes());
    buf.extend(iter::repeat(b'X').take(rand));
    buf.extend(suffix.as_bytes());

    // Randomize.
    let bytes = &mut buf[prefix.len()..prefix.len() + rand];
    rand::thread_rng().fill(bytes);
    for byte in bytes.iter_mut() {
        *byte = match *byte % 62 {
            v @ 0..=9 => (v + b'0'),
            v @ 10..=35 => (v - 10 + b'a'),
            v @ 36..=61 => (v - 36 + b'A'),
            _ => unreachable!(),
        }
    }
    // We guarantee utf8.
    let buf = String::from_utf8(buf).unwrap();
    tmpdir.push(buf);
    println_verbatim(tmpdir).map_err_context(|| "failed to print directory name".to_owned())
}

fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> {
    let context = || {
        format!(
            "failed to create file via template '{}{}{}'",
            prefix,
            "X".repeat(rand),
            suffix
        )
    };

    let mut builder = Builder::new();
    builder.prefix(prefix).rand_bytes(rand).suffix(suffix);

    let path = if make_dir {
        builder
            .tempdir_in(&dir)
            .map_err_context(context)?
            .into_path() // `into_path` consumes the TempDir without removing it
    } else {
        builder
            .tempfile_in(&dir)
            .map_err_context(context)?
            .keep() // `keep` ensures that the file is not deleted
            .map_err(|e| MkTempError::PersistError(e.file.path().to_path_buf()))?
            .1
    };
    println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned())
}
<commit_msg>mktemp: change directory permission after creation<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Sunrin SHIMURA
// Collaborator: Jian Zeng
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (paths) GPGHome

use clap::{crate_version, Arg, Command};
use uucore::display::{println_verbatim, Quotable};
use uucore::error::{FromIo, UError, UResult};
use uucore::format_usage;

use std::error::Error;
use std::fmt::Display;
use std::iter;
use std::os::unix::prelude::PermissionsExt;
use std::path::{is_separator, Path, PathBuf};
use std::{env, fs};

use rand::Rng;
use tempfile::Builder;

static ABOUT: &str = "create a temporary file or directory.";
const USAGE: &str = "{} [OPTION]... [TEMPLATE]";

static DEFAULT_TEMPLATE: &str = "tmp.XXXXXXXXXX";

static OPT_DIRECTORY: &str = "directory";
static OPT_DRY_RUN: &str = "dry-run";
static OPT_QUIET: &str = "quiet";
static OPT_SUFFIX: &str = "suffix";
static OPT_TMPDIR: &str = "tmpdir";
static OPT_T: &str = "t";

static ARG_TEMPLATE: &str = "template";

#[derive(Debug)]
enum MkTempError {
    PersistError(PathBuf),
    MustEndInX(String),
    TooFewXs(String),
    ContainsDirSeparator(String),
    InvalidTemplate(String),
}

impl UError for MkTempError {}

impl Error for MkTempError {}

impl Display for MkTempError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        use MkTempError::*;
        match self {
            PersistError(p) => write!(f, "could not persist file {}", p.quote()),
            MustEndInX(s) => write!(f, "with --suffix, template {} must end in X", s.quote()),
            TooFewXs(s) => write!(f, "too few X's in template {}", s.quote()),
            ContainsDirSeparator(s) => {
                write!(
                    f,
                    "invalid suffix {}, contains directory separator",
                    s.quote()
                )
            }
            InvalidTemplate(s) => write!(
                f,
                "invalid template, {}; with --tmpdir, it may not be absolute",
                s.quote()
            ),
        }
    }
}

#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let matches = uu_app().get_matches_from(args);

    let template = matches.value_of(ARG_TEMPLATE).unwrap();
    let tmpdir = matches.value_of(OPT_TMPDIR).unwrap_or_default();

    let (template, mut tmpdir) = if matches.is_present(OPT_TMPDIR)
        && !PathBuf::from(tmpdir).is_dir() // if a temp dir is provided, it must be an actual path
        && tmpdir.contains("XXX")
    // If this is a template, it has to contain at least 3 X
        && template == DEFAULT_TEMPLATE
    // That means that clap does not think we provided a template
    {
        // Special case to workaround a limitation of clap when doing
        // mktemp --tmpdir apt-key-gpghome.XXX
        // The behavior should be
        // mktemp --tmpdir $TMPDIR apt-key-gpghome.XX
        // As --tmpdir is empty
        //
        // Fixed in clap 3
        // See https://github.com/clap-rs/clap/pull/1587
        let tmp = env::temp_dir();
        (tmpdir, tmp)
    } else if !matches.is_present(OPT_TMPDIR) {
        let tmp = env::temp_dir();
        (template, tmp)
    } else {
        (template, PathBuf::from(tmpdir))
    };

    let make_dir = matches.is_present(OPT_DIRECTORY);
    let dry_run = matches.is_present(OPT_DRY_RUN);
    let suppress_file_err = matches.is_present(OPT_QUIET);

    let (prefix, rand, suffix) = parse_template(template, matches.value_of(OPT_SUFFIX))?;

    if matches.is_present(OPT_TMPDIR) && PathBuf::from(prefix).is_absolute() {
        return Err(MkTempError::InvalidTemplate(template.into()).into());
    }

    if matches.is_present(OPT_T) {
        tmpdir = env::temp_dir();
    }

    let res = if dry_run {
        dry_exec(tmpdir, prefix, rand, suffix)
    } else {
        exec(&tmpdir, prefix, rand, suffix, make_dir)
    };

    if suppress_file_err {
        // Mapping all UErrors to ExitCodes prevents the errors from being printed
        res.map_err(|e| e.code().into())
    } else {
        res
    }
}

pub fn uu_app<'a>() -> Command<'a> {
    Command::new(uucore::util_name())
        .version(crate_version!())
        .about(ABOUT)
        .override_usage(format_usage(USAGE))
        .infer_long_args(true)
        .arg(
            Arg::new(OPT_DIRECTORY)
                .short('d')
                .long(OPT_DIRECTORY)
                .help("Make a directory instead of a file"),
        )
        .arg(
            Arg::new(OPT_DRY_RUN)
                .short('u')
                .long(OPT_DRY_RUN)
                .help("do not create anything; merely print a name (unsafe)"),
        )
        .arg(
            Arg::new(OPT_QUIET)
                .short('q')
                .long("quiet")
                .help("Fail silently if an error occurs."),
        )
        .arg(
            Arg::new(OPT_SUFFIX)
                .long(OPT_SUFFIX)
                .help(
                    "append SUFFIX to TEMPLATE; SUFFIX must not contain a path separator. \
                     This option is implied if TEMPLATE does not end with X.",
                )
                .value_name("SUFFIX"),
        )
        .arg(
            Arg::new(OPT_TMPDIR)
                .short('p')
                .long(OPT_TMPDIR)
                .help(
                    "interpret TEMPLATE relative to DIR; if DIR is not specified, use \
                     $TMPDIR ($TMP on windows) if set, else /tmp. With this option, TEMPLATE must not \
                     be an absolute name; unlike with -t, TEMPLATE may contain \
                     slashes, but mktemp creates only the final component",
                )
                .value_name("DIR"),
        )
        .arg(Arg::new(OPT_T).short('t').help(
            "Generate a template (using the supplied prefix and TMPDIR (TMP on windows) if set) \
             to create a filename template [deprecated]",
        ))
        .arg(
            Arg::new(ARG_TEMPLATE)
                .multiple_occurrences(false)
                .takes_value(true)
                .max_values(1)
                .default_value(DEFAULT_TEMPLATE),
        )
}

fn parse_template<'a>(
    temp: &'a str,
    suffix: Option<&'a str>,
) -> UResult<(&'a str, usize, &'a str)> {
    let right = match temp.rfind('X') {
        Some(r) => r + 1,
        None => return Err(MkTempError::TooFewXs(temp.into()).into()),
    };
    let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1);
    let prefix = &temp[..left];
    let rand = right - left;

    if rand < 3 {
        return Err(MkTempError::TooFewXs(temp.into()).into());
    }

    let mut suf = &temp[right..];

    if let Some(s) = suffix {
        if suf.is_empty() {
            suf = s;
        } else {
            return Err(MkTempError::MustEndInX(temp.into()).into());
        }
    };

    if suf.chars().any(is_separator) {
        return Err(MkTempError::ContainsDirSeparator(suf.into()).into());
    }

    Ok((prefix, rand, suf))
}

pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) -> UResult<()> {
    let len = prefix.len() + suffix.len() + rand;
    let mut buf = Vec::with_capacity(len);
    buf.extend(prefix.as_bytes());
    buf.extend(iter::repeat(b'X').take(rand));
    buf.extend(suffix.as_bytes());

    // Randomize.
    let bytes = &mut buf[prefix.len()..prefix.len() + rand];
    rand::thread_rng().fill(bytes);
    for byte in bytes.iter_mut() {
        *byte = match *byte % 62 {
            v @ 0..=9 => (v + b'0'),
            v @ 10..=35 => (v - 10 + b'a'),
            v @ 36..=61 => (v - 36 + b'A'),
            _ => unreachable!(),
        }
    }
    // We guarantee utf8.
    let buf = String::from_utf8(buf).unwrap();
    tmpdir.push(buf);
    println_verbatim(tmpdir).map_err_context(|| "failed to print directory name".to_owned())
}

fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> {
    let context = || {
        format!(
            "failed to create file via template '{}{}{}'",
            prefix,
            "X".repeat(rand),
            suffix
        )
    };

    let mut builder = Builder::new();
    builder.prefix(prefix).rand_bytes(rand).suffix(suffix);

    let path = if make_dir {
        builder
            .tempdir_in(&dir)
            .map_err_context(context)?
            .into_path() // `into_path` consumes the TempDir without removing it
    } else {
        builder
            .tempfile_in(&dir)
            .map_err_context(context)?
            .keep() // `keep` ensures that the file is not deleted
            .map_err(|e| MkTempError::PersistError(e.file.path().to_path_buf()))?
            .1
    };
    if make_dir {
        fs::set_permissions(&path, fs::Permissions::from_mode(0o700))?;
    }
    println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned())
}
<|endoftext|>


<commit_before>use clap::App;

//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Jordi Boggiano <j.boggiano@seld.be>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

/* last synced with: whoami (GNU coreutils) 8.21 */

#[macro_use]
extern crate clap;
#[macro_use]
extern crate uucore;

mod platform;

pub fn uumain(args: impl uucore::Args) -> i32 {
    let app = uu_app();

    if let Err(err) = app.get_matches_from_safe(args) {
        if err.kind == clap::ErrorKind::HelpDisplayed
            || err.kind == clap::ErrorKind::VersionDisplayed
        {
            println!("{}", err);
            0
        } else {
            show_error!("{}", err);
            1
        }
    } else {
        exec();

        0
    }
}

pub fn uu_app() -> App<'static, 'static> {
    app_from_crate!()
}

pub fn exec() {
    unsafe {
        match platform::get_username() {
            Ok(username) => println!("{}", username),
            Err(err) => match err.raw_os_error() {
                Some(0) | None => crash!(1, "failed to get username"),
                Some(_) => crash!(1, "failed to get username: {}", err),
            },
        }
    }
}
<commit_msg>whoami: Added UResult<commit_after>use clap::App;

//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Jordi Boggiano <j.boggiano@seld.be>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

/* last synced with: whoami (GNU coreutils) 8.21 */

#[macro_use]
extern crate clap;
#[macro_use]
extern crate uucore;

use uucore::error::{UResult, USimpleError};

mod platform;

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let app = uu_app();

    if let Err(err) = app.get_matches_from_safe(args) {
        if err.kind == clap::ErrorKind::HelpDisplayed
            || err.kind == clap::ErrorKind::VersionDisplayed
        {
            println!("{}", err);
            Ok(())
        } else {
            return Err(USimpleError::new(1, format!("{}", err)));
        }
    } else {
        exec()
    }
}

pub fn uu_app() -> App<'static, 'static> {
    app_from_crate!()
}

pub fn exec() -> UResult<()> {
    unsafe {
        match platform::get_username() {
            Ok(username) => {
                println!("{}", username);
                Ok(())
            }
            Err(err) => match err.raw_os_error() {
                Some(0) | None => Err(USimpleError::new(1, "failed to get username")),
                Some(_) => Err(USimpleError::new(
                    1,
                    format!("failed to get username: {}", err),
                )),
            },
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use error::MarkdownError as ME;
use error::MarkdownErrorKind as MEK;
use error::*;
use link::extract_links;

use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagentryref::refstore::RefStore;
use libimagentryref::flags::RefFlags;
use libimagstore::store::Entry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagutil::iter::FoldResult;

use std::path::PathBuf;

use url::Url;

/// A link Processor which collects the links from a Markdown and passes them on to
/// `libimagentrylink` functionality
///
/// The processor can be configured to
///
///  * Process internal links (from store entry to store entry)
///  * Process internal links with automatically creating targets
///     If an internal link is encountered, the corrosponding target must be present in the store.
///     If it is not, it will either be created or the processing fails
///  * Process external links (from store entry to URL)
///  * Process refs (from store entry to files on the filesystem and outside of the store)
///  (default: false)
///
///  # Note
///
///  There's no LinkProcessor::new() function, please use `LinkProcessor::default()`.
///
pub struct LinkProcessor {
    process_internal_links: bool,
    create_internal_targets: bool,
    process_external_links: bool,
    process_refs: bool
}

impl LinkProcessor {

    /// Switch internal link processing on/off
    ///
    /// Internal links are links which are simply `dirctory/file`, but not `/directory/file`, as
    /// beginning an id with `/` is discouraged in imag.
    pub fn process_internal_links(mut self, b: bool) -> Self {
        self.process_internal_links = b;
        self
    }

    /// Switch internal link target creation on/off
    ///
    /// If a link points to a non-existing imag entry, a `false` here will cause the processor to
    /// return an error from `process()`. A `true` setting will create the entry and then fetch it
    /// to link it to the processed entry.
    pub fn create_internal_targets(mut self, b: bool) -> Self {
        self.create_internal_targets = b;
        self
    }

    /// Switch external link processing on/off
    ///
    /// An external link must start with `https://` or `http://`.
    pub fn process_external_links(mut self, b: bool) -> Self {
        self.process_external_links = b;
        self
    }

    /// Switch ref processing on/off
    ///
    /// A Ref is to be expected beeing a link with `file::///` at the beginning.
    pub fn process_refs(mut self, b: bool) -> Self {
        self.process_refs = b;
        self
    }

    /// Process an Entry for its links
    ///
    /// # Warning
    ///
    /// When `LinkProcessor::create_internal_targets()` was called to set the setting to true, this
    /// function returns all errors returned by the Store.
    ///
    pub fn process<'a>(&self, entry: &mut Entry, store: &'a Store) -> Result<()> {
        let text = entry.to_str();
        trace!("Processing: {:?}", entry.get_location());
        extract_links(&text)
            .into_iter()
            .fold_result::<_, MarkdownError, _>(|link| {
                trace!("Processing {:?}", link);
                match LinkQualification::qualify(&link.link) {
                    LinkQualification::InternalLink => {
                        if !self.process_internal_links {
                            return Ok(());
                        }

                        let spath      = Some(store.path().clone());
                        let id         = StoreId::new(spath, PathBuf::from(&link.link))?;
                        let mut target = if self.create_internal_targets {
                            try!(store.retrieve(id))
                        } else {
                            store.get(id.clone())?
                                .ok_or(ME::from_kind(MEK::StoreGetError(id)))?
                        };

                        entry.add_internal_link(&mut target).map_err(From::from)
                    },
                    LinkQualification::ExternalLink(url) => {
                        if !self.process_external_links {
                            return Ok(());
                        }

                        entry.add_external_link(store, url).map_err(From::from)
                    },
                    LinkQualification::RefLink(url) => {
                        if !self.process_refs {
                            return Ok(());
                        }

                        let flags = RefFlags::default()
                            .with_content_hashing(false)
                            .with_permission_tracking(false);
                        trace!("URL            = {:?}", url);
                        trace!("URL.path()     = {:?}", url.path());
                        trace!("URL.host_str() = {:?}", url.host_str());
                        let path = url.host_str().unwrap_or_else(|| url.path());
                        let path = PathBuf::from(path);
                        let mut target = try!(RefStore::create(store, path, flags));

                        entry.add_internal_link(&mut target).map_err(From::from)
                    },
                    LinkQualification::Undecidable(e) => {
                        // error
                        Err(e).chain_err(|| MEK::UndecidableLinkType(link.link.clone()))
                    },
                }
            })
    }

}

/// Enum to tell what kind of link a string of text is
enum LinkQualification {
    InternalLink,
    ExternalLink(Url),
    RefLink(Url),
    Undecidable(ME),
}

impl LinkQualification {
    fn qualify(text: &str) -> LinkQualification {
        match Url::parse(text) {
            Ok(url) => {
                if url.scheme() == "file" {
                    return LinkQualification::RefLink(url)
                }

                // else we assume the following, as other stuff gets thrown out by
                // url::Url::parse() as Err(_)
                //
                // if url.scheme() == "https" || url.scheme() == "http" {
                    return LinkQualification::ExternalLink(url);
                // }
            },

            Err(e) => {
                match e {
                    ::url::ParseError::RelativeUrlWithoutBase => {
                        LinkQualification::InternalLink
                    },

                    _ => LinkQualification::Undecidable(ME::from(e)),
                }
            }
        }
    }
}

impl Default for LinkProcessor {
    fn default() -> Self {
        LinkProcessor {
            process_internal_links: true,
            create_internal_targets: false,
            process_external_links: true,
            process_refs: false
        }
    }
}

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

    use std::path::PathBuf;

    use libimagstore::store::Store;
    use libimagentrylink::internal::InternalLinker;

    fn setup_logging() {
        use env_logger;
        let _ = env_logger::init().unwrap_or(());
    }

    pub fn get_store() -> Store {
        use libimagstore::file_abstraction::InMemoryFileAbstraction;
        let fs = InMemoryFileAbstraction::new();
        Store::new_with_backend(PathBuf::from("/"), None, Box::new(fs)).unwrap()
    }

    #[test]
    fn test_process_no_links() {
        setup_logging();
        let store = get_store();

        let mut base = store.create(PathBuf::from("test-1")).unwrap();
        *base.get_content_mut() = format!("This is an example entry with no links");

        let update = store.update(&mut base);
        assert!(update.is_ok());

        let processor = LinkProcessor::default();

        let result = processor.process(&mut base, &store);
        assert!(result.is_ok());
    }

    #[test]
    fn test_process_one_existing_file_linked() {
        setup_logging();
        let store = get_store();

        let mut base = store.create(PathBuf::from("test-2.1")).unwrap();
        *base.get_content_mut() = format!("This is an example entry with one [link](test-2.2)");

        let update = store.update(&mut base);
        assert!(update.is_ok());

        // immediately drop as we don't need this entry right now
        let _ = store.create(PathBuf::from("test-2.2")).unwrap();

        let processor = LinkProcessor::default()
            .process_internal_links(true)
            .create_internal_targets(false)
            .process_external_links(false)
            .process_refs(false);

        let result = processor.process(&mut base, &store);
        assert!(result.is_ok(), "Should be Ok(()): {:?}", result);

        {
            let base_links = base.get_internal_links();
            assert!(base_links.is_ok());
            let base_links : Vec<_> = base_links.unwrap().collect();

            assert_eq!(1, base_links.len());
            assert_eq!("test-2.2", base_links[0].to_str().unwrap());
        }

        {
            let link = store.get(PathBuf::from("test-2.2")).unwrap().unwrap();
            let link_links = link.get_internal_links();
            assert!(link_links.is_ok());
            let link_links : Vec<_> = link_links.unwrap().collect();

            assert_eq!(1, link_links.len());
            assert_eq!("test-2.1", link_links[0].to_str().unwrap());
        }
    }

    #[test]
    fn test_process_one_existing_file_linked_faulty() {
        setup_logging();
        let store = get_store();

        let mut base = store.create(PathBuf::from("test-2.1")).unwrap();
        *base.get_content_mut() = format!("This is an example entry with one [link](/test-2.2)");

        let update = store.update(&mut base);
        assert!(update.is_ok());

        let processor = LinkProcessor::default()
            .process_internal_links(true)
            .create_internal_targets(false)
            .process_external_links(false)
            .process_refs(false);

        let result = processor.process(&mut base, &store);
        assert!(result.is_err(), "Should be Err(_), but is Ok(())");
    }
}

<commit_msg>Add test for automatically creating linked entries<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use error::MarkdownError as ME;
use error::MarkdownErrorKind as MEK;
use error::*;
use link::extract_links;

use libimagentrylink::external::ExternalLinker;
use libimagentrylink::internal::InternalLinker;
use libimagentryref::refstore::RefStore;
use libimagentryref::flags::RefFlags;
use libimagstore::store::Entry;
use libimagstore::store::Store;
use libimagstore::storeid::StoreId;
use libimagutil::iter::FoldResult;

use std::path::PathBuf;

use url::Url;

/// A link Processor which collects the links from a Markdown and passes them on to
/// `libimagentrylink` functionality
///
/// The processor can be configured to
///
///  * Process internal links (from store entry to store entry)
///  * Process internal links with automatically creating targets
///     If an internal link is encountered, the corrosponding target must be present in the store.
///     If it is not, it will either be created or the processing fails
///  * Process external links (from store entry to URL)
///  * Process refs (from store entry to files on the filesystem and outside of the store)
///  (default: false)
///
///  # Note
///
///  There's no LinkProcessor::new() function, please use `LinkProcessor::default()`.
///
pub struct LinkProcessor {
    process_internal_links: bool,
    create_internal_targets: bool,
    process_external_links: bool,
    process_refs: bool
}

impl LinkProcessor {

    /// Switch internal link processing on/off
    ///
    /// Internal links are links which are simply `dirctory/file`, but not `/directory/file`, as
    /// beginning an id with `/` is discouraged in imag.
    pub fn process_internal_links(mut self, b: bool) -> Self {
        self.process_internal_links = b;
        self
    }

    /// Switch internal link target creation on/off
    ///
    /// If a link points to a non-existing imag entry, a `false` here will cause the processor to
    /// return an error from `process()`. A `true` setting will create the entry and then fetch it
    /// to link it to the processed entry.
    pub fn create_internal_targets(mut self, b: bool) -> Self {
        self.create_internal_targets = b;
        self
    }

    /// Switch external link processing on/off
    ///
    /// An external link must start with `https://` or `http://`.
    pub fn process_external_links(mut self, b: bool) -> Self {
        self.process_external_links = b;
        self
    }

    /// Switch ref processing on/off
    ///
    /// A Ref is to be expected beeing a link with `file::///` at the beginning.
    pub fn process_refs(mut self, b: bool) -> Self {
        self.process_refs = b;
        self
    }

    /// Process an Entry for its links
    ///
    /// # Warning
    ///
    /// When `LinkProcessor::create_internal_targets()` was called to set the setting to true, this
    /// function returns all errors returned by the Store.
    ///
    pub fn process<'a>(&self, entry: &mut Entry, store: &'a Store) -> Result<()> {
        let text = entry.to_str();
        trace!("Processing: {:?}", entry.get_location());
        extract_links(&text)
            .into_iter()
            .fold_result::<_, MarkdownError, _>(|link| {
                trace!("Processing {:?}", link);
                match LinkQualification::qualify(&link.link) {
                    LinkQualification::InternalLink => {
                        if !self.process_internal_links {
                            return Ok(());
                        }

                        let spath      = Some(store.path().clone());
                        let id         = StoreId::new(spath, PathBuf::from(&link.link))?;
                        let mut target = if self.create_internal_targets {
                            try!(store.retrieve(id))
                        } else {
                            store.get(id.clone())?
                                .ok_or(ME::from_kind(MEK::StoreGetError(id)))?
                        };

                        entry.add_internal_link(&mut target).map_err(From::from)
                    },
                    LinkQualification::ExternalLink(url) => {
                        if !self.process_external_links {
                            return Ok(());
                        }

                        entry.add_external_link(store, url).map_err(From::from)
                    },
                    LinkQualification::RefLink(url) => {
                        if !self.process_refs {
                            return Ok(());
                        }

                        let flags = RefFlags::default()
                            .with_content_hashing(false)
                            .with_permission_tracking(false);
                        trace!("URL            = {:?}", url);
                        trace!("URL.path()     = {:?}", url.path());
                        trace!("URL.host_str() = {:?}", url.host_str());
                        let path = url.host_str().unwrap_or_else(|| url.path());
                        let path = PathBuf::from(path);
                        let mut target = try!(RefStore::create(store, path, flags));

                        entry.add_internal_link(&mut target).map_err(From::from)
                    },
                    LinkQualification::Undecidable(e) => {
                        // error
                        Err(e).chain_err(|| MEK::UndecidableLinkType(link.link.clone()))
                    },
                }
            })
    }

}

/// Enum to tell what kind of link a string of text is
enum LinkQualification {
    InternalLink,
    ExternalLink(Url),
    RefLink(Url),
    Undecidable(ME),
}

impl LinkQualification {
    fn qualify(text: &str) -> LinkQualification {
        match Url::parse(text) {
            Ok(url) => {
                if url.scheme() == "file" {
                    return LinkQualification::RefLink(url)
                }

                // else we assume the following, as other stuff gets thrown out by
                // url::Url::parse() as Err(_)
                //
                // if url.scheme() == "https" || url.scheme() == "http" {
                    return LinkQualification::ExternalLink(url);
                // }
            },

            Err(e) => {
                match e {
                    ::url::ParseError::RelativeUrlWithoutBase => {
                        LinkQualification::InternalLink
                    },

                    _ => LinkQualification::Undecidable(ME::from(e)),
                }
            }
        }
    }
}

impl Default for LinkProcessor {
    fn default() -> Self {
        LinkProcessor {
            process_internal_links: true,
            create_internal_targets: false,
            process_external_links: true,
            process_refs: false
        }
    }
}

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

    use std::path::PathBuf;

    use libimagstore::store::Store;
    use libimagentrylink::internal::InternalLinker;

    fn setup_logging() {
        use env_logger;
        let _ = env_logger::init().unwrap_or(());
    }

    pub fn get_store() -> Store {
        use libimagstore::file_abstraction::InMemoryFileAbstraction;
        let fs = InMemoryFileAbstraction::new();
        Store::new_with_backend(PathBuf::from("/"), None, Box::new(fs)).unwrap()
    }

    #[test]
    fn test_process_no_links() {
        setup_logging();
        let store = get_store();

        let mut base = store.create(PathBuf::from("test-1")).unwrap();
        *base.get_content_mut() = format!("This is an example entry with no links");

        let update = store.update(&mut base);
        assert!(update.is_ok());

        let processor = LinkProcessor::default();

        let result = processor.process(&mut base, &store);
        assert!(result.is_ok());
    }

    #[test]
    fn test_process_one_existing_file_linked() {
        setup_logging();
        let store = get_store();

        let mut base = store.create(PathBuf::from("test-2.1")).unwrap();
        *base.get_content_mut() = format!("This is an example entry with one [link](test-2.2)");

        let update = store.update(&mut base);
        assert!(update.is_ok());

        // immediately drop as we don't need this entry right now
        let _ = store.create(PathBuf::from("test-2.2")).unwrap();

        let processor = LinkProcessor::default()
            .process_internal_links(true)
            .create_internal_targets(false)
            .process_external_links(false)
            .process_refs(false);

        let result = processor.process(&mut base, &store);
        assert!(result.is_ok(), "Should be Ok(()): {:?}", result);

        {
            let base_links = base.get_internal_links();
            assert!(base_links.is_ok());
            let base_links : Vec<_> = base_links.unwrap().collect();

            assert_eq!(1, base_links.len());
            assert_eq!("test-2.2", base_links[0].to_str().unwrap());
        }

        {
            let link = store.get(PathBuf::from("test-2.2")).unwrap().unwrap();
            let link_links = link.get_internal_links();
            assert!(link_links.is_ok());
            let link_links : Vec<_> = link_links.unwrap().collect();

            assert_eq!(1, link_links.len());
            assert_eq!("test-2.1", link_links[0].to_str().unwrap());
        }
    }

    #[test]
    fn test_process_one_existing_file_linked_faulty() {
        setup_logging();
        let store = get_store();

        let mut base = store.create(PathBuf::from("test-2.1")).unwrap();
        *base.get_content_mut() = format!("This is an example entry with one [link](/test-2.2)");

        let update = store.update(&mut base);
        assert!(update.is_ok());

        let processor = LinkProcessor::default()
            .process_internal_links(true)
            .create_internal_targets(false)
            .process_external_links(false)
            .process_refs(false);

        let result = processor.process(&mut base, &store);
        assert!(result.is_err(), "Should be Err(_), but is Ok(())");
    }

    #[test]
    fn test_process_one_nonexisting_file_linked() {
        setup_logging();
        let store = get_store();

        let mut base = store.create(PathBuf::from("test-2.1")).unwrap();
        *base.get_content_mut() = format!("This is an example entry with one [link](test-2.2)");

        let update = store.update(&mut base);
        assert!(update.is_ok());

        let processor = LinkProcessor::default()
            .process_internal_links(true)
            .create_internal_targets(true)
            .process_external_links(false)
            .process_refs(false);

        let result = processor.process(&mut base, &store);
        assert!(result.is_ok(), "Should be Ok(()): {:?}", result);

        {
            let base_links = base.get_internal_links();
            assert!(base_links.is_ok());
            let base_links : Vec<_> = base_links.unwrap().collect();

            assert_eq!(1, base_links.len());
            assert_eq!("test-2.2", base_links[0].to_str().unwrap());
        }

        {
            let link = store.get(PathBuf::from("test-2.2")).unwrap().unwrap();
            let link_links = link.get_internal_links();
            assert!(link_links.is_ok());
            let link_links : Vec<_> = link_links.unwrap().collect();

            assert_eq!(1, link_links.len());
            assert_eq!("test-2.1", link_links[0].to_str().unwrap());
        }
    }
}

<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate png;
extern crate std;
extern crate test;

use std::io;
use std::io::{File, Reader, Process};
use std::io::process::ExitStatus;
use std::os;
use std::str;
use test::{DynTestName, DynTestFn, TestDesc, TestOpts, TestDescAndFn};
use test::run_tests_console;

fn main() {
    let args = os::args();
    let mut parts = args.tail().split(|e| "--" == e.as_slice());

    let files = parts.next().unwrap();  // .split() is never empty
    let servo_args = parts.next().unwrap_or(&[]);

    if files.len() == 0 {
        fail!("error: at least one reftest list must be given");
    }

    let tests = parse_lists(files, servo_args);
    let test_opts = TestOpts {
        filter: None,
        run_ignored: false,
        logfile: None,
        run_tests: true,
        run_benchmarks: false,
        ratchet_noise_percent: None,
        ratchet_metrics: None,
        save_metrics: None,
        test_shard: None,
    };

    match run_tests_console(&test_opts, tests) {
        Ok(false) => os::set_exit_status(1), // tests failed
        Err(_) => os::set_exit_status(2),    // I/O-related failure
        _ => (),
    }
}

#[deriving(Eq)]
enum ReftestKind {
    Same,
    Different,
}

struct Reftest {
    name: ~str,
    kind: ReftestKind,
    files: [~str, ..2],
    id: uint,
    servo_args: ~[~str],
}

fn parse_lists(filenames: &[~str], servo_args: &[~str]) -> Vec<TestDescAndFn> {
    let mut tests = Vec::new();
    let mut next_id = 0;
    for file in filenames.iter() {
        let file_path = Path::new(file.clone());
        let contents = match File::open_mode(&file_path, io::Open, io::Read)
            .and_then(|mut f| {
                f.read_to_str()
            }) {
                Ok(s) => s,
                _ => fail!("Could not read file"),
            };

        for line in contents.lines() {
            // ignore comments
            if line.starts_with("#") {
                continue;
            }

            let parts: ~[&str] = line.split(' ').filter(|p| !p.is_empty()).collect();

            if parts.len() != 3 {
                fail!("reftest line: '{:s}' doesn't match 'KIND LEFT RIGHT'", line);
            }

            let kind = match parts[0] {
                "==" => Same,
                "!=" => Different,
                _ => fail!("reftest line: '{:s}' has invalid kind '{:s}'",
                           line, parts[0])
            };
            let src_path = file_path.dir_path();
            let src_dir = src_path.display().to_str();
            let file_left =  src_dir + "/" + parts[1];
            let file_right = src_dir + "/" + parts[2];

            let reftest = Reftest {
                name: parts[1] + " / " + parts[2],
                kind: kind,
                files: [file_left, file_right],
                id: next_id,
                servo_args: servo_args.to_owned(),
            };

            next_id += 1;

            tests.push(make_test(reftest));
        }
    }
    tests
}

fn make_test(reftest: Reftest) -> TestDescAndFn {
    let name = reftest.name.clone();
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(name),
            ignore: false,
            should_fail: false,
        },
        testfn: DynTestFn(proc() {
            check_reftest(reftest);
        }),
    }
}

fn capture(reftest: &Reftest, side: uint) -> png::Image {
    let filename = format!("/tmp/servo-reftest-{:06u}-{:u}.png", reftest.id, side);
    let mut args = reftest.servo_args.clone();
    args.push_all_move(~["-f".to_owned(), "-o".to_owned(), filename.clone(), reftest.files[side].clone()]);

    let retval = match Process::status("./servo", args) {
        Ok(status) => status,
        Err(e) => fail!("failed to execute process: {}", e),
    };
    assert!(retval == ExitStatus(0));

    png::load_png(&from_str::<Path>(filename).unwrap()).unwrap()
}

fn check_reftest(reftest: Reftest) {
    let left  = capture(&reftest, 0);
    let right = capture(&reftest, 1);

    let pixels: ~[u8] = left.pixels.iter().zip(right.pixels.iter()).map(|(&a, &b)| {
            if a as i8 - b as i8 == 0 {
                // White for correct
                0xFF
            } else {
                // "1100" in the RGBA channel with an error for an incorrect value
                // This results in some number of C0 and FFs, which is much more
                // readable (and distinguishable) than the previous difference-wise
                // scaling but does not require reconstructing the actual RGBA pixel.
                0xC0
            }
        }).collect();

    if pixels.iter().any(|&a| a < 255) {
        let output = from_str::<Path>(format!("/tmp/servo-reftest-{:06u}-diff.png", reftest.id)).unwrap();

        let img = png::Image {
            width: left.width,
            height: left.height,
            color_type: png::RGBA8,
            pixels: pixels,
        };
        let res = png::store_png(&img, &output);
        assert!(res.is_ok());

        assert!(reftest.kind == Different);
    } else {
        assert!(reftest.kind == Same);
    }
}
<commit_msg>auto merge of #2349 : zwarich/servo/reftest-print-diff, r=larsbergstrom<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate png;
extern crate std;
extern crate test;

use std::io;
use std::io::{File, Reader, Process};
use std::io::process::ExitStatus;
use std::os;
use std::str;
use test::{DynTestName, DynTestFn, TestDesc, TestOpts, TestDescAndFn};
use test::run_tests_console;

fn main() {
    let args = os::args();
    let mut parts = args.tail().split(|e| "--" == e.as_slice());

    let files = parts.next().unwrap();  // .split() is never empty
    let servo_args = parts.next().unwrap_or(&[]);

    if files.len() == 0 {
        fail!("error: at least one reftest list must be given");
    }

    let tests = parse_lists(files, servo_args);
    let test_opts = TestOpts {
        filter: None,
        run_ignored: false,
        logfile: None,
        run_tests: true,
        run_benchmarks: false,
        ratchet_noise_percent: None,
        ratchet_metrics: None,
        save_metrics: None,
        test_shard: None,
    };

    match run_tests_console(&test_opts, tests) {
        Ok(false) => os::set_exit_status(1), // tests failed
        Err(_) => os::set_exit_status(2),    // I/O-related failure
        _ => (),
    }
}

#[deriving(Eq)]
enum ReftestKind {
    Same,
    Different,
}

struct Reftest {
    name: ~str,
    kind: ReftestKind,
    files: [~str, ..2],
    id: uint,
    servo_args: ~[~str],
}

fn parse_lists(filenames: &[~str], servo_args: &[~str]) -> Vec<TestDescAndFn> {
    let mut tests = Vec::new();
    let mut next_id = 0;
    for file in filenames.iter() {
        let file_path = Path::new(file.clone());
        let contents = match File::open_mode(&file_path, io::Open, io::Read)
            .and_then(|mut f| {
                f.read_to_str()
            }) {
                Ok(s) => s,
                _ => fail!("Could not read file"),
            };

        for line in contents.lines() {
            // ignore comments
            if line.starts_with("#") {
                continue;
            }

            let parts: ~[&str] = line.split(' ').filter(|p| !p.is_empty()).collect();

            if parts.len() != 3 {
                fail!("reftest line: '{:s}' doesn't match 'KIND LEFT RIGHT'", line);
            }

            let kind = match parts[0] {
                "==" => Same,
                "!=" => Different,
                _ => fail!("reftest line: '{:s}' has invalid kind '{:s}'",
                           line, parts[0])
            };
            let src_path = file_path.dir_path();
            let src_dir = src_path.display().to_str();
            let file_left =  src_dir + "/" + parts[1];
            let file_right = src_dir + "/" + parts[2];

            let reftest = Reftest {
                name: parts[1] + " / " + parts[2],
                kind: kind,
                files: [file_left, file_right],
                id: next_id,
                servo_args: servo_args.to_owned(),
            };

            next_id += 1;

            tests.push(make_test(reftest));
        }
    }
    tests
}

fn make_test(reftest: Reftest) -> TestDescAndFn {
    let name = reftest.name.clone();
    TestDescAndFn {
        desc: TestDesc {
            name: DynTestName(name),
            ignore: false,
            should_fail: false,
        },
        testfn: DynTestFn(proc() {
            check_reftest(reftest);
        }),
    }
}

fn capture(reftest: &Reftest, side: uint) -> png::Image {
    let filename = format!("/tmp/servo-reftest-{:06u}-{:u}.png", reftest.id, side);
    let mut args = reftest.servo_args.clone();
    args.push_all_move(~["-f".to_owned(), "-o".to_owned(), filename.clone(), reftest.files[side].clone()]);

    let retval = match Process::status("./servo", args) {
        Ok(status) => status,
        Err(e) => fail!("failed to execute process: {}", e),
    };
    assert!(retval == ExitStatus(0));

    png::load_png(&from_str::<Path>(filename).unwrap()).unwrap()
}

fn check_reftest(reftest: Reftest) {
    let left  = capture(&reftest, 0);
    let right = capture(&reftest, 1);

    let pixels: ~[u8] = left.pixels.iter().zip(right.pixels.iter()).map(|(&a, &b)| {
            if a as i8 - b as i8 == 0 {
                // White for correct
                0xFF
            } else {
                // "1100" in the RGBA channel with an error for an incorrect value
                // This results in some number of C0 and FFs, which is much more
                // readable (and distinguishable) than the previous difference-wise
                // scaling but does not require reconstructing the actual RGBA pixel.
                0xC0
            }
        }).collect();

    if pixels.iter().any(|&a| a < 255) {
        let output_str = format!("/tmp/servo-reftest-{:06u}-diff.png", reftest.id);
        let output = from_str::<Path>(output_str).unwrap();

        let img = png::Image {
            width: left.width,
            height: left.height,
            color_type: png::RGBA8,
            pixels: pixels,
        };
        let res = png::store_png(&img, &output);
        assert!(res.is_ok());

        assert!(reftest.kind == Different, "rendering difference: {}", output_str);
    } else {
        assert!(reftest.kind == Same);
    }
}
<|endoftext|>