<commit_before>use std::any::Any;
use std::fmt::Debug;
use std::marker::PhantomData;
use approx::ApproxEq;

#[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer};

use alga::general::Field;

use core::{Scalar, SquareMatrix, OwnedSquareMatrix};
use core::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use core::storage::{Storage, StorageMut};
use core::allocator::Allocator;

/// Trait implemented by phantom types identifying the projective transformation type.
///
/// NOTE: this trait is not intended to be implementable outside of the `nalgebra` crate.
pub trait TCategory: Any + Debug + Copy + PartialEq + Send {
    /// Indicates whether a `Transform` with the category `Self` has a bottom-row different from
    /// `0 0 .. 1`.
    #[inline]
    fn has_normalizer() -> bool {
        true
    }

    /// Checks that the given matrix is a valid homogeneous representation of an element of the
    /// category `Self`.
    fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool
        where N: Scalar + Field + ApproxEq,
              D: DimName,
              S: Storage<N, D, D>,
              N::Epsilon: Copy;
}

/// Traits that gives the `Transform` category that is compatible with the result of the
/// multiplication of transformations with categories `Self` and `Other`.
pub trait TCategoryMul<Other: TCategory>: TCategory {
    /// The transform category that results from the multiplication of a `Transform<Self>` to a
    /// `Transform<Other>`. This is usually equal to `Self` or `Other`, whichever is the most
    /// general category.
    type Representative: TCategory;
}

/// Indicates that `Self` is a more general `Transform` category than `Other`.
pub trait SuperTCategoryOf<Other: TCategory>: TCategory { }

/// Indicates that `Self` is a more specific `Transform` category than `Other`.
///
/// Automatically implemented based on `SuperTCategoryOf`.
pub trait SubTCategoryOf<Other: TCategory>: TCategory { }
impl<T1, T2> SubTCategoryOf<T2> for T1
where T1: TCategory,
      T2: SuperTCategoryOf<T1> {
}

/// Tag representing the most general (not necessarily inversible) `Transform` type.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum TGeneral { }

/// Tag representing the most general inversible `Transform` type.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum TProjective { }

/// Tag representing an affine `Transform`. Its bottom-row is equal to `(0, 0 ... 0, 1)`.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum TAffine { }

impl TCategory for TGeneral {
    #[inline]
    fn check_homogeneous_invariants<N, D, S>(_: &SquareMatrix<N, D, S>) -> bool
        where N: Scalar + Field + ApproxEq,
              D: DimName,
              S: Storage<N, D, D>,
              N::Epsilon: Copy {
        true
    }
}

impl TCategory for TProjective {
    #[inline]
    fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool
        where N: Scalar + Field + ApproxEq,
              D: DimName,
              S: Storage<N, D, D>,
              N::Epsilon: Copy {
        mat.is_invertible()
    }
}

impl TCategory for TAffine {
    #[inline]
    fn has_normalizer() -> bool {
        false
    }

    #[inline]
    fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool
        where N: Scalar + Field + ApproxEq,
              D: DimName,
              S: Storage<N, D, D>,
              N::Epsilon: Copy {
        mat.is_invertible()                   &&
        mat[(D::dim(), D::dim())] == N::one() &&
        (0 .. D::dim()).all(|i| mat[(D::dim(), i)].is_zero())
    }
}

macro_rules! category_mul_impl(
    ($($a: ident * $b: ident => $c: ty);* $(;)*) => {$(
        impl TCategoryMul<$a> for $b {
            type Representative = $c;
        }
    )*}
);

// We require stability uppon multiplication.
impl<T: TCategory> TCategoryMul<T> for T {
    type Representative = T;
}

category_mul_impl!(
    // TGeneral * TGeneral     => TGeneral;
    TGeneral * TProjective  => TGeneral;
    TGeneral * TAffine      => TGeneral;

    TProjective * TGeneral     => TGeneral;
    // TProjective * TProjective  => TProjective;
    TProjective * TAffine      => TProjective;

    TAffine * TGeneral     => TGeneral;
    TAffine * TProjective  => TProjective;
    // TAffine * TAffine      => TAffine;
);

macro_rules! super_tcategory_impl(
    ($($a: ident >= $b: ident);* $(;)*) => {$(
        impl SuperTCategoryOf<$b> for $a { }
    )*}
);

impl<T: TCategory> SuperTCategoryOf<T> for T { }

super_tcategory_impl!(
    TGeneral >= TProjective;
    TGeneral >= TAffine;
    TProjective >= TAffine;
);

/// A transformation matrix that owns its data.
pub type OwnedTransform<N, D, A, C>
    = TransformBase<N, D, <A as Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>>::Buffer, C>;

/// A transformation matrix in homogeneous coordinates.
///
/// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a
/// 3D transformation.
#[repr(C)]
#[derive(Debug, Clone, Copy)] // FIXME: Hash
pub struct TransformBase<N: Scalar, D: DimNameAdd<U1>, S, C: TCategory> {
    matrix:   SquareMatrix<N, DimNameSum<D, U1>, S>,

    _phantom: PhantomData<C>
}

#[cfg(feature = "serde-serialize")]
impl<N, D, S, C> Serialize for TransformBase<N, D, S, C>
    where N: Scalar,
          D: DimNameAdd<U1>,
          C: TCategory,
          SquareMatrix<N, DimNameSum<D, U1>, S>: Serialize,
{
    fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error>
        where T: Serializer
    {
        self.matrix.serialize(serializer)
    }
}

#[cfg(feature = "serde-serialize")]
impl<'de, N, D, S, C> Deserialize<'de> for TransformBase<N, D, S, C>
    where N: Scalar,
          D: DimNameAdd<U1>,
          C: TCategory,
          SquareMatrix<N, DimNameSum<D, U1>, S>: Deserialize<'de>,
{
    fn deserialize<T>(deserializer: T) -> Result<Self, T::Error>
        where T: Deserializer<'de>
    {
        SquareMatrix::deserialize(deserializer).map(|x| TransformBase { matrix: x, _phantom: PhantomData })
    }
}

// XXX: for some reasons, implementing Clone and Copy manually causes an ICE…

impl<N, D, S, C: TCategory> Eq for TransformBase<N, D, S, C>
    where N: Scalar + Eq,
          D: DimNameAdd<U1>,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { }

impl<N, D, S, C: TCategory> PartialEq for TransformBase<N, D, S, C>
    where N: Scalar,
          D: DimNameAdd<U1>,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    #[inline]
    fn eq(&self, right: &Self) -> bool {
        self.matrix == right.matrix
    }
}

impl<N, D, S, C: TCategory> TransformBase<N, D, S, C>
    where N: Scalar,
          D: DimNameAdd<U1>,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    /// Creates a new transformation from the given homogeneous matrix. The transformation category
    /// of `Self` is not checked to be verified by the given matrix.
    #[inline]
    pub fn from_matrix_unchecked(matrix: SquareMatrix<N, DimNameSum<D, U1>, S>) -> Self {
        TransformBase {
            matrix:   matrix,
            _phantom: PhantomData
        }
    }

    /// Moves this transform into one that owns its data.
    #[inline]
    pub fn into_owned(self) -> OwnedTransform<N, D, S::Alloc, C> {
        TransformBase::from_matrix_unchecked(self.matrix.into_owned())
    }

    /// Clones this transform into one that owns its data.
    #[inline]
    pub fn clone_owned(&self) -> OwnedTransform<N, D, S::Alloc, C> {
        TransformBase::from_matrix_unchecked(self.matrix.clone_owned())
    }

    /// The underlying matrix.
    #[inline]
    pub fn unwrap(self) -> SquareMatrix<N, DimNameSum<D, U1>, S> {
        self.matrix
    }

    /// A reference to the underlynig matrix.
    #[inline]
    pub fn matrix(&self) -> &SquareMatrix<N, DimNameSum<D, U1>, S> {
        &self.matrix
    }

    /// A mutable reference to the underlying matrix.
    ///
    /// It is `_unchecked` because direct modifications of this matrix may break invariants
    /// identified by this transformation category.
    #[inline]
    pub fn matrix_mut_unchecked(&mut self) -> &mut SquareMatrix<N, DimNameSum<D, U1>, S> {
        &mut self.matrix
    }

    /// Sets the category of this transform.
    ///
    /// This can be done only if the new category is more general than the current one, e.g., a
    /// transform with category `TProjective` cannot be converted to a transform with category
    /// `TAffine` because not all projective transformations are affine (the other way-round is
    /// valid though).
    #[inline]
    pub fn set_category<CNew: SuperTCategoryOf<C>>(self) -> TransformBase<N, D, S, CNew> {
        TransformBase::from_matrix_unchecked(self.matrix)
    }

    /// Converts this transform into its equivalent homogeneous transformation matrix.
    #[inline]
    pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc> {
        self.matrix().clone_owned()
    }
}

impl<N, D, S, C> TransformBase<N, D, S, C>
    where N: Scalar + Field + ApproxEq,
          D: DimNameAdd<U1>,
          C: TCategory,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    /// Attempts to invert this transformation. You may use `.inverse` instead of this
    /// transformation has a subcategory of `TProjective`.
    #[inline]
    pub fn try_inverse(self) -> Option<OwnedTransform<N, D, S::Alloc, C>> {
        if let Some(m) = self.matrix.try_inverse() {
            Some(TransformBase::from_matrix_unchecked(m))
        }
        else {
            None
        }
    }

    /// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral`
    /// category (it may not be invertible).
    #[inline]
    pub fn inverse(self) -> OwnedTransform<N, D, S::Alloc, C>
        where C: SubTCategoryOf<TProjective> {
        // FIXME: specialize for TAffine?
        TransformBase::from_matrix_unchecked(self.matrix.try_inverse().unwrap())
    }
}

impl<N, D, S, C> TransformBase<N, D, S, C>
    where N: Scalar + Field + ApproxEq,
          D: DimNameAdd<U1>,
          C: TCategory,
          S: StorageMut<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    /// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this
    /// transformation has a subcategory of `TProjective`.
    #[inline]
    pub fn try_inverse_mut(&mut self) -> bool {
        self.matrix.try_inverse_mut()
    }

    /// Inverts this transformation in-place. Use `.try_inverse_mut` if this transform has the
    /// `TGeneral` category (it may not be invertible).
    #[inline]
    pub fn inverse_mut(&mut self)
        where C: SubTCategoryOf<TProjective> {
        let _ = self.matrix.try_inverse_mut();
    }
}

impl<N, D, S> TransformBase<N, D, S, TGeneral>
    where N: Scalar,
          D: DimNameAdd<U1>,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    /// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this
    /// transformation category is not `TGeneral`.
    #[inline]
    pub fn matrix_mut(&mut self) -> &mut SquareMatrix<N, DimNameSum<D, U1>, S> {
        self.matrix_mut_unchecked()
    }
}
<commit_msg>Fix TCategory implementation for TAffine<commit_after>use std::any::Any;
use std::fmt::Debug;
use std::marker::PhantomData;
use approx::ApproxEq;

#[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer};

use alga::general::Field;

use core::{Scalar, SquareMatrix, OwnedSquareMatrix};
use core::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use core::storage::{Storage, StorageMut};
use core::allocator::Allocator;

/// Trait implemented by phantom types identifying the projective transformation type.
///
/// NOTE: this trait is not intended to be implementable outside of the `nalgebra` crate.
pub trait TCategory: Any + Debug + Copy + PartialEq + Send {
    /// Indicates whether a `Transform` with the category `Self` has a bottom-row different from
    /// `0 0 .. 1`.
    #[inline]
    fn has_normalizer() -> bool {
        true
    }

    /// Checks that the given matrix is a valid homogeneous representation of an element of the
    /// category `Self`.
    fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool
        where N: Scalar + Field + ApproxEq,
              D: DimName,
              S: Storage<N, D, D>,
              N::Epsilon: Copy;
}

/// Traits that gives the `Transform` category that is compatible with the result of the
/// multiplication of transformations with categories `Self` and `Other`.
pub trait TCategoryMul<Other: TCategory>: TCategory {
    /// The transform category that results from the multiplication of a `Transform<Self>` to a
    /// `Transform<Other>`. This is usually equal to `Self` or `Other`, whichever is the most
    /// general category.
    type Representative: TCategory;
}

/// Indicates that `Self` is a more general `Transform` category than `Other`.
pub trait SuperTCategoryOf<Other: TCategory>: TCategory { }

/// Indicates that `Self` is a more specific `Transform` category than `Other`.
///
/// Automatically implemented based on `SuperTCategoryOf`.
pub trait SubTCategoryOf<Other: TCategory>: TCategory { }
impl<T1, T2> SubTCategoryOf<T2> for T1
where T1: TCategory,
      T2: SuperTCategoryOf<T1> {
}

/// Tag representing the most general (not necessarily inversible) `Transform` type.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum TGeneral { }

/// Tag representing the most general inversible `Transform` type.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum TProjective { }

/// Tag representing an affine `Transform`. Its bottom-row is equal to `(0, 0 ... 0, 1)`.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum TAffine { }

impl TCategory for TGeneral {
    #[inline]
    fn check_homogeneous_invariants<N, D, S>(_: &SquareMatrix<N, D, S>) -> bool
        where N: Scalar + Field + ApproxEq,
              D: DimName,
              S: Storage<N, D, D>,
              N::Epsilon: Copy {
        true
    }
}

impl TCategory for TProjective {
    #[inline]
    fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool
        where N: Scalar + Field + ApproxEq,
              D: DimName,
              S: Storage<N, D, D>,
              N::Epsilon: Copy {
        mat.is_invertible()
    }
}

impl TCategory for TAffine {
    #[inline]
    fn has_normalizer() -> bool {
        false
    }

    #[inline]
    fn check_homogeneous_invariants<N, D, S>(mat: &SquareMatrix<N, D, S>) -> bool
        where N: Scalar + Field + ApproxEq,
              D: DimName,
              S: Storage<N, D, D>,
              N::Epsilon: Copy {
        let last = D::dim() - 1;
        mat.is_invertible()           &&
        mat[(last, last)] == N::one() &&
        (0 .. last).all(|i| mat[(last, i)].is_zero())
    }
}

macro_rules! category_mul_impl(
    ($($a: ident * $b: ident => $c: ty);* $(;)*) => {$(
        impl TCategoryMul<$a> for $b {
            type Representative = $c;
        }
    )*}
);

// We require stability uppon multiplication.
impl<T: TCategory> TCategoryMul<T> for T {
    type Representative = T;
}

category_mul_impl!(
    // TGeneral * TGeneral     => TGeneral;
    TGeneral * TProjective  => TGeneral;
    TGeneral * TAffine      => TGeneral;

    TProjective * TGeneral     => TGeneral;
    // TProjective * TProjective  => TProjective;
    TProjective * TAffine      => TProjective;

    TAffine * TGeneral     => TGeneral;
    TAffine * TProjective  => TProjective;
    // TAffine * TAffine      => TAffine;
);

macro_rules! super_tcategory_impl(
    ($($a: ident >= $b: ident);* $(;)*) => {$(
        impl SuperTCategoryOf<$b> for $a { }
    )*}
);

impl<T: TCategory> SuperTCategoryOf<T> for T { }

super_tcategory_impl!(
    TGeneral >= TProjective;
    TGeneral >= TAffine;
    TProjective >= TAffine;
);

/// A transformation matrix that owns its data.
pub type OwnedTransform<N, D, A, C>
    = TransformBase<N, D, <A as Allocator<N, DimNameSum<D, U1>, DimNameSum<D, U1>>>::Buffer, C>;

/// A transformation matrix in homogeneous coordinates.
///
/// It is stored as a matrix with dimensions `(D + 1, D + 1)`, e.g., it stores a 4x4 matrix for a
/// 3D transformation.
#[repr(C)]
#[derive(Debug, Clone, Copy)] // FIXME: Hash
pub struct TransformBase<N: Scalar, D: DimNameAdd<U1>, S, C: TCategory> {
    matrix:   SquareMatrix<N, DimNameSum<D, U1>, S>,

    _phantom: PhantomData<C>
}

#[cfg(feature = "serde-serialize")]
impl<N, D, S, C> Serialize for TransformBase<N, D, S, C>
    where N: Scalar,
          D: DimNameAdd<U1>,
          C: TCategory,
          SquareMatrix<N, DimNameSum<D, U1>, S>: Serialize,
{
    fn serialize<T>(&self, serializer: T) -> Result<T::Ok, T::Error>
        where T: Serializer
    {
        self.matrix.serialize(serializer)
    }
}

#[cfg(feature = "serde-serialize")]
impl<'de, N, D, S, C> Deserialize<'de> for TransformBase<N, D, S, C>
    where N: Scalar,
          D: DimNameAdd<U1>,
          C: TCategory,
          SquareMatrix<N, DimNameSum<D, U1>, S>: Deserialize<'de>,
{
    fn deserialize<T>(deserializer: T) -> Result<Self, T::Error>
        where T: Deserializer<'de>
    {
        SquareMatrix::deserialize(deserializer).map(|x| TransformBase { matrix: x, _phantom: PhantomData })
    }
}

// XXX: for some reasons, implementing Clone and Copy manually causes an ICE…

impl<N, D, S, C: TCategory> Eq for TransformBase<N, D, S, C>
    where N: Scalar + Eq,
          D: DimNameAdd<U1>,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> { }

impl<N, D, S, C: TCategory> PartialEq for TransformBase<N, D, S, C>
    where N: Scalar,
          D: DimNameAdd<U1>,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    #[inline]
    fn eq(&self, right: &Self) -> bool {
        self.matrix == right.matrix
    }
}

impl<N, D, S, C: TCategory> TransformBase<N, D, S, C>
    where N: Scalar,
          D: DimNameAdd<U1>,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    /// Creates a new transformation from the given homogeneous matrix. The transformation category
    /// of `Self` is not checked to be verified by the given matrix.
    #[inline]
    pub fn from_matrix_unchecked(matrix: SquareMatrix<N, DimNameSum<D, U1>, S>) -> Self {
        TransformBase {
            matrix:   matrix,
            _phantom: PhantomData
        }
    }

    /// Moves this transform into one that owns its data.
    #[inline]
    pub fn into_owned(self) -> OwnedTransform<N, D, S::Alloc, C> {
        TransformBase::from_matrix_unchecked(self.matrix.into_owned())
    }

    /// Clones this transform into one that owns its data.
    #[inline]
    pub fn clone_owned(&self) -> OwnedTransform<N, D, S::Alloc, C> {
        TransformBase::from_matrix_unchecked(self.matrix.clone_owned())
    }

    /// The underlying matrix.
    #[inline]
    pub fn unwrap(self) -> SquareMatrix<N, DimNameSum<D, U1>, S> {
        self.matrix
    }

    /// A reference to the underlynig matrix.
    #[inline]
    pub fn matrix(&self) -> &SquareMatrix<N, DimNameSum<D, U1>, S> {
        &self.matrix
    }

    /// A mutable reference to the underlying matrix.
    ///
    /// It is `_unchecked` because direct modifications of this matrix may break invariants
    /// identified by this transformation category.
    #[inline]
    pub fn matrix_mut_unchecked(&mut self) -> &mut SquareMatrix<N, DimNameSum<D, U1>, S> {
        &mut self.matrix
    }

    /// Sets the category of this transform.
    ///
    /// This can be done only if the new category is more general than the current one, e.g., a
    /// transform with category `TProjective` cannot be converted to a transform with category
    /// `TAffine` because not all projective transformations are affine (the other way-round is
    /// valid though).
    #[inline]
    pub fn set_category<CNew: SuperTCategoryOf<C>>(self) -> TransformBase<N, D, S, CNew> {
        TransformBase::from_matrix_unchecked(self.matrix)
    }

    /// Converts this transform into its equivalent homogeneous transformation matrix.
    #[inline]
    pub fn to_homogeneous(&self) -> OwnedSquareMatrix<N, DimNameSum<D, U1>, S::Alloc> {
        self.matrix().clone_owned()
    }
}

impl<N, D, S, C> TransformBase<N, D, S, C>
    where N: Scalar + Field + ApproxEq,
          D: DimNameAdd<U1>,
          C: TCategory,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    /// Attempts to invert this transformation. You may use `.inverse` instead of this
    /// transformation has a subcategory of `TProjective`.
    #[inline]
    pub fn try_inverse(self) -> Option<OwnedTransform<N, D, S::Alloc, C>> {
        if let Some(m) = self.matrix.try_inverse() {
            Some(TransformBase::from_matrix_unchecked(m))
        }
        else {
            None
        }
    }

    /// Inverts this transformation. Use `.try_inverse` if this transform has the `TGeneral`
    /// category (it may not be invertible).
    #[inline]
    pub fn inverse(self) -> OwnedTransform<N, D, S::Alloc, C>
        where C: SubTCategoryOf<TProjective> {
        // FIXME: specialize for TAffine?
        TransformBase::from_matrix_unchecked(self.matrix.try_inverse().unwrap())
    }
}

impl<N, D, S, C> TransformBase<N, D, S, C>
    where N: Scalar + Field + ApproxEq,
          D: DimNameAdd<U1>,
          C: TCategory,
          S: StorageMut<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    /// Attempts to invert this transformation in-place. You may use `.inverse_mut` instead of this
    /// transformation has a subcategory of `TProjective`.
    #[inline]
    pub fn try_inverse_mut(&mut self) -> bool {
        self.matrix.try_inverse_mut()
    }

    /// Inverts this transformation in-place. Use `.try_inverse_mut` if this transform has the
    /// `TGeneral` category (it may not be invertible).
    #[inline]
    pub fn inverse_mut(&mut self)
        where C: SubTCategoryOf<TProjective> {
        let _ = self.matrix.try_inverse_mut();
    }
}

impl<N, D, S> TransformBase<N, D, S, TGeneral>
    where N: Scalar,
          D: DimNameAdd<U1>,
          S: Storage<N, DimNameSum<D, U1>, DimNameSum<D, U1>> {
    /// A mutable reference to underlying matrix. Use `.matrix_mut_unchecked` instead if this
    /// transformation category is not `TGeneral`.
    #[inline]
    pub fn matrix_mut(&mut self) -> &mut SquareMatrix<N, DimNameSum<D, U1>, S> {
        self.matrix_mut_unchecked()
    }
}

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

    #[test]
    fn checks_homogeneous_invariants_of_square_identity_matrix() {
        assert!(TAffine::check_homogeneous_invariants(&Matrix4::<f32>::identity()));
    }

}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;
extern crate exonum;
extern crate time;
extern crate env_logger;

use std::thread;
use std::net::SocketAddr;

use time::Duration;
use test::Bencher;

use exonum::events::{Events, Reactor, EventsConfiguration, Event, InternalEvent, NodeTimeout};
use exonum::events::{Network, NetworkConfiguration};
use exonum::messages::{MessageWriter, RawMessage};
use exonum::crypto::gen_keypair;

struct BenchConfig {
    times: usize,
    len: usize,
    tcp_nodelay: bool
}

trait EventsBench {
    fn with_addr(addr: SocketAddr, cfg: &BenchConfig) -> Events;

    fn wait_for_connect(&mut self, address: &SocketAddr);
    fn wait_for_msg(&mut self) -> Option<RawMessage>;
    fn gen_message(id: u16, len: usize) -> RawMessage;
    fn wait_for_messages(&mut self, mut count: usize, timeout: Duration) -> Result<(), String>;
    fn process_events(&mut self, timeout: Duration);
}

impl EventsBench for Events {
    fn with_addr(addr: SocketAddr, cfg: &BenchConfig) -> Events {
        let network = Network::with_config(NetworkConfiguration {
            listen_address: addr,
            max_incoming_connections: 128,
            max_outgoing_connections: 128,
            tcp_nodelay: cfg.tcp_nodelay,
            tcp_keep_alive: None,
            tcp_reconnect_timeout: 1000,
            tcp_reconnect_timeout_max: 600000,
        });
        Events::with_config(EventsConfiguration::new(), network).unwrap()
    }

    fn wait_for_connect(&mut self, address: &SocketAddr) {
        self.connect(address);

        let time = self.get_time() + Duration::milliseconds(10000);
        self.add_timeout(NodeTimeout::Status, time);
        loop {
            match self.poll() {
                Event::Internal(InternalEvent::Connected(_)) => return,
                Event::Timeout(_) => panic!("Unable to connect with addr {}", address),
                _ => {}
            }
        }
    }

    fn wait_for_msg(&mut self) -> Option<RawMessage> {
        let time = self.get_time() + Duration::milliseconds(10000);
        self.add_timeout(NodeTimeout::Status, time);
        loop {
            match self.poll() {
                Event::Incoming(msg) => return Some(msg),
                Event::Timeout(_) => return None,
                Event::Internal(InternalEvent::Error(_)) => return None,
                _ => {}
            }
        }
    }

    fn wait_for_messages(&mut self, mut count: usize, timeout: Duration) -> Result<(), String> {
        let time = self.get_time() + timeout;
        self.add_timeout(NodeTimeout::Status, time);
        loop {
            match self.poll() {
                Event::Incoming(_) => {
                    count = count - 1;
                }
                Event::Timeout(_) => {
                    return Err(format!("Timeout exceeded, {} messages is not received", count))
                }
                Event::Internal(InternalEvent::Error(_)) => {
                    return Err(format!("An error occured, {} messages is not received", count))
                }
                _ => {}
            }
            if count == 0 {
                return Ok(());
            }
        }
    }

    fn gen_message(id: u16, len: usize) -> RawMessage {
        let writer = MessageWriter::new(id, len);
        RawMessage::new(writer.sign(&gen_keypair().1))
    }

    fn process_events(&mut self, timeout: Duration) {
        let time = self.get_time() + timeout;
        self.add_timeout(NodeTimeout::Status, time);
        loop {
            match self.poll() {
                Event::Timeout(_) => break,
                Event::Internal(InternalEvent::Error(_)) => return,
                _ => {}
            }
        }
    }
}

fn bench_network(b: &mut Bencher, addrs: [SocketAddr; 2], cfg: BenchConfig) {
    b.iter(|| {
        let mut e1 = Events::with_addr(addrs[0], &cfg);
        let mut e2 = Events::with_addr(addrs[1], &cfg);
        e1.bind().unwrap();
        e2.bind().unwrap();

        let timeout = Duration::seconds(30);
        let len = cfg.len;
        let times = cfg.times;
        let t1 = thread::spawn(move || {
            e1.wait_for_connect(&addrs[1]);
            for _ in 0..times {
                let msg = Events::gen_message(0, len);
                e1.send_to(&addrs[1], msg);
                e1.wait_for_messages(1, timeout).unwrap();
            }
            e1.process_events(Duration::milliseconds(0));
            drop(e1);
        });
        let t2 = thread::spawn(move || {
            e2.wait_for_connect(&addrs[0]);
            for _ in 0..times {
                let msg = Events::gen_message(1, len);
                e2.send_to(&addrs[0], msg);
                e2.wait_for_messages(1, timeout).unwrap();
            }
            e2.process_events(Duration::milliseconds(0));
            drop(e2);
        });
        t1.join().unwrap();
        t2.join().unwrap();
    })
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_100(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100,
        times: 100
    };
    let addrs = ["127.0.0.1:9990".parse().unwrap(), "127.0.0.1:9991".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_1000(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100,
        times: 1000
    };
    let addrs = ["127.0.0.1:9992".parse().unwrap(), "127.0.0.1:9993".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_10000(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100,
        times: 10000
    };
    let addrs = ["127.0.0.1:9992".parse().unwrap(), "127.0.0.1:9993".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_100_nodelay(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: true,
        len: 100,
        times: 100
    };
    let addrs = ["127.0.0.1:9990".parse().unwrap(), "127.0.0.1:9991".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_10000_nodelay(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: true,
        len: 100,
        times: 10000
    };
    let addrs = ["127.0.0.1:9990".parse().unwrap(), "127.0.0.1:9991".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_long_10(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100000,
        times: 10
    };
    let addrs = ["127.0.0.1:9994".parse().unwrap(), "127.0.0.1:9995".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_long_100(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100000,
        times: 100
    };
    let addrs = ["127.0.0.1:9996".parse().unwrap(), "127.0.0.1:9997".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_long_1000(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100000,
        times: 1000
    };
    let addrs = ["127.0.0.1:9998".parse().unwrap(), "127.0.0.1:9999".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_long_1000_nodelay(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: true,
        len: 100000,
        times: 1000
    };
    let addrs = ["127.0.0.1:9998".parse().unwrap(), "127.0.0.1:9999".parse().unwrap()];
    bench_network(b, addrs, cfg);
}
<commit_msg>Remove dead code from benches<commit_after>#![feature(test)]

extern crate test;
extern crate exonum;
extern crate time;
extern crate env_logger;

use std::thread;
use std::net::SocketAddr;

use time::Duration;
use test::Bencher;

use exonum::events::{Events, Reactor, EventsConfiguration, Event, InternalEvent, NodeTimeout};
use exonum::events::{Network, NetworkConfiguration};
use exonum::messages::{MessageWriter, RawMessage};
use exonum::crypto::gen_keypair;

struct BenchConfig {
    times: usize,
    len: usize,
    tcp_nodelay: bool
}

trait EventsBench {
    fn with_addr(addr: SocketAddr, cfg: &BenchConfig) -> Events;

    fn wait_for_connect(&mut self, address: &SocketAddr);
    fn gen_message(id: u16, len: usize) -> RawMessage;
    fn wait_for_messages(&mut self, mut count: usize, timeout: Duration) -> Result<(), String>;
    fn process_events(&mut self, timeout: Duration);
}

impl EventsBench for Events {
    fn with_addr(addr: SocketAddr, cfg: &BenchConfig) -> Events {
        let network = Network::with_config(NetworkConfiguration {
            listen_address: addr,
            max_incoming_connections: 128,
            max_outgoing_connections: 128,
            tcp_nodelay: cfg.tcp_nodelay,
            tcp_keep_alive: None,
            tcp_reconnect_timeout: 1000,
            tcp_reconnect_timeout_max: 600000,
        });
        Events::with_config(EventsConfiguration::new(), network).unwrap()
    }

    fn wait_for_connect(&mut self, address: &SocketAddr) {
        self.connect(address);

        let time = self.get_time() + Duration::milliseconds(10000);
        self.add_timeout(NodeTimeout::Status, time);
        loop {
            match self.poll() {
                Event::Internal(InternalEvent::Connected(_)) => return,
                Event::Timeout(_) => panic!("Unable to connect with addr {}", address),
                _ => {}
            }
        }
    }

    fn wait_for_messages(&mut self, mut count: usize, timeout: Duration) -> Result<(), String> {
        let time = self.get_time() + timeout;
        self.add_timeout(NodeTimeout::Status, time);
        loop {
            match self.poll() {
                Event::Incoming(_) => {
                    count = count - 1;
                }
                Event::Timeout(_) => {
                    return Err(format!("Timeout exceeded, {} messages is not received", count))
                }
                Event::Internal(InternalEvent::Error(_)) => {
                    return Err(format!("An error occured, {} messages is not received", count))
                }
                _ => {}
            }
            if count == 0 {
                return Ok(());
            }
        }
    }

    fn gen_message(id: u16, len: usize) -> RawMessage {
        let writer = MessageWriter::new(id, len);
        RawMessage::new(writer.sign(&gen_keypair().1))
    }

    fn process_events(&mut self, timeout: Duration) {
        let time = self.get_time() + timeout;
        self.add_timeout(NodeTimeout::Status, time);
        loop {
            match self.poll() {
                Event::Timeout(_) => break,
                Event::Internal(InternalEvent::Error(_)) => return,
                _ => {}
            }
        }
    }
}

fn bench_network(b: &mut Bencher, addrs: [SocketAddr; 2], cfg: BenchConfig) {
    b.iter(|| {
        let mut e1 = Events::with_addr(addrs[0], &cfg);
        let mut e2 = Events::with_addr(addrs[1], &cfg);
        e1.bind().unwrap();
        e2.bind().unwrap();

        let timeout = Duration::seconds(30);
        let len = cfg.len;
        let times = cfg.times;
        let t1 = thread::spawn(move || {
            e1.wait_for_connect(&addrs[1]);
            for _ in 0..times {
                let msg = Events::gen_message(0, len);
                e1.send_to(&addrs[1], msg);
                e1.wait_for_messages(1, timeout).unwrap();
            }
            e1.process_events(Duration::milliseconds(0));
            drop(e1);
        });
        let t2 = thread::spawn(move || {
            e2.wait_for_connect(&addrs[0]);
            for _ in 0..times {
                let msg = Events::gen_message(1, len);
                e2.send_to(&addrs[0], msg);
                e2.wait_for_messages(1, timeout).unwrap();
            }
            e2.process_events(Duration::milliseconds(0));
            drop(e2);
        });
        t1.join().unwrap();
        t2.join().unwrap();
    })
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_100(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100,
        times: 100
    };
    let addrs = ["127.0.0.1:9990".parse().unwrap(), "127.0.0.1:9991".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_1000(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100,
        times: 1000
    };
    let addrs = ["127.0.0.1:9992".parse().unwrap(), "127.0.0.1:9993".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_10000(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100,
        times: 10000
    };
    let addrs = ["127.0.0.1:9992".parse().unwrap(), "127.0.0.1:9993".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_100_nodelay(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: true,
        len: 100,
        times: 100
    };
    let addrs = ["127.0.0.1:9990".parse().unwrap(), "127.0.0.1:9991".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_short_10000_nodelay(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: true,
        len: 100,
        times: 10000
    };
    let addrs = ["127.0.0.1:9990".parse().unwrap(), "127.0.0.1:9991".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_long_10(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100000,
        times: 10
    };
    let addrs = ["127.0.0.1:9994".parse().unwrap(), "127.0.0.1:9995".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_long_100(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100000,
        times: 100
    };
    let addrs = ["127.0.0.1:9996".parse().unwrap(), "127.0.0.1:9997".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_long_1000(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: false,
        len: 100000,
        times: 1000
    };
    let addrs = ["127.0.0.1:9998".parse().unwrap(), "127.0.0.1:9999".parse().unwrap()];
    bench_network(b, addrs, cfg);
}

#[cfg(feature = "long_benchmarks")]
#[bench]
fn bench_msg_long_1000_nodelay(b: &mut Bencher) {
    let cfg = BenchConfig {
        tcp_nodelay: true,
        len: 100000,
        times: 1000
    };
    let addrs = ["127.0.0.1:9998".parse().unwrap(), "127.0.0.1:9999".parse().unwrap()];
    bench_network(b, addrs, cfg);
}
<|endoftext|>


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

//! Different assorted utilities.

pub use self::types::{Height, Milliseconds, Round, ValidatorId, ZeroizeOnDrop};

pub mod config;
pub mod fabric;
pub mod user_agent;
#[macro_use]
pub mod metrics;

use env_logger::Builder;
use log::SetLoggerError;

use std::path::{Component, Path, PathBuf};

use crate::blockchain::{GenesisConfig, ValidatorKeys};
use crate::crypto::gen_keypair;
use crate::node::{ConnectListConfig, NodeConfig};

mod types;

/// Performs the logger initialization.
pub fn init_logger() -> Result<(), SetLoggerError> {
    Builder::from_default_env()
        .default_format_timestamp_nanos(true)
        .try_init()
}

/// Generates testnet configuration.
pub fn generate_testnet_config(count: u16, start_port: u16) -> Vec<NodeConfig> {
    let (validators, services): (Vec<_>, Vec<_>) = (0..count as usize)
        .map(|_| (gen_keypair(), gen_keypair()))
        .unzip();
    let genesis =
        GenesisConfig::new(
            validators
                .iter()
                .zip(services.iter())
                .map(|x| ValidatorKeys {
                    consensus_key: (x.0).0,
                    service_key: (x.1).0,
                }),
        );
    let peers = (0..validators.len())
        .map(|x| format!("127.0.0.1:{}", start_port + x as u16))
        .collect::<Vec<_>>();

    validators
        .into_iter()
        .zip(services.into_iter())
        .enumerate()
        .map(|(idx, (validator, service))| NodeConfig {
            listen_address: peers[idx].parse().unwrap(),
            external_address: peers[idx].clone(),
            network: Default::default(),
            consensus_public_key: validator.0,
            consensus_secret_key: validator.1,
            service_public_key: service.0,
            service_secret_key: service.1,
            genesis: genesis.clone(),
            connect_list: ConnectListConfig::from_validator_keys(&genesis.validator_keys, &peers),
            api: Default::default(),
            mempool: Default::default(),
            services_configs: Default::default(),
            database: Default::default(),
            thread_pool_size: Default::default(),
        })
        .collect::<Vec<_>>()
}

/// Basic trait to validate user defined input.
pub trait ValidateInput {
    /// The type returned in the event of a validate error.
    type Error;
    /// Performs parameters validation for this configuration and returns error if
    /// value is inconsistent.
    fn validate(&self) -> Result<(), Self::Error>;
}

/// This routine is adapted from the *old* Path's `path_relative_from`
/// function, which works differently from the new `relative_from` function.
/// In particular, this handles the case on unix where both paths are
/// absolute but with only the root as the common directory.
///
/// @see https://github.com/rust-lang/rust/blob/e1d0de82cc40b666b88d4a6d2c9dcbc81d7ed27f/src/librustc_back/rpath.rs#L116-L158
pub fn path_relative_from(path: impl AsRef<Path>, base: impl AsRef<Path>) -> Option<PathBuf> {
    let path = path.as_ref();
    let base = base.as_ref();

    if path.is_absolute() != base.is_absolute() {
        if path.is_absolute() {
            Some(PathBuf::from(path))
        } else {
            None
        }
    } else {
        let mut ita = path.components();
        let mut itb = base.components();
        let mut comps: Vec<Component> = vec![];
        loop {
            match (ita.next(), itb.next()) {
                (None, None) => break,
                (Some(a), None) => {
                    comps.push(a);
                    comps.extend(ita.by_ref());
                    break;
                }
                (None, _) => comps.push(Component::ParentDir),
                (Some(a), Some(b)) if comps.is_empty() && a == b => (),
                (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
                (Some(_), Some(b)) if b == Component::ParentDir => return None,
                (Some(a), Some(_)) => {
                    comps.push(Component::ParentDir);
                    for _ in itb {
                        comps.push(Component::ParentDir);
                    }
                    comps.push(a);
                    comps.extend(ita.by_ref());
                    break;
                }
            }
        }
        Some(comps.iter().map(|c| c.as_os_str()).collect())
    }
}

#[test]
fn test_path_relative_from() {
    let cases = vec![
        ("/b", "/c", Some("../b".into())),
        ("/a/b", "/a/c", Some("../b".into())),
        ("/a", "/a/c", Some("../".into())),
        ("/a/b/c", "/a/b", Some("c".into())),
        ("/a/b/c", "/a/b/d", Some("../c".into())),
        ("./a/b", "./a/c", Some("../b".into())),
    ];
    for c in cases {
        assert_eq!(path_relative_from(c.0, c.1), c.2);
    }
}
<commit_msg>Add clear_consensus_messages_cache function [ECR-3482] (#1444)<commit_after>// Copyright 2019 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Different assorted utilities.

pub use self::types::{Height, Milliseconds, Round, ValidatorId, ZeroizeOnDrop};

pub mod config;
pub mod fabric;
pub mod user_agent;
#[macro_use]
pub mod metrics;

use env_logger::Builder;
use log::SetLoggerError;

use std::path::{Component, Path, PathBuf};

use crate::blockchain::{GenesisConfig, Schema, ValidatorKeys};
use crate::crypto::gen_keypair;
use crate::exonum_merkledb::Fork;
use crate::node::{ConnectListConfig, NodeConfig};

mod types;

/// Performs the logger initialization.
pub fn init_logger() -> Result<(), SetLoggerError> {
    Builder::from_default_env()
        .default_format_timestamp_nanos(true)
        .try_init()
}

/// Generates testnet configuration.
pub fn generate_testnet_config(count: u16, start_port: u16) -> Vec<NodeConfig> {
    let (validators, services): (Vec<_>, Vec<_>) = (0..count as usize)
        .map(|_| (gen_keypair(), gen_keypair()))
        .unzip();
    let genesis =
        GenesisConfig::new(
            validators
                .iter()
                .zip(services.iter())
                .map(|x| ValidatorKeys {
                    consensus_key: (x.0).0,
                    service_key: (x.1).0,
                }),
        );
    let peers = (0..validators.len())
        .map(|x| format!("127.0.0.1:{}", start_port + x as u16))
        .collect::<Vec<_>>();

    validators
        .into_iter()
        .zip(services.into_iter())
        .enumerate()
        .map(|(idx, (validator, service))| NodeConfig {
            listen_address: peers[idx].parse().unwrap(),
            external_address: peers[idx].clone(),
            network: Default::default(),
            consensus_public_key: validator.0,
            consensus_secret_key: validator.1,
            service_public_key: service.0,
            service_secret_key: service.1,
            genesis: genesis.clone(),
            connect_list: ConnectListConfig::from_validator_keys(&genesis.validator_keys, &peers),
            api: Default::default(),
            mempool: Default::default(),
            services_configs: Default::default(),
            database: Default::default(),
            thread_pool_size: Default::default(),
        })
        .collect::<Vec<_>>()
}

/// Basic trait to validate user defined input.
pub trait ValidateInput {
    /// The type returned in the event of a validate error.
    type Error;
    /// Performs parameters validation for this configuration and returns error if
    /// value is inconsistent.
    fn validate(&self) -> Result<(), Self::Error>;
}

/// This routine is adapted from the *old* Path's `path_relative_from`
/// function, which works differently from the new `relative_from` function.
/// In particular, this handles the case on unix where both paths are
/// absolute but with only the root as the common directory.
///
/// @see https://github.com/rust-lang/rust/blob/e1d0de82cc40b666b88d4a6d2c9dcbc81d7ed27f/src/librustc_back/rpath.rs#L116-L158
pub fn path_relative_from(path: impl AsRef<Path>, base: impl AsRef<Path>) -> Option<PathBuf> {
    let path = path.as_ref();
    let base = base.as_ref();

    if path.is_absolute() != base.is_absolute() {
        if path.is_absolute() {
            Some(PathBuf::from(path))
        } else {
            None
        }
    } else {
        let mut ita = path.components();
        let mut itb = base.components();
        let mut comps: Vec<Component> = vec![];
        loop {
            match (ita.next(), itb.next()) {
                (None, None) => break,
                (Some(a), None) => {
                    comps.push(a);
                    comps.extend(ita.by_ref());
                    break;
                }
                (None, _) => comps.push(Component::ParentDir),
                (Some(a), Some(b)) if comps.is_empty() && a == b => (),
                (Some(a), Some(b)) if b == Component::CurDir => comps.push(a),
                (Some(_), Some(b)) if b == Component::ParentDir => return None,
                (Some(a), Some(_)) => {
                    comps.push(Component::ParentDir);
                    for _ in itb {
                        comps.push(Component::ParentDir);
                    }
                    comps.push(a);
                    comps.extend(ita.by_ref());
                    break;
                }
            }
        }
        Some(comps.iter().map(|c| c.as_os_str()).collect())
    }
}

/// Clears consensus messages cache.
///
/// Used in `exonum-cli` to implement `clear-cache` maintenance action.
pub fn clear_consensus_messages_cache(fork: &Fork) {
    Schema::new(fork).consensus_messages_cache().clear();
}

#[test]
fn test_path_relative_from() {
    let cases = vec![
        ("/b", "/c", Some("../b".into())),
        ("/a/b", "/a/c", Some("../b".into())),
        ("/a", "/a/c", Some("../".into())),
        ("/a/b/c", "/a/b", Some("c".into())),
        ("/a/b/c", "/a/b/d", Some("../c".into())),
        ("./a/b", "./a/c", Some("../b".into())),
    ];
    for c in cases {
        assert_eq!(path_relative_from(c.0, c.1), c.2);
    }
}
<|endoftext|>


<commit_before>use cpal::Device as DeviceTrait;
use cpal::platform::{Device as CpalDevice, Devices as CpalDevices};
use std::ops::Deref;

/// A device that can be used to spawn an audio stream.
pub struct Device {
    pub(crate) device: CpalDevice,
}

/// An iterator yielding all available audio devices.
pub struct Devices {
    pub(crate) devices: CpalDevices,
}

impl Device {
    /// The maximum number of output channels of any format supported by this device.
    pub fn max_supported_output_channels(&self) -> usize {
        self.supported_output_formats()
            .expect("failed to get supported output audio stream formats")
            .map(|fmt| fmt.channels as usize)
            .max()
            .unwrap_or(0)
    }

    /// The maximum number of input channels of any format supported by this device.
    pub fn max_supported_input_channels(&self) -> usize {
        self.supported_input_formats()
            .expect("failed to get supported input audio stream formats")
            .map(|fmt| fmt.channels as usize)
            .max()
            .unwrap_or(0)
    }
}

impl Deref for Device {
    type Target = CpalDevice;
    fn deref(&self) -> &Self::Target {
        &self.device
    }
}

impl Iterator for Devices {
    type Item = Device;
    fn next(&mut self) -> Option<Self::Item> {
        self.devices.next().map(|device| Device { device })
    }
}
<commit_msg>Add missing inherent methods from Device impl<commit_after>use cpal::Device as DeviceTrait;
use cpal::platform::{Device as CpalDevice, Devices as CpalDevices};
use std::ops::Deref;

/// A device that can be used to spawn an audio stream.
pub struct Device {
    pub(crate) device: CpalDevice,
}

/// An iterator yielding all available audio devices.
pub struct Devices {
    pub(crate) devices: CpalDevices,
}

/// An iterator yielding formats that are supported by the backend.
pub type SupportedInputFormats = cpal::platform::SupportedInputFormats;

/// An iterator yielding formats that are supported by the backend.
pub type SupportedOutputFormats = cpal::platform::SupportedOutputFormats;

impl Device {
    /// The unique name associated with this device.
    pub fn name(&self) -> Result<String, cpal::DeviceNameError> {
        self.device.name()
    }

    /// An iterator yielding formats that are supported by the backend.
    ///
    /// Can return an error if the device is no longer valid (e.g. it has been disconnected).
    pub fn supported_input_formats(
        &self
    ) -> Result<SupportedInputFormats, cpal::SupportedFormatsError> {
        self.device.supported_input_formats()
    }

    /// An iterator yielding formats that are supported by the backend.
    ///
    /// Can return an error if the device is no longer valid (e.g. it has been disconnected).
    pub fn supported_output_formats(
        &self
    ) -> Result<SupportedOutputFormats, cpal::SupportedFormatsError> {
        self.device.supported_output_formats()
    }

    /// The default format used for input streams.
    pub fn default_input_format(&self) -> Result<cpal::Format, cpal::DefaultFormatError> {
        self.device.default_input_format()
    }

    /// The default format used for output streams.
    pub fn default_output_format(&self) -> Result<cpal::Format, cpal::DefaultFormatError> {
        self.device.default_output_format()
    }

    /// The maximum number of output channels of any format supported by this device.
    pub fn max_supported_output_channels(&self) -> usize {
        self.supported_output_formats()
            .expect("failed to get supported output audio stream formats")
            .map(|fmt| fmt.channels as usize)
            .max()
            .unwrap_or(0)
    }

    /// The maximum number of input channels of any format supported by this device.
    pub fn max_supported_input_channels(&self) -> usize {
        self.supported_input_formats()
            .expect("failed to get supported input audio stream formats")
            .map(|fmt| fmt.channels as usize)
            .max()
            .unwrap_or(0)
    }
}

impl Deref for Device {
    type Target = CpalDevice;
    fn deref(&self) -> &Self::Target {
        &self.device
    }
}

impl Iterator for Devices {
    type Item = Device;
    fn next(&mut self) -> Option<Self::Item> {
        self.devices.next().map(|device| Device { device })
    }
}
<|endoftext|>


<commit_before>use super::XPathEvaluationContext;
use super::XPathValue;
use super::{Boolean,Number,String,Nodes};
use super::Nodeset;

pub trait XPathExpression {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue;
}

pub struct ExpressionAnd {
    pub left:  Box<XPathExpression>,
    pub right: Box<XPathExpression>,
}

impl XPathExpression for ExpressionAnd {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        Boolean(self.left.evaluate(context).boolean() &&
                self.right.evaluate(context).boolean())
    }
}

pub struct ExpressionContextNode;

impl XPathExpression for ExpressionContextNode {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        let mut result = Nodeset;
        result.add(context.node());
        Nodes(result)
    }
}

pub struct ExpressionEqual {
    pub left:  Box<XPathExpression>,
    pub right: Box<XPathExpression>,
}

impl ExpressionEqual {
    fn boolean_evaluate(&self, context: &XPathEvaluationContext) -> bool {
        let left_val = self.left.evaluate(context);
        let right_val = self.right.evaluate(context);

        match (&left_val, &right_val) {
            (&Boolean(_), _) |
            (_, &Boolean(_)) => left_val.boolean() == right_val.boolean(),
            (&Number(_), _) |
            (_, &Number(_)) => left_val.number() == right_val.number(),
            _ => left_val.string() == right_val.string()
        }
    }
}

impl XPathExpression for ExpressionEqual {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        Boolean(self.boolean_evaluate(context))
    }
}

pub struct ExpressionNotEqual {
    equal: ExpressionEqual,
}

impl ExpressionNotEqual {
    pub fn new(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionNotEqual {
        ExpressionNotEqual {
            equal: ExpressionEqual{left: left, right: right}
        }
    }
}

impl XPathExpression for ExpressionNotEqual {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        Boolean(!self.equal.boolean_evaluate(context))
    }
}

pub struct ExpressionFunction {
    pub name: String,
    pub arguments: Vec<Box<XPathExpression>>,
}

impl XPathExpression for ExpressionFunction {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        match context.function_for_name(self.name.as_slice()) {
            Some(fun) => {
                // TODO: Error when argument count mismatch
                let args = self.arguments.iter().map(|ref arg| arg.evaluate(context)).collect();

                fun.evaluate(context, args)
            },
            None => fail!("throw UnknownXPathFunctionException(_name)"),
        }
    }
}

pub struct ExpressionLiteral {
    pub value: XPathValue,
}

impl XPathExpression for ExpressionLiteral {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        self.value.clone()
    }
}

pub struct ExpressionMath {
    left:  Box<XPathExpression>,
    right: Box<XPathExpression>,
    operation: fn(f64, f64) -> f64,
}

fn      add(a: f64, b: f64) -> f64 {a + b}
fn subtract(a: f64, b: f64) -> f64 {a - b}
fn multiply(a: f64, b: f64) -> f64 {a * b}
fn   divide(a: f64, b: f64) -> f64 {a / b}
fn  modulus(a: f64, b: f64) -> f64 {a % b}

impl ExpressionMath {
    pub fn addition(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: add}
    }

    pub fn subtraction(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: subtract}
    }

    pub fn multiplication(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: multiply}
    }

    pub fn division(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: divide}
    }

    pub fn remainder(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: modulus}
    }
}

impl XPathExpression for ExpressionMath {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        let left = self.left.evaluate(context);
        let right = self.right.evaluate(context);
        let op = self.operation;
        return Number(op(left.number(), right.number()));
    }
}

pub struct ExpressionNegation {
    expression: Box<XPathExpression>,
}

impl XPathExpression for ExpressionNegation {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        let result = self.expression.evaluate(context);
        return Number(-result.number());
    }
}
<commit_msg>Add or expression<commit_after>use super::XPathEvaluationContext;
use super::XPathValue;
use super::{Boolean,Number,String,Nodes};
use super::Nodeset;

pub trait XPathExpression {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue;
}

pub struct ExpressionAnd {
    pub left:  Box<XPathExpression>,
    pub right: Box<XPathExpression>,
}

impl XPathExpression for ExpressionAnd {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        Boolean(self.left.evaluate(context).boolean() &&
                self.right.evaluate(context).boolean())
    }
}

pub struct ExpressionContextNode;

impl XPathExpression for ExpressionContextNode {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        let mut result = Nodeset;
        result.add(context.node());
        Nodes(result)
    }
}

pub struct ExpressionEqual {
    pub left:  Box<XPathExpression>,
    pub right: Box<XPathExpression>,
}

impl ExpressionEqual {
    fn boolean_evaluate(&self, context: &XPathEvaluationContext) -> bool {
        let left_val = self.left.evaluate(context);
        let right_val = self.right.evaluate(context);

        match (&left_val, &right_val) {
            (&Boolean(_), _) |
            (_, &Boolean(_)) => left_val.boolean() == right_val.boolean(),
            (&Number(_), _) |
            (_, &Number(_)) => left_val.number() == right_val.number(),
            _ => left_val.string() == right_val.string()
        }
    }
}

impl XPathExpression for ExpressionEqual {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        Boolean(self.boolean_evaluate(context))
    }
}

pub struct ExpressionNotEqual {
    equal: ExpressionEqual,
}

impl ExpressionNotEqual {
    pub fn new(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionNotEqual {
        ExpressionNotEqual {
            equal: ExpressionEqual{left: left, right: right}
        }
    }
}

impl XPathExpression for ExpressionNotEqual {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        Boolean(!self.equal.boolean_evaluate(context))
    }
}

pub struct ExpressionFunction {
    pub name: String,
    pub arguments: Vec<Box<XPathExpression>>,
}

impl XPathExpression for ExpressionFunction {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        match context.function_for_name(self.name.as_slice()) {
            Some(fun) => {
                // TODO: Error when argument count mismatch
                let args = self.arguments.iter().map(|ref arg| arg.evaluate(context)).collect();

                fun.evaluate(context, args)
            },
            None => fail!("throw UnknownXPathFunctionException(_name)"),
        }
    }
}

pub struct ExpressionLiteral {
    pub value: XPathValue,
}

impl XPathExpression for ExpressionLiteral {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        self.value.clone()
    }
}

pub struct ExpressionMath {
    left:  Box<XPathExpression>,
    right: Box<XPathExpression>,
    operation: fn(f64, f64) -> f64,
}

fn      add(a: f64, b: f64) -> f64 {a + b}
fn subtract(a: f64, b: f64) -> f64 {a - b}
fn multiply(a: f64, b: f64) -> f64 {a * b}
fn   divide(a: f64, b: f64) -> f64 {a / b}
fn  modulus(a: f64, b: f64) -> f64 {a % b}

impl ExpressionMath {
    pub fn addition(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: add}
    }

    pub fn subtraction(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: subtract}
    }

    pub fn multiplication(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: multiply}
    }

    pub fn division(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: divide}
    }

    pub fn remainder(left: Box<XPathExpression>, right: Box<XPathExpression>) -> ExpressionMath {
        ExpressionMath{left: left, right: right, operation: modulus}
    }
}

impl XPathExpression for ExpressionMath {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        let left = self.left.evaluate(context);
        let right = self.right.evaluate(context);
        let op = self.operation;
        return Number(op(left.number(), right.number()));
    }
}

pub struct ExpressionNegation {
    expression: Box<XPathExpression>,
}

impl XPathExpression for ExpressionNegation {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        let result = self.expression.evaluate(context);
        return Number(-result.number());
    }
}

pub struct ExpressionOr {
    left:  Box<XPathExpression>,
    right: Box<XPathExpression>,
}

impl XPathExpression for ExpressionOr {
    fn evaluate(&self, context: &XPathEvaluationContext) -> XPathValue {
        return Boolean(self.left.evaluate(context).boolean() ||
                       self.right.evaluate(context).boolean())
    }
}
<|endoftext|>


<commit_before>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate syntax;

use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
use rustc::session::{config, CompileIncomplete, Session};
use rustc::session::config::{ErrorOutputType, Input};
use std::path::PathBuf;
use std::process::Command;
use syntax::ast;

struct ClippyCompilerCalls {
    default: RustcDefaultCalls,
    run_lints: bool,
}

impl ClippyCompilerCalls {
    fn new(run_lints: bool) -> Self {
        Self {
            default: RustcDefaultCalls,
            run_lints: run_lints,
        }
    }
}

impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default
            .early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default
            .no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        crate_stores: &rustc::middle::cstore::CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default
            .late_callback(matches, sess, crate_stores, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);

        if self.run_lints {
            let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
            control.after_parse.callback = Box::new(move |state| {
                {
                    let mut registry = rustc_plugin::registry::Registry::new(
                        state.session,
                        state
                            .krate
                            .as_ref()
                            .expect(
                                "at this compilation stage \
                                 the krate must be parsed",
                            )
                            .span,
                    );
                    registry.args_hidden = Some(Vec::new());
                    clippy_lints::register_plugins(&mut registry);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, to) in lint_groups {
                        ls.register_group(Some(sess), true, name, to);
                    }

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                }
                old(state);
            });
        }

        control
    }
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    use std::env;

    if env::var("CLIPPY_DOGFOOD").is_ok() {
        panic!("yummy");
    }

    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
        format!("{}/toolchains/{}", home, toolchain)
    } else {
        option_env!("SYSROOT")
            .map(|s| s.to_owned())
            .or_else(|| {
                Command::new("rustc")
                    .arg("--print")
                    .arg("sysroot")
                    .output()
                    .ok()
                    .and_then(|out| String::from_utf8(out.stdout).ok())
                    .map(|s| s.trim().to_owned())
            })
            .expect(
                "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
            )
    };

    rustc_driver::in_rustc_thread(|| {
        // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
        // We're invoking the compiler programatically, so we ignore this/
        let mut orig_args: Vec<String> = env::args().collect();
        if orig_args[1] == "rustc" {
            // we still want to be able to invoke it normally though
            orig_args.remove(1);
        }
        // this conditional check for the --sysroot flag is there so users can call
        // `clippy_driver` directly
        // without having to pass --sysroot or anything
        let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
            orig_args.clone()
        } else {
            orig_args.clone().into_iter()
                .chain(Some("--sysroot".to_owned()))
                .chain(Some(sys_root))
                .collect()
        };

        // this check ensures that dependencies are built but not linted and the final
        // crate is
        // linted but not built
        let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") ||
            orig_args.iter().any(|s| s == "--emit=metadata");

        if clippy_enabled {
            args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
        }

        let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
        let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
        if let Err(CompileIncomplete::Errored(_)) = result {
            std::process::exit(1);
        }
    }).expect("rustc_thread failed");
}
<commit_msg>Avoid panicking when no arg is given to clippy_driver<commit_after>// error-pattern:yummy
#![feature(box_syntax)]
#![feature(rustc_private)]
#![allow(unknown_lints, missing_docs_in_private_items)]

extern crate clippy_lints;
extern crate getopts;
extern crate rustc;
extern crate rustc_driver;
extern crate rustc_errors;
extern crate rustc_plugin;
extern crate syntax;

use rustc_driver::{driver, Compilation, CompilerCalls, RustcDefaultCalls};
use rustc::session::{config, CompileIncomplete, Session};
use rustc::session::config::{ErrorOutputType, Input};
use std::path::PathBuf;
use std::process::Command;
use syntax::ast;

struct ClippyCompilerCalls {
    default: RustcDefaultCalls,
    run_lints: bool,
}

impl ClippyCompilerCalls {
    fn new(run_lints: bool) -> Self {
        Self {
            default: RustcDefaultCalls,
            run_lints: run_lints,
        }
    }
}

impl<'a> CompilerCalls<'a> for ClippyCompilerCalls {
    fn early_callback(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        descriptions: &rustc_errors::registry::Registry,
        output: ErrorOutputType,
    ) -> Compilation {
        self.default
            .early_callback(matches, sopts, cfg, descriptions, output)
    }
    fn no_input(
        &mut self,
        matches: &getopts::Matches,
        sopts: &config::Options,
        cfg: &ast::CrateConfig,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
        descriptions: &rustc_errors::registry::Registry,
    ) -> Option<(Input, Option<PathBuf>)> {
        self.default
            .no_input(matches, sopts, cfg, odir, ofile, descriptions)
    }
    fn late_callback(
        &mut self,
        matches: &getopts::Matches,
        sess: &Session,
        crate_stores: &rustc::middle::cstore::CrateStore,
        input: &Input,
        odir: &Option<PathBuf>,
        ofile: &Option<PathBuf>,
    ) -> Compilation {
        self.default
            .late_callback(matches, sess, crate_stores, input, odir, ofile)
    }
    fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> driver::CompileController<'a> {
        let mut control = self.default.build_controller(sess, matches);

        if self.run_lints {
            let old = std::mem::replace(&mut control.after_parse.callback, box |_| {});
            control.after_parse.callback = Box::new(move |state| {
                {
                    let mut registry = rustc_plugin::registry::Registry::new(
                        state.session,
                        state
                            .krate
                            .as_ref()
                            .expect(
                                "at this compilation stage \
                                 the krate must be parsed",
                            )
                            .span,
                    );
                    registry.args_hidden = Some(Vec::new());
                    clippy_lints::register_plugins(&mut registry);

                    let rustc_plugin::registry::Registry {
                        early_lint_passes,
                        late_lint_passes,
                        lint_groups,
                        llvm_passes,
                        attributes,
                        ..
                    } = registry;
                    let sess = &state.session;
                    let mut ls = sess.lint_store.borrow_mut();
                    for pass in early_lint_passes {
                        ls.register_early_pass(Some(sess), true, pass);
                    }
                    for pass in late_lint_passes {
                        ls.register_late_pass(Some(sess), true, pass);
                    }

                    for (name, to) in lint_groups {
                        ls.register_group(Some(sess), true, name, to);
                    }

                    sess.plugin_llvm_passes.borrow_mut().extend(llvm_passes);
                    sess.plugin_attributes.borrow_mut().extend(attributes);
                }
                old(state);
            });
        }

        control
    }
}

#[allow(print_stdout)]
fn show_version() {
    println!("{}", env!("CARGO_PKG_VERSION"));
}

pub fn main() {
    use std::env;

    if env::var("CLIPPY_DOGFOOD").is_ok() {
        panic!("yummy");
    }

    if std::env::args().any(|a| a == "--version" || a == "-V") {
        show_version();
        return;
    }

    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
    let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) {
        format!("{}/toolchains/{}", home, toolchain)
    } else {
        option_env!("SYSROOT")
            .map(|s| s.to_owned())
            .or_else(|| {
                Command::new("rustc")
                    .arg("--print")
                    .arg("sysroot")
                    .output()
                    .ok()
                    .and_then(|out| String::from_utf8(out.stdout).ok())
                    .map(|s| s.trim().to_owned())
            })
            .expect(
                "need to specify SYSROOT env var during clippy compilation, or use rustup or multirust",
            )
    };

    rustc_driver::in_rustc_thread(|| {
        // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
        // We're invoking the compiler programatically, so we ignore this/
        let mut orig_args: Vec<String> = env::args().collect();
        if orig_args.len() <= 1 {
            std::process::exit(1);
        }
        if orig_args[1] == "rustc" {
            // we still want to be able to invoke it normally though
            orig_args.remove(1);
        }
        // this conditional check for the --sysroot flag is there so users can call
        // `clippy_driver` directly
        // without having to pass --sysroot or anything
        let mut args: Vec<String> = if orig_args.iter().any(|s| s == "--sysroot") {
            orig_args.clone()
        } else {
            orig_args.clone().into_iter()
                .chain(Some("--sysroot".to_owned()))
                .chain(Some(sys_root))
                .collect()
        };

        // this check ensures that dependencies are built but not linted and the final
        // crate is
        // linted but not built
        let clippy_enabled = env::var("CLIPPY_TESTS").ok().map_or(false, |val| val == "true") ||
            orig_args.iter().any(|s| s == "--emit=metadata");

        if clippy_enabled {
            args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
        }

        let mut ccc = ClippyCompilerCalls::new(clippy_enabled);
        let (result, _) = rustc_driver::run_compiler(&args, &mut ccc, None, None);
        if let Err(CompileIncomplete::Errored(_)) = result {
            std::process::exit(1);
        }
    }).expect("rustc_thread failed");
}
<|endoftext|>


<commit_before>use std::fs::create_dir_all;
use std::path::Path;
use std::process::Command;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};

use anyhow::Result;
use clap::Clap;
use simplelog::{Config, LevelFilter, SimpleLogger};

use pueue::message::Message;
use pueue::settings::Settings;
use pueue::state::State;

use crate::cli::CliArguments;
use crate::socket::accept_incoming;
use crate::task_handler::TaskHandler;

mod cli;
mod instructions;
mod platform;
mod response_helper;
mod socket;
mod streaming;
mod task_handler;

#[async_std::main]
async fn main() -> Result<()> {
    // Parse commandline options.
    let opt = CliArguments::parse();

    if opt.daemonize {
        fork_daemon(&opt)?;
    }

    // Set the verbosity level of the logger.
    let level = match opt.verbose {
        0 => LevelFilter::Error,
        1 => LevelFilter::Warn,
        2 => LevelFilter::Info,
        _ => LevelFilter::Debug,
    };
    SimpleLogger::init(level, Config::default()).unwrap();

    // Try to read settings from the configuration file.
    let settings = match Settings::read(false, &opt.config) {
        Ok(settings) => settings,
        Err(_) => {
            // There's something wrong with the config file or something's missing.
            // Try to read the config and fill missing values with defaults.
            // This might be possible on version upgrade or first run.
            let settings = Settings::new(false, &opt.config)?;

            // Since we needed to add values to the configuration, we have to save it.
            // This also creates the save file in case it didn't exist yet.
            if let Err(error) = settings.save(&opt.config) {
                println!("Failed saving config file.");
                println!("{:?}", error);
            }
            settings
        }
    };

    init_directories(&settings.shared.pueue_directory);

    let state = State::new(&settings, opt.config.clone());
    let state = Arc::new(Mutex::new(state));

    let (sender, receiver) = channel();
    let mut task_handler = TaskHandler::new(state.clone(), receiver);

    // This section handles Shutdown via SigTerm/SigInt process signals
    // 1. Remove the unix socket (if it exists).
    // 2. Notify the TaskHandler, so it can shutdown gracefully.
    //
    // The actual program exit will be done via the TaskHandler.
    let unix_socket_path = settings.shared.unix_socket_path.clone();
    let sender_clone = sender.clone();
    ctrlc::set_handler(move || {
        // Clean up the unix socket if we're using it and it exists.
        if settings.shared.use_unix_socket && std::path::PathBuf::from(&unix_socket_path).exists() {
            std::fs::remove_file(&unix_socket_path)
                .expect("Failed to remove unix socket on shutdown");
        }

        // Notify the task handler
        sender_clone
            .send(Message::DaemonShutdown)
            .expect("Failed to send Message to TaskHandler on Shutdown");
    })?;

    let orig_hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |panic_info| {
        // invoke the default handler and exit the process
        orig_hook(panic_info);
        std::process::exit(1);
    }));

    std::thread::spawn(move || {
        task_handler.run();
    });

    accept_incoming(sender, state.clone()).await?;

    Ok(())
}

/// Initialize all directories needed for normal operation.
fn init_directories(path: &str) {
    // Pueue base path
    let pueue_dir = Path::new(path);
    if !pueue_dir.exists() {
        if let Err(error) = create_dir_all(&pueue_dir) {
            panic!(
                "Failed to create main directory at {:?} error: {:?}",
                pueue_dir, error
            );
        }
    }

    // Task log dir
    let log_dir = pueue_dir.join("log");
    if !log_dir.exists() {
        if let Err(error) = create_dir_all(&log_dir) {
            panic!(
                "Failed to create log directory at {:?} error: {:?}",
                log_dir, error
            );
        }
    }

    // Task log dir
    let logs_dir = pueue_dir.join("task_logs");
    if !logs_dir.exists() {
        if let Err(error) = create_dir_all(&logs_dir) {
            panic!(
                "Failed to create task logs directory at {:?} error: {:?}",
                logs_dir, error
            );
        }
    }
}

/// This is a simple and cheap custom fork method.
/// Simply spawn a new child with identical arguments and exit right away.
fn fork_daemon(opt: &CliArguments) -> Result<()> {
    let mut arguments = Vec::<String>::new();

    if let Some(config) = &opt.config {
        arguments.push("--config".to_string());
        arguments.push(config.to_string_lossy().into_owned());
    }

    if opt.verbose > 0 {
        arguments.push("-".to_string() + &" ".repeat(opt.verbose as usize));
    }

    Command::new("pueued").args(&arguments).spawn()?;

    println!("Pueued is now running in the background");
    std::process::exit(0);
}
<commit_msg>Better daemon fork code flow<commit_after>use std::fs::create_dir_all;
use std::path::Path;
use std::process::Command;
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};

use anyhow::Result;
use clap::Clap;
use simplelog::{Config, LevelFilter, SimpleLogger};

use pueue::message::Message;
use pueue::settings::Settings;
use pueue::state::State;

use crate::cli::CliArguments;
use crate::socket::accept_incoming;
use crate::task_handler::TaskHandler;

mod cli;
mod instructions;
mod platform;
mod response_helper;
mod socket;
mod streaming;
mod task_handler;

#[async_std::main]
async fn main() -> Result<()> {
    // Parse commandline options.
    let opt = CliArguments::parse();

    if opt.daemonize {
        return fork_daemon(&opt);
    }

    // Set the verbosity level of the logger.
    let level = match opt.verbose {
        0 => LevelFilter::Error,
        1 => LevelFilter::Warn,
        2 => LevelFilter::Info,
        _ => LevelFilter::Debug,
    };
    SimpleLogger::init(level, Config::default()).unwrap();

    // Try to read settings from the configuration file.
    let settings = match Settings::read(false, &opt.config) {
        Ok(settings) => settings,
        Err(_) => {
            // There's something wrong with the config file or something's missing.
            // Try to read the config and fill missing values with defaults.
            // This might be possible on version upgrade or first run.
            let settings = Settings::new(false, &opt.config)?;

            // Since we needed to add values to the configuration, we have to save it.
            // This also creates the save file in case it didn't exist yet.
            if let Err(error) = settings.save(&opt.config) {
                println!("Failed saving config file.");
                println!("{:?}", error);
            }
            settings
        }
    };

    init_directories(&settings.shared.pueue_directory);

    let state = State::new(&settings, opt.config.clone());
    let state = Arc::new(Mutex::new(state));

    let (sender, receiver) = channel();
    let mut task_handler = TaskHandler::new(state.clone(), receiver);

    // This section handles Shutdown via SigTerm/SigInt process signals
    // 1. Remove the unix socket (if it exists).
    // 2. Notify the TaskHandler, so it can shutdown gracefully.
    //
    // The actual program exit will be done via the TaskHandler.
    let unix_socket_path = settings.shared.unix_socket_path.clone();
    let sender_clone = sender.clone();
    ctrlc::set_handler(move || {
        // Clean up the unix socket if we're using it and it exists.
        if settings.shared.use_unix_socket && std::path::PathBuf::from(&unix_socket_path).exists() {
            std::fs::remove_file(&unix_socket_path)
                .expect("Failed to remove unix socket on shutdown");
        }

        // Notify the task handler
        sender_clone
            .send(Message::DaemonShutdown)
            .expect("Failed to send Message to TaskHandler on Shutdown");
    })?;

    let orig_hook = std::panic::take_hook();
    std::panic::set_hook(Box::new(move |panic_info| {
        // invoke the default handler and exit the process
        orig_hook(panic_info);
        std::process::exit(1);
    }));

    std::thread::spawn(move || {
        task_handler.run();
    });

    accept_incoming(sender, state.clone()).await?;

    Ok(())
}

/// Initialize all directories needed for normal operation.
fn init_directories(path: &str) {
    // Pueue base path
    let pueue_dir = Path::new(path);
    if !pueue_dir.exists() {
        if let Err(error) = create_dir_all(&pueue_dir) {
            panic!(
                "Failed to create main directory at {:?} error: {:?}",
                pueue_dir, error
            );
        }
    }

    // Task log dir
    let log_dir = pueue_dir.join("log");
    if !log_dir.exists() {
        if let Err(error) = create_dir_all(&log_dir) {
            panic!(
                "Failed to create log directory at {:?} error: {:?}",
                log_dir, error
            );
        }
    }

    // Task log dir
    let logs_dir = pueue_dir.join("task_logs");
    if !logs_dir.exists() {
        if let Err(error) = create_dir_all(&logs_dir) {
            panic!(
                "Failed to create task logs directory at {:?} error: {:?}",
                logs_dir, error
            );
        }
    }
}

/// This is a simple and cheap custom fork method.
/// Simply spawn a new child with identical arguments and exit right away.
fn fork_daemon(opt: &CliArguments) -> Result<()> {
    let mut arguments = Vec::<String>::new();

    if let Some(config) = &opt.config {
        arguments.push("--config".to_string());
        arguments.push(config.to_string_lossy().into_owned());
    }

    if opt.verbose > 0 {
        arguments.push("-".to_string() + &" ".repeat(opt.verbose as usize));
    }

    Command::new("pueued").args(&arguments).spawn()?;

    println!("Pueued is now running in the background");
    Ok(())
}
<|endoftext|>