<commit_before>use crate::{
    fa::{Parameterised, StateFunction, Weights, WeightsView, WeightsViewMut},
    policies::{DifferentiablePolicy, Policy},
    spaces::Space,
};
use ndarray::{Array2, ArrayView2, Axis};
use rand::Rng;
use rstat::{ContinuousDistribution, Distribution};
use std::fmt::Debug;

pub mod mean;
use self::mean::Mean;

pub mod stddev;
use self::stddev::StdDev;

import_all!(dbuilder);

#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct Gaussian<M, S> {
    pub mean: M,
    pub stddev: S,

    pub alpha: f64,
}

impl<M, S> Gaussian<M, S> {
    pub fn new(mean: M, stddev: S) -> Self {
        Gaussian {
            mean,
            stddev,
            alpha: 1.0,
        }
    }
}

impl<M, S> Gaussian<M, S> {
    #[inline]
    pub fn compute_mean<I>(&self, input: &I) -> M::Output
    where
        M: Mean<I, <S as StateFunction<I>>::Output>,
        S: StdDev<I, <M as StateFunction<I>>::Output>,
    {
        self.mean.mean(input)
    }

    #[inline]
    pub fn compute_stddev<I>(&self, input: &I) -> S::Output
    where
        M: Mean<I, <S as StateFunction<I>>::Output>,
        S: StdDev<I, <M as StateFunction<I>>::Output>,
    {
        self.stddev.stddev(input)
    }
}

impl<I, M, S> Policy<I> for Gaussian<M, S>
where
    M: Mean<I, <S as StateFunction<I>>::Output>,
    M::Output: Clone + Debug,
    S: StdDev<I, <M as StateFunction<I>>::Output>,
    S::Output: Clone + Debug,
    GB: DistBuilder<M::Output, S::Output>,
    GBSupport<M::Output, S::Output>: Space<Value = M::Output>,
{
    type Action = M::Output;

    fn sample<R: Rng + ?Sized>(&self, rng: &mut R, input: &I) -> Self::Action {
        GB::build(self.compute_mean(input), self.compute_stddev(input)).sample(rng)
    }

    fn mpa(&self, input: &I) -> Self::Action { self.compute_mean(input) }

    fn probability(&self, input: &I, a: &Self::Action) -> f64
    where Self::Action: Clone {
        GB::build(self.compute_mean(input), self.compute_stddev(input)).pdf(a.clone())
    }
}

impl<I, M, S> DifferentiablePolicy<I> for Gaussian<M, S>
where
    M: Mean<I, <S as StateFunction<I>>::Output>,
    M::Output: Clone + Debug,
    S: StdDev<I, <M as StateFunction<I>>::Output>,
    S::Output: Clone + Debug,
    GB: DistBuilder<M::Output, S::Output>,
    GBSupport<M::Output, S::Output>: Space<Value = M::Output>,
{
    fn update(&mut self, input: &I, a: &Self::Action, error: f64) {
        let mean = self.compute_mean(input);
        let stddev = self.compute_stddev(input);

        self.mean.update_mean(input, &a, stddev, error);
        self.stddev.update_stddev(input, &a, mean, error);
    }

    fn update_grad(&mut self, grad: &ArrayView2<f64>) {
        let w_mean = self.mean.weights_dim();

        match w_mean {
            [r, c] if r > 0 => {
                let grad_mean = grad.slice(s![0..r, 0..c]);

                self.mean
                    .weights_view_mut()
                    .scaled_add(self.alpha, &grad_mean);
            },
            _ => {},
        }

        match self.stddev.weights_dim() {
            [r, c] if r > 0 => {
                let grad_stddev = grad.slice(s![w_mean[0]..(w_mean[0] + r), 0..c]);

                self.stddev
                    .weights_view_mut()
                    .scaled_add(self.alpha, &grad_stddev);
            },
            _ => {},
        }
    }

    fn update_grad_scaled(&mut self, grad: &ArrayView2<f64>, factor: f64) {
        let w_mean = self.mean.weights_dim();

        match w_mean {
            [r, c] if r > 0 => {
                let grad_mean = grad.slice(s![0..r, 0..c]);

                self.mean
                    .weights_view_mut()
                    .scaled_add(self.alpha * factor, &grad_mean);
            },
            _ => {},
        }

        match self.stddev.weights_dim() {
            [r, c] if r > 0 => {
                let grad_stddev = grad.slice(s![w_mean[0]..(w_mean[0] + r), 0..c]);

                self.stddev
                    .weights_view_mut()
                    .scaled_add(self.alpha * factor, &grad_stddev);
            },
            _ => {},
        }
    }

    fn grad_log(&self, input: &I, a: &Self::Action) -> Array2<f64> {
        let mean = self.compute_mean(input);
        let stddev = self.compute_stddev(input);

        let gl_mean = self.mean.grad_log(input, &a, stddev);
        let gl_stddev = self.stddev.grad_log(input, &a, mean);

        if gl_stddev.len() == 0 {
            gl_mean
        } else {
            stack![Axis(0), gl_mean, gl_stddev]
        }
    }
}

impl<M, S> Parameterised for Gaussian<M, S>
where
    M: Parameterised,
    S: Parameterised,
{
    fn weights(&self) -> Weights {
        let w_mean = self.mean.weights();
        let w_stddev = self.stddev.weights();

        if w_stddev.len() == 0 {
            w_mean
        } else {
            stack![Axis(0), w_mean, w_stddev]
        }
    }

    fn weights_view(&self) -> WeightsView { unimplemented!() }

    fn weights_view_mut(&mut self) -> WeightsViewMut { unimplemented!() }

    fn weights_dim(&self) -> [usize; 2] {
        let [rm, cm] = self.mean.weights_dim();
        let [rs, cs] = self.stddev.weights_dim();

        [rm + rs, cm.max(cs)]
    }
}
<commit_msg>feat(policies): remove redundant alpha param in Gaussian policy<commit_after>use crate::{
    fa::{Parameterised, StateFunction, Weights, WeightsView, WeightsViewMut},
    policies::{DifferentiablePolicy, Policy},
    spaces::Space,
};
use ndarray::{Array2, ArrayView2, Axis};
use rand::Rng;
use rstat::{ContinuousDistribution, Distribution};
use std::{fmt::Debug, ops::AddAssign};

pub mod mean;
use self::mean::Mean;

pub mod stddev;
use self::stddev::StdDev;

import_all!(dbuilder);

#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct Gaussian<M, S> {
    pub mean: M,
    pub stddev: S,
}

impl<M, S> Gaussian<M, S> {
    pub fn new(mean: M, stddev: S) -> Self {
        Gaussian {
            mean,
            stddev,
        }
    }
}

impl<M, S> Gaussian<M, S> {
    #[inline]
    pub fn compute_mean<I>(&self, input: &I) -> M::Output
    where
        M: Mean<I, <S as StateFunction<I>>::Output>,
        S: StdDev<I, <M as StateFunction<I>>::Output>,
    {
        self.mean.mean(input)
    }

    #[inline]
    pub fn compute_stddev<I>(&self, input: &I) -> S::Output
    where
        M: Mean<I, <S as StateFunction<I>>::Output>,
        S: StdDev<I, <M as StateFunction<I>>::Output>,
    {
        self.stddev.stddev(input)
    }
}

impl<I, M, S> Policy<I> for Gaussian<M, S>
where
    M: Mean<I, <S as StateFunction<I>>::Output>,
    M::Output: Clone + Debug,
    S: StdDev<I, <M as StateFunction<I>>::Output>,
    S::Output: Clone + Debug,
    GB: DistBuilder<M::Output, S::Output>,
    GBSupport<M::Output, S::Output>: Space<Value = M::Output>,
{
    type Action = M::Output;

    fn sample<R: Rng + ?Sized>(&self, rng: &mut R, input: &I) -> Self::Action {
        GB::build(self.compute_mean(input), self.compute_stddev(input)).sample(rng)
    }

    fn mpa(&self, input: &I) -> Self::Action { self.compute_mean(input) }

    fn probability(&self, input: &I, a: &Self::Action) -> f64
    where Self::Action: Clone {
        GB::build(self.compute_mean(input), self.compute_stddev(input)).pdf(a.clone())
    }
}

impl<I, M, S> DifferentiablePolicy<I> for Gaussian<M, S>
where
    M: Mean<I, <S as StateFunction<I>>::Output>,
    M::Output: Clone + Debug,
    S: StdDev<I, <M as StateFunction<I>>::Output>,
    S::Output: Clone + Debug,
    GB: DistBuilder<M::Output, S::Output>,
    GBSupport<M::Output, S::Output>: Space<Value = M::Output>,
{
    fn update(&mut self, input: &I, a: &Self::Action, error: f64) {
        let mean = self.compute_mean(input);
        let stddev = self.compute_stddev(input);

        self.mean.update_mean(input, &a, stddev, error);
        self.stddev.update_stddev(input, &a, mean, error);
    }

    fn update_grad(&mut self, grad: &ArrayView2<f64>) {
        let w_mean = self.mean.weights_dim();

        match w_mean {
            [r, c] if r > 0 => {
                let grad_mean = grad.slice(s![0..r, 0..c]);

                self.mean.weights_view_mut().add_assign(&grad_mean);
            },
            _ => {},
        }

        match self.stddev.weights_dim() {
            [r, c] if r > 0 => {
                let grad_stddev = grad.slice(s![w_mean[0]..(w_mean[0] + r), 0..c]);

                self.stddev.weights_view_mut().add_assign(&grad_stddev);
            },
            _ => {},
        }
    }

    fn update_grad_scaled(&mut self, grad: &ArrayView2<f64>, factor: f64) {
        let w_mean = self.mean.weights_dim();

        match w_mean {
            [r, c] if r > 0 => {
                let grad_mean = grad.slice(s![0..r, 0..c]);

                self.mean
                    .weights_view_mut()
                    .scaled_add(factor, &grad_mean);
            },
            _ => {},
        }

        match self.stddev.weights_dim() {
            [r, c] if r > 0 => {
                let grad_stddev = grad.slice(s![w_mean[0]..(w_mean[0] + r), 0..c]);

                self.stddev
                    .weights_view_mut()
                    .scaled_add(factor, &grad_stddev);
            },
            _ => {},
        }
    }

    fn grad_log(&self, input: &I, a: &Self::Action) -> Array2<f64> {
        let mean = self.compute_mean(input);
        let stddev = self.compute_stddev(input);

        let gl_mean = self.mean.grad_log(input, &a, stddev);
        let gl_stddev = self.stddev.grad_log(input, &a, mean);

        if gl_stddev.len() == 0 {
            gl_mean
        } else {
            stack![Axis(0), gl_mean, gl_stddev]
        }
    }
}

impl<M, S> Parameterised for Gaussian<M, S>
where
    M: Parameterised,
    S: Parameterised,
{
    fn weights(&self) -> Weights {
        let w_mean = self.mean.weights();
        let w_stddev = self.stddev.weights();

        if w_stddev.len() == 0 {
            w_mean
        } else {
            stack![Axis(0), w_mean, w_stddev]
        }
    }

    fn weights_view(&self) -> WeightsView { unimplemented!() }

    fn weights_view_mut(&mut self) -> WeightsViewMut { unimplemented!() }

    fn weights_dim(&self) -> [usize; 2] {
        let [rm, cm] = self.mean.weights_dim();
        let [rs, cs] = self.stddev.weights_dim();

        [rm + rs, cm.max(cs)]
    }
}
<|endoftext|>


<commit_before>use super::geo_class_and_kind;
use crate::util::AsArray2D;
use crate::StrError;
use russell_lab::{Matrix, Vector};

/// Holds the state of a shape entity
#[derive(Clone, Debug)]
pub struct StateOfShape {
    // -- steady ----------------------------------------------------------------------------------------------------
    //
    /// Matrix Xᵀ: (space_ndim,nnode) transposed coordinates matrix (real space)
    ///
    /// ```text
    /// The (non-transposed) matrix X is such that:
    ///
    ///     ┌               ┐
    ///     | x⁰₀  x⁰₁  x⁰₂ |  subscript = dimension
    ///     | x¹₀  x¹₁  x¹₂ |  superscript = node
    /// X = | x²₀  x²₁  x²₂ |
    ///     |      ...      |
    ///     | xᴹ₀  xᴹ₁  xᴹ₂ |
    ///     └               ┘_(nnode,space_ndim)
    ///
    /// where `M = nnode - 1`
    /// ```
    pub coords_transp: Matrix,

    /// Minimum (space_ndim) coordinates from the X matrix
    pub coords_min: Vec<f64>,

    /// Maximum (space_ndim) coordinates from the X matrix
    pub coords_max: Vec<f64>,

    // -- transient -------------------------------------------------------------------------------------------------
    //
    /// Array N: (nnode) interpolation functions at reference coordinate ksi
    pub interp: Vector,

    /// Matrix L: (nnode,geo_ndim) derivatives of interpolation functions w.r.t reference coordinate ksi
    pub deriv: Matrix,

    /// Matrix J: (space_ndim,geo_ndim) Jacobian matrix
    pub jacobian: Matrix,

    /// Matrix inv(J): (space_ndim,space_ndim) Inverse Jacobian matrix (only if geo_ndim == space_ndim) at ksi
    pub inv_jacobian: Matrix,

    /// Matrix G: (nnode,space_ndim) Gradient of shape functions (only if geo_ndim == space_ndim) at ksi
    pub gradient: Matrix,
}

impl StateOfShape {
    /// Allocates a new instance
    ///
    /// # Input
    ///
    /// * `geo_ndim` -- the dimension of the shape; e.g. a 1D line in a 3D space
    /// * `coords` -- the (non-transposed) matrix of coordinates (`X` matrix); see below
    ///
    /// ```text
    ///          ┌               ┐
    ///          | x⁰₀  x⁰₁  x⁰₂ |  subscript = dimension
    ///          | x¹₀  x¹₁  x¹₂ |  superscript = node
    /// coords = | x²₀  x²₁  x²₂ |
    ///          |      ...      |
    ///          | xᴹ₀  xᴹ₁  xᴹ₂ |
    ///          └               ┘_(nnode,space_ndim)
    /// ```
    pub fn new<'a, T>(geo_ndim: usize, coords: &'a T) -> Result<Self, StrError>
    where
        T: AsArray2D<'a, f64>,
    {
        let (nnode, space_ndim) = coords.size();
        if space_ndim < 2 || space_ndim > 3 {
            return Err("space_ndim must be 2 or 3");
        }
        geo_class_and_kind(geo_ndim, nnode)?; // just to check combination
        let mut state = StateOfShape {
            coords_transp: Matrix::new(space_ndim, nnode),
            coords_min: vec![f64::MAX; space_ndim],
            coords_max: vec![f64::MIN; space_ndim],
            interp: Vector::new(nnode),
            deriv: Matrix::new(nnode, geo_ndim),
            jacobian: Matrix::new(space_ndim, geo_ndim),
            inv_jacobian: if geo_ndim == space_ndim {
                Matrix::new(space_ndim, space_ndim)
            } else {
                Matrix::new(0, 0)
            },
            gradient: if geo_ndim == space_ndim {
                Matrix::new(nnode, space_ndim)
            } else {
                Matrix::new(0, 0)
            },
        };
        for m in 0..nnode {
            for j in 0..space_ndim {
                let value = coords.at(m, j);
                state.coords_transp[j][m] = value;
                if value < state.coords_min[j] {
                    state.coords_min[j] = value;
                }
                if value > state.coords_max[j] {
                    state.coords_max[j] = value;
                }
            }
        }
        Ok(state)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::shapes::StateOfShape;
    use crate::StrError;

    #[test]
    fn new_fails_on_wrong_input() {
        assert_eq!(
            StateOfShape::new(100, &[[1.0, 1.0], [2.0, 2.0]]).err(),
            Some("(geo_ndim,nnode) combination is invalid")
        );
        assert_eq!(StateOfShape::new(1, &[[], []]).err(), Some("space_ndim must be 2 or 3"));
        assert_eq!(
            StateOfShape::new(1, &[[0.0], [0.0]]).err(),
            Some("space_ndim must be 2 or 3")
        );
        assert_eq!(
            StateOfShape::new(1, &[[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]).err(),
            Some("space_ndim must be 2 or 3")
        );
    }

    #[test]
    fn new_works() -> Result<(), StrError> {
        let space_ndim = 2;
        let geo_ndim = 1;
        let nnode = 2;
        let state = StateOfShape::new(geo_ndim, &[[-1.23, 1.23], [-4.56, 4.56]])?;
        assert_eq!(
            format!("{}", state.coords_transp),
            "┌             ┐\n\
             │ -1.23 -4.56 │\n\
             │  1.23  4.56 │\n\
             └             ┘"
        );
        assert_eq!(state.coords_min, &[-4.56, 1.23]);
        assert_eq!(state.coords_max, &[-1.23, 4.56]);
        assert_eq!(state.interp.dim(), nnode);
        assert_eq!(state.deriv.dims(), (nnode, geo_ndim));
        assert_eq!(state.jacobian.dims(), (space_ndim, geo_ndim));
        assert_eq!(state.inv_jacobian.dims(), (0, 0));
        assert_eq!(state.gradient.dims(), (0, 0));

        let space_ndim = 2;
        let geo_ndim = 2;
        let nnode = 3;
        let state = StateOfShape::new(geo_ndim, &[[-1.23, 1.23], [-4.56, 4.56], [-7.89, 7.89]])?;
        assert_eq!(
            format!("{}", state.coords_transp),
            "┌                   ┐\n\
             │ -1.23 -4.56 -7.89 │\n\
             │  1.23  4.56  7.89 │\n\
             └                   ┘"
        );
        assert_eq!(state.coords_min, &[-7.89, 1.23]);
        assert_eq!(state.coords_max, &[-1.23, 7.89]);
        assert_eq!(state.interp.dim(), nnode);
        assert_eq!(state.deriv.dims(), (nnode, geo_ndim));
        assert_eq!(state.jacobian.dims(), (space_ndim, geo_ndim));
        assert_eq!(state.inv_jacobian.dims(), (space_ndim, space_ndim));
        assert_eq!(state.gradient.dims(), (nnode, space_ndim));
        Ok(())
    }

    #[test]
    fn derive_works() -> Result<(), StrError> {
        let state = StateOfShape::new(2, &[[-1.23, 1.23], [-4.56, 4.56], [-7.89, 7.89]])?;
        let state_clone = state.clone();
        assert_eq!(format!("{:?}", state), "StateOfShape { coords_transp: NumMatrix { nrow: 2, ncol: 3, data: [-1.23, -4.56, -7.89, 1.23, 4.56, 7.89] }, coords_min: [-7.89, 1.23], coords_max: [-1.23, 7.89], interp: NumVector { data: [0.0, 0.0, 0.0] }, deriv: NumMatrix { nrow: 3, ncol: 2, data: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] }, jacobian: NumMatrix { nrow: 2, ncol: 2, data: [0.0, 0.0, 0.0, 0.0] }, inv_jacobian: NumMatrix { nrow: 2, ncol: 2, data: [0.0, 0.0, 0.0, 0.0] }, gradient: NumMatrix { nrow: 3, ncol: 2, data: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] } }");
        assert_eq!(state_clone.coords_min, &[-7.89, 1.23]);
        assert_eq!(state_clone.coords_max, &[-1.23, 7.89]);
        Ok(())
    }
}
<commit_msg>Improve test for StateOfShape<commit_after>use super::geo_class_and_kind;
use crate::util::AsArray2D;
use crate::StrError;
use russell_lab::{Matrix, Vector};

/// Holds the state of a shape entity
#[derive(Clone, Debug)]
pub struct StateOfShape {
    // -- steady ----------------------------------------------------------------------------------------------------
    //
    /// Matrix Xᵀ: (space_ndim,nnode) transposed coordinates matrix (real space)
    ///
    /// ```text
    /// The (non-transposed) matrix X is such that:
    ///
    ///     ┌               ┐
    ///     | x⁰₀  x⁰₁  x⁰₂ |  subscript = dimension
    ///     | x¹₀  x¹₁  x¹₂ |  superscript = node
    /// X = | x²₀  x²₁  x²₂ |
    ///     |      ...      |
    ///     | xᴹ₀  xᴹ₁  xᴹ₂ |
    ///     └               ┘_(nnode,space_ndim)
    ///
    /// where `M = nnode - 1`
    /// ```
    pub coords_transp: Matrix,

    /// Minimum (space_ndim) coordinates from the X matrix
    pub coords_min: Vec<f64>,

    /// Maximum (space_ndim) coordinates from the X matrix
    pub coords_max: Vec<f64>,

    // -- transient -------------------------------------------------------------------------------------------------
    //
    /// Array N: (nnode) interpolation functions at reference coordinate ksi
    pub interp: Vector,

    /// Matrix L: (nnode,geo_ndim) derivatives of interpolation functions w.r.t reference coordinate ksi
    pub deriv: Matrix,

    /// Matrix J: (space_ndim,geo_ndim) Jacobian matrix
    pub jacobian: Matrix,

    /// Matrix inv(J): (space_ndim,space_ndim) Inverse Jacobian matrix (only if geo_ndim == space_ndim) at ksi
    pub inv_jacobian: Matrix,

    /// Matrix G: (nnode,space_ndim) Gradient of shape functions (only if geo_ndim == space_ndim) at ksi
    pub gradient: Matrix,
}

impl StateOfShape {
    /// Allocates a new instance
    ///
    /// # Input
    ///
    /// * `geo_ndim` -- the dimension of the shape; e.g. a 1D line in a 3D space
    /// * `coords` -- the (non-transposed) matrix of coordinates (`X` matrix); see below
    ///
    /// ```text
    ///          ┌               ┐
    ///          | x⁰₀  x⁰₁  x⁰₂ |  subscript = dimension
    ///          | x¹₀  x¹₁  x¹₂ |  superscript = node
    /// coords = | x²₀  x²₁  x²₂ |
    ///          |      ...      |
    ///          | xᴹ₀  xᴹ₁  xᴹ₂ |
    ///          └               ┘_(nnode,space_ndim)
    /// ```
    pub fn new<'a, T>(geo_ndim: usize, coords: &'a T) -> Result<Self, StrError>
    where
        T: AsArray2D<'a, f64>,
    {
        let (nnode, space_ndim) = coords.size();
        if space_ndim < 2 || space_ndim > 3 {
            return Err("space_ndim must be 2 or 3");
        }
        geo_class_and_kind(geo_ndim, nnode)?; // just to check combination
        let mut state = StateOfShape {
            coords_transp: Matrix::new(space_ndim, nnode),
            coords_min: vec![f64::MAX; space_ndim],
            coords_max: vec![f64::MIN; space_ndim],
            interp: Vector::new(nnode),
            deriv: Matrix::new(nnode, geo_ndim),
            jacobian: Matrix::new(space_ndim, geo_ndim),
            inv_jacobian: if geo_ndim == space_ndim {
                Matrix::new(space_ndim, space_ndim)
            } else {
                Matrix::new(0, 0)
            },
            gradient: if geo_ndim == space_ndim {
                Matrix::new(nnode, space_ndim)
            } else {
                Matrix::new(0, 0)
            },
        };
        for m in 0..nnode {
            for j in 0..space_ndim {
                let value = coords.at(m, j);
                state.coords_transp[j][m] = value;
                if value < state.coords_min[j] {
                    state.coords_min[j] = value;
                }
                if value > state.coords_max[j] {
                    state.coords_max[j] = value;
                }
            }
        }
        Ok(state)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::shapes::StateOfShape;
    use crate::StrError;

    #[test]
    fn new_fails_on_wrong_input() {
        assert_eq!(
            StateOfShape::new(100, &[[1.0, 1.0], [2.0, 2.0]]).err(),
            Some("(geo_ndim,nnode) combination is invalid")
        );
        assert_eq!(StateOfShape::new(1, &[[], []]).err(), Some("space_ndim must be 2 or 3"));
        assert_eq!(
            StateOfShape::new(1, &[[0.0], [0.0]]).err(),
            Some("space_ndim must be 2 or 3")
        );
        assert_eq!(
            StateOfShape::new(1, &[[1.0, 2.0, 3.0, 4.0], [1.0, 2.0, 3.0, 4.0]]).err(),
            Some("space_ndim must be 2 or 3")
        );
    }

    #[test]
    fn new_works() -> Result<(), StrError> {
        let space_ndim = 2;
        let geo_ndim = 1;
        let nnode = 2;
        let state = StateOfShape::new(geo_ndim, &[[-1.23, 1.23], [-4.56, 4.56]])?;
        assert_eq!(
            format!("{}", state.coords_transp),
            "┌             ┐\n\
             │ -1.23 -4.56 │\n\
             │  1.23  4.56 │\n\
             └             ┘"
        );
        assert_eq!(state.coords_min, &[-4.56, 1.23]);
        assert_eq!(state.coords_max, &[-1.23, 4.56]);
        assert_eq!(state.interp.dim(), nnode);
        assert_eq!(state.deriv.dims(), (nnode, geo_ndim));
        assert_eq!(state.jacobian.dims(), (space_ndim, geo_ndim));
        assert_eq!(state.inv_jacobian.dims(), (0, 0));
        assert_eq!(state.gradient.dims(), (0, 0));

        let space_ndim = 2;
        let geo_ndim = 2;
        let nnode = 3;
        let state = StateOfShape::new(geo_ndim, &[[-1.23, 1.23], [-4.56, 4.56], [-7.89, 7.89]])?;
        assert_eq!(
            format!("{}", state.coords_transp),
            "┌                   ┐\n\
             │ -1.23 -4.56 -7.89 │\n\
             │  1.23  4.56  7.89 │\n\
             └                   ┘"
        );
        assert_eq!(state.coords_min, &[-7.89, 1.23]);
        assert_eq!(state.coords_max, &[-1.23, 7.89]);
        assert_eq!(state.interp.dim(), nnode);
        assert_eq!(state.deriv.dims(), (nnode, geo_ndim));
        assert_eq!(state.jacobian.dims(), (space_ndim, geo_ndim));
        assert_eq!(state.inv_jacobian.dims(), (space_ndim, space_ndim));
        assert_eq!(state.gradient.dims(), (nnode, space_ndim));

        let space_ndim = 3;
        let geo_ndim = 3;
        let nnode = 4;
        let state = StateOfShape::new(
            geo_ndim,
            &[[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]],
        )?;
        assert_eq!(
            format!("{}", state.coords_transp),
            "┌         ┐\n\
             │ 0 1 0 0 │\n\
             │ 0 0 1 0 │\n\
             │ 0 0 0 1 │\n\
             └         ┘"
        );
        assert_eq!(state.coords_min, &[0.0, 0.0, 0.0]);
        assert_eq!(state.coords_max, &[1.0, 1.0, 1.0]);
        assert_eq!(state.interp.dim(), nnode);
        assert_eq!(state.deriv.dims(), (nnode, geo_ndim));
        assert_eq!(state.jacobian.dims(), (space_ndim, geo_ndim));
        assert_eq!(state.inv_jacobian.dims(), (space_ndim, space_ndim));
        assert_eq!(state.gradient.dims(), (nnode, space_ndim));
        Ok(())
    }

    #[test]
    fn derive_works() -> Result<(), StrError> {
        let state = StateOfShape::new(2, &[[-1.23, 1.23], [-4.56, 4.56], [-7.89, 7.89]])?;
        let state_clone = state.clone();
        assert_eq!(format!("{:?}", state), "StateOfShape { coords_transp: NumMatrix { nrow: 2, ncol: 3, data: [-1.23, -4.56, -7.89, 1.23, 4.56, 7.89] }, coords_min: [-7.89, 1.23], coords_max: [-1.23, 7.89], interp: NumVector { data: [0.0, 0.0, 0.0] }, deriv: NumMatrix { nrow: 3, ncol: 2, data: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] }, jacobian: NumMatrix { nrow: 2, ncol: 2, data: [0.0, 0.0, 0.0, 0.0] }, inv_jacobian: NumMatrix { nrow: 2, ncol: 2, data: [0.0, 0.0, 0.0, 0.0] }, gradient: NumMatrix { nrow: 3, ncol: 2, data: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0] } }");
        assert_eq!(state_clone.coords_min, &[-7.89, 1.23]);
        assert_eq!(state_clone.coords_max, &[-1.23, 7.89]);
        Ok(())
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use server::transport::RaftStoreRouter;
use raftstore::errors::Error as RaftServerError;
use raftstore::coprocessor::{RegionSnapshot, RegionIterator};
use raftstore::store::engine::Peekable;
use kvproto::raft_cmdpb::{RaftCmdRequest, RaftCmdResponse, RaftRequestHeader, Request, Response,
                          CmdType, DeleteRequest, PutRequest};
use kvproto::errorpb;
use kvproto::kvrpcpb::Context;

use uuid::Uuid;
use std::sync::Arc;
use std::fmt::{self, Formatter, Debug};
use std::io::Error as IoError;
use std::time::Duration;
use std::result;
use rocksdb::DB;
use protobuf::RepeatedField;

use storage::engine;
use super::{CbContext, Engine, Modify, Cursor, Snapshot, ScanMode, Callback,
            Iterator as EngineIterator};
use storage::{Key, Value, CfName, CF_DEFAULT};
use super::metrics::*;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        RequestFailed(e: errorpb::Error) {
            from()
            description(e.get_message())
        }
        Io(e: IoError) {
            from()
            cause(e)
            description(e.description())
        }
        RocksDb(reason: String) {
            description(reason)
        }
        Server(e: RaftServerError) {
            from()
            cause(e)
            description(e.description())
        }
        InvalidResponse(reason: String) {
            description(reason)
        }
        InvalidRequest(reason: String) {
            description(reason)
        }
        Timeout(d: Duration) {
            description("request timeout")
            display("timeout after {:?}", d)
        }
    }
}

pub type Result<T> = result::Result<T, Error>;

impl From<Error> for engine::Error {
    fn from(e: Error) -> engine::Error {
        match e {
            Error::RequestFailed(e) => engine::Error::Request(e),
            Error::Server(e) => e.into(),
            e => box_err!(e),
        }
    }
}

impl From<RaftServerError> for engine::Error {
    fn from(e: RaftServerError) -> engine::Error {
        engine::Error::Request(e.into())
    }
}

/// `RaftKv` is a storage engine base on `RaftStore`.
#[derive(Clone)]
pub struct RaftKv<S: RaftStoreRouter + 'static> {
    db: Arc<DB>,
    router: S,
}

enum CmdRes {
    Resp(Vec<Response>),
    Snap(RegionSnapshot),
}

fn on_result(mut resp: RaftCmdResponse,
             resp_cnt: usize,
             uuid: &[u8],
             db: Arc<DB>)
             -> (CbContext, Result<CmdRes>) {
    let mut cb_ctx = CbContext::new();
    cb_ctx.term = Some(resp.get_header().get_current_term());

    if resp.get_header().get_uuid() != uuid {
        return (cb_ctx, Err(Error::InvalidResponse("response is not correct!!!".to_owned())));
    }
    if resp.get_header().has_error() {
        return (cb_ctx, Err(Error::RequestFailed(resp.take_header().take_error())));
    }
    if resp_cnt != resp.get_responses().len() {
        return (cb_ctx,
                Err(Error::InvalidResponse("response count is not equal to requests, something \
                                            must go wrong."
            .to_owned())));
    }
    let mut resps = resp.take_responses();
    if resps.len() != 1 || resps[0].get_cmd_type() != CmdType::Snap {
        return (cb_ctx, Ok(CmdRes::Resp(resps.into_vec())));
    }
    let snap = RegionSnapshot::from_raw(db, resps[0].take_snap().take_region());
    (cb_ctx, Ok(CmdRes::Snap(snap)))
}

impl<S: RaftStoreRouter> RaftKv<S> {
    /// Create a RaftKv using specified configuration.
    pub fn new(db: Arc<DB>, router: S) -> RaftKv<S> {
        RaftKv {
            db: db,
            router: router,
        }
    }

    fn call_command(&self, req: RaftCmdRequest, cb: Callback<CmdRes>) -> Result<()> {
        let uuid = req.get_header().get_uuid().to_vec();
        let l = req.get_requests().len();
        let db = self.db.clone();
        try!(self.router.send_command(req,
                                      box move |resp| {
                                          let (cb_ctx, res) = on_result(resp, l, &uuid, db);
                                          cb((cb_ctx, res.map_err(Error::into)));
                                      }));
        Ok(())
    }

    fn new_request_header(&self, ctx: &Context) -> RaftRequestHeader {
        let mut header = RaftRequestHeader::new();
        header.set_region_id(ctx.get_region_id());
        header.set_peer(ctx.get_peer().clone());
        header.set_region_epoch(ctx.get_region_epoch().clone());
        header.set_uuid(Uuid::new_v4().as_bytes().to_vec());
        header.set_read_quorum(ctx.get_read_quorum());
        if ctx.get_term() != 0 {
            header.set_term(ctx.get_term());
        }
        header
    }

    fn exec_requests(&self, ctx: &Context, reqs: Vec<Request>, cb: Callback<CmdRes>) -> Result<()> {
        let header = self.new_request_header(ctx);
        let mut cmd = RaftCmdRequest::new();
        cmd.set_header(header);
        cmd.set_requests(RepeatedField::from_vec(reqs));
        self.call_command(cmd, cb)
    }
}

fn invalid_resp_type(exp: CmdType, act: CmdType) -> Error {
    Error::InvalidResponse(format!("cmd type not match, want {:?}, got {:?}!", exp, act))
}

impl<S: RaftStoreRouter> Debug for RaftKv<S> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "RaftKv")
    }
}

impl<S: RaftStoreRouter> Engine for RaftKv<S> {
    fn async_write(&self,
                   ctx: &Context,
                   mut modifies: Vec<Modify>,
                   cb: Callback<()>)
                   -> engine::Result<()> {
        let mut reqs = Vec::with_capacity(modifies.len());
        while !modifies.is_empty() {
            let m = modifies.pop().unwrap();
            let mut req = Request::new();
            match m {
                Modify::Delete(cf, k) => {
                    let mut delete = DeleteRequest::new();
                    delete.set_key(k.encoded().to_owned());
                    if cf != CF_DEFAULT {
                        delete.set_cf(cf.to_string());
                    }
                    req.set_cmd_type(CmdType::Delete);
                    req.set_delete(delete);
                }
                Modify::Put(cf, k, v) => {
                    let mut put = PutRequest::new();
                    put.set_key(k.encoded().to_owned());
                    put.set_value(v);
                    if cf != CF_DEFAULT {
                        put.set_cf(cf.to_string());
                    }
                    req.set_cmd_type(CmdType::Put);
                    req.set_put(put);
                }
            }
            reqs.push(req);
        }

        ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["write", "all"]).inc();
        let req_timer = ASYNC_REQUESTS_DURATIONS_VEC.with_label_values(&["write"]).start_timer();

        try!(self.exec_requests(ctx,
                                reqs,
                                box move |(cb_ctx, res)| {
            match res {
                Ok(CmdRes::Resp(_)) => {
                    req_timer.observe_duration();
                    ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["write", "success"]).inc();

                    cb((cb_ctx, Ok(())))
                }
                Ok(CmdRes::Snap(_)) => {
                    cb((cb_ctx, Err(box_err!("unexpect snapshot, should mutate instead."))))
                }
                Err(e) => {
                    ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["write", "failed"]).inc();
                    cb((cb_ctx, Err(e)))
                }
            }
        }));
        Ok(())
    }

    fn async_snapshot(&self, ctx: &Context, cb: Callback<Box<Snapshot>>) -> engine::Result<()> {
        let mut req = Request::new();
        req.set_cmd_type(CmdType::Snap);

        ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["snapshot", "all"]).inc();
        let req_timer = ASYNC_REQUESTS_DURATIONS_VEC.with_label_values(&["snapshot"]).start_timer();

        try!(self.exec_requests(ctx,
                                vec![req],
                                box move |(cb_ctx, res)| {
            match res {
                Ok(CmdRes::Resp(r)) => {
                    cb((cb_ctx, Err(invalid_resp_type(CmdType::Snap, r[0].get_cmd_type()).into())))
                }
                Ok(CmdRes::Snap(s)) => {
                    req_timer.observe_duration();
                    ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["snapshot", "success"]).inc();
                    cb((cb_ctx, Ok(box s)))
                }
                Err(e) => {
                    ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["snapshot", "failed"]).inc();
                    cb((cb_ctx, Err(e)))
                }
            }
        }));
        Ok(())
    }

    fn clone(&self) -> Box<Engine> {
        box RaftKv::new(self.db.clone(), self.router.clone())
    }
}

impl Snapshot for RegionSnapshot {
    fn get(&self, key: &Key) -> engine::Result<Option<Value>> {
        let v = box_try!(self.get_value(key.encoded()));
        Ok(v.map(|v| v.to_vec()))
    }

    fn get_cf(&self, cf: CfName, key: &Key) -> engine::Result<Option<Value>> {
        let v = box_try!(self.get_value_cf(cf, key.encoded()));
        Ok(v.map(|v| v.to_vec()))
    }

    #[allow(needless_lifetimes)]
    fn iter<'b>(&'b self,
                upper_bound: Option<&[u8]>,
                fill_cache: bool,
                mode: ScanMode)
                -> engine::Result<Cursor<'b>> {
        Ok(Cursor::new(RegionSnapshot::iter(self, upper_bound, fill_cache), mode))
    }

    #[allow(needless_lifetimes)]
    fn iter_cf<'b>(&'b self,
                   cf: CfName,
                   upper_bound: Option<&[u8]>,
                   fill_cache: bool,
                   mode: ScanMode)
                   -> engine::Result<Cursor<'b>> {
        Ok(Cursor::new(try!(RegionSnapshot::iter_cf(self, cf, upper_bound, fill_cache)),
                       mode))
    }
}

impl<'a> EngineIterator for RegionIterator<'a> {
    fn next(&mut self) -> bool {
        RegionIterator::next(self)
    }

    fn prev(&mut self) -> bool {
        RegionIterator::prev(self)
    }

    fn seek(&mut self, key: &Key) -> engine::Result<bool> {
        RegionIterator::seek(self, key.encoded()).map_err(From::from)
    }

    fn seek_to_first(&mut self) -> bool {
        RegionIterator::seek_to_first(self)
    }

    fn seek_to_last(&mut self) -> bool {
        RegionIterator::seek_to_last(self)
    }

    fn valid(&self) -> bool {
        RegionIterator::valid(self)
    }

    fn key(&self) -> &[u8] {
        RegionIterator::key(self)
    }

    fn value(&self) -> &[u8] {
        RegionIterator::value(self)
    }

    fn validate_key(&self, key: &Key) -> engine::Result<()> {
        self.should_seekable(key.encoded()).map_err(From::from)
    }
}
<commit_msg>metrics: add fail reason (#1492)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use server::transport::RaftStoreRouter;
use raftstore::errors::Error as RaftServerError;
use raftstore::coprocessor::{RegionSnapshot, RegionIterator};
use raftstore::store::engine::Peekable;
use kvproto::raft_cmdpb::{RaftCmdRequest, RaftCmdResponse, RaftRequestHeader, Request, Response,
                          CmdType, DeleteRequest, PutRequest};
use kvproto::errorpb;
use kvproto::kvrpcpb::Context;

use uuid::Uuid;
use std::sync::Arc;
use std::fmt::{self, Formatter, Debug};
use std::io::Error as IoError;
use std::time::Duration;
use std::result;
use rocksdb::DB;
use protobuf::RepeatedField;

use storage::engine;
use super::{CbContext, Engine, Modify, Cursor, Snapshot, ScanMode, Callback,
            Iterator as EngineIterator};
use storage::{Key, Value, CfName, CF_DEFAULT};
use super::metrics::*;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        RequestFailed(e: errorpb::Error) {
            from()
            description(e.get_message())
        }
        Io(e: IoError) {
            from()
            cause(e)
            description(e.description())
        }
        RocksDb(reason: String) {
            description(reason)
        }
        Server(e: RaftServerError) {
            from()
            cause(e)
            description(e.description())
        }
        InvalidResponse(reason: String) {
            description(reason)
        }
        InvalidRequest(reason: String) {
            description(reason)
        }
        Timeout(d: Duration) {
            description("request timeout")
            display("timeout after {:?}", d)
        }
    }
}

fn get_tag_from_header(header: &errorpb::Error) -> &'static str {
    if header.has_not_leader() {
        "not_leader"
    } else if header.has_region_not_found() {
        "region_not_found"
    } else if header.has_key_not_in_region() {
        "key_not_in_region"
    } else if header.has_stale_epoch() {
        "stale_epoch"
    } else if header.has_server_is_busy() {
        "server_is_busy"
    } else {
        "other"
    }
}

fn get_tag_from_error(e: &Error) -> &'static str {
    match *e {
        Error::RequestFailed(ref header) => get_tag_from_header(header),
        Error::Io(_) => "io",
        Error::RocksDb(_) => "rocksdb",
        Error::Server(_) => "server",
        Error::InvalidResponse(_) => "invalid_resp",
        Error::InvalidRequest(_) => "invalid_req",
        Error::Timeout(_) => "timeout",
    }
}

fn get_tag_from_engine_error(e: &engine::Error) -> &'static str {
    match *e {
        engine::Error::Request(ref header) => get_tag_from_header(header),
        engine::Error::RocksDb(_) => "rocksdb",
        engine::Error::Timeout(_) => "timeout",
        engine::Error::Other(_) => "other",
    }
}

pub type Result<T> = result::Result<T, Error>;

impl From<Error> for engine::Error {
    fn from(e: Error) -> engine::Error {
        match e {
            Error::RequestFailed(e) => engine::Error::Request(e),
            Error::Server(e) => e.into(),
            e => box_err!(e),
        }
    }
}

impl From<RaftServerError> for engine::Error {
    fn from(e: RaftServerError) -> engine::Error {
        engine::Error::Request(e.into())
    }
}

/// `RaftKv` is a storage engine base on `RaftStore`.
#[derive(Clone)]
pub struct RaftKv<S: RaftStoreRouter + 'static> {
    db: Arc<DB>,
    router: S,
}

enum CmdRes {
    Resp(Vec<Response>),
    Snap(RegionSnapshot),
}

fn on_result(mut resp: RaftCmdResponse,
             resp_cnt: usize,
             uuid: &[u8],
             db: Arc<DB>)
             -> (CbContext, Result<CmdRes>) {
    let mut cb_ctx = CbContext::new();
    cb_ctx.term = Some(resp.get_header().get_current_term());

    if resp.get_header().get_uuid() != uuid {
        return (cb_ctx, Err(Error::InvalidResponse("response is not correct!!!".to_owned())));
    }
    if resp.get_header().has_error() {
        return (cb_ctx, Err(Error::RequestFailed(resp.take_header().take_error())));
    }
    if resp_cnt != resp.get_responses().len() {
        return (cb_ctx,
                Err(Error::InvalidResponse("response count is not equal to requests, something \
                                            must go wrong."
            .to_owned())));
    }
    let mut resps = resp.take_responses();
    if resps.len() != 1 || resps[0].get_cmd_type() != CmdType::Snap {
        return (cb_ctx, Ok(CmdRes::Resp(resps.into_vec())));
    }
    let snap = RegionSnapshot::from_raw(db, resps[0].take_snap().take_region());
    (cb_ctx, Ok(CmdRes::Snap(snap)))
}

impl<S: RaftStoreRouter> RaftKv<S> {
    /// Create a RaftKv using specified configuration.
    pub fn new(db: Arc<DB>, router: S) -> RaftKv<S> {
        RaftKv {
            db: db,
            router: router,
        }
    }

    fn call_command(&self, req: RaftCmdRequest, cb: Callback<CmdRes>) -> Result<()> {
        let uuid = req.get_header().get_uuid().to_vec();
        let l = req.get_requests().len();
        let db = self.db.clone();
        try!(self.router.send_command(req,
                                      box move |resp| {
                                          let (cb_ctx, res) = on_result(resp, l, &uuid, db);
                                          cb((cb_ctx, res.map_err(Error::into)));
                                      }));
        Ok(())
    }

    fn new_request_header(&self, ctx: &Context) -> RaftRequestHeader {
        let mut header = RaftRequestHeader::new();
        header.set_region_id(ctx.get_region_id());
        header.set_peer(ctx.get_peer().clone());
        header.set_region_epoch(ctx.get_region_epoch().clone());
        header.set_uuid(Uuid::new_v4().as_bytes().to_vec());
        header.set_read_quorum(ctx.get_read_quorum());
        if ctx.get_term() != 0 {
            header.set_term(ctx.get_term());
        }
        header
    }

    fn exec_requests(&self, ctx: &Context, reqs: Vec<Request>, cb: Callback<CmdRes>) -> Result<()> {
        let header = self.new_request_header(ctx);
        let mut cmd = RaftCmdRequest::new();
        cmd.set_header(header);
        cmd.set_requests(RepeatedField::from_vec(reqs));
        self.call_command(cmd, cb)
    }
}

fn invalid_resp_type(exp: CmdType, act: CmdType) -> Error {
    Error::InvalidResponse(format!("cmd type not match, want {:?}, got {:?}!", exp, act))
}

impl<S: RaftStoreRouter> Debug for RaftKv<S> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        write!(f, "RaftKv")
    }
}

impl<S: RaftStoreRouter> Engine for RaftKv<S> {
    fn async_write(&self,
                   ctx: &Context,
                   mut modifies: Vec<Modify>,
                   cb: Callback<()>)
                   -> engine::Result<()> {
        let mut reqs = Vec::with_capacity(modifies.len());
        while !modifies.is_empty() {
            let m = modifies.pop().unwrap();
            let mut req = Request::new();
            match m {
                Modify::Delete(cf, k) => {
                    let mut delete = DeleteRequest::new();
                    delete.set_key(k.encoded().to_owned());
                    if cf != CF_DEFAULT {
                        delete.set_cf(cf.to_string());
                    }
                    req.set_cmd_type(CmdType::Delete);
                    req.set_delete(delete);
                }
                Modify::Put(cf, k, v) => {
                    let mut put = PutRequest::new();
                    put.set_key(k.encoded().to_owned());
                    put.set_value(v);
                    if cf != CF_DEFAULT {
                        put.set_cf(cf.to_string());
                    }
                    req.set_cmd_type(CmdType::Put);
                    req.set_put(put);
                }
            }
            reqs.push(req);
        }

        ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["write", "all"]).inc();
        let req_timer = ASYNC_REQUESTS_DURATIONS_VEC.with_label_values(&["write"]).start_timer();

        self.exec_requests(ctx,
                           reqs,
                           box move |(cb_ctx, res)| {
                match res {
                    Ok(CmdRes::Resp(_)) => {
                        req_timer.observe_duration();
                        ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["write", "success"]).inc();

                        cb((cb_ctx, Ok(())))
                    }
                    Ok(CmdRes::Snap(_)) => {
                        cb((cb_ctx, Err(box_err!("unexpect snapshot, should mutate instead."))))
                    }
                    Err(e) => {
                        let tag = get_tag_from_engine_error(&e);
                        ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["write", tag]).inc();
                        cb((cb_ctx, Err(e)))
                    }
                }
            })
            .map_err(|e| {
                let tag = get_tag_from_error(&e);
                ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["write", tag]).inc();
                e.into()
            })
    }

    fn async_snapshot(&self, ctx: &Context, cb: Callback<Box<Snapshot>>) -> engine::Result<()> {
        let mut req = Request::new();
        req.set_cmd_type(CmdType::Snap);

        ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["snapshot", "all"]).inc();
        let req_timer = ASYNC_REQUESTS_DURATIONS_VEC.with_label_values(&["snapshot"]).start_timer();

        self.exec_requests(ctx,
                           vec![req],
                           box move |(cb_ctx, res)| {
                match res {
                    Ok(CmdRes::Resp(r)) => {
                        cb((cb_ctx,
                            Err(invalid_resp_type(CmdType::Snap, r[0].get_cmd_type()).into())))
                    }
                    Ok(CmdRes::Snap(s)) => {
                        req_timer.observe_duration();
                        ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["snapshot", "success"])
                            .inc();
                        cb((cb_ctx, Ok(box s)))
                    }
                    Err(e) => {
                        let tag = get_tag_from_engine_error(&e);
                        ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["snapshot", tag]).inc();
                        cb((cb_ctx, Err(e)))
                    }
                }
            })
            .map_err(|e| {
                let tag = get_tag_from_error(&e);
                ASYNC_REQUESTS_COUNTER_VEC.with_label_values(&["snapshot", tag]).inc();
                e.into()
            })
    }

    fn clone(&self) -> Box<Engine> {
        box RaftKv::new(self.db.clone(), self.router.clone())
    }
}

impl Snapshot for RegionSnapshot {
    fn get(&self, key: &Key) -> engine::Result<Option<Value>> {
        let v = box_try!(self.get_value(key.encoded()));
        Ok(v.map(|v| v.to_vec()))
    }

    fn get_cf(&self, cf: CfName, key: &Key) -> engine::Result<Option<Value>> {
        let v = box_try!(self.get_value_cf(cf, key.encoded()));
        Ok(v.map(|v| v.to_vec()))
    }

    #[allow(needless_lifetimes)]
    fn iter<'b>(&'b self,
                upper_bound: Option<&[u8]>,
                fill_cache: bool,
                mode: ScanMode)
                -> engine::Result<Cursor<'b>> {
        Ok(Cursor::new(RegionSnapshot::iter(self, upper_bound, fill_cache), mode))
    }

    #[allow(needless_lifetimes)]
    fn iter_cf<'b>(&'b self,
                   cf: CfName,
                   upper_bound: Option<&[u8]>,
                   fill_cache: bool,
                   mode: ScanMode)
                   -> engine::Result<Cursor<'b>> {
        Ok(Cursor::new(try!(RegionSnapshot::iter_cf(self, cf, upper_bound, fill_cache)),
                       mode))
    }
}

impl<'a> EngineIterator for RegionIterator<'a> {
    fn next(&mut self) -> bool {
        RegionIterator::next(self)
    }

    fn prev(&mut self) -> bool {
        RegionIterator::prev(self)
    }

    fn seek(&mut self, key: &Key) -> engine::Result<bool> {
        RegionIterator::seek(self, key.encoded()).map_err(From::from)
    }

    fn seek_to_first(&mut self) -> bool {
        RegionIterator::seek_to_first(self)
    }

    fn seek_to_last(&mut self) -> bool {
        RegionIterator::seek_to_last(self)
    }

    fn valid(&self) -> bool {
        RegionIterator::valid(self)
    }

    fn key(&self) -> &[u8] {
        RegionIterator::key(self)
    }

    fn value(&self) -> &[u8] {
        RegionIterator::value(self)
    }

    fn validate_key(&self, key: &Key) -> engine::Result<()> {
        self.should_seekable(key.encoded()).map_err(From::from)
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix depreciations<commit_after><|endoftext|>


<commit_before>#![allow(dead_code, unused_variables, unused_imports)]
#![cfg(test)]
/// The utils module is used by other tests to make writing tests easier.
///
/// The idea is to provide tests with a neat interface that allows tests to define a pipeline of
/// transformations on the input.
/// The test is then returned with a result struct that contains information about all the
/// intermediate stages to assert! for correctness.

extern crate radeco;

use radeco::frontend::parser::{Parser};
use radeco::frontend::structs::{LOpInfo, LRegInfo};
use radeco::frontend::r2::R2;
use radeco::frontend::esilssa::SSAConstruction;
use radeco::middle::ir::{MInst};
use radeco::middle::cfg::CFG;
use radeco::middle::dot;
use radeco::middle::ssa::SSAStorage;

use std::io::prelude::*;
use std::fs::{File, create_dir};

macro_rules! out {
	($str: expr, $m: expr) => { if $m { println!($str) } }
}

fn write_file(fname: &str, res: String) {
	let mut file = File::create(fname).ok().expect("Error. Cannot create file!\n");
	file.write_all(res.as_bytes()).ok().expect("Error. Cannot write file!\n");
}

#[derive(Clone, Copy, Debug)]
pub enum Analysis {
	ConstProp,
}

#[derive(Clone, Copy, Debug)]
pub enum Pipeline {
	ReadFromR2,
	ParseEsil,
	CFG,
	SSA,
	AnalyzeSSA(Analysis),
	CWriter,
}

impl Pipeline {
	fn to_string(&self) -> String {
		let s = match *self {
			Pipeline::ReadFromR2 => "r2",
			Pipeline::ParseEsil => "radecoIR",
			Pipeline::CFG => "cfg",
			Pipeline::SSA => "ssa",
			Pipeline::AnalyzeSSA(a) => unimplemented!(),
			Pipeline::CWriter => unimplemented!(),
		};
		s.to_string()
	}
}

// Enum that represents the output of a stage in the Pipeline.
// Every stage has a corresponding Pipeout type.
#[derive(Clone)]
pub enum Pipeout {
	Esil(Vec<String>),
	LOpInfo(Vec<LOpInfo>),
	Instructions {i: Vec<MInst>},
	CFG {cfg: CFG},
	SSA {ssa: SSAStorage},
}

impl Pipeout {
	fn to_string(&self) -> String {
		let s = match *self {
			Pipeout::Esil(_) => "esil",
			Pipeout::LOpInfo(_) => "esil",
			Pipeout::Instructions {i: _} => "radecoIR",
			Pipeout::CFG {cfg: _} => "cfg",
			Pipeout::SSA {ssa: _} => "ssa",
		};
		s.to_string()
	}
}

// States all the vars important to various stages of the pipeline together.
// Also acts as the result struct.
pub struct State<'a> {
	r2: Option<R2>,
	esil: Option<Vec<String>>,
	reg_info: Option<LRegInfo>,
	p: Option<Parser<'a>>,
	cfg: Option<CFG>,
	ssa: Option<SSAStorage>,
	pipeout: Option<Pipeout>,
}

impl<'a> State<'a> {
	fn new() -> State<'a> {
		State {
			r2: None,
			esil: None,
			reg_info: None,
			p: None,
			cfg: None,
			ssa: None,
			pipeout: None,
		}
	}
}

pub struct Test<'a> {
	name: String,
	bin_name: Option<String>,
	addr: Option<String>,
	verbose: bool,
	pipeline: Vec<Pipeline>,
	results: Vec<Pipeout>,
	state: State<'a>,
}

impl<'a> Test<'a> {

	pub fn new(name: String, bin_name: Option<String>,
			   addr: Option<String>, verbose: bool,
			   pipeline: Vec<Pipeline>) -> Test<'a> {
		Test {
			name: name,
			bin_name: bin_name,
			addr: addr,
			verbose: verbose,
			pipeline: pipeline,
			results: Vec::new(),
			state: State::new(),
		}
	}

	fn set_reg_info(&mut self, reg_info: &LRegInfo) {
		self.state.reg_info = Some(reg_info.clone());
	}

	fn set_pipeout(&mut self, pipeout: &Pipeout) {
		self.state.pipeout = Some(pipeout.clone());
	}

	fn read_from_r2(&mut self) {
		assert!(!self.bin_name.is_none());
		assert!(!self.addr.is_none());

		out!("[*] Reading from R2", self.verbose);
		let bin_name = self.bin_name.clone().unwrap();
		let mut r2 = R2::new(&*bin_name);
		r2.init();
		let reg_info = r2.get_reg_info().unwrap();
		self.set_reg_info(&reg_info);
		let addr = self.addr.clone().unwrap();
		let func_info = r2.get_function(&*addr).unwrap();
		self.set_pipeout(&Pipeout::LOpInfo(func_info.ops.unwrap()));
		self.state.r2 = Some(r2);
	}

	fn parse_esil(&mut self) {
		let pipein = self.state.pipeout.clone().unwrap();
		out!("[*] Parsing ESIL", self.verbose);
		let mut p = Parser::new(None);
		if let Some(ref r) = self.state.reg_info {
			p.set_register_profile(r);
		}

		match pipein {
			Pipeout::Esil(strs) => {
				for _str in strs {
					p.parse_str(&*_str).ok();
				}
			},
			Pipeout::LOpInfo(mut ops) => {
				for op in ops.iter_mut() {
					p.parse_opinfo(op).ok();
				}
			},
			_  => panic!("Incompatible type found in the pipeline!"),
		}

		let insts = p.emit_insts();
		let pipeout = Pipeout::Instructions {i: insts};
		self.set_pipeout(&pipeout);
		self.state.p = Some(p);
	}

	fn construct_cfg(&mut self) {
		let mut pipein = self.state.pipeout.clone().unwrap();
		out!("[*] Starting CFG Construction", self.verbose);
		match pipein {
			Pipeout::Instructions {i: ref mut insts} => {
				let mut cfg = CFG::new();
				cfg.build(insts);
				let pipeout = Pipeout::CFG {cfg: cfg.clone()};
				self.set_pipeout(&pipeout);
				self.state.cfg = Some(cfg);
			},
			_ => panic!("Incompatible type found in the pipeline!"),
		}
	}

	fn construct_ssa(&mut self) {
		// TODO: Relax this condition.
		assert!(self.state.reg_info.is_some());
		out!("[*] Starting SSA Construction", self.verbose);
		let pipein = self.state.pipeout.clone().unwrap();
		let r = self.state.reg_info.clone().unwrap();
		match pipein {
			Pipeout::CFG {ref cfg} => {
				let mut ssa = SSAStorage::new();

				{
					let mut con = SSAConstruction::new(&mut ssa, &r);
					con.run(cfg);
				}

				let pipeout = Pipeout::SSA {ssa: ssa.clone()};
				self.set_pipeout(&pipeout);
				self.state.ssa = Some(ssa);
			},
			_ => panic!("Incompatible type found in the pipeline!"),
		}
	}

	pub fn run(&mut self) {
		let pipe_iter = self.pipeline.clone();
		for stage in pipe_iter.iter() {

			match *stage {
				Pipeline::ReadFromR2 => self.read_from_r2(),
				Pipeline::ParseEsil => self.parse_esil(),
				Pipeline::CFG => self.construct_cfg(),
				Pipeline::SSA => self.construct_ssa(),
				Pipeline::AnalyzeSSA(a) => unimplemented!(),
				Pipeline::CWriter => unimplemented!(),
			}
			self.results.push(self.state.pipeout.clone().unwrap());
		}
	}

	pub fn dump(&self) {
		for res in self.results.iter() {
			let mut write_out = String::new();
			let mut ext;
			match *res {
				Pipeout::Esil(ref s) => {
					ext = "esil";
					for esil in s {
						let tmp = format!("{}\n",esil);
						write_out.push_str(&*tmp);
					}
				},
				Pipeout::LOpInfo(ref ops) => {
					ext = "esil";
					for op in ops {
						let tmp = format!("{}:\t{}\n", op.offset.unwrap(), op.esil.clone().unwrap());
						write_out.push_str(&*tmp);
					}
				},
				Pipeout::Instructions {i: ref insts} => {
					ext = "insts";
					for inst in insts {
						let tmp = format!("0x{:08X}:\t{}\n", inst.addr.val, inst);
						write_out.push_str(&*tmp);
					}
				},
				Pipeout::CFG {ref cfg} => {
					ext = "dot";
					let tmp = dot::emit_dot(cfg);
					write_out.push_str(&*tmp);
				},
				Pipeout::SSA {ref ssa} => {
					ext = "dot";
					let tmp = dot::emit_dot(ssa);
					write_out.push_str(&*tmp);
				},
			}

			let dir = format!("outputs/{}/", self.name);
			create_dir(&*dir).ok();
			let fname = format!("{}{}_{}.{}", dir, self.name, res.to_string(), ext);
			write_file(&*fname, write_out);
		}
	}
}
<commit_msg>Removes compiler lints<commit_after>#![cfg(test)]
/// The utils module is used by other tests to make writing tests easier.
///
/// The idea is to provide tests with a neat interface that allows tests to define a pipeline of
/// transformations on the input.
/// The test is then returned with a result struct that contains information about all the
/// intermediate stages to assert! for correctness.

extern crate radeco;

use radeco::frontend::parser::{Parser};
use radeco::frontend::structs::{LOpInfo, LRegInfo};
use radeco::frontend::r2::R2;
use radeco::frontend::esilssa::SSAConstruction;
use radeco::middle::ir::{MInst};
use radeco::middle::cfg::CFG;
use radeco::middle::dot;
use radeco::middle::ssa::SSAStorage;

use std::io::prelude::*;
use std::fs::{File, create_dir};

macro_rules! out {
	($str: expr, $m: expr) => { if $m { println!($str) } }
}

fn write_file(fname: &str, res: String) {
	let mut file = File::create(fname).ok().expect("Error. Cannot create file!\n");
	file.write_all(res.as_bytes()).ok().expect("Error. Cannot write file!\n");
}

#[derive(Clone, Copy, Debug)]
pub enum Analysis {
	ConstProp,
}

#[derive(Clone, Copy, Debug)]
pub enum Pipeline {
	ReadFromR2,
	ParseEsil,
	CFG,
	SSA,
	AnalyzeSSA(Analysis),
	CWriter,
}

// Enum that represents the output of a stage in the Pipeline.
// Every stage has a corresponding Pipeout type.
#[derive(Clone)]
pub enum Pipeout {
	Esil(Vec<String>),
	LOpInfo(Vec<LOpInfo>),
	Instructions {i: Vec<MInst>},
	CFG {cfg: CFG},
	SSA {ssa: SSAStorage},
}

impl Pipeout {
	fn to_string(&self) -> String {
		let s = match *self {
			Pipeout::Esil(_) => "esil",
			Pipeout::LOpInfo(_) => "esil",
			Pipeout::Instructions {i: _} => "radecoIR",
			Pipeout::CFG {cfg: _} => "cfg",
			Pipeout::SSA {ssa: _} => "ssa",
		};
		s.to_string()
	}
}

// States all the vars important to various stages of the pipeline together.
// Also acts as the result struct.
#[allow(dead_code)]
pub struct State<'a> {
	r2: Option<R2>,
	esil: Option<Vec<String>>,
	reg_info: Option<LRegInfo>,
	p: Option<Parser<'a>>,
	cfg: Option<CFG>,
	ssa: Option<SSAStorage>,
	pipeout: Option<Pipeout>,
}

impl<'a> State<'a> {
	fn new() -> State<'a> {
		State {
			r2: None,
			esil: None,
			reg_info: None,
			p: None,
			cfg: None,
			ssa: None,
			pipeout: None,
		}
	}
}

pub struct Test<'a> {
	name: String,
	bin_name: Option<String>,
	addr: Option<String>,
	verbose: bool,
	pipeline: Vec<Pipeline>,
	results: Vec<Pipeout>,
	state: State<'a>,
}

impl<'a> Test<'a> {

	pub fn new(name: String, bin_name: Option<String>,
			   addr: Option<String>, verbose: bool,
			   pipeline: Vec<Pipeline>) -> Test<'a> {
		Test {
			name: name,
			bin_name: bin_name,
			addr: addr,
			verbose: verbose,
			pipeline: pipeline,
			results: Vec::new(),
			state: State::new(),
		}
	}

	fn set_reg_info(&mut self, reg_info: &LRegInfo) {
		self.state.reg_info = Some(reg_info.clone());
	}

	fn set_pipeout(&mut self, pipeout: &Pipeout) {
		self.state.pipeout = Some(pipeout.clone());
	}

	fn read_from_r2(&mut self) {
		assert!(!self.bin_name.is_none());
		assert!(!self.addr.is_none());
		out!("[*] Reading from R2", self.verbose);
		let bin_name = self.bin_name.clone().unwrap();
		let mut r2 = R2::new(&*bin_name);
		r2.init();
		let reg_info = r2.get_reg_info().unwrap();
		self.set_reg_info(&reg_info);
		let addr = self.addr.clone().unwrap();
		let func_info = r2.get_function(&*addr).unwrap();
		self.set_pipeout(&Pipeout::LOpInfo(func_info.ops.unwrap()));
		self.state.r2 = Some(r2);
	}

	fn parse_esil(&mut self) {
		let pipein = self.state.pipeout.clone().unwrap();
		out!("[*] Parsing ESIL", self.verbose);
		let mut p = Parser::new(None);
		if let Some(ref r) = self.state.reg_info {
			p.set_register_profile(r);
		}
		match pipein {
			Pipeout::Esil(strs) => {
				for _str in strs {
					p.parse_str(&*_str).ok();
				}
			},
			Pipeout::LOpInfo(mut ops) => {
				for op in ops.iter_mut() {
					p.parse_opinfo(op).ok();
				}
			},
			_  => panic!("Incompatible type found in the pipeline!"),
		}

		let insts = p.emit_insts();
		let pipeout = Pipeout::Instructions {i: insts};
		self.set_pipeout(&pipeout);
		self.state.p = Some(p);
	}

	fn construct_cfg(&mut self) {
		let mut pipein = self.state.pipeout.clone().unwrap();
		out!("[*] Starting CFG Construction", self.verbose);
		match pipein {
			Pipeout::Instructions {i: ref mut insts} => {
				let mut cfg = CFG::new();
				cfg.build(insts);
				let pipeout = Pipeout::CFG {cfg: cfg.clone()};
				self.set_pipeout(&pipeout);
				self.state.cfg = Some(cfg);
			},
			_ => panic!("Incompatible type found in the pipeline!"),
		}
	}

	fn construct_ssa(&mut self) {
		// TODO: Relax this condition.
		assert!(self.state.reg_info.is_some());
		out!("[*] Starting SSA Construction", self.verbose);
		let pipein = self.state.pipeout.clone().unwrap();
		let r = self.state.reg_info.clone().unwrap();
		match pipein {
			Pipeout::CFG {ref cfg} => {
				let mut ssa = SSAStorage::new();
				{
					let mut con = SSAConstruction::new(&mut ssa, &r);
					con.run(cfg);
				}
				let pipeout = Pipeout::SSA {ssa: ssa.clone()};
				self.set_pipeout(&pipeout);
				self.state.ssa = Some(ssa);
			},
			_ => panic!("Incompatible type found in the pipeline!"),
		}
	}

	pub fn run(&mut self) {
		let pipe_iter = self.pipeline.clone();
		for stage in pipe_iter.iter() {
			match *stage {
				Pipeline::ReadFromR2 => self.read_from_r2(),
				Pipeline::ParseEsil => self.parse_esil(),
				Pipeline::CFG => self.construct_cfg(),
				Pipeline::SSA => self.construct_ssa(),
				Pipeline::AnalyzeSSA(_) => unimplemented!(),
				Pipeline::CWriter => unimplemented!(),
			}
			self.results.push(self.state.pipeout.clone().unwrap());
		}
	}

	pub fn dump(&self) {
		for res in self.results.iter() {
			let mut write_out = String::new();
			let mut ext;
			match *res {
				Pipeout::Esil(ref s) => {
					ext = "esil";
					for esil in s {
						let tmp = format!("{}\n",esil);
						write_out.push_str(&*tmp);
					}
				},
				Pipeout::LOpInfo(ref ops) => {
					ext = "esil";
					for op in ops {
						let tmp = format!("{}:\t{}\n", op.offset.unwrap(), op.esil.clone().unwrap());
						write_out.push_str(&*tmp);
					}
				},
				Pipeout::Instructions {i: ref insts} => {
					ext = "insts";
					for inst in insts {
						let tmp = format!("0x{:08X}:\t{}\n", inst.addr.val, inst);
						write_out.push_str(&*tmp);
					}
				},
				Pipeout::CFG {ref cfg} => {
					ext = "dot";
					let tmp = dot::emit_dot(cfg);
					write_out.push_str(&*tmp);
				},
				Pipeout::SSA {ref ssa} => {
					ext = "dot";
					let tmp = dot::emit_dot(ssa);
					write_out.push_str(&*tmp);
				},
			}
			let dir = format!("outputs/{}/", self.name);
			create_dir(&*dir).ok();
			let fname = format!("{}{}_{}.{}", dir, self.name, res.to_string(), ext);
			write_file(&*fname, write_out);
		}
	}
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use std::rc::Rc;

#[derive(Debug, Clone)]
struct Node<A> {
    parent: Option<(u8, Rc<Node<A>>)>,
    value: A,
    children: Vec<Option<Rc<Node<A>>>>,
}

impl<A> Node<A> {
    pub fn new(a: A) -> Node<A>{
        Node { value: a, children: Vec::new(), parent: None }
    }

    pub fn map<B>(&self, f: &Fn(&A) -> B) -> Node<B> {
        let new_parent = match self.parent {
            Some((i, ref p)) => Some((i, Rc::new(p.map(f)))),
            None => None,
        };
        let new_children = self.children.iter().map(|o| o.clone().map(|v| Rc::new(v.map(f)))).collect();
        Node { parent: new_parent, value: f(&self.value), children: new_children }
    }

    pub fn map_mut<B: Clone>(&self, f: &mut FnMut(&A) -> B) -> Node<B> {
        let new_parent = match self.parent {
            Some((i, ref p)) => Some((i, Rc::new(p.map_mut(f)))),
            None => None,
        };
        let new_children = self.children.iter().map(|o| o.clone().map(|v| Rc::new(v.map_mut(f)))).collect();
        Node { parent: new_parent, value: f(&self.value), children: new_children }
    }
}

impl<A: PartialEq> PartialEq for Node<A> {
    fn eq(&self, other: &Self) -> bool {
        let comp = |p1, p2| Rc::ptr_eq(p1, p2) || p1 == p2;
        self.value == other.value
            && match (&self.parent, &other.parent) {
                (&Some((i1, ref p1)), &Some((i2, ref p2))) => i1 == i2 && comp(p1, p2),
                (&None, &None)                             => true,
                _                                          => false,
            }
            && self.children == other.children
    }
}

impl<A: Eq> Eq for Node<A> {}

/// Upside-down tree with a designated position (the *stack pointer*) and *nodes* of type `A`.
#[derive(Debug)]
pub struct TreeStack<A> {
    current_node: Rc<Node<A>>,  // TODO replace by unique pointer when std::ptr::Unique has landed
}

impl<A: Clone> Clone for TreeStack<A> {
    fn clone(&self) -> Self {
        Self { current_node: Rc::new(self.current_node.deref().clone()) }
    }
}

impl<A: Clone> TreeStack<A> {
    /// Creates a new `TreeStack<A>` with root label `a`.
    pub fn new(a: A) -> TreeStack<A> {
        Self::from_node(Node::new(a))
    }

    fn from_node(n: Node<A>) -> Self {
        TreeStack { current_node: Rc::new(n) }
    }

    /// Returns `True` if the stack pointer points to the bottom node.
    pub fn is_at_bottom(&self) -> bool {
        self.current_node.parent.is_none()
    }

    /// Returns a reference to label of the current node.
    pub fn current_symbol(&self) -> &A {
        &self.current_node.value
    }

    /// Applies a function `Fn(&A) -> B`to every node in a `TreeStack<A>`.
    pub fn map<B: Clone + PartialEq>(&self, f: &Fn(&A) -> B) -> TreeStack<B> {
        TreeStack::from_node(self.current_node.map(f))
    }

    /// Applies a function `FnMut(&A) -> B`to every node in a `TreeStack<A>`.
    pub fn map_mut<B: Clone + PartialEq>(&self, f: &mut FnMut(&A) -> B) -> TreeStack<B> {
        TreeStack::from_node(self.current_node.map_mut(f))
    }

    /// Replaces the current value by the given value.
    pub fn set(mut self, a: A) -> Self {
        {
            let mut cn = match Rc::get_mut(&mut self.current_node) {
                Some(c) => c,
                None => panic!("multiple pointers to the same `current_node`."),
            };
            cn.value = a;
        }

        self
    }

    /// Writes a value to the specified child position (if the child position is vacant) and returns the resulting `TreeStack` in an `Ok`.
    /// Returns the unmodified `TreeStack` in an `Err` otherwise.
    pub fn push(mut self, n: u8, a: A) -> Result<Self, Self> {
        if {
            let mut cn = match Rc::get_mut(&mut self.current_node) {
                Some(c) => c,
                None => panic!("multiple pointers to the same `current_node`."),
            };

            let filler = &mut vec![None; usize::from(n) - cn.children.len() + 1];
            cn.children.append(filler);

            cn.children[usize::from(n)].is_none()
        } {
            Ok(Self::from_node(Node { value: a,
                                      children: Vec::new(),
                                      parent: Some((n, self.current_node)) }))
        } else {
            Err(self)
        }
    }

    /// Goes up to a specific child position (if this position is occupied) and returns the resulting `TreeStack` in an `Ok`.
    /// Returns the unmodified `TreeStack` in an `Err` otherwise.
    pub fn up(mut self, n: u8) -> Result<Self, Self> {
        match {
            let mut cn = match Rc::get_mut(&mut self.current_node) {
                Some(c) => c,
                None => panic!("multiple pointers to the same `current_node`."),
            };

            if cn.children.len() > usize::from(n) {
                cn.children.push(None);
                cn.children.swap_remove(usize::from(n))
            } else {
                None
            }
        } {
            Some(tn) => Ok(Self::from_node(Node { value: tn.value.clone(),
                                                  children: tn.children.clone(),
                                                  parent: Some((n, self.current_node)) })),
            None => Err(self),
        }
    }

    /// Goes down to the parent position (if there is one) and returns the resulting `TreeStack` in an `Ok`.
    /// Returns the unmodified `TreeStack` in an `Err` otherwise.
    pub fn down(mut self) -> Result<Self, Self> {
        match {
            let mut cn = match Rc::get_mut(&mut self.current_node) {
                Some(c) => c,
                None => panic!("multiple pointers to the same `current_node`."),
            };

            cn.parent.take()
        } {
            Some((n, pn)) => {
                let mut new_pch = pn.children.clone();
                new_pch[usize::from(n)] = Some(self.current_node);
                Ok(Self::from_node(Node { value: pn.value.clone(),
                                          children: new_pch,
                                          parent: pn.parent.clone() }))
            },
            None => Err(self),
        }
    }
}

#[test]
fn test_tree_stack() {
    let mut ts: TreeStack<u8> = TreeStack::new(0);
    assert_eq!(&0, ts.current_symbol());

    ts = ts.push(1, 1).unwrap().clone();
    assert_eq!(&1, ts.current_symbol());

    ts = ts.down().unwrap().clone();
    assert_eq!(&0, ts.current_symbol());

    ts = ts.push(2, 2).unwrap().clone();
    assert_eq!(&2, ts.current_symbol());

    ts = ts.down().unwrap().clone();
    ts = ts.up(1).unwrap().clone();
    assert_eq!(&1, ts.current_symbol());

    let ts1 = ts.clone().push(1, 11);
    let ts2 = ts.push(1, 11);
    assert_eq!(ts1, ts2);
}

impl<A: PartialEq> PartialEq for TreeStack<A> {
    fn eq(&self, other: &Self) -> bool {
        Rc::ptr_eq(&self.current_node, &other.current_node)
            || self.current_node == other.current_node
    }
}

impl<A: PartialEq> Eq for TreeStack<A> {}
<commit_msg>src/tree_stack/tree_stack.rs: removed intermediate Rc-Pointer<commit_after>use std::rc::Rc;

/// upside-down tree with a designated position (the *stack pointer*) and *nodes* of type `a`.
#[derive(Debug, Clone)]
pub struct TreeStack<A> {
    parent: Option<(u8, Rc<TreeStack<A>>)>,
    value: A,
    children: Vec<Option<Rc<TreeStack<A>>>>,
}

impl<A> TreeStack<A> {
    /// Creates a new `TreeStack<A>` with root label `a`.
    pub fn new(a: A) -> Self {
        TreeStack { value: a, children: Vec::new(), parent: None }
    }

    /// Applies a function `Fn(&A) -> B`to every node in a `TreeStack<A>`.
    pub fn map<B>(&self, f: &Fn(&A) -> B) -> TreeStack<B> {
        let new_parent = match self.parent {
            Some((i, ref p)) => Some((i, Rc::new(p.map(f)))),
            None => None,
        };
        let new_children = self.children.iter().map(|o| o.clone().map(|v| Rc::new(v.map(f)))).collect();
        TreeStack { parent: new_parent, value: f(&self.value), children: new_children }
    }

    /// Applies a function `FnMut(&A) -> B`to every node in a `TreeStack<A>`.
    pub fn map_mut<B: Clone>(&self, f: &mut FnMut(&A) -> B) -> TreeStack<B> {
        let new_parent = match self.parent {
            Some((i, ref p)) => Some((i, Rc::new(p.map_mut(f)))),
            None => None,
        };
        let new_children = self.children.iter().map(|o| o.clone().map(|v| Rc::new(v.map_mut(f)))).collect();
        TreeStack { parent: new_parent, value: f(&self.value), children: new_children }
    }

    /// Returns `True` if the stack pointer points to the bottom node.
    pub fn is_at_bottom(&self) -> bool {
        self.parent.is_none()
    }

    /// Returns a reference to label of the current node.
    pub fn current_symbol(&self) -> &A {
        &self.value
    }

    /// Replaces the current value by the given value.
    pub fn set(mut self, a: A) -> Self {
        self.value = a;
        self
    }

    /// Writes a value to the specified child position (if the child position is vacant) and returns the resulting `TreeStack` in an `Ok`.
    /// Returns the unmodified `TreeStack` in an `Err` otherwise.
    pub fn push(mut self, n: u8, a: A) -> Result<Self, Self> {
        if {
            let filler = &mut vec![None; usize::from(n) - self.children.len() + 1];
            self.children.append(filler);

            self.children[usize::from(n)].is_none()
        } {
            Ok(TreeStack { value: a,
                           children: Vec::new(),
                           parent: Some((n, Rc::new(self))) })
        } else {
            Err(self)
        }
    }
}

impl<A: Clone> TreeStack<A> {
    /// Goes up to a specific child position (if this position is occupied) and returns the resulting `TreeStack` in an `Ok`.
    /// Returns the unmodified `TreeStack` in an `Err` otherwise.
    pub fn up(mut self, n: u8) -> Result<Self, Self> {
        match {
            if self.children.len() > usize::from(n) {
                self.children.push(None);
                self.children.swap_remove(usize::from(n))
            } else {
                None
            }
        } {
            Some(ref tn) => Ok(TreeStack { value: tn.value.clone(),
                                           children: tn.children.clone(),
                                           parent: Some((n, Rc::new(self))) }),
            _ => Err(self),
        }
    }

    /// Goes down to the parent position (if there is one) and returns the resulting `TreeStack` in an `Ok`.
    /// Returns the unmodified `TreeStack` in an `Err` otherwise.
    pub fn down(mut self) -> Result<Self, Self> {
        match self.parent.take() {
            Some((n, pn)) => {
                let mut new_pch = pn.children.clone();
                new_pch[usize::from(n)] = Some(Rc::new(self));
                Ok(TreeStack { value: pn.value.clone(),
                               children: new_pch,
                               parent: pn.parent.clone() })
            },
            None => Err(self),
        }
    }
}

impl<A: PartialEq> PartialEq for TreeStack<A> {
    fn eq(&self, other: &Self) -> bool {
        let comp = |p1, p2| Rc::ptr_eq(p1, p2) || p1 == p2;
        self.value == other.value
            && match (&self.parent, &other.parent) {
                (&Some((i1, ref p1)), &Some((i2, ref p2))) => i1 == i2 && comp(p1, p2),
                (&None, &None)                             => true,
                _                                          => false,
            }
            && self.children == other.children
    }
}

impl<A: Eq> Eq for TreeStack<A> {}

#[test]
fn test_tree_stack() {
    let mut ts: TreeStack<u8> = TreeStack::new(0);
    assert_eq!(&0, ts.current_symbol());

    ts = ts.push(1, 1).unwrap().clone();
    assert_eq!(&1, ts.current_symbol());

    ts = ts.down().unwrap().clone();
    assert_eq!(&0, ts.current_symbol());

    ts = ts.push(2, 2).unwrap().clone();
    assert_eq!(&2, ts.current_symbol());

    ts = ts.down().unwrap().clone();
    ts = ts.up(1).unwrap().clone();
    assert_eq!(&1, ts.current_symbol());

    let ts1 = ts.clone().push(1, 11);
    let ts2 = ts.push(1, 11);
    assert_eq!(ts1, ts2);
}
<|endoftext|>


<commit_before><commit_msg>Improve solution for Pythagorean Triplet<commit_after><|endoftext|>


<commit_before>fn main() {
    // Pull in jemalloc when enabled.
    //
    // Note that we're pulling in a static copy of jemalloc which means that to
    // pull it in we need to actually reference its symbols for it to get
    // linked. The two crates we link to here, std and rustc_driver, are both
    // dynamic libraries. That means to pull in jemalloc we actually need to
    // reference allocation symbols one way or another (as this file is the only
    // object code in the rustc executable).
    #[cfg(feature = "jemalloc-sys")]
    {
        use std::os::raw::{c_int, c_void};

        #[used]
        static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
        #[used]
        static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
            jemalloc_sys::posix_memalign;
        #[used]
        static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
        #[used]
        static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
        #[used]
        static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
        #[used]
        static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;
    }

    rustc_driver::set_sigpipe_handler();
    rustc_driver::main()
}
<commit_msg>Rollup merge of #82642 - sfackler:jemalloc-zone, r=pnkfelix<commit_after>fn main() {
    // Pull in jemalloc when enabled.
    //
    // Note that we're pulling in a static copy of jemalloc which means that to
    // pull it in we need to actually reference its symbols for it to get
    // linked. The two crates we link to here, std and rustc_driver, are both
    // dynamic libraries. That means to pull in jemalloc we actually need to
    // reference allocation symbols one way or another (as this file is the only
    // object code in the rustc executable).
    #[cfg(feature = "jemalloc-sys")]
    {
        use std::os::raw::{c_int, c_void};

        #[used]
        static _F1: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::calloc;
        #[used]
        static _F2: unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> c_int =
            jemalloc_sys::posix_memalign;
        #[used]
        static _F3: unsafe extern "C" fn(usize, usize) -> *mut c_void = jemalloc_sys::aligned_alloc;
        #[used]
        static _F4: unsafe extern "C" fn(usize) -> *mut c_void = jemalloc_sys::malloc;
        #[used]
        static _F5: unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void = jemalloc_sys::realloc;
        #[used]
        static _F6: unsafe extern "C" fn(*mut c_void) = jemalloc_sys::free;

        // On OSX, jemalloc doesn't directly override malloc/free, but instead
        // registers itself with the allocator's zone APIs in a ctor. However,
        // the linker doesn't seem to consider ctors as "used" when statically
        // linking, so we need to explicitly depend on the function.
        #[cfg(target_os = "macos")]
        {
            extern "C" {
                fn _rjem_je_zone_register();
            }

            #[used]
            static _F7: unsafe extern "C" fn() = _rjem_je_zone_register;
        }
    }

    rustc_driver::set_sigpipe_handler();
    rustc_driver::main()
}
<|endoftext|>


<commit_before>extern crate sovrin;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate lazy_static;

#[path = "utils/mod.rs"]
mod utils;

use sovrin::api::ErrorCode;
use sovrin::api::pool::{sovrin_create_pool_ledger_config, sovrin_open_pool_ledger};
use sovrin::api::ledger::sovrin_submit_request;

#[path = "../src/utils/environment.rs"]
mod environment;

use environment::EnvironmentUtils;

use std::fs;

use std::ptr::null;

use std::time::Duration;

use utils::callbacks::CallbacksHelpers;

use std::sync::mpsc::{channel};
use std::ffi::{CString};
use std::io::Write;

fn _create_default_pool_transaction_file() {
    let mut f = fs::File::create("./pool_transactions_sandbox").unwrap();
    let data = format!("{}\n{}\n{}\n{}\n",
                       "{\"data\":{\"alias\":\"Node1\",\"client_ip\":\"10.0.0.2\",\"client_port\":9702,\"node_ip\":\"10.0.0.2\",\"node_port\":9701,\"services\":[\"VALIDATOR\"]},\"dest\":\"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv\",\"identifier\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\",\"txnId\":\"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62\",\"type\":\"0\"}",
                       "{\"data\":{\"alias\":\"Node2\",\"client_ip\":\"10.0.0.3\",\"client_port\":9704,\"node_ip\":\"10.0.0.3\",\"node_port\":9703,\"services\":[\"VALIDATOR\"]},\"dest\":\"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb\",\"identifier\":\"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy\",\"txnId\":\"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc\",\"type\":\"0\"}",
                       "{\"data\":{\"alias\":\"Node3\",\"client_ip\":\"10.0.0.4\",\"client_port\":9706,\"node_ip\":\"10.0.0.4\",\"node_port\":9705,\"services\":[\"VALIDATOR\"]},\"dest\":\"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya\",\"identifier\":\"2yAeV5ftuasWNgQwVYzeHeTuM7LwwNtPR3Zg9N4JiDgF\",\"txnId\":\"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4\",\"type\":\"0\"}",
                       "{\"data\":{\"alias\":\"Node4\",\"client_ip\":\"10.0.0.5\",\"client_port\":9708,\"node_ip\":\"10.0.0.5\",\"node_port\":9707,\"services\":[\"VALIDATOR\"]},\"dest\":\"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA\",\"identifier\":\"FTE95CVthRtrBnK2PYCBbC9LghTcGwi9Zfi1Gz2dnyNx\",\"txnId\":\"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008\",\"type\":\"0\"}");
    f.write_all(data.as_bytes()).unwrap();
    f.flush().unwrap();
}

#[test]
fn sovrin_create_pool_ledger_can_be_called() {
    let (sender, receiver) = channel();

    let cb = Box::new(move |err| {
        sender.send(err).unwrap();
    });

    let (command_handle, callback) = CallbacksHelpers::closure_to_create_pool_ledger_cb(cb);

    let pool_name = CString::new("test_open").unwrap();
    let pool_config = CString::new("{\"genesis_txn\": \"./pool_transactions_sandbox\"}").unwrap();
    _create_default_pool_transaction_file();

    let err = sovrin_create_pool_ledger_config(command_handle,
                                               pool_name.as_ptr(),
                                               pool_config.as_ptr(),
                                               callback);

    assert_eq!(ErrorCode::Success, err);

    let err = receiver.recv_timeout(Duration::from_secs(1)).unwrap();
    std::fs::remove_file("./test_open_src.txn").unwrap();
    std::fs::remove_dir_all(EnvironmentUtils::pool_path("test_open")).unwrap();
    assert_eq!(ErrorCode::Success, err);
}

#[test]
fn sovrin_open_pool_ledger_can_be_called() {
    let (sender, receiver) = channel();
    let sender2 = sender.clone();

    let cb = Box::new(move |err, _| {
        sender.send(err).unwrap();
    });
    let cb2 = Box::new(move |err, _| {
        sender2.send(err).unwrap();
    });

    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb);

    let pool_name: String = "test1".to_string();
    let c_pool_name = CString::new(pool_name.as_str()).unwrap();
    let mut path = environment::EnvironmentUtils::pool_path(pool_name.as_str());
    fs::create_dir_all(path.as_path()).unwrap();
    path.push(pool_name);
    path.set_extension("txn");
    fs::File::create(path.as_path()).unwrap();

    let err = sovrin_open_pool_ledger(command_handle,
                                      c_pool_name.as_ptr(),
                                      null(),
                                      callback);

    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv_timeout(Duration::from_secs(1)).unwrap();
    assert_eq!(ErrorCode::Success, err);

    //TODO separate test to check error after open the same pool multiply times
    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb2);
    let err = sovrin_open_pool_ledger(command_handle,
                                      c_pool_name.as_ptr(),
                                      null(),
                                      callback);

    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv_timeout(Duration::from_secs(1)).unwrap();
    assert_eq!(ErrorCode::PoolLedgerInvalidPoolHandle, err);
}

#[test]
#[ignore] //required nodes pool available from CI
fn sovrin_submit_request_can_be_called() {
    std::fs::remove_dir_all(EnvironmentUtils::pool_path("test")).unwrap();
    //create pool
    let (sender, receiver) = channel();
    let cb = Box::new(move |err| {
        sender.send(err).unwrap();
    });
    let (command_handle, callback) = CallbacksHelpers::closure_to_create_pool_ledger_cb(cb);
    let pool_name = CString::new("test").unwrap();
    let pool_config = CString::new("{\"genesis_txn\": \"./pool_transactions_sandbox\"}").unwrap();
    _create_default_pool_transaction_file();
    let err = sovrin_create_pool_ledger_config(command_handle,
                                               pool_name.as_ptr(),
                                               pool_config.as_ptr(),
                                               callback);
    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv_timeout(Duration::from_secs(1)).unwrap();
    assert_eq!(ErrorCode::Success, err);
    //open pool
    let (sender, receiver) = channel();
    let cb = Box::new(move |err, handle| {
        sender.send((err, handle)).unwrap();
    });
    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb);
    let pool_name = CString::new("test").unwrap();
    let err = sovrin_open_pool_ledger(command_handle,
                                      pool_name.as_ptr(),
                                      null(),
                                      callback);
    assert_eq!(ErrorCode::Success, err);
    let (err, pool_handle) = receiver.recv_timeout(std::time::Duration::from_secs(1)).unwrap();
    assert_eq!(ErrorCode::Success, err);
    std::thread::sleep(std::time::Duration::from_secs(1)); //TODO
    //test communication
    let (sender, receiver) = channel();
    let cb_send = Box::new(move |err, resp| {
        sender.send((err, resp)).unwrap();
    });
    let json = "{\
            \"reqId\":1491566332010860,\
            \"identifier\":\"Th7MpTaRZVRYnPiabds81Y\",\
            \"operation\":{\
                \"type\":\"105\",\
                \"dest\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\"\
            },\
            \"signature\":\"4o86XfkiJ4e2r3J6Ufoi17UU3W5Zi9sshV6FjBjkVw4sgEQFQov9dxqDEtLbAJAWffCWd5KfAk164QVo7mYwKkiV\"\
        }\
        ";
    let req = CString::new(json).unwrap();
    let (command_handle, callback) = CallbacksHelpers::closure_to_send_tx_cb(cb_send);

    let err = sovrin_submit_request(command_handle,
                                    pool_handle,
                                    req.as_ptr(),
                                    callback);

    assert_eq!(ErrorCode::Success, err);
    let recv = receiver.recv_timeout(std::time::Duration::from_secs(1));

    #[derive(Deserialize, Eq, PartialEq, Debug)]
    struct Reply {
        op: String,
        result: ReplyResult,
    }
    #[derive(Deserialize, Eq, PartialEq, Debug)]
    #[serde(rename_all = "camelCase")]
    struct ReplyResult {
        txn_id: String,
        req_id: u64,
    }
    let exp_reply = Reply {
        op: "REPLY".to_string(),
        result: ReplyResult {
            req_id: 1491566332010860,
            txn_id: "5511e5493c1d37dfa67b73269a392a7aca5b71e9d10ac106adc7f9e552aee560".to_string(),
        }
    };
    let act_reply: Reply = serde_json::from_str(recv.unwrap().1.as_str()).unwrap();
    assert_eq!(act_reply, exp_reply);
    //    std::fs::remove_dir_all(EnvironmentUtils::pool_path("test")).unwrap();
}
<commit_msg>Refactoring pool integration tests.<commit_after>extern crate sovrin;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
#[macro_use]
extern crate lazy_static;

#[path = "utils/mod.rs"]
mod utils;

use utils::callbacks::CallbacksHelpers;

#[path = "../src/utils/environment.rs"]
mod environment;

use environment::EnvironmentUtils;

use sovrin::api::ErrorCode;
use sovrin::api::pool::{sovrin_create_pool_ledger_config, sovrin_open_pool_ledger};
use sovrin::api::ledger::sovrin_submit_request;

use std::fs;
use std::ptr::null;
use std::time::Duration;
use std::sync::mpsc::{channel};
use std::ffi::{CString};
use std::io::Write;

fn _create_default_pool_transaction_file() {
    let mut f = fs::File::create("./pool_transactions_sandbox").unwrap();
    let data = format!("{}\n{}\n{}\n{}\n",
                       "{\"data\":{\"alias\":\"Node1\",\"client_ip\":\"10.0.0.2\",\"client_port\":9702,\"node_ip\":\"10.0.0.2\",\"node_port\":9701,\"services\":[\"VALIDATOR\"]},\"dest\":\"Gw6pDLhcBcoQesN72qfotTgFa7cbuqZpkX3Xo6pLhPhv\",\"identifier\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\",\"txnId\":\"fea82e10e894419fe2bea7d96296a6d46f50f93f9eeda954ec461b2ed2950b62\",\"type\":\"0\"}",
                       "{\"data\":{\"alias\":\"Node2\",\"client_ip\":\"10.0.0.3\",\"client_port\":9704,\"node_ip\":\"10.0.0.3\",\"node_port\":9703,\"services\":[\"VALIDATOR\"]},\"dest\":\"8ECVSk179mjsjKRLWiQtssMLgp6EPhWXtaYyStWPSGAb\",\"identifier\":\"8QhFxKxyaFsJy4CyxeYX34dFH8oWqyBv1P4HLQCsoeLy\",\"txnId\":\"1ac8aece2a18ced660fef8694b61aac3af08ba875ce3026a160acbc3a3af35fc\",\"type\":\"0\"}",
                       "{\"data\":{\"alias\":\"Node3\",\"client_ip\":\"10.0.0.4\",\"client_port\":9706,\"node_ip\":\"10.0.0.4\",\"node_port\":9705,\"services\":[\"VALIDATOR\"]},\"dest\":\"DKVxG2fXXTU8yT5N7hGEbXB3dfdAnYv1JczDUHpmDxya\",\"identifier\":\"2yAeV5ftuasWNgQwVYzeHeTuM7LwwNtPR3Zg9N4JiDgF\",\"txnId\":\"7e9f355dffa78ed24668f0e0e369fd8c224076571c51e2ea8be5f26479edebe4\",\"type\":\"0\"}",
                       "{\"data\":{\"alias\":\"Node4\",\"client_ip\":\"10.0.0.5\",\"client_port\":9708,\"node_ip\":\"10.0.0.5\",\"node_port\":9707,\"services\":[\"VALIDATOR\"]},\"dest\":\"4PS3EDQ3dW1tci1Bp6543CfuuebjFrg36kLAUcskGfaA\",\"identifier\":\"FTE95CVthRtrBnK2PYCBbC9LghTcGwi9Zfi1Gz2dnyNx\",\"txnId\":\"aa5e817d7cc626170eca175822029339a444eb0ee8f0bd20d3b0b76e566fb008\",\"type\":\"0\"}");
    f.write_all(data.as_bytes()).unwrap();
    f.flush().unwrap();
    f.sync_all().unwrap();
}

fn _create_pool_ledger(pool_name: &str) -> ErrorCode {
    let c_pool_name = CString::new(pool_name).unwrap();
    let (sender, receiver) = channel();

    let cb = Box::new(move |err| {
        sender.send(err).unwrap();
    });

    let (command_handle, callback) = CallbacksHelpers::closure_to_create_pool_ledger_cb(cb);

    let pool_config = CString::new("{\"genesis_txn\": \"./pool_transactions_sandbox\"}").unwrap();
    _create_default_pool_transaction_file();

    let err = sovrin_create_pool_ledger_config(command_handle,
                                               c_pool_name.as_ptr(),
                                               pool_config.as_ptr(),
                                               callback);

    assert_eq!(ErrorCode::Success, err);

    receiver.recv_timeout(Duration::from_secs(1)).unwrap()
}

#[test]
fn sovrin_create_pool_ledger_works() {
    let pool_name = "test_create_pool";
    #[allow(unused_must_use)]
    { fs::remove_dir_all(EnvironmentUtils::pool_path(pool_name)); }

    let err = _create_pool_ledger(pool_name);

    assert_eq!(ErrorCode::Success, err);
}

#[test]
fn sovrin_open_pool_ledger_works() {
    let pool_name = "test_open_pool";
    #[allow(unused_must_use)]
    { fs::remove_dir_all(EnvironmentUtils::pool_path(pool_name)); }

    //create pool
    let err = _create_pool_ledger(pool_name);
    assert_eq!(ErrorCode::Success, err);

    //test open pool
    let c_pool_name = CString::new(pool_name).unwrap();
    let (sender, receiver) = channel();
    let sender2 = sender.clone();

    let cb = Box::new(move |err, _| {
        sender.send(err).unwrap();
    });
    let cb2 = Box::new(move |err, _| {
        sender2.send(err).unwrap();
    });

    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb);

    let err = sovrin_open_pool_ledger(command_handle,
                                      c_pool_name.as_ptr(),
                                      null(),
                                      callback);

    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv_timeout(Duration::from_secs(1)).unwrap();
    assert_eq!(ErrorCode::Success, err);

    //TODO separate test to check error after open the same pool multiply times
    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb2);
    let err = sovrin_open_pool_ledger(command_handle,
                                      c_pool_name.as_ptr(),
                                      null(),
                                      callback);

    assert_eq!(ErrorCode::Success, err);
    let err = receiver.recv_timeout(Duration::from_secs(1)).unwrap();
    assert_eq!(ErrorCode::PoolLedgerInvalidPoolHandle, err);
    fs::remove_dir_all(EnvironmentUtils::pool_path(pool_name)).unwrap();
}

#[test]
#[ignore] //required nodes pool available from CI
fn sovrin_submit_request_works() {
    let pool_name = "test_submit_tx";
    #[allow(unused_must_use)]
    { fs::remove_dir_all(EnvironmentUtils::pool_path(pool_name)); }
    //create pool
    let err = _create_pool_ledger(pool_name);
    assert_eq!(ErrorCode::Success, err);
    //open pool
    let c_pool_name = CString::new(pool_name).unwrap();
    let (sender, receiver) = channel();
    let cb = Box::new(move |err, handle| {
        sender.send((err, handle)).unwrap();
    });
    let (command_handle, callback) = CallbacksHelpers::closure_to_open_pool_ledger_cb(cb);
    let err = sovrin_open_pool_ledger(command_handle,
                                      c_pool_name.as_ptr(),
                                      null(),
                                      callback);
    assert_eq!(ErrorCode::Success, err);
    let (err, pool_handle) = receiver.recv_timeout(Duration::from_secs(1)).unwrap();
    assert_eq!(ErrorCode::Success, err);
    std::thread::sleep(std::time::Duration::from_secs(1)); //TODO
    //test communication
    let (sender, receiver) = channel();
    let cb_send = Box::new(move |err, resp| {
        sender.send((err, resp)).unwrap();
    });
    let json = "{\
            \"reqId\":1491566332010860,\
            \"identifier\":\"Th7MpTaRZVRYnPiabds81Y\",\
            \"operation\":{\
                \"type\":\"105\",\
                \"dest\":\"FYmoFw55GeQH7SRFa37dkx1d2dZ3zUF8ckg7wmL7ofN4\"\
            },\
            \"signature\":\"4o86XfkiJ4e2r3J6Ufoi17UU3W5Zi9sshV6FjBjkVw4sgEQFQov9dxqDEtLbAJAWffCWd5KfAk164QVo7mYwKkiV\"\
        }\
        ";
    let req = CString::new(json).unwrap();
    let (command_handle, callback) = CallbacksHelpers::closure_to_send_tx_cb(cb_send);

    let err = sovrin_submit_request(command_handle,
                                    pool_handle,
                                    req.as_ptr(),
                                    callback);

    assert_eq!(ErrorCode::Success, err);
    let resp = receiver.recv_timeout(Duration::from_secs(1));

    #[derive(Deserialize, Eq, PartialEq, Debug)]
    struct Reply {
        op: String,
        result: ReplyResult,
    }
    #[derive(Deserialize, Eq, PartialEq, Debug)]
    #[serde(rename_all = "camelCase")]
    struct ReplyResult {
        txn_id: String,
        req_id: u64,
    }
    let exp_reply = Reply {
        op: "REPLY".to_string(),
        result: ReplyResult {
            req_id: 1491566332010860,
            txn_id: "5511e5493c1d37dfa67b73269a392a7aca5b71e9d10ac106adc7f9e552aee560".to_string(),
        }
    };
    let act_reply: Reply = serde_json::from_str(resp.unwrap().1.as_str()).unwrap();
    assert_eq!(act_reply, exp_reply);
    fs::remove_dir_all(EnvironmentUtils::pool_path(pool_name)).unwrap();
}
<|endoftext|>


<commit_before>use cleaner::{French, Cleaner};
use super::test_eq;

#[test]
fn cleaner_default() {
    let mut res = String::from("   Remove    supplementary   spaces    but    don't    trim     either   ");
    ().clean(&mut res);
    test_eq(&res, " Remove supplementary spaces but don't trim either ");
}

#[test]
fn cleaner_french() {
    let mut res = String::from("  «  Comment allez-vous ? » demanda-t-elle à son   interlocutrice  qui lui répondit  : « Mais très bien ma chère  !  »");
    let french = French::new('~');
    french.clean(&mut res);
    println!("{}", &res);
    test_eq(&res, " «~Comment allez-vous~?~» demanda-t-elle à son interlocutrice qui lui répondit~: «~Mais très bien ma chère~!~»");
}
<commit_msg>Fix cleaner test<commit_after>use cleaner::{French, Cleaner};
use super::test_eq;

#[test]
fn cleaner_default() {
    let mut res = String::from("   Remove    supplementary   spaces    but    don't    trim     either   ");
    ().clean(&mut res);
    test_eq(&res, " Remove supplementary spaces but don't trim either ");
}

#[test]
fn cleaner_french() {
    let mut res = String::from("  «  Comment allez-vous ? » demanda-t-elle à son   interlocutrice  qui lui répondit  : « Mais très bien ma chère  !  »");
    let french = French::new('~');
    french.clean(&mut res);
    println!("{}", &res);
    test_eq(&res, " « Comment allez-vous~? » demanda-t-elle à son interlocutrice qui lui répondit : « Mais très bien ma chère~! »");
}
<|endoftext|>