<commit_before>use crate::base::dimension::{Dim, DimName, Dynamic, U1};
use crate::base::matrix_slice::{SliceStorage, SliceStorageMut};
use crate::base::{MatrixSliceMN, MatrixSliceMutMN, Scalar};

use num_rational::Ratio;
/*
 *
 * Slice constructors.
 *
 */
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
    MatrixSliceMN<'a, N, R, C, RStride, CStride>
{
    /// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// This method is unsafe because the input data array is not checked to contain enough elements.
    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub unsafe fn from_slice_with_strides_generic_unchecked(
        data: &'a [N],
        start: usize,
        nrows: R,
        ncols: C,
        rstride: RStride,
        cstride: CStride,
    ) -> Self
    {
        let data = SliceStorage::from_raw_parts(
            data.as_ptr().offset(start as isize),
            (nrows, ncols),
            (rstride, cstride),
        );
        Self::from_data(data)
    }

    /// Creates a matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// Panics if the input data array dose not contain enough elements.
    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub fn from_slice_with_strides_generic(
        data: &'a [N],
        nrows: R,
        ncols: C,
        rstride: RStride,
        cstride: CStride,
    ) -> Self
    {
        // NOTE: The assertion implements the following formula, but without subtractions to avoid
        // underflow panics:
        //      len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1
        assert!(
            data.len() + cstride.value() + rstride.value()
                >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1,
            "Matrix slice: input data buffer to small."
        );

        unsafe {
            Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride)
        }
    }
}

impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
    MatrixSliceMutMN<'a, N, R, C, RStride, CStride>
{
    /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// This method is unsafe because the input data array is not checked to contain enough elements.
    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub unsafe fn from_slice_with_strides_generic_unchecked(
        data: &'a mut [N],
        start: usize,
        nrows: R,
        ncols: C,
        rstride: RStride,
        cstride: CStride,
    ) -> Self
    {
        let data = SliceStorageMut::from_raw_parts(
            data.as_mut_ptr().offset(start as isize),
            (nrows, ncols),
            (rstride, cstride),
        );
        Self::from_data(data)
    }

    /// Creates a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// Panics if the input data array dose not contain enough elements.
    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub fn from_slice_with_strides_generic(
        data: &'a mut [N],
        nrows: R,
        ncols: C,
        rstride: RStride,
        cstride: CStride,
    ) -> Self
    {
        // NOTE: The assertion implements the following formula, but without subtractions to avoid
        // underflow panics:
        //      len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1
        assert!(
            data.len() + cstride.value() + rstride.value()
                >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1,
            "Matrix slice: input data buffer to small."
        );

        assert!({
            let nrows = nrows.value();
            let ncols = ncols.value();
            let rstride = rstride.value();
            let cstride = cstride.value();

            // `Storage::linear_index`
            let index = |i, j| (i * rstride) + (j * cstride);

            // The final condition of each arm is an expression in the form:
            //    index(i₀, j₀) != index(i₁, j₁)
            // If this expression is `false`, then the values (i₀, j₀)
            // and (i₁, j₁) are concrete examples of indices that would
            // collide if the matrix was actually constructed.
            nrows * ncols <= 1 ||
                match (rstride, cstride) {
                    (0, 0) => index(0, 0) != index(nrows - 1, ncols - 1),
                    (0, _) => nrows <= 1 || index(0, 0) != index(nrows - 1, 0),
                    (_, 0) => ncols <= 1 || index(0, 0) != index(0, ncols - 1),
                    (_, _) => {
                        let ratio = Ratio::new(rstride, cstride);
                        let numer = *ratio.numer();
                        let denom = *ratio.denom();

                        nrows <= denom || ncols <= numer
                            || index(0, numer) != index(denom, 0)
                    }
                }
            },
            "Matrix slice: dimensions and strides result in aliased indices.");

        unsafe {
            Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride)
        }
    }
}

impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMN<'a, N, R, C> {
    /// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances.
    ///
    /// This method is unsafe because the input data array is not checked to contain enough elements.
    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub unsafe fn from_slice_generic_unchecked(
        data: &'a [N],
        start: usize,
        nrows: R,
        ncols: C,
    ) -> Self
    {
        Self::from_slice_with_strides_generic_unchecked(data, start, nrows, ncols, U1, nrows)
    }

    /// Creates a matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// Panics if the input data array dose not contain enough elements.
    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub fn from_slice_generic(data: &'a [N], nrows: R, ncols: C) -> Self {
        Self::from_slice_with_strides_generic(data, nrows, ncols, U1, nrows)
    }
}

impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, N, R, C> {
    /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances.
    ///
    /// This method is unsafe because the input data array is not checked to contain enough elements.
    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub unsafe fn from_slice_generic_unchecked(
        data: &'a mut [N],
        start: usize,
        nrows: R,
        ncols: C,
    ) -> Self
    {
        Self::from_slice_with_strides_generic_unchecked(data, start, nrows, ncols, U1, nrows)
    }

    /// Creates a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// Panics if the input data array dose not contain enough elements.
    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub fn from_slice_generic(data: &'a mut [N], nrows: R, ncols: C) -> Self {
        Self::from_slice_with_strides_generic(data, nrows, ncols, U1, nrows)
    }
}

macro_rules! impl_constructors(
    ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
        impl<'a, N: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMN<'a, N, $($Dims),*> {
            /// Creates a new matrix slice from the given data array.
            ///
            /// Panics if `data` does not contain enough elements.
            #[inline]
            pub fn from_slice(data: &'a [N], $($args: usize),*) -> Self {
                Self::from_slice_generic(data, $($gargs),*)
            }

            /// Creates, without bound checking, a new matrix slice from the given data array.
            #[inline]
            pub unsafe fn from_slice_unchecked(data: &'a [N], start: usize, $($args: usize),*) -> Self {
                Self::from_slice_generic_unchecked(data, start, $($gargs),*)
            }
        }

        impl<'a, N: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMN<'a, N, $($Dims,)* Dynamic, Dynamic> {
            /// Creates a new matrix slice with the specified strides from the given data array.
            ///
            /// Panics if `data` does not contain enough elements.
            #[inline]
            pub fn from_slice_with_strides(data: &'a [N], $($args: usize,)* rstride: usize, cstride: usize) -> Self {
                Self::from_slice_with_strides_generic(data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
            }

            /// Creates, without bound checking, a new matrix slice with the specified strides from the given data array.
            #[inline]
            pub unsafe fn from_slice_with_strides_unchecked(data: &'a [N], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self {
                Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
            }
        }
    }
);

// FIXME: this is not very pretty. We could find a better call syntax.
impl_constructors!(R, C;                         // Arguments for Matrix<N, ..., S>
                   => R: DimName, => C: DimName; // Type parameters for impl<N, ..., S>
                   R::name(), C::name();         // Arguments for `_generic` constructors.
                   ); // Arguments for non-generic constructors.

impl_constructors!(R, Dynamic;
                   => R: DimName;
                   R::name(), Dynamic::new(ncols);
                   ncols);

impl_constructors!(Dynamic, C;
                   => C: DimName;
                   Dynamic::new(nrows), C::name();
                   nrows);

impl_constructors!(Dynamic, Dynamic;
                   ;
                   Dynamic::new(nrows), Dynamic::new(ncols);
                   nrows, ncols);

macro_rules! impl_constructors_mut(
    ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
        impl<'a, N: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, N, $($Dims),*> {
            /// Creates a new mutable matrix slice from the given data array.
            ///
            /// Panics if `data` does not contain enough elements.
            #[inline]
            pub fn from_slice(data: &'a mut [N], $($args: usize),*) -> Self {
                Self::from_slice_generic(data, $($gargs),*)
            }

            /// Creates, without bound checking, a new mutable matrix slice from the given data array.
            #[inline]
            pub unsafe fn from_slice_unchecked(data: &'a mut [N], start: usize, $($args: usize),*) -> Self {
                Self::from_slice_generic_unchecked(data, start, $($gargs),*)
            }
        }

        impl<'a, N: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMutMN<'a, N, $($Dims,)* Dynamic, Dynamic> {
            /// Creates a new mutable matrix slice with the specified strides from the given data array.
            ///
            /// Panics if `data` does not contain enough elements.
            #[inline]
            pub fn from_slice_with_strides_mut(data: &'a mut [N], $($args: usize,)* rstride: usize, cstride: usize) -> Self {
                Self::from_slice_with_strides_generic(
                    data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
            }

            /// Creates, without bound checking, a new mutable matrix slice with the specified strides from the given data array.
            #[inline]
            pub unsafe fn from_slice_with_strides_unchecked(data: &'a mut [N], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self {
                Self::from_slice_with_strides_generic_unchecked(
                    data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
            }
        }
    }
);

// FIXME: this is not very pretty. We could find a better call syntax.
impl_constructors_mut!(R, C;                         // Arguments for Matrix<N, ..., S>
                       => R: DimName, => C: DimName; // Type parameters for impl<N, ..., S>
                       R::name(), C::name();         // Arguments for `_generic` constructors.
                       ); // Arguments for non-generic constructors.

impl_constructors_mut!(R, Dynamic;
                       => R: DimName;
                       R::name(), Dynamic::new(ncols);
                       ncols);

impl_constructors_mut!(Dynamic, C;
                       => C: DimName;
                       Dynamic::new(nrows), C::name();
                       nrows);

impl_constructors_mut!(Dynamic, Dynamic;
                       ;
                       Dynamic::new(nrows), Dynamic::new(ncols);
                       nrows, ncols);
<commit_msg>simplify anti-aliasing assertion<commit_after>use crate::base::dimension::{Dim, DimName, Dynamic, U1};
use crate::base::matrix_slice::{SliceStorage, SliceStorageMut};
use crate::base::{MatrixSliceMN, MatrixSliceMutMN, Scalar};

use num_rational::Ratio;
/*
 *
 * Slice constructors.
 *
 */
impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
    MatrixSliceMN<'a, N, R, C, RStride, CStride>
{
    /// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// This method is unsafe because the input data array is not checked to contain enough elements.
    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub unsafe fn from_slice_with_strides_generic_unchecked(
        data: &'a [N],
        start: usize,
        nrows: R,
        ncols: C,
        rstride: RStride,
        cstride: CStride,
    ) -> Self
    {
        let data = SliceStorage::from_raw_parts(
            data.as_ptr().offset(start as isize),
            (nrows, ncols),
            (rstride, cstride),
        );
        Self::from_data(data)
    }

    /// Creates a matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// Panics if the input data array dose not contain enough elements.
    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub fn from_slice_with_strides_generic(
        data: &'a [N],
        nrows: R,
        ncols: C,
        rstride: RStride,
        cstride: CStride,
    ) -> Self
    {
        // NOTE: The assertion implements the following formula, but without subtractions to avoid
        // underflow panics:
        //      len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1
        assert!(
            data.len() + cstride.value() + rstride.value()
                >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1,
            "Matrix slice: input data buffer to small."
        );

        unsafe {
            Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride)
        }
    }
}

impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim>
    MatrixSliceMutMN<'a, N, R, C, RStride, CStride>
{
    /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// This method is unsafe because the input data array is not checked to contain enough elements.
    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub unsafe fn from_slice_with_strides_generic_unchecked(
        data: &'a mut [N],
        start: usize,
        nrows: R,
        ncols: C,
        rstride: RStride,
        cstride: CStride,
    ) -> Self
    {
        let data = SliceStorageMut::from_raw_parts(
            data.as_mut_ptr().offset(start as isize),
            (nrows, ncols),
            (rstride, cstride),
        );
        Self::from_data(data)
    }

    /// Creates a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// Panics if the input data array dose not contain enough elements.
    /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub fn from_slice_with_strides_generic(
        data: &'a mut [N],
        nrows: R,
        ncols: C,
        rstride: RStride,
        cstride: CStride,
    ) -> Self
    {
        // NOTE: The assertion implements the following formula, but without subtractions to avoid
        // underflow panics:
        //      len >= (ncols - 1) * cstride + (nrows - 1) * rstride + 1
        assert!(
            data.len() + cstride.value() + rstride.value()
                >= ncols.value() * cstride.value() + nrows.value() * rstride.value() + 1,
            "Matrix slice: input data buffer to small."
        );

        assert!({
            let nrows = nrows.value();
            let ncols = ncols.value();
            let rstride = rstride.value();
            let cstride = cstride.value();

            nrows * ncols <= 1 ||
                match (rstride, cstride) {
                    (0, 0) => false,      // otherwise: matrix[(0, 0)] == index[(nrows - 1, ncols - 1)],
                    (0, _) => nrows <= 1, // otherwise: matrix[(0, 0)] == index[(nrows - 1, 0)],
                    (_, 0) => ncols <= 1, // otherwise: matrix[(0, 0)] == index[(0, ncols - 1)],
                    (_, _) => {           // otherwise: matrix[(0, numer)] == index[(denom, 0)]
                        let ratio = Ratio::new(rstride, cstride);
                        nrows <= *ratio.denom() || ncols <= *ratio.numer()
                    }
                }
            },
            "Matrix slice: dimensions and strides result in aliased indices.");

        unsafe {
            Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride)
        }
    }
}

impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMN<'a, N, R, C> {
    /// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances.
    ///
    /// This method is unsafe because the input data array is not checked to contain enough elements.
    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub unsafe fn from_slice_generic_unchecked(
        data: &'a [N],
        start: usize,
        nrows: R,
        ncols: C,
    ) -> Self
    {
        Self::from_slice_with_strides_generic_unchecked(data, start, nrows, ncols, U1, nrows)
    }

    /// Creates a matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// Panics if the input data array dose not contain enough elements.
    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub fn from_slice_generic(data: &'a [N], nrows: R, ncols: C) -> Self {
        Self::from_slice_with_strides_generic(data, nrows, ncols, U1, nrows)
    }
}

impl<'a, N: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, N, R, C> {
    /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances.
    ///
    /// This method is unsafe because the input data array is not checked to contain enough elements.
    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub unsafe fn from_slice_generic_unchecked(
        data: &'a mut [N],
        start: usize,
        nrows: R,
        ncols: C,
    ) -> Self
    {
        Self::from_slice_with_strides_generic_unchecked(data, start, nrows, ncols, U1, nrows)
    }

    /// Creates a mutable matrix slice from an array and with dimensions and strides specified by generic types instances.
    ///
    /// Panics if the input data array dose not contain enough elements.
    /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`.
    #[inline]
    pub fn from_slice_generic(data: &'a mut [N], nrows: R, ncols: C) -> Self {
        Self::from_slice_with_strides_generic(data, nrows, ncols, U1, nrows)
    }
}

macro_rules! impl_constructors(
    ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
        impl<'a, N: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMN<'a, N, $($Dims),*> {
            /// Creates a new matrix slice from the given data array.
            ///
            /// Panics if `data` does not contain enough elements.
            #[inline]
            pub fn from_slice(data: &'a [N], $($args: usize),*) -> Self {
                Self::from_slice_generic(data, $($gargs),*)
            }

            /// Creates, without bound checking, a new matrix slice from the given data array.
            #[inline]
            pub unsafe fn from_slice_unchecked(data: &'a [N], start: usize, $($args: usize),*) -> Self {
                Self::from_slice_generic_unchecked(data, start, $($gargs),*)
            }
        }

        impl<'a, N: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMN<'a, N, $($Dims,)* Dynamic, Dynamic> {
            /// Creates a new matrix slice with the specified strides from the given data array.
            ///
            /// Panics if `data` does not contain enough elements.
            #[inline]
            pub fn from_slice_with_strides(data: &'a [N], $($args: usize,)* rstride: usize, cstride: usize) -> Self {
                Self::from_slice_with_strides_generic(data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
            }

            /// Creates, without bound checking, a new matrix slice with the specified strides from the given data array.
            #[inline]
            pub unsafe fn from_slice_with_strides_unchecked(data: &'a [N], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self {
                Self::from_slice_with_strides_generic_unchecked(data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
            }
        }
    }
);

// FIXME: this is not very pretty. We could find a better call syntax.
impl_constructors!(R, C;                         // Arguments for Matrix<N, ..., S>
                   => R: DimName, => C: DimName; // Type parameters for impl<N, ..., S>
                   R::name(), C::name();         // Arguments for `_generic` constructors.
                   ); // Arguments for non-generic constructors.

impl_constructors!(R, Dynamic;
                   => R: DimName;
                   R::name(), Dynamic::new(ncols);
                   ncols);

impl_constructors!(Dynamic, C;
                   => C: DimName;
                   Dynamic::new(nrows), C::name();
                   nrows);

impl_constructors!(Dynamic, Dynamic;
                   ;
                   Dynamic::new(nrows), Dynamic::new(ncols);
                   nrows, ncols);

macro_rules! impl_constructors_mut(
    ($($Dims: ty),*; $(=> $DimIdent: ident: $DimBound: ident),*; $($gargs: expr),*; $($args: ident),*) => {
        impl<'a, N: Scalar, $($DimIdent: $DimBound),*> MatrixSliceMutMN<'a, N, $($Dims),*> {
            /// Creates a new mutable matrix slice from the given data array.
            ///
            /// Panics if `data` does not contain enough elements.
            #[inline]
            pub fn from_slice(data: &'a mut [N], $($args: usize),*) -> Self {
                Self::from_slice_generic(data, $($gargs),*)
            }

            /// Creates, without bound checking, a new mutable matrix slice from the given data array.
            #[inline]
            pub unsafe fn from_slice_unchecked(data: &'a mut [N], start: usize, $($args: usize),*) -> Self {
                Self::from_slice_generic_unchecked(data, start, $($gargs),*)
            }
        }

        impl<'a, N: Scalar, $($DimIdent: $DimBound, )*> MatrixSliceMutMN<'a, N, $($Dims,)* Dynamic, Dynamic> {
            /// Creates a new mutable matrix slice with the specified strides from the given data array.
            ///
            /// Panics if `data` does not contain enough elements.
            #[inline]
            pub fn from_slice_with_strides_mut(data: &'a mut [N], $($args: usize,)* rstride: usize, cstride: usize) -> Self {
                Self::from_slice_with_strides_generic(
                    data, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
            }

            /// Creates, without bound checking, a new mutable matrix slice with the specified strides from the given data array.
            #[inline]
            pub unsafe fn from_slice_with_strides_unchecked(data: &'a mut [N], start: usize, $($args: usize,)* rstride: usize, cstride: usize) -> Self {
                Self::from_slice_with_strides_generic_unchecked(
                    data, start, $($gargs,)* Dynamic::new(rstride), Dynamic::new(cstride))
            }
        }
    }
);

// FIXME: this is not very pretty. We could find a better call syntax.
impl_constructors_mut!(R, C;                         // Arguments for Matrix<N, ..., S>
                       => R: DimName, => C: DimName; // Type parameters for impl<N, ..., S>
                       R::name(), C::name();         // Arguments for `_generic` constructors.
                       ); // Arguments for non-generic constructors.

impl_constructors_mut!(R, Dynamic;
                       => R: DimName;
                       R::name(), Dynamic::new(ncols);
                       ncols);

impl_constructors_mut!(Dynamic, C;
                       => C: DimName;
                       Dynamic::new(nrows), C::name();
                       nrows);

impl_constructors_mut!(Dynamic, Dynamic;
                       ;
                       Dynamic::new(nrows), Dynamic::new(ncols);
                       nrows, ncols);
<|endoftext|>


<commit_before>use std::fmt;
use std::fmt::{Show,Formatter};
use std::str;
use std::io::{UserDir,AllPermissions};
use std::io::fs::{mkdir_recursive,rmdir_recursive,chmod};
use serialize::{Encodable,Encoder};

use core::source::{Location, Local, Remote};
use util::{CargoResult, ChainError, ProcessBuilder, process, human};

#[deriving(PartialEq,Clone,Encodable)]
pub enum GitReference {
    Master,
    Other(String)
}

impl GitReference {
    pub fn for_str<S: Str>(string: S) -> GitReference {
        if string.as_slice() == "master" {
            Master
        } else {
            Other(string.as_slice().to_str())
        }
    }
}

impl Str for GitReference {
    fn as_slice<'a>(&'a self) -> &'a str {
        match *self {
            Master => "master",
            Other(ref string) => string.as_slice()
        }
    }
}

impl Show for GitReference {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

macro_rules! git(
    ($config:expr, $str:expr, $($rest:expr),*) => (
        try!(git_inherit(&$config, format!($str, $($rest),*)))
    );

    ($config:expr, $str:expr) => (
        try!(git_inherit(&$config, format!($str)))
    );
)

macro_rules! git_output(
    ($config:expr, $str:expr, $($rest:expr),*) => ({
        try!(git_output(&$config, format!($str, $($rest),*)))
    });

    ($config:expr, $str:expr) => ({
        try!(git_output(&$config, format!($str)))
    });
)

macro_rules! errln(
    ($($arg:tt)*) => (let _ = writeln!(::std::io::stdio::stderr(), $($arg)*))
)

/// GitRemote represents a remote repository. It gets cloned into a local
/// GitDatabase.
#[deriving(PartialEq,Clone,Show)]
pub struct GitRemote {
    location: Location,
}

#[deriving(PartialEq,Clone,Encodable)]
struct EncodableGitRemote {
    location: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitRemote {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitRemote {
            location: self.location.to_str()
        }.encode(s)
    }
}

/// GitDatabase is a local clone of a remote repository's database. Multiple
/// GitCheckouts can be cloned from this GitDatabase.
#[deriving(PartialEq,Clone)]
pub struct GitDatabase {
    remote: GitRemote,
    path: Path,
}

#[deriving(Encodable)]
pub struct EncodableGitDatabase {
    remote: GitRemote,
    path: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitDatabase {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitDatabase {
            remote: self.remote.clone(),
            path: self.path.display().to_str()
        }.encode(s)
    }
}

/// GitCheckout is a local checkout of a particular revision. Calling
/// `clone_into` with a reference will resolve the reference into a revision,
/// and return a CargoError if no revision for that reference was found.
pub struct GitCheckout {
    database: GitDatabase,
    location: Path,
    reference: GitReference,
    revision: String,
}

#[deriving(Encodable)]
pub struct EncodableGitCheckout {
    database: GitDatabase,
    location: String,
    reference: String,
    revision: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitCheckout {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitCheckout {
            database: self.database.clone(),
            location: self.location.display().to_str(),
            reference: self.reference.to_str(),
            revision: self.revision.to_str()
        }.encode(s)
    }
}

// Implementations

impl GitRemote {
    pub fn new(location: &Location) -> GitRemote {
        GitRemote { location: location.clone() }
    }

    pub fn get_location<'a>(&'a self) -> &'a Location {
        &self.location
    }

    pub fn has_ref<S: Str>(&self, path: &Path, reference: S) -> CargoResult<()> {
        git_output!(*path, "rev-parse {}", reference.as_slice());
        Ok(())
    }

    pub fn checkout(&self, into: &Path) -> CargoResult<GitDatabase> {
        if into.exists() {
            try!(self.fetch_into(into));
        } else {
            try!(self.clone_into(into));
        }

        Ok(GitDatabase { remote: self.clone(), path: into.clone() })
    }

    pub fn db_at(&self, db_path: &Path) -> GitDatabase {
        GitDatabase { remote: self.clone(), path: db_path.clone() }
    }

    fn fetch_into(&self, path: &Path) -> CargoResult<()> {
        Ok(git!(*path, "fetch --force --quiet --tags {} \
                        refs/heads/*:refs/heads/*", self.fetch_location()))
    }

    fn clone_into(&self, path: &Path) -> CargoResult<()> {
        let dirname = Path::new(path.dirname());

        try!(mkdir_recursive(path, UserDir));

        Ok(git!(dirname, "clone {} {} --bare --no-hardlinks --quiet",
                self.fetch_location(), path.display()))
    }

    fn fetch_location(&self) -> String {
        match self.location {
            Local(ref p) => p.display().to_str(),
            Remote(ref u) => u.to_str(),
        }
    }
}

impl GitDatabase {
    fn get_path<'a>(&'a self) -> &'a Path {
        &self.path
    }

    pub fn copy_to<S: Str>(&self, reference: S,
                           dest: &Path) -> CargoResult<GitCheckout> {
        let checkout = try!(GitCheckout::clone_into(dest, self.clone(),
                                  GitReference::for_str(reference.as_slice())));

        try!(checkout.fetch());
        try!(checkout.update_submodules());

        Ok(checkout)
    }

    pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<String> {
        Ok(git_output!(self.path, "rev-parse {}", reference.as_slice()))
    }

}

impl GitCheckout {
    fn clone_into(into: &Path, database: GitDatabase,
                  reference: GitReference) -> CargoResult<GitCheckout> {
        let revision = try!(database.rev_for(reference.as_slice()));
        let checkout = GitCheckout {
            location: into.clone(),
            database: database,
            reference: reference,
            revision: revision,
        };

        // If the git checkout already exists, we don't need to clone it again
        if !checkout.location.join(".git").exists() {
            try!(checkout.clone_repo());
        }

        Ok(checkout)
    }

    fn get_source<'a>(&'a self) -> &'a Path {
        self.database.get_path()
    }

    fn clone_repo(&self) -> CargoResult<()> {
        let dirname = Path::new(self.location.dirname());

        try!(mkdir_recursive(&dirname, UserDir).chain_error(|| {
            human(format!("Couldn't mkdir {}",
                          Path::new(self.location.dirname()).display()))
        }));

        if self.location.exists() {
            try!(rmdir_recursive(&self.location).chain_error(|| {
                human(format!("Couldn't rmdir {}",
                              Path::new(&self.location).display()))
            }));
        }

        git!(dirname, "clone --no-checkout --quiet {} {}",
             self.get_source().display(), self.location.display());
        try!(chmod(&self.location, AllPermissions));

        Ok(())
    }

    fn fetch(&self) -> CargoResult<()> {
        // In git 1.8, apparently --tags explicitly *only* fetches tags, it does
        // not fetch anything else. In git 1.9, however, git apparently fetches
        // everything when --tags is passed.
        //
        // This means that if we want to fetch everything we need to execute
        // both with and without --tags on 1.8 (apparently), and only with
        // --tags on 1.9. For simplicity, we execute with and without --tags for
        // all gits.
        //
        // FIXME: This is suspicious. I have been informated that, for example,
        //        bundler does not do this, yet bundler appears to work!
        git!(self.location, "fetch --force --quiet {}",
             self.get_source().display());
        git!(self.location, "fetch --force --quiet --tags {}",
             self.get_source().display());
        try!(self.reset(self.revision.as_slice()));
        Ok(())
    }

    fn reset<T: Show>(&self, revision: T) -> CargoResult<()> {
        Ok(git!(self.location, "reset -q --hard {}", revision))
    }

    fn update_submodules(&self) -> CargoResult<()> {
        Ok(git!(self.location, "submodule update --init --recursive --quiet"))
    }
}

fn git(path: &Path, str: &str) -> ProcessBuilder {
    debug!("Executing git {} @ {}", str, path.display());

    process("git").args(str.split(' ').collect::<Vec<&str>>().as_slice())
                  .cwd(path.clone())
}

fn git_inherit(path: &Path, str: String) -> CargoResult<()> {
    git(path, str.as_slice()).exec().chain_error(|| {
        human(format!("Executing `git {}` failed", str))
    })
}

fn git_output(path: &Path, str: String) -> CargoResult<String> {
    let output = try!(git(path, str.as_slice()).exec_with_output()
                                                     .chain_error(||
        human(format!("Executing `git {}` failed", str))));

    Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str())
}

fn to_str(vec: &[u8]) -> String {
    str::from_utf8_lossy(vec).to_str()
}

<commit_msg>auto merge of #101 : alexcrichton/cargo/fix-git-1.7, r=wycats<commit_after>use std::fmt;
use std::fmt::{Show,Formatter};
use std::str;
use std::io::{UserDir,AllPermissions};
use std::io::fs::{mkdir_recursive,rmdir_recursive,chmod};
use serialize::{Encodable,Encoder};

use core::source::{Location, Local, Remote};
use util::{CargoResult, ChainError, ProcessBuilder, process, human};

#[deriving(PartialEq,Clone,Encodable)]
pub enum GitReference {
    Master,
    Other(String)
}

impl GitReference {
    pub fn for_str<S: Str>(string: S) -> GitReference {
        if string.as_slice() == "master" {
            Master
        } else {
            Other(string.as_slice().to_str())
        }
    }
}

impl Str for GitReference {
    fn as_slice<'a>(&'a self) -> &'a str {
        match *self {
            Master => "master",
            Other(ref string) => string.as_slice()
        }
    }
}

impl Show for GitReference {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}

macro_rules! git(
    ($config:expr, $str:expr, $($rest:expr),*) => (
        try!(git_inherit(&$config, format!($str, $($rest),*)))
    );

    ($config:expr, $str:expr) => (
        try!(git_inherit(&$config, format!($str)))
    );
)

macro_rules! git_output(
    ($config:expr, $str:expr, $($rest:expr),*) => ({
        try!(git_output(&$config, format!($str, $($rest),*)))
    });

    ($config:expr, $str:expr) => ({
        try!(git_output(&$config, format!($str)))
    });
)

macro_rules! errln(
    ($($arg:tt)*) => (let _ = writeln!(::std::io::stdio::stderr(), $($arg)*))
)

/// GitRemote represents a remote repository. It gets cloned into a local
/// GitDatabase.
#[deriving(PartialEq,Clone,Show)]
pub struct GitRemote {
    location: Location,
}

#[deriving(PartialEq,Clone,Encodable)]
struct EncodableGitRemote {
    location: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitRemote {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitRemote {
            location: self.location.to_str()
        }.encode(s)
    }
}

/// GitDatabase is a local clone of a remote repository's database. Multiple
/// GitCheckouts can be cloned from this GitDatabase.
#[deriving(PartialEq,Clone)]
pub struct GitDatabase {
    remote: GitRemote,
    path: Path,
}

#[deriving(Encodable)]
pub struct EncodableGitDatabase {
    remote: GitRemote,
    path: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitDatabase {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitDatabase {
            remote: self.remote.clone(),
            path: self.path.display().to_str()
        }.encode(s)
    }
}

/// GitCheckout is a local checkout of a particular revision. Calling
/// `clone_into` with a reference will resolve the reference into a revision,
/// and return a CargoError if no revision for that reference was found.
pub struct GitCheckout {
    database: GitDatabase,
    location: Path,
    reference: GitReference,
    revision: String,
}

#[deriving(Encodable)]
pub struct EncodableGitCheckout {
    database: GitDatabase,
    location: String,
    reference: String,
    revision: String,
}

impl<E, S: Encoder<E>> Encodable<S, E> for GitCheckout {
    fn encode(&self, s: &mut S) -> Result<(), E> {
        EncodableGitCheckout {
            database: self.database.clone(),
            location: self.location.display().to_str(),
            reference: self.reference.to_str(),
            revision: self.revision.to_str()
        }.encode(s)
    }
}

// Implementations

impl GitRemote {
    pub fn new(location: &Location) -> GitRemote {
        GitRemote { location: location.clone() }
    }

    pub fn get_location<'a>(&'a self) -> &'a Location {
        &self.location
    }

    pub fn has_ref<S: Str>(&self, path: &Path, reference: S) -> CargoResult<()> {
        git_output!(*path, "rev-parse {}", reference.as_slice());
        Ok(())
    }

    pub fn checkout(&self, into: &Path) -> CargoResult<GitDatabase> {
        if into.exists() {
            try!(self.fetch_into(into));
        } else {
            try!(self.clone_into(into));
        }

        Ok(GitDatabase { remote: self.clone(), path: into.clone() })
    }

    pub fn db_at(&self, db_path: &Path) -> GitDatabase {
        GitDatabase { remote: self.clone(), path: db_path.clone() }
    }

    fn fetch_into(&self, path: &Path) -> CargoResult<()> {
        Ok(git!(*path, "fetch --force --quiet --tags {} \
                        refs/heads/*:refs/heads/*", self.fetch_location()))
    }

    fn clone_into(&self, path: &Path) -> CargoResult<()> {
        let dirname = Path::new(path.dirname());

        try!(mkdir_recursive(path, UserDir));

        Ok(git!(dirname, "clone {} {} --bare --no-hardlinks --quiet",
                self.fetch_location(), path.display()))
    }

    fn fetch_location(&self) -> String {
        match self.location {
            Local(ref p) => p.display().to_str(),
            Remote(ref u) => u.to_str(),
        }
    }
}

impl GitDatabase {
    fn get_path<'a>(&'a self) -> &'a Path {
        &self.path
    }

    pub fn copy_to<S: Str>(&self, reference: S,
                           dest: &Path) -> CargoResult<GitCheckout> {
        let checkout = try!(GitCheckout::clone_into(dest, self.clone(),
                                  GitReference::for_str(reference.as_slice())));

        try!(checkout.fetch());
        try!(checkout.update_submodules());

        Ok(checkout)
    }

    pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<String> {
        Ok(git_output!(self.path, "rev-parse {}", reference.as_slice()))
    }

}

impl GitCheckout {
    fn clone_into(into: &Path, database: GitDatabase,
                  reference: GitReference) -> CargoResult<GitCheckout> {
        let revision = try!(database.rev_for(reference.as_slice()));
        let checkout = GitCheckout {
            location: into.clone(),
            database: database,
            reference: reference,
            revision: revision,
        };

        // If the git checkout already exists, we don't need to clone it again
        if !checkout.location.join(".git").exists() {
            try!(checkout.clone_repo());
        }

        Ok(checkout)
    }

    fn get_source<'a>(&'a self) -> &'a Path {
        self.database.get_path()
    }

    fn clone_repo(&self) -> CargoResult<()> {
        let dirname = Path::new(self.location.dirname());

        try!(mkdir_recursive(&dirname, UserDir).chain_error(|| {
            human(format!("Couldn't mkdir {}",
                          Path::new(self.location.dirname()).display()))
        }));

        if self.location.exists() {
            try!(rmdir_recursive(&self.location).chain_error(|| {
                human(format!("Couldn't rmdir {}",
                              Path::new(&self.location).display()))
            }));
        }

        git!(dirname, "clone --no-checkout --quiet {} {}",
             self.get_source().display(), self.location.display());
        try!(chmod(&self.location, AllPermissions));

        Ok(())
    }

    fn fetch(&self) -> CargoResult<()> {
        // In git 1.8, apparently --tags explicitly *only* fetches tags, it does
        // not fetch anything else. In git 1.9, however, git apparently fetches
        // everything when --tags is passed.
        //
        // This means that if we want to fetch everything we need to execute
        // both with and without --tags on 1.8 (apparently), and only with
        // --tags on 1.9. For simplicity, we execute with and without --tags for
        // all gits.
        //
        // FIXME: This is suspicious. I have been informed that, for example,
        //        bundler does not do this, yet bundler appears to work!
        //
        // And to continue the fun, git before 1.7.3 had the fun bug that if a
        // branch was tracking a remote, then `git fetch $url` doesn't work!
        //
        // For details, see
        // https://www.kernel.org/pub/software/scm/git/docs/RelNotes-1.7.3.txt
        //
        // In this case we just use `origin` here instead of the database path.
        git!(self.location, "fetch --force --quiet origin");
        git!(self.location, "fetch --force --quiet --tags origin");
        try!(self.reset(self.revision.as_slice()));
        Ok(())
    }

    fn reset<T: Show>(&self, revision: T) -> CargoResult<()> {
        Ok(git!(self.location, "reset -q --hard {}", revision))
    }

    fn update_submodules(&self) -> CargoResult<()> {
        Ok(git!(self.location, "submodule update --init --recursive --quiet"))
    }
}

fn git(path: &Path, str: &str) -> ProcessBuilder {
    debug!("Executing git {} @ {}", str, path.display());

    process("git").args(str.split(' ').collect::<Vec<&str>>().as_slice())
                  .cwd(path.clone())
}

fn git_inherit(path: &Path, str: String) -> CargoResult<()> {
    git(path, str.as_slice()).exec().chain_error(|| {
        human(format!("Executing `git {}` failed", str))
    })
}

fn git_output(path: &Path, str: String) -> CargoResult<String> {
    let output = try!(git(path, str.as_slice()).exec_with_output()
                                                     .chain_error(||
        human(format!("Executing `git {}` failed", str))));

    Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str())
}

fn to_str(vec: &[u8]) -> String {
    str::from_utf8_lossy(vec).to_str()
}

<|endoftext|>


<commit_before>use regex::Regex;
use time::Timespec;

use timefmt::parse_time_str;

pub struct FileNameInfo<'a> {
    pub file_name: &'a str,
    pub info: Info,
}

#[derive(Eq, PartialEq, Debug)]
pub struct Info {
    pub tp: Type,
    pub compressed: bool,
    pub encrypted: bool,
}

#[derive(Eq, PartialEq, Debug)]
pub enum Type {
    Full {
        time: Timespec,
        volume_number: usize,
    },
    FullManifest {
        time: Timespec,
        partial: bool,
    },
    Inc {
        start_time: Timespec,
        end_time: Timespec,
        volume_number: usize,
    },
    IncManifest {
        start_time: Timespec,
        end_time: Timespec,
        partial: bool,
    },
    FullSig {
        time: Timespec,
        partial: bool,
    },
    NewSig {
        start_time: Timespec,
        end_time: Timespec,
        partial: bool,
    },
}

pub struct FileNameParser {
    full_vol_re: Regex,
    full_manifest_re: Regex,
    inc_vol_re: Regex,
    inc_manifest_re: Regex,
    full_sig_re: Regex,
    new_sig_re: Regex,
}

impl<'a> FileNameInfo<'a> {
    pub fn new(name: &'a str, info: Info) -> Self {
        FileNameInfo {
            file_name: &name,
            info: info,
        }
    }

    pub fn start_time(&self) -> Timespec {
        self.info.tp.time_range().0
    }
}

impl Type {
    pub fn time_range(&self) -> (Timespec, Timespec) {
        match *self {
            Type::Full{ time, .. } |
            Type::FullSig{ time, .. } |
            Type::FullManifest{ time, .. } => (time, time),
            Type::Inc{ start_time, end_time, .. } |
            Type::IncManifest{ start_time, end_time, .. } |
            Type::NewSig{ start_time, end_time, .. } => (start_time, end_time),
        }
    }
}

impl FileNameParser {
    pub fn new() -> Self {
        FileNameParser {
            full_vol_re: Regex::new(r"^duplicity-full\.(?P<time>.*?)\.vol(?P<num>[0-9]+)\.difftar(?P<partial>(\.part))?($|\.)").unwrap(),
            full_manifest_re: Regex::new(r"^duplicity-full\.(?P<time>.*?)\.manifest(?P<partial>(\.part))?($|\.)").unwrap(),
            inc_vol_re: Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.vol(?P<num>[0-9]+)\.difftar($|\.)").unwrap(),
            inc_manifest_re: Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.manifest(?P<partial>(\.part))?(\.|$)").unwrap(),
            full_sig_re: Regex::new(r"^duplicity-full-signatures\.(?P<time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
            new_sig_re: Regex::new(r"^duplicity-new-signatures\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
        }
    }

    pub fn parse(&self, filename: &str) -> Option<Info> {
        use std::ascii::AsciiExt;

        let lower_fname = filename.to_ascii_lowercase();
        let opt_type = self.check_full(&lower_fname)
                           .or(self.check_inc(&lower_fname))
                           .or(self.check_sig(&lower_fname));
        opt_type.map(|t| {
            Info {
                tp: t,
                compressed: is_compressed(lower_fname.as_ref()),
                encrypted: is_encrypted(lower_fname.as_ref()),
            }
        })
    }

    fn check_full(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.full_vol_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            let vol_num = try_opt!(get_vol_num(captures.name("num").unwrap()));
            Some(Type::Full {
                time: time,
                volume_number: vol_num,
            })
        } else if let Some(captures) = self.full_manifest_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            Some(Type::FullManifest {
                time: time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }

    fn check_inc(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.inc_vol_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            let vol_num = try_opt!(get_vol_num(captures.name("num").unwrap()));
            Some(Type::Inc {
                start_time: start_time,
                end_time: end_time,
                volume_number: vol_num,
            })
        } else if let Some(captures) = self.inc_manifest_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            Some(Type::IncManifest {
                start_time: start_time,
                end_time: end_time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }

    fn check_sig(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.full_sig_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            Some(Type::FullSig {
                time: time,
                partial: captures.name("partial").is_some(),
            })
        } else if let Some(captures) = self.new_sig_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            Some(Type::NewSig {
                start_time: start_time,
                end_time: end_time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }
}

fn get_vol_num(s: &str) -> Option<usize> {
    s.parse::<usize>().ok()
}

fn is_encrypted(s: &str) -> bool {
    s.ends_with(".gpg") || s.ends_with(".g")
}

fn is_compressed(s: &str) -> bool {
    s.ends_with(".gz") || s.ends_with(".z")
}

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

    #[test]
    fn parser_test() {
        let parser = FileNameParser::new();
        // invalid
        assert_eq!(parser.parse("invalid"), None);
        // full
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.vol1.difftar.gz"),
                   Some(Info {
                       tp: Type::Full {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           volume_number: 1,
                       },
                       compressed: true,
                       encrypted: false,
                   }));
        // full manifest
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.manifest"),
                   Some(Info {
                       tp: Type::FullManifest {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           partial: false,
                       },
                       compressed: false,
                       encrypted: false,
                   }));
        // inc
        assert_eq!(parser.parse("duplicity-inc.20150617T182629Z.to.20150617T182650Z.vol1.difftar.gz"),
                   Some(Info{ tp: Type::Inc{ start_time: parse_time_str("20150617t182629z").unwrap(),
                                             end_time: parse_time_str("20150617t182650z").unwrap(),
                                             volume_number: 1 },
                              compressed: true,
                              encrypted: false }));
        // inc manifest
        assert_eq!(parser.parse("duplicity-inc.20150617T182545Z.to.20150617T182629Z.manifest"),
                   Some(Info {
                       tp: Type::IncManifest {
                           start_time: parse_time_str("20150617t182545z").unwrap(),
                           end_time: parse_time_str("20150617t182629z").unwrap(),
                           partial: false,
                       },
                       compressed: false,
                       encrypted: false,
                   }));
        // new sig
        assert_eq!(parser.parse("duplicity-new-signatures.20150617T182545Z.to.20150617T182629Z.sigtar.gz"),
                   Some(Info{ tp: Type::NewSig{ start_time: parse_time_str("20150617t182545z").unwrap(),
                                                end_time: parse_time_str("20150617t182629z").unwrap(),
                                                partial: false },
                              compressed: true,
                              encrypted: false }));
        // full sig
        assert_eq!(parser.parse("duplicity-full-signatures.20150617T182545Z.sigtar.gz"),
                   Some(Info {
                       tp: Type::FullSig {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           partial: false,
                       },
                       compressed: true,
                       encrypted: false,
                   }));
    }
}
<commit_msg>Added missing clone implementation<commit_after>use regex::Regex;
use time::Timespec;

use timefmt::parse_time_str;

pub struct FileNameInfo<'a> {
    pub file_name: &'a str,
    pub info: Info,
}

#[derive(Eq, PartialEq, Debug)]
pub struct Info {
    pub tp: Type,
    pub compressed: bool,
    pub encrypted: bool,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Type {
    Full {
        time: Timespec,
        volume_number: usize,
    },
    FullManifest {
        time: Timespec,
        partial: bool,
    },
    Inc {
        start_time: Timespec,
        end_time: Timespec,
        volume_number: usize,
    },
    IncManifest {
        start_time: Timespec,
        end_time: Timespec,
        partial: bool,
    },
    FullSig {
        time: Timespec,
        partial: bool,
    },
    NewSig {
        start_time: Timespec,
        end_time: Timespec,
        partial: bool,
    },
}

pub struct FileNameParser {
    full_vol_re: Regex,
    full_manifest_re: Regex,
    inc_vol_re: Regex,
    inc_manifest_re: Regex,
    full_sig_re: Regex,
    new_sig_re: Regex,
}

impl<'a> FileNameInfo<'a> {
    pub fn new(name: &'a str, info: Info) -> Self {
        FileNameInfo {
            file_name: &name,
            info: info,
        }
    }

    pub fn start_time(&self) -> Timespec {
        self.info.tp.time_range().0
    }
}

impl Type {
    pub fn time_range(&self) -> (Timespec, Timespec) {
        match *self {
            Type::Full{ time, .. } |
            Type::FullSig{ time, .. } |
            Type::FullManifest{ time, .. } => (time, time),
            Type::Inc{ start_time, end_time, .. } |
            Type::IncManifest{ start_time, end_time, .. } |
            Type::NewSig{ start_time, end_time, .. } => (start_time, end_time),
        }
    }
}

impl FileNameParser {
    pub fn new() -> Self {
        FileNameParser {
            full_vol_re: Regex::new(r"^duplicity-full\.(?P<time>.*?)\.vol(?P<num>[0-9]+)\.difftar(?P<partial>(\.part))?($|\.)").unwrap(),
            full_manifest_re: Regex::new(r"^duplicity-full\.(?P<time>.*?)\.manifest(?P<partial>(\.part))?($|\.)").unwrap(),
            inc_vol_re: Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.vol(?P<num>[0-9]+)\.difftar($|\.)").unwrap(),
            inc_manifest_re: Regex::new(r"^duplicity-inc\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.manifest(?P<partial>(\.part))?(\.|$)").unwrap(),
            full_sig_re: Regex::new(r"^duplicity-full-signatures\.(?P<time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
            new_sig_re: Regex::new(r"^duplicity-new-signatures\.(?P<start_time>.*?)\.to\.(?P<end_time>.*?)\.sigtar(?P<partial>(\.part))?(\.|$)").unwrap(),
        }
    }

    pub fn parse(&self, filename: &str) -> Option<Info> {
        use std::ascii::AsciiExt;

        let lower_fname = filename.to_ascii_lowercase();
        let opt_type = self.check_full(&lower_fname)
                           .or(self.check_inc(&lower_fname))
                           .or(self.check_sig(&lower_fname));
        opt_type.map(|t| {
            Info {
                tp: t,
                compressed: is_compressed(lower_fname.as_ref()),
                encrypted: is_encrypted(lower_fname.as_ref()),
            }
        })
    }

    fn check_full(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.full_vol_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            let vol_num = try_opt!(get_vol_num(captures.name("num").unwrap()));
            Some(Type::Full {
                time: time,
                volume_number: vol_num,
            })
        } else if let Some(captures) = self.full_manifest_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            Some(Type::FullManifest {
                time: time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }

    fn check_inc(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.inc_vol_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            let vol_num = try_opt!(get_vol_num(captures.name("num").unwrap()));
            Some(Type::Inc {
                start_time: start_time,
                end_time: end_time,
                volume_number: vol_num,
            })
        } else if let Some(captures) = self.inc_manifest_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            Some(Type::IncManifest {
                start_time: start_time,
                end_time: end_time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }

    fn check_sig(&self, filename: &str) -> Option<Type> {
        if let Some(captures) = self.full_sig_re.captures(filename) {
            let time = try_opt!(parse_time_str(captures.name("time").unwrap()));
            Some(Type::FullSig {
                time: time,
                partial: captures.name("partial").is_some(),
            })
        } else if let Some(captures) = self.new_sig_re.captures(filename) {
            let start_time = try_opt!(parse_time_str(captures.name("start_time").unwrap()));
            let end_time = try_opt!(parse_time_str(captures.name("end_time").unwrap()));
            Some(Type::NewSig {
                start_time: start_time,
                end_time: end_time,
                partial: captures.name("partial").is_some(),
            })
        } else {
            None
        }
    }
}

fn get_vol_num(s: &str) -> Option<usize> {
    s.parse::<usize>().ok()
}

fn is_encrypted(s: &str) -> bool {
    s.ends_with(".gpg") || s.ends_with(".g")
}

fn is_compressed(s: &str) -> bool {
    s.ends_with(".gz") || s.ends_with(".z")
}

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

    #[test]
    fn parser_test() {
        let parser = FileNameParser::new();
        // invalid
        assert_eq!(parser.parse("invalid"), None);
        // full
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.vol1.difftar.gz"),
                   Some(Info {
                       tp: Type::Full {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           volume_number: 1,
                       },
                       compressed: true,
                       encrypted: false,
                   }));
        // full manifest
        assert_eq!(parser.parse("duplicity-full.20150617T182545Z.manifest"),
                   Some(Info {
                       tp: Type::FullManifest {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           partial: false,
                       },
                       compressed: false,
                       encrypted: false,
                   }));
        // inc
        assert_eq!(parser.parse("duplicity-inc.20150617T182629Z.to.20150617T182650Z.vol1.difftar.gz"),
                   Some(Info{ tp: Type::Inc{ start_time: parse_time_str("20150617t182629z").unwrap(),
                                             end_time: parse_time_str("20150617t182650z").unwrap(),
                                             volume_number: 1 },
                              compressed: true,
                              encrypted: false }));
        // inc manifest
        assert_eq!(parser.parse("duplicity-inc.20150617T182545Z.to.20150617T182629Z.manifest"),
                   Some(Info {
                       tp: Type::IncManifest {
                           start_time: parse_time_str("20150617t182545z").unwrap(),
                           end_time: parse_time_str("20150617t182629z").unwrap(),
                           partial: false,
                       },
                       compressed: false,
                       encrypted: false,
                   }));
        // new sig
        assert_eq!(parser.parse("duplicity-new-signatures.20150617T182545Z.to.20150617T182629Z.sigtar.gz"),
                   Some(Info{ tp: Type::NewSig{ start_time: parse_time_str("20150617t182545z").unwrap(),
                                                end_time: parse_time_str("20150617t182629z").unwrap(),
                                                partial: false },
                              compressed: true,
                              encrypted: false }));
        // full sig
        assert_eq!(parser.parse("duplicity-full-signatures.20150617T182545Z.sigtar.gz"),
                   Some(Info {
                       tp: Type::FullSig {
                           time: parse_time_str("20150617t182545z").unwrap(),
                           partial: false,
                       },
                       compressed: true,
                       encrypted: false,
                   }));
    }
}
<|endoftext|>


<commit_before>extern crate ispc;

fn main() {
    ispc::compile_library("ao", &["src/ao.ispc"]);
}

<commit_msg>use aobench as an example of multiple isa targets<commit_after>extern crate ispc;

fn main() {
    // This build script shows how to target a specific of vector ISAs
    // using the target_isas function. We can also compile for all ISAs,
    // in which case ISPC will internally dispatch the function calls to
    // the correct ISA for the host system
    ispc::Config::new()
        .file("src/ao.ispc")
        .target_isas(vec![ispc::TargetISA::SSE2i32x4,
                     ispc::TargetISA::SSE4i32x4,
                     ispc::TargetISA::AVX11i32x8,
                     ispc::TargetISA::AVX2i32x8,
                     ispc::TargetISA::AVX512KNLi32x16,
                     ispc::TargetISA::AVX512SKXi32x16])
        .opt_level(3)
        .optimization_opt(ispc::OptimizationOpt::FastMath)
        .compile("ao");
}

<|endoftext|>


<commit_before>extern crate rosc;
extern crate byteorder;

use byteorder::{ByteOrder, BigEndian};
use std::{mem, iter};
use std::ascii::AsciiExt;

use rosc::{types, errors, decoder, utils};

#[test]
fn test_decode_no_args() {
    // message to build: /some/valid/address/4 ,
    let raw_addr = "/some/valid/address/4";
    let addr = to_osc_string(raw_addr.as_bytes());
    let type_tags = to_osc_string(b",");
    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .collect();
    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    assert!(osc_packet.is_ok());
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            assert!(msg.args.is_none());
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

#[test]
fn test_decode_args() {
    // /another/valid/address/123 ,fdih 3.1415 3.14159265359 12345678i32
    // -1234567891011
    let raw_addr = "/another/valid/address/123";
    let addr = to_osc_string(raw_addr.as_bytes());
    // args
    let f = 3.1415f32;
    let mut f_bytes: [u8; 4] = [0u8; 4];
    BigEndian::write_f32(&mut f_bytes, f);
    assert_eq!(BigEndian::read_f32(&f_bytes), f);

    let d = 3.14159265359f64;
    let mut d_bytes: [u8; 8] = [0u8; 8];
    BigEndian::write_f64(&mut d_bytes, d);
    assert_eq!(BigEndian::read_f64(&d_bytes), d);

    let i = 12345678i32;
    let i_bytes: [u8; 4] = unsafe { mem::transmute(i.to_be()) };

    let l = -1234567891011i64;
    let h_bytes: [u8; 8] = unsafe { mem::transmute(l.to_be()) };

    let s = "I am an osc test string.";
    assert!(s.is_ascii());

    // Osc strings are null terminated like in C!
    let s_bytes: Vec<u8> = to_osc_string(s.as_bytes());

    let type_tags = to_osc_string(b",fdsih");

    let args: Vec<u8> = f_bytes.iter()
                               .chain(d_bytes.iter())
                               .chain(s_bytes.iter())
                               .chain(i_bytes.iter())
                               .chain(h_bytes.iter())
                               .map(|x| *x)
                               .collect::<Vec<u8>>();

    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .chain(args)
                              .collect::<Vec<u8>>();

    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            for arg in msg.args.unwrap() {
                match arg {
                    types::OscType::Int(x) => assert_eq!(i, x),
                    types::OscType::Long(x) => assert_eq!(l, x),
                    types::OscType::Float(x) => assert_eq!(f, x),
                    types::OscType::Double(x) => assert_eq!(d, x),
                    types::OscType::String(x) => assert_eq!(s, x),
                    _ => panic!(),
                }
            }
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

/// Nul terminates the data and pads with zero bytes to a length that is a multiple of 4.
fn to_osc_string(data: &[u8]) -> Vec<u8> {
    let mut v: Vec<u8> = data.iter()
                             .cloned()
                             .chain(iter::once(0u8))
                             .collect();
    // v;
    let pad_len: usize = utils::pad(v.len() as u64) as usize;
    while v.len() < pad_len {
        v.push(0u8);
    }
    v
}<commit_msg>Add test for OSC blobs<commit_after>extern crate rosc;
extern crate byteorder;

use byteorder::{ByteOrder, BigEndian};
use std::{mem, iter};
use std::ascii::AsciiExt;

use rosc::{types, errors, decoder, utils};

#[test]
fn test_decode_no_args() {
    // message to build: /some/valid/address/4 ,
    let raw_addr = "/some/valid/address/4";
    let addr = to_osc_string(raw_addr.as_bytes());
    let type_tags = to_osc_string(b",");
    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .collect();
    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    assert!(osc_packet.is_ok());
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            assert!(msg.args.is_none());
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

#[test]
fn test_decode_args() {
    // /another/valid/address/123 ,fdih 3.1415 3.14159265359 12345678i32
    // -1234567891011
    let raw_addr = "/another/valid/address/123";
    let addr = to_osc_string(raw_addr.as_bytes());
    // args
    let f = 3.1415f32;
    let mut f_bytes: [u8; 4] = [0u8; 4];
    BigEndian::write_f32(&mut f_bytes, f);
    assert_eq!(BigEndian::read_f32(&f_bytes), f);

    let d = 3.14159265359f64;
    let mut d_bytes: [u8; 8] = [0u8; 8];
    BigEndian::write_f64(&mut d_bytes, d);
    assert_eq!(BigEndian::read_f64(&d_bytes), d);

    let i = 12345678i32;
    let i_bytes: [u8; 4] = unsafe { mem::transmute(i.to_be()) };

    let l = -1234567891011i64;
    let h_bytes: [u8; 8] = unsafe { mem::transmute(l.to_be()) };

    let blob_size: [u8; 4] = unsafe { mem::transmute(6u32.to_be()) };
    let blob: Vec<u8> = vec![1u8, 2u8, 3u8, 4u8, 5u8, 6u8];

    let s = "I am an osc test string.";
    assert!(s.is_ascii());

    // Osc strings are null terminated like in C!
    let s_bytes: Vec<u8> = to_osc_string(s.as_bytes());

    let type_tags = to_osc_string(b",fdsihb");

    let args: Vec<u8> = f_bytes.iter()
                               .chain(d_bytes.iter())
                               .chain(s_bytes.iter())
                               .chain(i_bytes.iter())
                               .chain(h_bytes.iter())
                               .chain(blob_size.iter())
                               .chain(blob.iter())
                               .chain(vec![0u8, 0u8].iter())
                               .map(|x| *x)
                               .collect::<Vec<u8>>();

    let merged: Vec<u8> = addr.into_iter()
                              .chain(type_tags.into_iter())
                              .chain(args)
                              .collect::<Vec<u8>>();

    let osc_packet: Result<types::OscPacket, errors::OscError> = decoder::decode(&merged);
    match osc_packet {
        Ok(types::OscPacket::Message(msg)) => {
            assert_eq!(raw_addr, msg.addr);
            for arg in msg.args.unwrap() {
                match arg {
                    types::OscType::Int(x) => assert_eq!(i, x),
                    types::OscType::Long(x) => assert_eq!(l, x),
                    types::OscType::Float(x) => assert_eq!(f, x),
                    types::OscType::Double(x) => assert_eq!(d, x),
                    types::OscType::String(x) => assert_eq!(s, x),
                    types::OscType::Blob(x) => assert_eq!(blob, x),
                    _ => panic!(),
                }
            }
        }
        Ok(_) => panic!("Expected an OscMessage!"),
        Err(e) => panic!(e),
    }
}

/// Nul terminates the data and pads with zero bytes to a length that is a multiple of 4.
fn to_osc_string(data: &[u8]) -> Vec<u8> {
    let mut v: Vec<u8> = data.iter()
                             .cloned()
                             .chain(iter::once(0u8))
                             .collect();
    // v;
    let pad_len: usize = utils::pad(v.len() as u64) as usize;
    while v.len() < pad_len {
        v.push(0u8);
    }
    v
}<|endoftext|>


<commit_before>mod game1 {
    fn func1(){
        println!("我是不是可见的?");
    }

    pub fn func2(){
        println!("func2调用");
    }
}

fn main() {
    //game1::func1(); //错误
    game1::func2();
}<commit_msg>struct<commit_after>mod game1 {
    fn func1(){
        println!("我是不是可见的?");
    }

    pub fn func2(){
        println!("func2调用");
    }

    #[derive(Debug)]
    pub struct Magician {
        pub name: String,
        pub age: i32,
        power:i32
    }

    impl Magician {
        pub fn new(n: String, a: i32, p: i32) -> Magician {
            Magician { name: n, age: a, power: p}
        }
    }
}

fn main() {
    //game1::func1(); //错误
    game1::func2();
    let mag1 = game1::Magician::new("Liu Lixiang".to_string(), 28, 100);
    println!("{:?}", mag1);
}<|endoftext|>


<commit_before>use crate::error::Error;
use crate::state::{State, Step, StepStatus};
use async_trait::async_trait;
use common::document::ContainerDocument;
use cucumber::{t, StepContext, Steps};
use mimir2::adapters::primary::{
    common::coord::Coord, common::dsl::build_query, common::filters::Filters,
    common::settings::QuerySettings,
};
use mimir2::adapters::secondary::elasticsearch::ElasticsearchStorage;
use mimir2::domain::{model::query::Query, ports::primary::search_documents::SearchDocuments};
use places::{addr::Addr, admin::Admin, poi::Poi, stop::Stop, street::Street};

pub fn steps() -> Steps<State> {
    let mut steps: Steps<State> = Steps::new();

    steps.when_regex_async(
        r#"the user searches (.*) datatype(?: in (.*))? for "(.*)"(?: at \((.*),(.*)\))?"#,
        t!(|mut state, ctx| {
            let places = ctx.matches[1].clone();
            let places = if places == "all" {
                vec![
                    Addr::static_doc_type().to_string(),
                    Admin::static_doc_type().to_string(),
                    Street::static_doc_type().to_string(),
                    Stop::static_doc_type().to_string(),
                    Poi::static_doc_type().to_string(),
                ]
            } else {
                places.split(',').map(|s| s.trim().to_string()).collect()
            };
            let lat = ctx.matches[4].trim();
            let lon = ctx.matches[5].trim();
            let coord = if lat.is_empty() {
                None
            } else {
                // round to 4 digits
                let lat = (lat.parse::<f32>().expect("lat is f32") * 10000.0).round() / 10000.0;
                let lon = (lon.parse::<f32>().expect("lon is f32") * 10000.0).round() / 10000.0;
                Some(Coord::new(lat, lon))
            };
            let filters = Filters {
                coord,
                ..Default::default()
            };

            let query = ctx.matches[3].clone();
            let search = Search {
                filters,
                places,
                query,
                results: Vec::new(),
            };

            state.execute(search, &ctx).await.expect("failed to search");

            state
        }),
    );

    steps.then_regex_async(
        r#"he finds "(.*)" as the first result"#,
        t!(|mut state, ctx| {
            let id = ctx.matches[1].clone();

            state
                .execute(HasDocument { id, max_rank: 1 }, &ctx)
                .await
                .expect("failed to find document");

            state
        }),
    );

    steps.then_regex_async(
        r#"he finds "(.*)", "(.*)", "(.*)", and "(.*)" in the first "(.*)" results"#,
        t!(|mut state, ctx| {
            let house = Some(ctx.matches[1].clone()).and_then(|house| {
                if house.is_empty() {
                    None
                } else {
                    Some(house)
                }
            });
            let street = Some(ctx.matches[2].clone()).and_then(|street| {
                if street.is_empty() {
                    None
                } else {
                    Some(street)
                }
            });
            let city = Some(ctx.matches[3].clone()).and_then(|city| {
                if city.is_empty() {
                    None
                } else {
                    Some(city)
                }
            });
            let postcode = Some(ctx.matches[4].clone()).and_then(|postcode| {
                if postcode.is_empty() {
                    None
                } else {
                    Some(postcode)
                }
            });
            let limit = ctx.matches[5].clone();
            let limit = if limit.is_empty() {
                1
            } else {
                limit.parse().expect("limit as usize")
            };

            state
                .execute(
                    HasAddress {
                        house,
                        street,
                        city,
                        postcode,
                        limit,
                    },
                    &ctx,
                )
                .await
                .expect("failed to find document");

            state
        }),
    );

    steps
}

/// Perform a search in current Elasticsearch DB.
#[derive(Debug)]
pub struct Search {
    places: Vec<String>, // What kind of places we're searching
    query: String,       // The search string
    filters: Filters,    // Search filters
    results: Vec<serde_json::Value>,
}

#[async_trait(?Send)]
impl Step for Search {
    async fn execute(&mut self, _state: &State, ctx: &StepContext) -> Result<StepStatus, Error> {
        let client: &ElasticsearchStorage = ctx.get().expect("could not get ES client");
        // Build ES query
        let dsl = build_query(
            &self.query,
            self.filters.clone(),
            &["fr"],
            &QuerySettings::default(),
        );

        // println!("{}", serde_json::to_string_pretty(&dsl).unwrap());

        // Fetch documents
        self.results = {
            client
                .search_documents(self.places.clone(), Query::QueryDSL(dsl))
                .await
                .unwrap()
        };

        Ok(StepStatus::Done)
    }
}

/// Check if given document is in the output.
///
/// It assumes that a Search has already been performed before.
pub struct HasDocument {
    id: String,
    max_rank: usize,
}

#[async_trait(?Send)]
impl Step for HasDocument {
    async fn execute(&mut self, state: &State, _ctx: &StepContext) -> Result<StepStatus, Error> {
        let (search, _) = state
            .steps_for::<Search>()
            .next_back()
            .expect("the user must perform a search before checking results");

        let (rank, _) = (search.results.iter().enumerate())
            .find(|(_, doc)| {
                println!("{} vs {}", self.id, doc["id"].as_str().unwrap());
                self.id == doc["id"].as_str().unwrap()
            })
            .expect("document was not found in search results");

        assert!(rank < self.max_rank);
        Ok(StepStatus::Done)
    }
}

/// Check if given document is in the output.
///
/// It assumes that a Search has already been performed before.
pub struct HasAddress {
    house: Option<String>,
    street: Option<String>,
    city: Option<String>,
    postcode: Option<String>,
    limit: usize,
}

#[async_trait(?Send)]
impl Step for HasAddress {
    async fn execute(&mut self, state: &State, _ctx: &StepContext) -> Result<StepStatus, Error> {
        let (search, _) = state
            .steps_for::<Search>()
            .next_back()
            .expect("the user must perform a search before checking results");

        let rank = search
            .results
            .clone()
            .into_iter()
            .enumerate()
            .find_map(|(num, doc)| {
                let addr: Addr = serde_json::from_value(doc).expect("address");
                if let Some(house) = &self.house {
                    if house != addr.house_number.as_str() {
                        return None;
                    }
                }
                if let Some(street) = &self.street {
                    if street != addr.street.name.as_str() {
                        return None;
                    }
                }
                if let Some(postcode) = &self.postcode {
                    if postcode != addr.zip_codes[0].as_str() {
                        return None;
                    }
                }
                if let Some(city) = &self.city {
                    if city != addr.city().expect("city").as_str() {
                        return None;
                    }
                }
                Some(num)
            })
            .expect("document was not found in search results");

        assert!(rank < self.limit);
        Ok(StepStatus::Done)
    }
}
<commit_msg>fix remove comment<commit_after>use crate::error::Error;
use crate::state::{State, Step, StepStatus};
use async_trait::async_trait;
use common::document::ContainerDocument;
use cucumber::{t, StepContext, Steps};
use mimir2::adapters::primary::{
    common::coord::Coord, common::dsl::build_query, common::filters::Filters,
    common::settings::QuerySettings,
};
use mimir2::adapters::secondary::elasticsearch::ElasticsearchStorage;
use mimir2::domain::{model::query::Query, ports::primary::search_documents::SearchDocuments};
use places::{addr::Addr, admin::Admin, poi::Poi, stop::Stop, street::Street};

pub fn steps() -> Steps<State> {
    let mut steps: Steps<State> = Steps::new();

    steps.when_regex_async(
        r#"the user searches (.*) datatype(?: in (.*))? for "(.*)"(?: at \((.*),(.*)\))?"#,
        t!(|mut state, ctx| {
            let places = ctx.matches[1].clone();
            let places = if places == "all" {
                vec![
                    Addr::static_doc_type().to_string(),
                    Admin::static_doc_type().to_string(),
                    Street::static_doc_type().to_string(),
                    Stop::static_doc_type().to_string(),
                    Poi::static_doc_type().to_string(),
                ]
            } else {
                places.split(',').map(|s| s.trim().to_string()).collect()
            };
            let lat = ctx.matches[4].trim();
            let lon = ctx.matches[5].trim();
            let coord = if lat.is_empty() {
                None
            } else {
                // round to 4 digits
                let lat = (lat.parse::<f32>().expect("lat is f32") * 10000.0).round() / 10000.0;
                let lon = (lon.parse::<f32>().expect("lon is f32") * 10000.0).round() / 10000.0;
                Some(Coord::new(lat, lon))
            };
            let filters = Filters {
                coord,
                ..Default::default()
            };

            let query = ctx.matches[3].clone();
            let search = Search {
                filters,
                places,
                query,
                results: Vec::new(),
            };

            state.execute(search, &ctx).await.expect("failed to search");

            state
        }),
    );

    steps.then_regex_async(
        r#"he finds "(.*)" as the first result"#,
        t!(|mut state, ctx| {
            let id = ctx.matches[1].clone();

            state
                .execute(HasDocument { id, max_rank: 1 }, &ctx)
                .await
                .expect("failed to find document");

            state
        }),
    );

    steps.then_regex_async(
        r#"he finds "(.*)", "(.*)", "(.*)", and "(.*)" in the first "(.*)" results"#,
        t!(|mut state, ctx| {
            let house = Some(ctx.matches[1].clone()).and_then(|house| {
                if house.is_empty() {
                    None
                } else {
                    Some(house)
                }
            });
            let street = Some(ctx.matches[2].clone()).and_then(|street| {
                if street.is_empty() {
                    None
                } else {
                    Some(street)
                }
            });
            let city = Some(ctx.matches[3].clone()).and_then(|city| {
                if city.is_empty() {
                    None
                } else {
                    Some(city)
                }
            });
            let postcode = Some(ctx.matches[4].clone()).and_then(|postcode| {
                if postcode.is_empty() {
                    None
                } else {
                    Some(postcode)
                }
            });
            let limit = ctx.matches[5].clone();
            let limit = if limit.is_empty() {
                1
            } else {
                limit.parse().expect("limit as usize")
            };

            state
                .execute(
                    HasAddress {
                        house,
                        street,
                        city,
                        postcode,
                        limit,
                    },
                    &ctx,
                )
                .await
                .expect("failed to find document");

            state
        }),
    );

    steps
}

/// Perform a search in current Elasticsearch DB.
#[derive(Debug)]
pub struct Search {
    places: Vec<String>, // What kind of places we're searching
    query: String,       // The search string
    filters: Filters,    // Search filters
    results: Vec<serde_json::Value>,
}

#[async_trait(?Send)]
impl Step for Search {
    async fn execute(&mut self, _state: &State, ctx: &StepContext) -> Result<StepStatus, Error> {
        let client: &ElasticsearchStorage = ctx.get().expect("could not get ES client");
        // Build ES query
        let dsl = build_query(
            &self.query,
            self.filters.clone(),
            &["fr"],
            &QuerySettings::default(),
        );

        // Fetch documents
        self.results = {
            client
                .search_documents(self.places.clone(), Query::QueryDSL(dsl))
                .await
                .unwrap()
        };

        Ok(StepStatus::Done)
    }
}

/// Check if given document is in the output.
///
/// It assumes that a Search has already been performed before.
pub struct HasDocument {
    id: String,
    max_rank: usize,
}

#[async_trait(?Send)]
impl Step for HasDocument {
    async fn execute(&mut self, state: &State, _ctx: &StepContext) -> Result<StepStatus, Error> {
        let (search, _) = state
            .steps_for::<Search>()
            .next_back()
            .expect("the user must perform a search before checking results");

        let (rank, _) = (search.results.iter().enumerate())
            .find(|(_, doc)| {
                println!("{} vs {}", self.id, doc["id"].as_str().unwrap());
                self.id == doc["id"].as_str().unwrap()
            })
            .expect("document was not found in search results");

        assert!(rank < self.max_rank);
        Ok(StepStatus::Done)
    }
}

/// Check if given document is in the output.
///
/// It assumes that a Search has already been performed before.
pub struct HasAddress {
    house: Option<String>,
    street: Option<String>,
    city: Option<String>,
    postcode: Option<String>,
    limit: usize,
}

#[async_trait(?Send)]
impl Step for HasAddress {
    async fn execute(&mut self, state: &State, _ctx: &StepContext) -> Result<StepStatus, Error> {
        let (search, _) = state
            .steps_for::<Search>()
            .next_back()
            .expect("the user must perform a search before checking results");

        let rank = search
            .results
            .clone()
            .into_iter()
            .enumerate()
            .find_map(|(num, doc)| {
                let addr: Addr = serde_json::from_value(doc).expect("address");
                if let Some(house) = &self.house {
                    if house != addr.house_number.as_str() {
                        return None;
                    }
                }
                if let Some(street) = &self.street {
                    if street != addr.street.name.as_str() {
                        return None;
                    }
                }
                if let Some(postcode) = &self.postcode {
                    if postcode != addr.zip_codes[0].as_str() {
                        return None;
                    }
                }
                if let Some(city) = &self.city {
                    if city != addr.city().expect("city").as_str() {
                        return None;
                    }
                }
                Some(num)
            })
            .expect("document was not found in search results");

        assert!(rank < self.limit);
        Ok(StepStatus::Done)
    }
}
<|endoftext|>