<commit_before>use std::ops::{Mul, Add};

use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use rblas::{Gemm, Matrix};
use rblas::attribute::Transpose;

use ndarray::{ArrayBase, DataOwned, DataMut};
use ndarray::blas::{BlasArrayViewMut, AsBlas};

use helpers::random01;

pub trait ShapeAsTuple<T> {
    fn shape_as_tuple(&self) -> T;
}

pub type FloatT = f32;

impl<T> ShapeAsTuple<(usize, usize)> for ArrayBase<Vec<T>, (usize, usize)> {
    #[inline]
    fn shape_as_tuple(&self) -> (usize, usize) {
        (self.shape()[0], self.shape()[1])
    }
}

pub type Ix = (usize, usize);
pub type MyMatrix = ArrayBase<Vec<FloatT>, Ix>;

pub struct OrthogonalNMFBlas {
    pub hidden: MyMatrix,
    pub weights: MyMatrix,

    // these hold temporary results during an iteration.
    // kept in this struct to prevent unnecessary memory allocations.
    pub weights_multiplier: MyMatrix,
    pub weights_divisor: MyMatrix,
    pub weights_divisor_reconstruction: MyMatrix,

    pub hidden_multiplier: MyMatrix,
    pub hidden_divisor: MyMatrix,
    pub hidden_divisor_partial: MyMatrix,

    pub gamma: MyMatrix,
}

impl OrthogonalNMFBlas
    // where FloatT: 'a + Float + Mul + Zero + Clone + Gemm,
          // ArrayBase<Vec<FloatT>, (usize, usize)>: 'a + AsBlas<FloatT, ArrayBase<Vec<FloatT>, (usize, usize)>, (usize, usize)> + DataOwned<Elem=FloatT> + DataMut<Elem=FloatT>,
          // BlasArrayViewMut<'a, FloatT, (usize, usize)>: Matrix<FloatT>,
          // Closed01<FloatT>: Rand
{
    pub fn new_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas {
        let mut hidden = MyMatrix::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = MyMatrix::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::new(hidden, weights)
    }

    pub fn new(hidden: MyMatrix, weights: MyMatrix) -> OrthogonalNMFBlas {
        let weights_shape = weights.shape_as_tuple();
        let hidden_shape = hidden.shape_as_tuple();

        let nhidden = hidden_shape.0;
        let nobserved = hidden_shape.1;
        let nsamples = weights_shape.0;

        let samples_shape = (nsamples, nobserved);

        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,

            weights_multiplier: MyMatrix::zeros(weights_shape),
            weights_divisor: MyMatrix::zeros(weights_shape),
            weights_divisor_reconstruction: MyMatrix::zeros(samples_shape),

            hidden_multiplier: MyMatrix::zeros(hidden_shape),
            hidden_divisor: MyMatrix::zeros(hidden_shape),
            hidden_divisor_partial: MyMatrix::zeros((nhidden, nhidden)),

            gamma: OrthogonalNMFBlas::gamma(nhidden),
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    pub fn samples_shape(&self) -> (usize, usize) {
        (self.nsamples(), self.nobserved())
    }

    /// gamma is a symetric matrix with diagonal elements equal to zero
    /// and other elements equal to 1
    pub fn gamma(size: usize) -> MyMatrix {
        let mut gamma = MyMatrix::from_elem((size, size), 1.);
        for x in gamma.diag_mut().iter_mut() {
            *x = 0.
        }
        gamma
    }

    /// `samples * hidden.transpose()`
    #[inline]
    pub fn update_weights_multiplier(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &samples.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_multiplier.blas());

    }

    // TODO this is the slowest
    /// `weights * hidden * hidden.transpose()`
    #[inline]
    pub fn update_weights_divisor(&mut self) {
        // TODO weights * hidden which we compute first is really large
        // we could first compute partial = hidden * hidden.transpose()
        // partial.shape() = (nhidden, nhidden)
        // and then in the second step compute
        // weights * partial.
        // however since we can't alias hidden we need to copy
        // it for this.
        // the question is whether the copying is faster than
        // the larger matrix multiplication. i guess it is.
        // TODO multiplying a matrix by its transpose is symetric
        // can we exploit that ?
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor_reconstruction.blas());
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights_divisor_reconstruction.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor.blas());
    }

    /// `weights.transpose() * samples`
    #[inline]
    pub fn update_hidden_multiplier(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &samples.blas(),
            &0.,
            &mut self.hidden_multiplier.blas());
    }

    // surprisingly this is the fastest
    /// `weights.transpose() * weights * hidden + alpha * gamma * hidden`
    #[inline]
    pub fn update_hidden_divisor(&mut self, alpha: FloatT) {
        // TODO benchmark whether using clone_from is faster
        let mut weights_copy = self.weights.clone();
        // partial <- weights.transpose() * weights
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut self.hidden_divisor_partial.blas());
        // partial.shape() = (nhidden, nhidden) very small
        // divisor <- alpha * gamma * hidden
        Gemm::gemm(
            &alpha,
            Transpose::NoTrans, &self.gamma.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.hidden_divisor.blas());
        // divisor <- divisor + partial * hidden
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.hidden_divisor_partial.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            // add to previous contents of self.hidden_divisor
            &1.,
            &mut self.hidden_divisor.blas());
    }

    /// `result(i,j) <- result(i,j) * multiplier(i,j) / divisor(i,j)`
    #[inline]
    pub fn update_from_multiplier_and_divisor(
        multiplier: &MyMatrix,
        divisor: &MyMatrix,
        result: &mut MyMatrix,
    ) {
        let shape = result.shape_as_tuple();
        assert_eq!(shape, multiplier.shape_as_tuple());
        assert_eq!(shape, divisor.shape_as_tuple());

        for row in 0..shape.0 {
            for col in 0..shape.1 {
                let index = (row, col);
                let mut div = unsafe { divisor.uget(index).clone() };
                // if we have any 0 in any of the matrixes
                // self.weights or self.hidden then
                // divisor will be 0.
                // we can't divide by 0.
                // so we change them to the min positive value.
                if FloatT::zero() == div {
                    div = FloatT::min_positive_value();
                }
                unsafe {
                    *result.uget_mut(index) *= multiplier.uget(index) / div;
                }
            }
        }
    }

    // TODO consider calling this something like iteration_step
    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// does one iteration step.
    /// `weights` and `hidden` get better and better with each iteration.
    /// usually around `10000` iterations are required.
    /// `samples` contains one observed per column, one sample per row.
    pub fn iterate(&mut self, alpha: FloatT, samples: &mut MyMatrix) {
        assert_eq!(samples.shape_as_tuple(), self.samples_shape());

        // weights_multiplier <- samples * hidden.transpose()
        self.update_weights_multiplier(samples);
        // weights_divisor <- weights * hidden * hidden.transpose()
        self.update_weights_divisor();
        // hidden_multiplier <- weights.transpose() * samples
        self.update_hidden_multiplier(samples);
        // hidden_divisor <-
        // weights.transpose() * weights * hidden + alpha * gamma * hidden
        self.update_hidden_divisor(alpha);

        // weights(i,j) <-
        // weights(i,j) * weights_multiplier(i,j) / weights_divisor(i,j)
        OrthogonalNMFBlas::update_from_multiplier_and_divisor(
            &self.weights_multiplier,
            &self.weights_divisor,
            &mut self.weights);
        // hidden(i,j) <-
        // hidden(i,j) * hidden_multiplier(i,j) / hidden_divisor(i,j)
        OrthogonalNMFBlas::update_from_multiplier_and_divisor(
            &self.hidden_multiplier,
            &self.hidden_divisor,
            &mut self.hidden);
    }
}
<commit_msg>add comments<commit_after>use std::ops::{Mul, Add};

use rand::{Rand, Rng, Closed01};
use num::{Float, Zero};

use rblas::{Gemm, Matrix};
use rblas::attribute::Transpose;

use ndarray::{ArrayBase, DataOwned, DataMut};
use ndarray::blas::{BlasArrayViewMut, AsBlas};

use helpers::random01;

pub trait ShapeAsTuple<T> {
    fn shape_as_tuple(&self) -> T;
}

pub type FloatT = f32;

impl<T> ShapeAsTuple<(usize, usize)> for ArrayBase<Vec<T>, (usize, usize)> {
    #[inline]
    fn shape_as_tuple(&self) -> (usize, usize) {
        (self.shape()[0], self.shape()[1])
    }
}

pub type Ix = (usize, usize);
pub type MyMatrix = ArrayBase<Vec<FloatT>, Ix>;

pub struct OrthogonalNMFBlas {
    pub hidden: MyMatrix,
    pub weights: MyMatrix,

    // these hold temporary results during an iteration.
    // kept in this struct to prevent unnecessary memory allocations.
    pub weights_multiplier: MyMatrix,
    pub weights_divisor: MyMatrix,
    pub weights_divisor_reconstruction: MyMatrix,

    pub hidden_multiplier: MyMatrix,
    pub hidden_divisor: MyMatrix,
    pub hidden_divisor_partial: MyMatrix,

    pub gamma: MyMatrix,
}

impl OrthogonalNMFBlas
    // where FloatT: 'a + Float + Mul + Zero + Clone + Gemm,
          // ArrayBase<Vec<FloatT>, (usize, usize)>: 'a + AsBlas<FloatT, ArrayBase<Vec<FloatT>, (usize, usize)>, (usize, usize)> + DataOwned<Elem=FloatT> + DataMut<Elem=FloatT>,
          // BlasArrayViewMut<'a, FloatT, (usize, usize)>: Matrix<FloatT>,
          // Closed01<FloatT>: Rand
{
    pub fn new_random01<R: Rng>(nhidden: usize, nobserved: usize, nsamples: usize, rng: &mut R) -> OrthogonalNMFBlas {
        let mut hidden = MyMatrix::zeros((nhidden, nobserved));
        for x in hidden.iter_mut() {
            *x = random01(rng);
        }

        let mut weights = MyMatrix::zeros((nsamples, nhidden));
        for x in weights.iter_mut() {
            *x = random01(rng);
        }

        Self::new(hidden, weights)
    }

    pub fn new(hidden: MyMatrix, weights: MyMatrix) -> OrthogonalNMFBlas {
        let weights_shape = weights.shape_as_tuple();
        let hidden_shape = hidden.shape_as_tuple();

        let nhidden = hidden_shape.0;
        let nobserved = hidden_shape.1;
        let nsamples = weights_shape.0;

        let samples_shape = (nsamples, nobserved);

        OrthogonalNMFBlas {
            hidden: hidden,
            weights: weights,

            weights_multiplier: MyMatrix::zeros(weights_shape),
            weights_divisor: MyMatrix::zeros(weights_shape),
            weights_divisor_reconstruction: MyMatrix::zeros(samples_shape),

            hidden_multiplier: MyMatrix::zeros(hidden_shape),
            hidden_divisor: MyMatrix::zeros(hidden_shape),
            hidden_divisor_partial: MyMatrix::zeros((nhidden, nhidden)),

            gamma: OrthogonalNMFBlas::gamma(nhidden),
        }
    }

    /// returns the number of observed variables
    #[inline]
    pub fn nobserved(&self) -> usize {
        self.hidden.shape()[1]
    }

    /// returns the number of hidden variables
    #[inline]
    pub fn nhidden(&self) -> usize {
        self.hidden.shape()[0]
    }

    /// returns the number of data points
    #[inline]
    pub fn nsamples(&self) -> usize {
        self.weights.shape()[0]
    }

    pub fn samples_shape(&self) -> (usize, usize) {
        (self.nsamples(), self.nobserved())
    }

    /// gamma is a symetric matrix with diagonal elements equal to zero
    /// and other elements equal to 1
    pub fn gamma(size: usize) -> MyMatrix {
        let mut gamma = MyMatrix::from_elem((size, size), 1.);
        for x in gamma.diag_mut().iter_mut() {
            *x = 0.
        }
        gamma
    }

    /// `samples * hidden.transpose()`
    #[inline]
    pub fn update_weights_multiplier(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &samples.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_multiplier.blas());

    }

    // TODO this is the slowest
    /// `weights * hidden * hidden.transpose()`
    #[inline]
    pub fn update_weights_divisor(&mut self) {
        // TODO weights * hidden which we compute first is really large
        // we could first compute partial = hidden * hidden.transpose()
        // partial.shape() = (nhidden, nhidden)
        // and then in the second step compute
        // weights * partial.
        // however since we can't alias hidden we need to copy
        // it for this.
        // the question is whether the copying is faster than
        // the larger matrix multiplication. i guess it is.
        // TODO multiplying a matrix by its transpose is symetric
        // can we exploit that ?
        // reconstruction <- weights * hidden
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor_reconstruction.blas());
        // divisor <- reconstruction * hidden.transpose()
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.weights_divisor_reconstruction.blas(),
            Transpose::Trans, &self.hidden.blas(),
            &0.,
            &mut self.weights_divisor.blas());
    }

    /// `weights.transpose() * samples`
    #[inline]
    pub fn update_hidden_multiplier(&mut self, samples: &mut MyMatrix) {
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &samples.blas(),
            &0.,
            &mut self.hidden_multiplier.blas());
    }

    // surprisingly this is the fastest
    /// `weights.transpose() * weights * hidden + alpha * gamma * hidden`
    #[inline]
    pub fn update_hidden_divisor(&mut self, alpha: FloatT) {
        // TODO benchmark whether using clone_from is faster
        let mut weights_copy = self.weights.clone();
        // partial <- weights.transpose() * weights
        Gemm::gemm(
            &1.,
            Transpose::Trans, &self.weights.blas(),
            Transpose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut self.hidden_divisor_partial.blas());
        // partial.shape() = (nhidden, nhidden) very small
        // divisor <- alpha * gamma * hidden
        Gemm::gemm(
            &alpha,
            Transpose::NoTrans, &self.gamma.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            &0.,
            &mut self.hidden_divisor.blas());
        // divisor <- divisor + partial * hidden
        Gemm::gemm(
            &1.,
            Transpose::NoTrans, &self.hidden_divisor_partial.blas(),
            Transpose::NoTrans, &self.hidden.blas(),
            // add to previous contents of self.hidden_divisor
            &1.,
            &mut self.hidden_divisor.blas());
    }

    /// `result(i,j) <- result(i,j) * multiplier(i,j) / divisor(i,j)`
    #[inline]
    pub fn update_from_multiplier_and_divisor(
        multiplier: &MyMatrix,
        divisor: &MyMatrix,
        result: &mut MyMatrix,
    ) {
        let shape = result.shape_as_tuple();
        assert_eq!(shape, multiplier.shape_as_tuple());
        assert_eq!(shape, divisor.shape_as_tuple());

        for row in 0..shape.0 {
            for col in 0..shape.1 {
                let index = (row, col);
                let mut div = unsafe { divisor.uget(index).clone() };
                // if we have any 0 in any of the matrixes
                // self.weights or self.hidden then
                // divisor will be 0.
                // we can't divide by 0.
                // so we change them to the min positive value.
                if FloatT::zero() == div {
                    div = FloatT::min_positive_value();
                }
                unsafe {
                    *result.uget_mut(index) *= multiplier.uget(index) / div;
                }
            }
        }
    }

    // TODO consider calling this something like iteration_step
    // TODO how many iterations ?
    // TODO compare this to the seoung solution
    /// does one iteration step.
    /// `weights` and `hidden` get better and better with each iteration.
    /// usually around `10000` iterations are required.
    /// `samples` contains one observed per column, one sample per row.
    pub fn iterate(&mut self, alpha: FloatT, samples: &mut MyMatrix) {
        assert_eq!(samples.shape_as_tuple(), self.samples_shape());

        // weights_multiplier <- samples * hidden.transpose()
        self.update_weights_multiplier(samples);
        // weights_divisor <- weights * hidden * hidden.transpose()
        self.update_weights_divisor();
        // hidden_multiplier <- weights.transpose() * samples
        self.update_hidden_multiplier(samples);
        // hidden_divisor <-
        // weights.transpose() * weights * hidden + alpha * gamma * hidden
        self.update_hidden_divisor(alpha);

        // weights(i,j) <-
        // weights(i,j) * weights_multiplier(i,j) / weights_divisor(i,j)
        OrthogonalNMFBlas::update_from_multiplier_and_divisor(
            &self.weights_multiplier,
            &self.weights_divisor,
            &mut self.weights);
        // hidden(i,j) <-
        // hidden(i,j) * hidden_multiplier(i,j) / hidden_divisor(i,j)
        OrthogonalNMFBlas::update_from_multiplier_and_divisor(
            &self.hidden_multiplier,
            &self.hidden_divisor,
            &mut self.hidden);
    }
}
<|endoftext|>


<commit_before>use std::process::Command;

fn is_command_available(command: String) -> bool {
    // TODO NiCo: remove output on terminal for this check
    let mut result = Command::new(command)
                         .arg("-v")
                         .status();
    match result {
        Ok(status) => true,
        Err(_) => false,
    }
}

// Attention: if this test fails all other test will/should do so too
#[test]
fn original_xxd_is_available() {
    assert!(is_command_available("xxd".to_string()));
}

#[test]
fn xxd_rs_is_available() {
    assert!(is_command_available("xxd-rs".to_string()));
}
<commit_msg>Refactored command availability check<commit_after>use std::process::{Command, Stdio};

fn is_command_available(command: String) -> bool {
    match Command::new(command).arg("-v").stdout(Stdio::null()).status() {
        Ok(status) => status.success(),
        _ => false,
    }
}

#[test]
fn original_xxd_is_available() {
    assert!(is_command_available("xxd".to_string()));
}
<|endoftext|>


<commit_before>use {Field, Matrix2d, Color};

/// A polygon color context.
pub struct PolygonColorContext<'a> {
    /// Base/origin transform.
    base: Field<'a, Matrix2d>,
    /// Current transform.
    transform: Field<'a, Matrix2d>,
    /// Current color.
    color: Field<'a, Color>,
    /// Current polygon.
    polygon: Field<'a, &'a [f64]>,
}

<commit_msg>Implemented Transform2d for PolygonColorContext<commit_after>use {Field, Value, Borrowed, Matrix2d, Color};
use vecmath::{multiply, translate, rotate_radians, scale, shear};
use {Transform2d};

/// A polygon color context.
pub struct PolygonColorContext<'a> {
    /// Base/origin transform.
    base: Field<'a, Matrix2d>,
    /// Current transform.
    transform: Field<'a, Matrix2d>,
    /// Current color.
    color: Field<'a, Color>,
    /// Current polygon.
    polygon: Field<'a, &'a [f64]>,
}

impl<'a> Transform2d<'a> for PolygonColorContext<'a> {
    #[inline(always)]
    fn trans(&'a self, x: f64, y: f64) -> PolygonColorContext<'a> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let trans = translate(x, y);
                Value(multiply(&trans, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn rot_rad(&'a self, angle: f64) -> PolygonColorContext<'a> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let rot = rotate_radians(angle);
                Value(multiply(&rot, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn scale(&'a self, sx: f64, sy: f64) -> PolygonColorContext<'a> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let scale = scale(sx, sy);
                Value(multiply(&scale, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
            color: Borrowed(self.color.get()),
        }
    }

    #[inline(always)]
    fn shear(&'a self, sx: f64, sy: f64) -> PolygonColorContext<'a> {
        PolygonColorContext {
            base: Borrowed(self.base.get()),
            transform: {
                let shear = shear(sx, sy);
                Value(multiply(&shear, self.transform.get()))
            },
            polygon: Borrowed(self.polygon.get()),
            color: Borrowed(self.color.get()),
        }
    }
}
<|endoftext|>


<commit_before>#![allow(unused_parens)] // FIXME: Remove this attribute once false positive is resolved.

use super::backend::{FailedToLookupTypeError, InnerPgTypeMetadata};
use super::{PgTypeMetadata, Pg};
use crate::prelude::*;

use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;

/// Determines the OID of types at runtime
pub trait PgMetadataLookup {
    /// Determine the type metadata for the given `type_name`
    ///
    /// This function should only be used for user defined types, or types which
    /// come from an extension. This function may perform a SQL query to look
    /// up the type. For built-in types, a static OID should be preferred.
    fn lookup_type(&self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata;
}

impl<T> PgMetadataLookup for T
    where T: Connection<Backend=Pg> + GetPgTypeMetadataCache
{
    fn lookup_type(&self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata {
        let metadata_cache = self.get_metadata_cache();
        let cache_key = PgMetadataCacheKey {
            schema: schema.map(Cow::Borrowed),
            type_name: Cow::Borrowed(type_name),
        };

        metadata_cache.lookup_type(&cache_key).unwrap_or_else(|| {
            let r = lookup_type(&cache_key, self);

            match r {
                Ok(type_metadata) => {
                    metadata_cache.store_type(cache_key, type_metadata);
                    PgTypeMetadata(Ok(type_metadata))
                }
                Err(_e) => {
                    PgTypeMetadata(Err(FailedToLookupTypeError::new(cache_key.into_owned())))
                }
            }
        })
    }
}

pub trait GetPgTypeMetadataCache {
    fn get_metadata_cache(&self) -> &PgMetadataCache;
}

fn lookup_type<T: Connection<Backend=Pg> + GetPgTypeMetadataCache>(
    cache_key: &PgMetadataCacheKey<'_>,
    conn: &T,
) -> QueryResult<InnerPgTypeMetadata> {
    let search_path: String;
    let mut search_path_has_temp_schema = false;

    let search_schema = match cache_key.schema.as_deref() {
        Some("pg_temp") => {
            search_path_has_temp_schema = true;
            Vec::new()
        }
        Some(schema) => vec![schema],
        None => {
            search_path = crate::dsl::sql("SHOW search_path").get_result::<String>(conn)?;

            search_path
                .split(',')
                // skip the `$user` entry for now
                .filter(|f| !f.starts_with("\"$"))
                .map(|s| s.trim())
                .filter(|&f| {
                    let is_temp = f == "pg_temp";
                    search_path_has_temp_schema |= is_temp;
                    !is_temp
                })
                .collect()
        }
    };

    let metadata_query = pg_type::table
        .inner_join(pg_namespace::table)
        .filter(pg_type::typname.eq(&cache_key.type_name))
        .select((pg_type::oid, pg_type::typarray));
    let nspname_filter = pg_namespace::nspname.eq(crate::dsl::any(search_schema));

    let metadata = if search_path_has_temp_schema {
        metadata_query
            .filter(nspname_filter.or(pg_namespace::oid.eq(pg_my_temp_schema())))
            .first(conn)?
    } else {
        metadata_query.filter(nspname_filter).first(conn)?
    };

    Ok(metadata)
}

#[derive(Hash, PartialEq, Eq, Debug, Clone)]
pub(in crate::pg) struct PgMetadataCacheKey<'a> {
    pub(crate) schema: Option<Cow<'a, str>>,
    pub(crate) type_name: Cow<'a, str>,
}

impl<'a> PgMetadataCacheKey<'a> {
    fn into_owned(self) -> PgMetadataCacheKey<'static> {
        let PgMetadataCacheKey { schema, type_name } = self;
        PgMetadataCacheKey {
            schema: schema.map(|s| Cow::Owned(s.into_owned())),
            type_name: Cow::Owned(type_name.into_owned()),
        }
    }
}

/// Stores a cache for the OID of custom types
#[allow(missing_debug_implementations)]
pub struct PgMetadataCache {
    cache: RefCell<HashMap<PgMetadataCacheKey<'static>, InnerPgTypeMetadata>>,
}

impl PgMetadataCache {
    pub(crate) fn new() -> Self {
        PgMetadataCache {
            cache: RefCell::new(HashMap::new()),
        }
    }

    fn lookup_type(&self, type_name: &PgMetadataCacheKey) -> Option<PgTypeMetadata> {
        Some(PgTypeMetadata(Ok(*self.cache.borrow().get(type_name)?)))
    }

    fn store_type(&self, type_name: PgMetadataCacheKey, type_metadata: InnerPgTypeMetadata) {
        self.cache
            .borrow_mut()
            .insert(type_name.into_owned(), type_metadata);
    }
}

table! {
    pg_type (oid) {
        oid -> Oid,
        typname -> Text,
        typarray -> Oid,
        typnamespace -> Oid,
    }
}

table! {
    pg_namespace (oid) {
        oid -> Oid,
        nspname -> Text,
    }
}

joinable!(pg_type -> pg_namespace(typnamespace));
allow_tables_to_appear_in_same_query!(pg_type, pg_namespace);

sql_function! { fn pg_my_temp_schema() -> Oid; }
<commit_msg>refactor: :fire: remove unneccessary trait bounds<commit_after>#![allow(unused_parens)] // FIXME: Remove this attribute once false positive is resolved.

use super::backend::{FailedToLookupTypeError, InnerPgTypeMetadata};
use super::{PgTypeMetadata, Pg};
use crate::prelude::*;

use std::borrow::Cow;
use std::cell::RefCell;
use std::collections::HashMap;

/// Determines the OID of types at runtime
pub trait PgMetadataLookup {
    /// Determine the type metadata for the given `type_name`
    ///
    /// This function should only be used for user defined types, or types which
    /// come from an extension. This function may perform a SQL query to look
    /// up the type. For built-in types, a static OID should be preferred.
    fn lookup_type(&self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata;
}

impl<T> PgMetadataLookup for T
    where T: Connection<Backend=Pg> + GetPgTypeMetadataCache
{
    fn lookup_type(&self, type_name: &str, schema: Option<&str>) -> PgTypeMetadata {
        let metadata_cache = self.get_metadata_cache();
        let cache_key = PgMetadataCacheKey {
            schema: schema.map(Cow::Borrowed),
            type_name: Cow::Borrowed(type_name),
        };

        metadata_cache.lookup_type(&cache_key).unwrap_or_else(|| {
            let r = lookup_type(&cache_key, self);

            match r {
                Ok(type_metadata) => {
                    metadata_cache.store_type(cache_key, type_metadata);
                    PgTypeMetadata(Ok(type_metadata))
                }
                Err(_e) => {
                    PgTypeMetadata(Err(FailedToLookupTypeError::new(cache_key.into_owned())))
                }
            }
        })
    }
}

pub trait GetPgTypeMetadataCache {
    fn get_metadata_cache(&self) -> &PgMetadataCache;
}

fn lookup_type<T: Connection<Backend=Pg>>(
    cache_key: &PgMetadataCacheKey<'_>,
    conn: &T,
) -> QueryResult<InnerPgTypeMetadata> {
    let search_path: String;
    let mut search_path_has_temp_schema = false;

    let search_schema = match cache_key.schema.as_deref() {
        Some("pg_temp") => {
            search_path_has_temp_schema = true;
            Vec::new()
        }
        Some(schema) => vec![schema],
        None => {
            search_path = crate::dsl::sql("SHOW search_path").get_result::<String>(conn)?;

            search_path
                .split(',')
                // skip the `$user` entry for now
                .filter(|f| !f.starts_with("\"$"))
                .map(|s| s.trim())
                .filter(|&f| {
                    let is_temp = f == "pg_temp";
                    search_path_has_temp_schema |= is_temp;
                    !is_temp
                })
                .collect()
        }
    };

    let metadata_query = pg_type::table
        .inner_join(pg_namespace::table)
        .filter(pg_type::typname.eq(&cache_key.type_name))
        .select((pg_type::oid, pg_type::typarray));
    let nspname_filter = pg_namespace::nspname.eq(crate::dsl::any(search_schema));

    let metadata = if search_path_has_temp_schema {
        metadata_query
            .filter(nspname_filter.or(pg_namespace::oid.eq(pg_my_temp_schema())))
            .first(conn)?
    } else {
        metadata_query.filter(nspname_filter).first(conn)?
    };

    Ok(metadata)
}

#[derive(Hash, PartialEq, Eq, Debug, Clone)]
pub(in crate::pg) struct PgMetadataCacheKey<'a> {
    pub(crate) schema: Option<Cow<'a, str>>,
    pub(crate) type_name: Cow<'a, str>,
}

impl<'a> PgMetadataCacheKey<'a> {
    fn into_owned(self) -> PgMetadataCacheKey<'static> {
        let PgMetadataCacheKey { schema, type_name } = self;
        PgMetadataCacheKey {
            schema: schema.map(|s| Cow::Owned(s.into_owned())),
            type_name: Cow::Owned(type_name.into_owned()),
        }
    }
}

/// Stores a cache for the OID of custom types
#[allow(missing_debug_implementations)]
pub struct PgMetadataCache {
    cache: RefCell<HashMap<PgMetadataCacheKey<'static>, InnerPgTypeMetadata>>,
}

impl PgMetadataCache {
    pub(crate) fn new() -> Self {
        PgMetadataCache {
            cache: RefCell::new(HashMap::new()),
        }
    }

    fn lookup_type(&self, type_name: &PgMetadataCacheKey) -> Option<PgTypeMetadata> {
        Some(PgTypeMetadata(Ok(*self.cache.borrow().get(type_name)?)))
    }

    fn store_type(&self, type_name: PgMetadataCacheKey, type_metadata: InnerPgTypeMetadata) {
        self.cache
            .borrow_mut()
            .insert(type_name.into_owned(), type_metadata);
    }
}

table! {
    pg_type (oid) {
        oid -> Oid,
        typname -> Text,
        typarray -> Oid,
        typnamespace -> Oid,
    }
}

table! {
    pg_namespace (oid) {
        oid -> Oid,
        nspname -> Text,
    }
}

joinable!(pg_type -> pg_namespace(typnamespace));
allow_tables_to_appear_in_same_query!(pg_type, pg_namespace);

sql_function! { fn pg_my_temp_schema() -> Oid; }
<|endoftext|>


<commit_before>//! lint on missing cargo common metadata

use crate::utils::span_lint;
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use syntax::{ast::*, source_map::DUMMY_SP};

use cargo_metadata;

declare_clippy_lint! {
    /// **What it does:** Checks to see if all common metadata is defined in
    /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
    ///
    /// **Why is this bad?** It will be more difficult for users to discover the
    /// purpose of the crate, and key information related to it.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```toml
    /// # This `Cargo.toml` is missing an authors field:
    /// [package]
    /// name = "clippy"
    /// version = "0.0.212"
    /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
    /// repository = "https://github.com/rust-lang/rust-clippy"
    /// readme = "README.md"
    /// license = "MIT/Apache-2.0"
    /// keywords = ["clippy", "lint", "plugin"]
    /// categories = ["development-tools", "development-tools::cargo-plugins"]
    /// ```
    pub CARGO_COMMON_METADATA,
    cargo,
    "common metadata is defined in `Cargo.toml`"
}

fn warning(cx: &EarlyContext<'_>, message: &str) {
    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
}

fn missing_warning(cx: &EarlyContext<'_>, package: &cargo_metadata::Package, field: &str) {
    let message = format!("package `{}` is missing `{}` metadata", package.name, field);
    warning(cx, &message);
}

fn is_empty_str(value: &Option<String>) -> bool {
    value.as_ref().map_or(true, String::is_empty)
}

fn is_empty_vec(value: &[String]) -> bool {
    // This works because empty iterators return true
    value.iter().all(std::string::String::is_empty)
}

declare_lint_pass!(CargoCommonMetadata => [CARGO_COMMON_METADATA]);

impl EarlyLintPass for CargoCommonMetadata {
    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() {
            metadata
        } else {
            warning(cx, "could not read cargo metadata");
            return;
        };

        for package in metadata.packages {
            if is_empty_vec(&package.authors) {
                missing_warning(cx, &package, "package.authors");
            }

            if is_empty_str(&package.description) {
                missing_warning(cx, &package, "package.description");
            }

            if is_empty_str(&package.license) {
                missing_warning(cx, &package, "package.license");
            }

            if is_empty_str(&package.repository) {
                missing_warning(cx, &package, "package.repository");
            }

            if is_empty_str(&package.readme) {
                missing_warning(cx, &package, "package.readme");
            }

            if is_empty_vec(&package.keywords) {
                missing_warning(cx, &package, "package.keywords");
            }

            if is_empty_vec(&package.categories) {
                missing_warning(cx, &package, "package.categories");
            }
        }
    }
}
<commit_msg>Auto merge of #4518 - imp:4517_license-file, r=phansch<commit_after>//! lint on missing cargo common metadata

use std::path::PathBuf;

use crate::utils::span_lint;
use rustc::lint::{EarlyContext, EarlyLintPass, LintArray, LintPass};
use rustc::{declare_lint_pass, declare_tool_lint};
use syntax::{ast::*, source_map::DUMMY_SP};

use cargo_metadata;

declare_clippy_lint! {
    /// **What it does:** Checks to see if all common metadata is defined in
    /// `Cargo.toml`. See: https://rust-lang-nursery.github.io/api-guidelines/documentation.html#cargotoml-includes-all-common-metadata-c-metadata
    ///
    /// **Why is this bad?** It will be more difficult for users to discover the
    /// purpose of the crate, and key information related to it.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```toml
    /// # This `Cargo.toml` is missing an authors field:
    /// [package]
    /// name = "clippy"
    /// version = "0.0.212"
    /// description = "A bunch of helpful lints to avoid common pitfalls in Rust"
    /// repository = "https://github.com/rust-lang/rust-clippy"
    /// readme = "README.md"
    /// license = "MIT/Apache-2.0"
    /// keywords = ["clippy", "lint", "plugin"]
    /// categories = ["development-tools", "development-tools::cargo-plugins"]
    /// ```
    pub CARGO_COMMON_METADATA,
    cargo,
    "common metadata is defined in `Cargo.toml`"
}

fn warning(cx: &EarlyContext<'_>, message: &str) {
    span_lint(cx, CARGO_COMMON_METADATA, DUMMY_SP, message);
}

fn missing_warning(cx: &EarlyContext<'_>, package: &cargo_metadata::Package, field: &str) {
    let message = format!("package `{}` is missing `{}` metadata", package.name, field);
    warning(cx, &message);
}

fn is_empty_str(value: &Option<String>) -> bool {
    value.as_ref().map_or(true, String::is_empty)
}

fn is_empty_path(value: &Option<PathBuf>) -> bool {
    value.as_ref().and_then(|x| x.to_str()).map_or(true, str::is_empty)
}

fn is_empty_vec(value: &[String]) -> bool {
    // This works because empty iterators return true
    value.iter().all(std::string::String::is_empty)
}

declare_lint_pass!(CargoCommonMetadata => [CARGO_COMMON_METADATA]);

impl EarlyLintPass for CargoCommonMetadata {
    fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &Crate) {
        let metadata = if let Ok(metadata) = cargo_metadata::MetadataCommand::new().no_deps().exec() {
            metadata
        } else {
            warning(cx, "could not read cargo metadata");
            return;
        };

        for package in metadata.packages {
            if is_empty_vec(&package.authors) {
                missing_warning(cx, &package, "package.authors");
            }

            if is_empty_str(&package.description) {
                missing_warning(cx, &package, "package.description");
            }

            if is_empty_str(&package.license) && is_empty_path(&package.license_file) {
                missing_warning(cx, &package, "either package.license or package.license_file");
            }

            if is_empty_str(&package.repository) {
                missing_warning(cx, &package, "package.repository");
            }

            if is_empty_str(&package.readme) {
                missing_warning(cx, &package, "package.readme");
            }

            if is_empty_vec(&package.keywords) {
                missing_warning(cx, &package, "package.keywords");
            }

            if is_empty_vec(&package.categories) {
                missing_warning(cx, &package, "package.categories");
            }
        }
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
extern crate libstratis;
extern crate rand;
extern crate tempdir;
extern crate time;
extern crate uuid;

use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::{Path, PathBuf};

use self::devicemapper::DM;
use self::devicemapper::consts::SECTOR_SIZE;
use self::devicemapper::types::{DataBlocks, Sectors};
use self::tempdir::TempDir;
use self::time::now;
use self::uuid::Uuid;

use libstratis::engine::Engine;
use libstratis::engine::strat_engine::StratEngine;
use libstratis::engine::strat_engine::blockdev::{blkdev_size, initialize, resolve_devices,
                                                 write_sectors, BlockDev};
use libstratis::engine::strat_engine::engine::DevOwnership;
use libstratis::engine::strat_engine::lineardev::LinearDev;
use libstratis::engine::strat_engine::thindev::ThinDev;
use libstratis::engine::strat_engine::thinpooldev::ThinPoolDev;
use libstratis::engine::strat_engine::metadata::{StaticHeader, BDA_STATIC_HDR_SECTORS,
                                                 MIN_MDA_SECTORS};
use libstratis::engine::strat_engine::pool::StratPool;

/// Dirty sectors where specified, with 1s.
fn dirty_sectors(path: &Path, offset: Sectors, length: Sectors) {
    write_sectors(path, offset, length, &[1u8; SECTOR_SIZE]).unwrap();
}

/// Verify that it is impossible to initialize a set of disks of which
/// even one is dirty, i.e, has some data written within BDA_STATIC_HDR_SECTORS
/// of start of disk. Choose the dirty disk randomly. This means that even
/// if our code is broken with respect to this property, this test might
/// sometimes succeed.
/// FIXME: Consider enriching device specs so that this test will fail
/// consistently.
/// Verify that force flag allows all dirty disks to be initialized.
pub fn test_force_flag_dirty(paths: &[&Path]) -> () {

    let index = rand::random::<u8>() as usize % paths.len();
    dirty_sectors(paths[index],
                  Sectors(index as u64 % *BDA_STATIC_HDR_SECTORS),
                  Sectors(1));

    let unique_devices = resolve_devices(&paths).unwrap();

    let uuid = Uuid::new_v4();
    assert!(initialize(&uuid, unique_devices.clone(), MIN_MDA_SECTORS, false).is_err());
    assert!(paths.iter().enumerate().all(|(i, path)| {
        StaticHeader::determine_ownership(&mut OpenOptions::new()
                .read(true)
                .open(path)
                .unwrap())
            .unwrap() ==
        if i == index {
            DevOwnership::Theirs
        } else {
            DevOwnership::Unowned
        }
    }));

    assert!(initialize(&uuid, unique_devices.clone(), MIN_MDA_SECTORS, true).is_ok());
    assert!(paths.iter().all(|path| {
        StaticHeader::determine_ownership(&mut OpenOptions::new()
                .read(true)
                .open(path)
                .unwrap())
            .unwrap() == DevOwnership::Ours(uuid)
    }));
}

/// Verify that it is impossible to steal blockdevs from another Stratis
/// pool.
/// 1. Initialize devices with uuid.
/// 2. Initializing again with different uuid must fail.
/// 3. Initializing again with same uuid must fail, because all the
/// devices already belong.
/// 4. Initializing again with different uuid and force = true also fails.
pub fn test_force_flag_stratis(paths: &[&Path]) -> () {
    let unique_devices = resolve_devices(&paths).unwrap();

    let uuid = Uuid::new_v4();
    let uuid2 = Uuid::new_v4();

    initialize(&uuid, unique_devices.clone(), MIN_MDA_SECTORS, false).unwrap();
    assert!(initialize(&uuid2, unique_devices.clone(), MIN_MDA_SECTORS, false).is_err());

    // FIXME: once requirement that number of devices added be at least 2 is removed
    // this should succeed.
    assert!(initialize(&uuid, unique_devices.clone(), MIN_MDA_SECTORS, false).is_err());

    // FIXME: this should succeed, but currently it fails, to be extra safe.
    // See: https://github.com/stratis-storage/stratisd/pull/292
    assert!(initialize(&uuid2, unique_devices.clone(), MIN_MDA_SECTORS, true).is_err());
}

/// Verify that the sum of the lengths of the available range of the
/// blockdevs in the linear device equals the size of the linear device.
pub fn test_linear_device(paths: &[&Path]) -> () {
    let unique_devices = resolve_devices(&paths).unwrap();
    let initialized = initialize(&Uuid::new_v4(),
                                 unique_devices.clone(),
                                 MIN_MDA_SECTORS,
                                 false)
        .unwrap();
    let total_blockdev_size = initialized.iter().fold(Sectors(0), |s, i| s + i.avail_range().1);

    let initialized_refs: Vec<&BlockDev> = initialized.iter().collect();
    let device_name = "stratis_testing_linear";
    let dm = DM::new().unwrap();
    let lineardev = LinearDev::new(&device_name, &dm, &initialized_refs).unwrap();

    let mut linear_dev_path = PathBuf::from("/dev/mapper");
    linear_dev_path.push(device_name);

    let lineardev_size = blkdev_size(&File::open(linear_dev_path).unwrap()).unwrap();
    assert!(total_blockdev_size.bytes() == lineardev_size);
    lineardev.teardown(&dm).unwrap();
}

/// Verify no errors when writing files to a mounted filesystem on a thin
/// device.
pub fn test_thinpool_device(paths: &[&Path]) -> () {
    let initialized = initialize(&Uuid::new_v4(),
                                 resolve_devices(&paths).unwrap(),
                                 MIN_MDA_SECTORS,
                                 false)
        .unwrap();

    let (metadata_blockdev, data_blockdev) = (initialized.first().unwrap(),
                                              initialized.last().unwrap());

    let dm = DM::new().unwrap();
    let metadata_dev = LinearDev::new("stratis_testing_thinpool_metadata",
                                      &dm,
                                      &vec![metadata_blockdev])
        .unwrap();
    let data_dev = LinearDev::new("stratis_testing_thinpool_datadev",
                                  &dm,
                                  &vec![data_blockdev])
        .unwrap();
    let thinpool_dev = ThinPoolDev::new("stratis_testing_thinpool",
                                        &dm,
                                        data_dev.size().unwrap().sectors(),
                                        Sectors(1024),
                                        DataBlocks(256000),
                                        metadata_dev,
                                        data_dev)
        .unwrap();
    let thin_dev = ThinDev::new("stratis_testing_thindev",
                                &dm,
                                &thinpool_dev,
                                7,
                                Sectors(300000))
        .unwrap();

    thin_dev.create_fs().unwrap();

    let tmp_dir = TempDir::new("stratis_testing").unwrap();
    thin_dev.mount_fs(tmp_dir.path()).unwrap();
    ThinDev::unmount_fs(tmp_dir.path()).unwrap();
    for i in 0..100 {
        let file_path = tmp_dir.path().join(format!("stratis_test{}.txt", i));
        writeln!(&File::create(file_path).unwrap(), "data").unwrap();
    }
    thin_dev.teardown(&dm).unwrap();
    thinpool_dev.teardown(&dm).unwrap();
}

/// Test that creating a pool claims all blockdevs and that destroying a pool
/// releases all blockdevs.
pub fn test_pool_blockdevs(paths: &[&Path]) -> () {
    let mut engine = StratEngine::new();
    let (uuid, blockdevs) = engine.create_pool("test_pool", paths, None, true).unwrap();
    assert!(blockdevs.iter().all(|path| {
        StaticHeader::determine_ownership(&mut OpenOptions::new()
                .read(true)
                .open(path)
                .unwrap())
            .unwrap() == DevOwnership::Ours(uuid)
    }));
    engine.destroy_pool(&uuid).unwrap();
    assert!(blockdevs.iter().all(|path| {
        StaticHeader::determine_ownership(&mut OpenOptions::new()
                .read(true)
                .open(path)
                .unwrap())
            .unwrap() == DevOwnership::Unowned
    }));
}

/// Test reading and writing metadata on a set of blockdevs sharing one pool
/// UUID.
/// 1. Verify that it is impossible to read variable length metadata off new
/// devices.
/// 2. Write metadata and verify that it is now available.
/// 3. Write different metadata, with a newer time, and verify that the new
/// metadata is now available.
/// FIXME: it would be best if StratPool::save_state() returned an error when
/// writing with an early time, currently it just panics.
pub fn test_variable_length_metadata_times(paths: &[&Path]) -> () {
    let unique_devices = resolve_devices(&paths).unwrap();
    let uuid = Uuid::new_v4();
    let mut blockdevs = initialize(&uuid, unique_devices, MIN_MDA_SECTORS, false).unwrap();
    assert!(StratPool::load_state(&blockdevs.iter().collect::<Vec<&BlockDev>>()).is_none());

    let (state1, state2) = (vec![1u8, 2u8, 3u8, 4u8], vec![5u8, 6u8, 7u8, 8u8]);
    let current_time = now().to_timespec();
    StratPool::save_state(&mut blockdevs.iter_mut().collect::<Vec<&mut BlockDev>>(),
                          &current_time,
                          &state1)
        .unwrap();
    assert!(StratPool::load_state(&blockdevs.iter().collect::<Vec<&BlockDev>>()).unwrap() ==
            state1);

    StratPool::save_state(&mut blockdevs.iter_mut().collect::<Vec<&mut BlockDev>>(),
                          &now().to_timespec(),
                          &state2)
        .unwrap();
    assert!(StratPool::load_state(&blockdevs.iter().collect::<Vec<&BlockDev>>()).unwrap() ==
            state2);
}
<commit_msg>Update integration tests to use devicemapper-rs 4.5<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

extern crate devicemapper;
extern crate libstratis;
extern crate rand;
extern crate tempdir;
extern crate time;
extern crate uuid;

use std::fs::{File, OpenOptions};
use std::io::Write;
use std::path::{Path, PathBuf};

use self::devicemapper::DM;
use self::devicemapper::consts::SECTOR_SIZE;
use self::devicemapper::lineardev::LinearDev;
use self::devicemapper::segment::Segment;
use self::devicemapper::types::{DataBlocks, Sectors};
use self::devicemapper::thindev::ThinDev;
use self::devicemapper::thinpooldev::ThinPoolDev;

use self::tempdir::TempDir;
use self::time::now;
use self::uuid::Uuid;

use libstratis::engine::Engine;
use libstratis::engine::strat_engine::StratEngine;
use libstratis::engine::strat_engine::blockdev::{blkdev_size, initialize, resolve_devices,
                                                 write_sectors, BlockDev};
use libstratis::engine::strat_engine::engine::DevOwnership;
use libstratis::engine::strat_engine::filesystem::{create_fs, mount_fs, unmount_fs};
use libstratis::engine::strat_engine::metadata::{StaticHeader, BDA_STATIC_HDR_SECTORS,
                                                 MIN_MDA_SECTORS};
use libstratis::engine::strat_engine::pool::StratPool;

/// Dirty sectors where specified, with 1s.
fn dirty_sectors(path: &Path, offset: Sectors, length: Sectors) {
    write_sectors(path, offset, length, &[1u8; SECTOR_SIZE]).unwrap();
}

/// Verify that it is impossible to initialize a set of disks of which
/// even one is dirty, i.e, has some data written within BDA_STATIC_HDR_SECTORS
/// of start of disk. Choose the dirty disk randomly. This means that even
/// if our code is broken with respect to this property, this test might
/// sometimes succeed.
/// FIXME: Consider enriching device specs so that this test will fail
/// consistently.
/// Verify that force flag allows all dirty disks to be initialized.
pub fn test_force_flag_dirty(paths: &[&Path]) -> () {

    let index = rand::random::<u8>() as usize % paths.len();
    dirty_sectors(paths[index],
                  Sectors(index as u64 % *BDA_STATIC_HDR_SECTORS),
                  Sectors(1));

    let unique_devices = resolve_devices(&paths).unwrap();

    let uuid = Uuid::new_v4();
    assert!(initialize(&uuid, unique_devices.clone(), MIN_MDA_SECTORS, false).is_err());
    assert!(paths.iter().enumerate().all(|(i, path)| {
        StaticHeader::determine_ownership(&mut OpenOptions::new()
                .read(true)
                .open(path)
                .unwrap())
            .unwrap() ==
        if i == index {
            DevOwnership::Theirs
        } else {
            DevOwnership::Unowned
        }
    }));

    assert!(initialize(&uuid, unique_devices.clone(), MIN_MDA_SECTORS, true).is_ok());
    assert!(paths.iter().all(|path| {
        StaticHeader::determine_ownership(&mut OpenOptions::new()
                .read(true)
                .open(path)
                .unwrap())
            .unwrap() == DevOwnership::Ours(uuid)
    }));
}

/// Verify that it is impossible to steal blockdevs from another Stratis
/// pool.
/// 1. Initialize devices with uuid.
/// 2. Initializing again with different uuid must fail.
/// 3. Initializing again with same uuid must fail, because all the
/// devices already belong.
/// 4. Initializing again with different uuid and force = true also fails.
pub fn test_force_flag_stratis(paths: &[&Path]) -> () {
    let unique_devices = resolve_devices(&paths).unwrap();

    let uuid = Uuid::new_v4();
    let uuid2 = Uuid::new_v4();

    initialize(&uuid, unique_devices.clone(), MIN_MDA_SECTORS, false).unwrap();
    assert!(initialize(&uuid2, unique_devices.clone(), MIN_MDA_SECTORS, false).is_err());

    // FIXME: once requirement that number of devices added be at least 2 is removed
    // this should succeed.
    assert!(initialize(&uuid, unique_devices.clone(), MIN_MDA_SECTORS, false).is_err());

    // FIXME: this should succeed, but currently it fails, to be extra safe.
    // See: https://github.com/stratis-storage/stratisd/pull/292
    assert!(initialize(&uuid2, unique_devices.clone(), MIN_MDA_SECTORS, true).is_err());
}

/// Verify that the sum of the lengths of the available range of the
/// blockdevs in the linear device equals the size of the linear device.
pub fn test_linear_device(paths: &[&Path]) -> () {
    let unique_devices = resolve_devices(&paths).unwrap();
    let initialized = initialize(&Uuid::new_v4(),
                                 unique_devices.clone(),
                                 MIN_MDA_SECTORS,
                                 false)
        .unwrap();
    let total_blockdev_size = initialized.iter()
        .fold(Sectors(0), |s, i| s + i.avail_range_segment().range().1);

    let segments = initialized.iter()
        .map(|block_dev| block_dev.avail_range_segment())
        .collect::<Vec<Segment>>();

    let segments_refs: Vec<&Segment> = segments.iter().collect();
    let device_name = "stratis_testing_linear";
    let dm = DM::new().unwrap();
    let lineardev = LinearDev::new(&device_name, &dm, &segments_refs).unwrap();

    let mut linear_dev_path = PathBuf::from("/dev/mapper");
    linear_dev_path.push(device_name);

    let lineardev_size = blkdev_size(&File::open(linear_dev_path).unwrap()).unwrap();
    assert!(total_blockdev_size.bytes() == lineardev_size);
    lineardev.teardown(&dm).unwrap();
}

/// Verify no errors when writing files to a mounted filesystem on a thin
/// device.
pub fn test_thinpool_device(paths: &[&Path]) -> () {
    let initialized = initialize(&Uuid::new_v4(),
                                 resolve_devices(&paths).unwrap(),
                                 MIN_MDA_SECTORS,
                                 false)
        .unwrap();

    let (metadata_blockdev, data_blockdev) = (initialized.first().unwrap(),
                                              initialized.last().unwrap());

    let dm = DM::new().unwrap();
    let metadata_dev = LinearDev::new("stratis_testing_thinpool_metadata",
                                      &dm,
                                      &vec![&metadata_blockdev.avail_range_segment()])
        .unwrap();
    let data_dev = LinearDev::new("stratis_testing_thinpool_datadev",
                                  &dm,
                                  &vec![&data_blockdev.avail_range_segment()])
        .unwrap();
    let thinpool_dev = ThinPoolDev::new("stratis_testing_thinpool",
                                        &dm,
                                        data_dev.size().unwrap().sectors(),
                                        Sectors(1024),
                                        DataBlocks(256000),
                                        metadata_dev,
                                        data_dev)
        .unwrap();
    let thin_dev = ThinDev::new("stratis_testing_thindev",
                                &dm,
                                &thinpool_dev,
                                7,
                                Sectors(300000))
        .unwrap();

    create_fs(&thin_dev.devnode().unwrap()).unwrap();

    let tmp_dir = TempDir::new("stratis_testing").unwrap();
    mount_fs(&thin_dev.devnode().unwrap(), tmp_dir.path()).unwrap();
    unmount_fs(tmp_dir.path()).unwrap();
    for i in 0..100 {
        let file_path = tmp_dir.path().join(format!("stratis_test{}.txt", i));
        writeln!(&File::create(file_path).unwrap(), "data").unwrap();
    }
    thin_dev.teardown(&dm).unwrap();
    thinpool_dev.teardown(&dm).unwrap();
}

/// Test that creating a pool claims all blockdevs and that destroying a pool
/// releases all blockdevs.
pub fn test_pool_blockdevs(paths: &[&Path]) -> () {
    let mut engine = StratEngine::new();
    let (uuid, blockdevs) = engine.create_pool("test_pool", paths, None, true).unwrap();
    assert!(blockdevs.iter().all(|path| {
        StaticHeader::determine_ownership(&mut OpenOptions::new()
                .read(true)
                .open(path)
                .unwrap())
            .unwrap() == DevOwnership::Ours(uuid)
    }));
    engine.destroy_pool(&uuid).unwrap();
    assert!(blockdevs.iter().all(|path| {
        StaticHeader::determine_ownership(&mut OpenOptions::new()
                .read(true)
                .open(path)
                .unwrap())
            .unwrap() == DevOwnership::Unowned
    }));
}

/// Test reading and writing metadata on a set of blockdevs sharing one pool
/// UUID.
/// 1. Verify that it is impossible to read variable length metadata off new
/// devices.
/// 2. Write metadata and verify that it is now available.
/// 3. Write different metadata, with a newer time, and verify that the new
/// metadata is now available.
/// FIXME: it would be best if StratPool::save_state() returned an error when
/// writing with an early time, currently it just panics.
pub fn test_variable_length_metadata_times(paths: &[&Path]) -> () {
    let unique_devices = resolve_devices(&paths).unwrap();
    let uuid = Uuid::new_v4();
    let mut blockdevs = initialize(&uuid, unique_devices, MIN_MDA_SECTORS, false).unwrap();
    assert!(StratPool::load_state(&blockdevs.iter().collect::<Vec<&BlockDev>>()).is_none());

    let (state1, state2) = (vec![1u8, 2u8, 3u8, 4u8], vec![5u8, 6u8, 7u8, 8u8]);
    let current_time = now().to_timespec();
    StratPool::save_state(&mut blockdevs.iter_mut().collect::<Vec<&mut BlockDev>>(),
                          &current_time,
                          &state1)
        .unwrap();
    assert!(StratPool::load_state(&blockdevs.iter().collect::<Vec<&BlockDev>>()).unwrap() ==
            state1);

    StratPool::save_state(&mut blockdevs.iter_mut().collect::<Vec<&mut BlockDev>>(),
                          &now().to_timespec(),
                          &state2)
        .unwrap();
    assert!(StratPool::load_state(&blockdevs.iter().collect::<Vec<&BlockDev>>()).unwrap() ==
            state2);
}
<|endoftext|>


<commit_before>use std::env;
use std::rc::Rc;
use std::cell::RefCell;
use sfml::graphics::{RenderWindow, RenderTarget, Font};
use sfml::window::{ContextSettings, VideoMode, Close};
use sfml::window::event;
use sfml::window::keyboard::Key;
use sfml::window::mouse::MouseButton;
use sfml::graphics::Color;
use sfml::system::vector2::Vector2i;
use na::{Pnt2, Pnt3, Iso2};
use na;
use nphysics::world::World;
use nphysics::object::RigidBody;
use nphysics::detection::joint::{Fixed, Anchor};
use camera::Camera;
use fps::Fps;
use engine::GraphicsManager;
use draw_helper;

fn usage(exe_name: &str) {
    println!("Usage: {} [OPTION] ", exe_name);
    println!("");
    println!("Options:");
    println!("    --help  - prints this help message and exits.");
    println!("    --pause - do not start the simulation right away.");
    println!("");
    println!("The following keyboard commands are supported:");
    println!("    t     - pause/continue the simulation.");
    println!("    s     - pause then execute only one simulation step.");
    println!("    space - display/hide contacts.");
}

#[derive(PartialEq)]
enum RunMode {
    Running,
    Stop,
    Step
}

pub struct Testbed<'a> {
    world:    World,
    window:   RenderWindow,
    graphics: GraphicsManager<'a>
}

struct TestbedState<'a> {
    running: RunMode,
    draw_colls: bool,
    camera: Camera,
    fps: Fps<'a>,
    grabbed_object: Option<Rc<RefCell<RigidBody>>>,
    grabbed_object_joint: Option<Rc<RefCell<Fixed>>>,
}

impl<'a> TestbedState<'a> {
    fn new(fnt: &'a Font) -> TestbedState<'a> {
        TestbedState{
            running: RunMode::Running,
            draw_colls: false,
            camera: Camera::new(),
            fps: Fps::new(&fnt),
            grabbed_object: None,
            grabbed_object_joint: None,
        }
    }
}

impl<'a> Testbed<'a> {
    pub fn new_empty() -> Testbed<'a> {
        let mode    = VideoMode::new_init(800, 600, 32);
        let setting = ContextSettings {
            depth_bits:         10,
            stencil_bits:       10,
            antialiasing_level: 2,
            major_version:      0,
            minor_version:      1
        };
        let window =
            match RenderWindow::new(mode, "nphysics 2d demo", Close, &setting) {
                Some(rwindow) => rwindow,
                None          => panic!("Error on creating the sfml window.")
            };
        let graphics = GraphicsManager::new();

        Testbed {
            world:    World::new(),
            window:   window,
            graphics: graphics
        }
    }

    pub fn new(world: World) -> Testbed<'a> {
        let mut res = Testbed::new_empty();

        res.set_world(world);

        res
    }

    pub fn set_world(&mut self, world: World) {
        self.world = world;
        self.graphics.clear();

        for rb in self.world.bodies() {
            self.graphics.add(rb.clone());
        }
    }

    pub fn set_color(&mut self, body: &Rc<RefCell<RigidBody>>, color: Pnt3<f32>) {
        let color = Pnt3::new(
            (color.x * 255.0) as u8,
            (color.y * 255.0) as u8,
            (color.z * 255.0) as u8
        );

        self.graphics.set_color(body, color);
    }

    pub fn run(&mut self) {
        let font_mem = include_bytes!("Inconsolata.otf");
        let     fnt  = Font::new_from_memory(font_mem).unwrap();

        let mut state = TestbedState::new(&fnt);

        let mut args    = env::args();

        if args.len() > 1 {
            let exname = args.next().unwrap();
            for arg in args {
                if &arg[..] == "--help" || &arg[..] == "-h" {
                    usage(&exname[..]);
                    return;
                }
                else if &arg[..] == "--pause" {
                    state.running = RunMode::Stop;
                }
            }
        }

        self.window.set_framerate_limit(60);

        self.foo(state);

        self.window.close();
    }

    fn foo(&mut self, mut state: TestbedState) {
        while self.window.is_open() {
            self.foo_loop(&mut state);

            self.window.clear(&Color::black());

            state.fps.reset();

            if state.running != RunMode::Stop {
                self.world.step(0.016);
            }

            if state.running == RunMode::Step {
                state.running = RunMode::Stop;
            }
            state.fps.register_delta();
            self.graphics.draw(&mut self.window, &state.camera);

            state.camera.activate_scene(&mut self.window);
            if state.draw_colls {
                draw_helper::draw_colls(&mut self.window, &mut self.world);
            }

            state.camera.activate_ui(&mut self.window);
            state.fps.draw_registered(&mut self.window);

            self.window.display();
        }
    }

    fn foo_loop(&mut self, mut state: &mut TestbedState) {
        loop {
            match self.window.poll_event() {
                event::KeyPressed{code, ..} => self.process_key_press(&mut state, code),
                event::MouseButtonPressed{button, x, y} => {
                    match button {
                        MouseButton::MouseLeft => {
                            let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                            let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                            self.world.interferences_with_point(&mapped_point, |b| {
                                if b.borrow().can_move() {
                                    state.grabbed_object = Some(b.clone())
                                }
                            });

                            match state.grabbed_object {
                                Some(ref b) => {
                                    for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                                        match state.grabbed_object_joint {
                                            Some(ref j) => self.world.remove_fixed(j),
                                            None        => { }
                                        }

                                        let _1: Iso2<f32> = na::one();
                                        let attach2 = na::append_translation(&_1, mapped_point.as_vec());
                                        let attach1 = na::inv(&na::transformation(b.borrow().position())).unwrap() * attach2;
                                        let anchor1 = Anchor::new(Some(state.grabbed_object.as_ref().unwrap().clone()), attach1);
                                        let anchor2 = Anchor::new(None, attach2);
                                        let joint = Fixed::new(anchor1, anchor2);
                                        state.grabbed_object_joint = Some(self.world.add_fixed(joint));
                                        node.select()
                                    }
                                },
                                None => { }
                            }
                        },
                        _ => {
                            state.camera.handle_event(&event::MouseButtonPressed{ button: button, x: x, y: y })
                        }
                    }
                },
                event::MouseButtonReleased{button, x, y} => {
                    match button {
                        MouseButton::MouseLeft => {
                            match state.grabbed_object {
                                Some(ref b) => {
                                    for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                                        node.unselect()
                                    }
                                },
                                None => { }
                            }

                            match state.grabbed_object_joint {
                                Some(ref j) => self.world.remove_fixed(j),
                                None => { }
                            }

                            state.grabbed_object = None;
                            state.grabbed_object_joint = None;
                        },
                        _ => {
                            state.camera.handle_event(&event::MouseButtonReleased{ button: button, x: x, y: y })
                        }
                    }
                }
                event::MouseMoved{x, y} => {
                    let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                    let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                    let _1: Iso2<f32> = na::one();
                    let attach2 = na::append_translation(&_1, (mapped_point).as_vec());
                    match state.grabbed_object {
                        Some(_) => {
                            let joint = state.grabbed_object_joint.as_ref().unwrap();
                            joint.borrow_mut().set_local2(attach2);
                        },
                        None => state.camera.handle_event(&event::MouseMoved{x: x, y: y})
                    };
                },
                event::Closed  => self.window.close(),
                event::NoEvent => break,
                e              => state.camera.handle_event(&e)
            }
        }
    }

    fn process_key_press(&mut self, state: &mut TestbedState, code: Key) {
        match code {
            Key::Escape => self.window.close(),
            Key::S      => state.running = RunMode::Step,
            Key::Space  => state.draw_colls = !state.draw_colls,
            Key::T      => {
                if state.running == RunMode::Stop {
                    state.running = RunMode::Running;
                }
                else {
                    state.running = RunMode::Stop;
                }
            },
            _                => { }
        }
    }
}
<commit_msg>Factored out mouse press<commit_after>use std::env;
use std::rc::Rc;
use std::cell::RefCell;
use sfml::graphics::{RenderWindow, RenderTarget, Font};
use sfml::window::{ContextSettings, VideoMode, Close};
use sfml::window::event;
use sfml::window::keyboard::Key;
use sfml::window::mouse::MouseButton;
use sfml::graphics::Color;
use sfml::system::vector2::Vector2i;
use na::{Pnt2, Pnt3, Iso2};
use na;
use nphysics::world::World;
use nphysics::object::RigidBody;
use nphysics::detection::joint::{Fixed, Anchor};
use camera::Camera;
use fps::Fps;
use engine::GraphicsManager;
use draw_helper;

fn usage(exe_name: &str) {
    println!("Usage: {} [OPTION] ", exe_name);
    println!("");
    println!("Options:");
    println!("    --help  - prints this help message and exits.");
    println!("    --pause - do not start the simulation right away.");
    println!("");
    println!("The following keyboard commands are supported:");
    println!("    t     - pause/continue the simulation.");
    println!("    s     - pause then execute only one simulation step.");
    println!("    space - display/hide contacts.");
}

#[derive(PartialEq)]
enum RunMode {
    Running,
    Stop,
    Step
}

pub struct Testbed<'a> {
    world:    World,
    window:   RenderWindow,
    graphics: GraphicsManager<'a>
}

struct TestbedState<'a> {
    running: RunMode,
    draw_colls: bool,
    camera: Camera,
    fps: Fps<'a>,
    grabbed_object: Option<Rc<RefCell<RigidBody>>>,
    grabbed_object_joint: Option<Rc<RefCell<Fixed>>>,
}

impl<'a> TestbedState<'a> {
    fn new(fnt: &'a Font) -> TestbedState<'a> {
        TestbedState{
            running: RunMode::Running,
            draw_colls: false,
            camera: Camera::new(),
            fps: Fps::new(&fnt),
            grabbed_object: None,
            grabbed_object_joint: None,
        }
    }
}

impl<'a> Testbed<'a> {
    pub fn new_empty() -> Testbed<'a> {
        let mode    = VideoMode::new_init(800, 600, 32);
        let setting = ContextSettings {
            depth_bits:         10,
            stencil_bits:       10,
            antialiasing_level: 2,
            major_version:      0,
            minor_version:      1
        };
        let window =
            match RenderWindow::new(mode, "nphysics 2d demo", Close, &setting) {
                Some(rwindow) => rwindow,
                None          => panic!("Error on creating the sfml window.")
            };
        let graphics = GraphicsManager::new();

        Testbed {
            world:    World::new(),
            window:   window,
            graphics: graphics
        }
    }

    pub fn new(world: World) -> Testbed<'a> {
        let mut res = Testbed::new_empty();

        res.set_world(world);

        res
    }

    pub fn set_world(&mut self, world: World) {
        self.world = world;
        self.graphics.clear();

        for rb in self.world.bodies() {
            self.graphics.add(rb.clone());
        }
    }

    pub fn set_color(&mut self, body: &Rc<RefCell<RigidBody>>, color: Pnt3<f32>) {
        let color = Pnt3::new(
            (color.x * 255.0) as u8,
            (color.y * 255.0) as u8,
            (color.z * 255.0) as u8
        );

        self.graphics.set_color(body, color);
    }

    pub fn run(&mut self) {
        let font_mem = include_bytes!("Inconsolata.otf");
        let     fnt  = Font::new_from_memory(font_mem).unwrap();

        let mut state = TestbedState::new(&fnt);

        let mut args    = env::args();

        if args.len() > 1 {
            let exname = args.next().unwrap();
            for arg in args {
                if &arg[..] == "--help" || &arg[..] == "-h" {
                    usage(&exname[..]);
                    return;
                }
                else if &arg[..] == "--pause" {
                    state.running = RunMode::Stop;
                }
            }
        }

        self.window.set_framerate_limit(60);

        self.foo(state);

        self.window.close();
    }

    fn foo(&mut self, mut state: TestbedState) {
        while self.window.is_open() {
            self.foo_loop(&mut state);

            self.window.clear(&Color::black());

            state.fps.reset();

            if state.running != RunMode::Stop {
                self.world.step(0.016);
            }

            if state.running == RunMode::Step {
                state.running = RunMode::Stop;
            }
            state.fps.register_delta();
            self.graphics.draw(&mut self.window, &state.camera);

            state.camera.activate_scene(&mut self.window);
            if state.draw_colls {
                draw_helper::draw_colls(&mut self.window, &mut self.world);
            }

            state.camera.activate_ui(&mut self.window);
            state.fps.draw_registered(&mut self.window);

            self.window.display();
        }
    }

    fn foo_loop(&mut self, mut state: &mut TestbedState) {
        loop {
            match self.window.poll_event() {
                event::KeyPressed{code, ..} => self.process_key_press(&mut state, code),
                event::MouseButtonPressed{button, x, y} => self.process_mouse_press(&mut state, button, x, y),
                event::MouseButtonReleased{button, x, y} => {
                    match button {
                        MouseButton::MouseLeft => {
                            match state.grabbed_object {
                                Some(ref b) => {
                                    for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                                        node.unselect()
                                    }
                                },
                                None => { }
                            }

                            match state.grabbed_object_joint {
                                Some(ref j) => self.world.remove_fixed(j),
                                None => { }
                            }

                            state.grabbed_object = None;
                            state.grabbed_object_joint = None;
                        },
                        _ => {
                            state.camera.handle_event(&event::MouseButtonReleased{ button: button, x: x, y: y })
                        }
                    }
                }
                event::MouseMoved{x, y} => {
                    let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                    let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                    let _1: Iso2<f32> = na::one();
                    let attach2 = na::append_translation(&_1, (mapped_point).as_vec());
                    match state.grabbed_object {
                        Some(_) => {
                            let joint = state.grabbed_object_joint.as_ref().unwrap();
                            joint.borrow_mut().set_local2(attach2);
                        },
                        None => state.camera.handle_event(&event::MouseMoved{x: x, y: y})
                    };
                },
                event::Closed  => self.window.close(),
                event::NoEvent => break,
                e              => state.camera.handle_event(&e)
            }
        }
    }

    fn process_key_press(&mut self, state: &mut TestbedState, code: Key) {
        match code {
            Key::Escape => self.window.close(),
            Key::S      => state.running = RunMode::Step,
            Key::Space  => state.draw_colls = !state.draw_colls,
            Key::T      => {
                if state.running == RunMode::Stop {
                    state.running = RunMode::Running;
                }
                else {
                    state.running = RunMode::Stop;
                }
            },
            _                => { }
        }
    }

    fn process_mouse_press(&mut self, state: &mut TestbedState, button: MouseButton, x: i32, y: i32) {
        match button {
            MouseButton::MouseLeft => {
                let mapped_coords = state.camera.map_pixel_to_coords(Vector2i::new(x, y));
                let mapped_point = Pnt2::new(mapped_coords.x, mapped_coords.y);
                self.world.interferences_with_point(&mapped_point, |b| {
                    if b.borrow().can_move() {
                        state.grabbed_object = Some(b.clone())
                    }
                });

                match state.grabbed_object {
                    Some(ref b) => {
                        for node in self.graphics.body_to_scene_node(b).unwrap().iter_mut() {
                            match state.grabbed_object_joint {
                                Some(ref j) => self.world.remove_fixed(j),
                                None        => { }
                            }

                            let _1: Iso2<f32> = na::one();
                            let attach2 = na::append_translation(&_1, mapped_point.as_vec());
                            let attach1 = na::inv(&na::transformation(b.borrow().position())).unwrap() * attach2;
                            let anchor1 = Anchor::new(Some(state.grabbed_object.as_ref().unwrap().clone()), attach1);
                            let anchor2 = Anchor::new(None, attach2);
                            let joint = Fixed::new(anchor1, anchor2);
                            state.grabbed_object_joint = Some(self.world.add_fixed(joint));
                            node.select()
                        }
                    },
                    None => { }
                }
            },
            _ => {
                state.camera.handle_event(&event::MouseButtonPressed{ button: button, x: x, y: y })
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::convert::From;
use std::env::{var, VarError};
use std::fmt;
use std::sync::Arc;

/// Variable is an abstraction over parameters to credential providers, allowing to abstract on
/// how (source) and when (time) parameter values are resolved. A lot of credentials providers
/// use external information sources such as environment variables or files to obtain parameter
/// values needed to produce AWS credentials.
///
/// # Information Sources
///
/// - In memory values (static)
/// - Environment variables (dynamic)
/// - Files (dynamic)
/// - ...
///
/// # Resolving Behaviour
///
/// - Static variables always resolve to the same value.
/// - Dynamic variables can resolve to different values over time.
///
/// Most prominent examples for dynamic variables are parameters which read their value from
/// environment variables or files.
pub enum Variable<T, E = super::CredentialsError> {
    /// Static variable always resolving to the same given value.
    Static(T),
    /// Dynamic variable can resolve to different values over time.
    Dynamic(Arc<dyn Fn() -> Result<T, E> + Send + Sync>),
    /// Fallback try variables in given order returning the value of the first variable that
    /// does resolve.
    Fallback(Box<Variable<T, E>>, Box<Variable<T, E>>),
}

impl<T, E> From<T> for Variable<T, E>
where
    T: Clone,
{
    fn from(value: T) -> Self {
        Variable::with_value(value)
    }
}

impl<E> From<&str> for Variable<String, E> {
    fn from(value: &str) -> Self {
        Variable::with_value(value.to_owned())
    }
}

/*
impl<T, E, V> From<&V> for Variable<T, E>
where
    T: Clone + std::borrow::Borrow<V>,
    V: ToOwned<Owned = T> + ?Sized,
{
    fn from(value: &V) -> Self {
        Variable::with_value(value.to_owned())
    }
}*/

impl<T: fmt::Debug, E> fmt::Debug for Variable<T, E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Static(t) => write!(f, "Variable::Static({:?})", t),
            Self::Dynamic(_) => write!(f, "Variable::Dynamic(...)"),
            Self::Fallback(a, b) => write!(f, "Variable::Fallback({:?}, {:?})", a, b),
        }
    }
}

/// Custom Clone implementation as type parameter E doesn't have to be cloneable.
impl<T: Clone, E> Clone for Variable<T, E> {
    fn clone(&self) -> Self {
        match self {
            Self::Static(t) => Self::Static(t.clone()),
            Self::Dynamic(f) => Self::Dynamic(f.clone()),
            Self::Fallback(a, b) => Self::Fallback(a.clone(), b.clone()),
        }
    }
}

impl<T: Clone, E> Variable<T, E> {
    /// Variable which statically resolves to a provided (in-memory) value.
    pub fn with_value<V: Into<T>>(value: V) -> Self {
        Self::Static(value.into())
    }

    /// Resolve the variable's value.
    pub fn resolve(&self) -> Result<T, E> {
        match self {
            Self::Static(t) => Ok(t.clone()),
            Self::Dynamic(f) => f(),
            Self::Fallback(a, b) => a.resolve().or_else(|_| b.resolve()),
        }
    }

    /// Combine this Variable with a fallback Variable. Resolving the variable's value will be
    /// done lazily, stopping on the first Variable that successfuly resolves.
    ///
    /// # Example Usage
    ///
    /// ```rust
    /// # use rusoto_credential::Variable;
    /// let primary: Variable<String> = Variable::from_env_var("AWS_SECRET_ACCESS_KEY");
    /// let fallback = Variable::from_env_var("AWS_SECRET_KEY");
    /// let aws_secret_access_key = primary.or(fallback);
    /// ```
    pub fn or(self, other: Variable<T, E>) -> Self {
        Self::Fallback(Box::new(self), Box::new(other))
    }
}

impl<T: 'static, E: 'static> Variable<T, E> {
    /// Variable which dynamically resolves to the value returned from the provided closure. Use
    /// this constructor function to create dynamically resolving Variables with custom logic.
    pub fn dynamic(f: impl Fn() -> Result<T, E> + Send + Sync + 'static) -> Self {
        Self::Dynamic(Arc::new(f))
    }
}

impl<T, E> Variable<T, E>
where
    T: From<String> + 'static,
    E: From<VarError> + 'static,
{
    /// Variable which dynamically resolves to the value of a given environment variable.
    pub fn from_env_var<K: AsRef<std::ffi::OsStr>>(key: K) -> Self {
        let tmp = key.as_ref().to_os_string();
        Self::dynamic(move || match var(&tmp) {
            Ok(ref v) if !v.trim().is_empty() => Ok(T::from(v.trim().to_string())),
            Ok(_) => Err(E::from(VarError::NotPresent)),
            Err(e) => Err(E::from(e)),
        })
    }
}

impl<T, E> Variable<Option<T>, E>
where
    T: From<String> + 'static,
    E: From<VarError> + 'static,
{
    /// Variable which dynamically resolves to the value of a given environment variable.
    pub fn from_env_var_optional<K: AsRef<std::ffi::OsStr>>(key: K) -> Self {
        let tmp = key.as_ref().to_os_string();
        Self::dynamic(move || match var(&tmp) {
            Ok(ref v) if !v.trim().is_empty() => Ok(Some(T::from(v.trim().to_string()))),
            Ok(_) => Ok(None),
            Err(VarError::NotPresent) => Ok(None),
            Err(e) => Err(E::from(e)),
        })
    }
}

impl<T, E> Variable<T, E>
where
    T: From<String> + 'static,
    E: From<std::io::Error> + From<std::string::FromUtf8Error> + 'static,
{
    /// Variable which dynamically resolves to the value of an UTF-8 encoded text file
    /// (removing all leading and trailing whitespaces.
    pub fn from_text_file<K: AsRef<std::path::Path>>(file: K) -> Self {
        use std::fs::read;
        let tmp = file.as_ref().to_path_buf();
        Self::dynamic(move || {
            Ok(T::from(
                String::from_utf8(read(&tmp)?)?.as_str().trim().to_string(),
            ))
        })
    }
}

impl<T, E> Variable<T, E>
where
    T: From<Vec<u8>> + 'static,
    E: From<std::io::Error> + 'static,
{
    /// Variable which dynamically resolves to the value of a binary file.
    pub fn from_binary_file<K: AsRef<std::path::Path>>(file: K) -> Self {
        use std::fs::read;
        let tmp = file.as_ref().to_path_buf();
        Self::dynamic(move || Ok(T::from(read(&tmp)?)))
    }
}

#[cfg(test)]
mod test {
    use super::super::CredentialsError;
    use super::*;
    use crate::test_utils::lock_env;
    use std::io::Write;
    use tempfile::NamedTempFile;

    #[test]
    fn api_ergonomics() {
        let _tmp: Variable<String> = "".to_string().into();
        let _tmp: Variable<String> = "".into();
        let _tmp: Variable<u32> = 1.into();
    }

    #[test]
    fn is_send() {
        fn _send<T: Send>(_t: T) {}
        let var = Variable::<i32, ()>::with_value(1);
        _send(var);
    }

    #[test]
    fn is_sync() {
        fn _sync<T: Sync>(_t: T) {}
        let var = Variable::<i32, ()>::with_value(1);
        _sync(var);
    }

    #[test]
    fn from_value() {
        let var = Variable::<i32, ()>::with_value(1);
        assert_eq!(var.resolve(), Ok(1));
        assert_eq!(var.resolve(), Ok(1));
    }

    #[test]
    fn dynamic() {
        fn xx() -> Result<i32, ()> {
            Ok(1)
        }
        let var = Variable::<i32, ()>::dynamic(|| Ok(1));
        assert_eq!(var.resolve(), Ok(1));
        assert_eq!(var.resolve(), Ok(1));
        let var = Variable::<i32, ()>::dynamic(xx);
        assert_eq!(var.resolve(), Ok(1));
        assert_eq!(var.resolve(), Ok(1));
    }

    #[test]
    fn from_env_var() {
        let _guard = lock_env();
        const VALUE: &str = "E6591691_C658_4C63_A7CF_C822D8FFC15B";
        std::env::set_var(VALUE, VALUE);
        let var = Variable::<String, CredentialsError>::from_env_var(VALUE);
        assert_eq!(var.resolve(), Ok(VALUE.to_string()));
        assert_eq!(var.resolve(), Ok(VALUE.to_string()));
        std::env::remove_var(VALUE);
        assert_eq!(var.resolve().is_ok(), false);
    }

    #[test]
    fn from_empty_env_var() {
        let _guard = lock_env();
        const VALUE: &str = "90E839DA_2254_4416_8295_AB82BD44D822";
        std::env::set_var(VALUE, "");
        let var = Variable::<String>::from_env_var(VALUE);
        assert_eq!(var.resolve().is_ok(), false);
        std::env::remove_var(VALUE);
    }

    #[test]
    fn from_text_file() -> Result<(), CredentialsError> {
        const VALUE: &str = "value";
        let mut file = NamedTempFile::new()?;
        writeln!(file, "{}", VALUE)?;
        let var = Variable::<String>::from_text_file(file.path());
        assert_eq!(var.resolve(), Ok(VALUE.to_string()));
        assert_eq!(var.resolve(), Ok(VALUE.to_string()));
        Ok(())
    }

    #[test]
    fn from_binary_file() -> Result<(), CredentialsError> {
        const VALUE: &[u8] = b"value";
        let mut file = NamedTempFile::new()?;
        file.write(VALUE)?;
        let var = Variable::<Vec<u8>>::from_binary_file(file.path());
        assert_eq!(var.resolve().as_ref().map(|v| v.as_slice()), Ok(VALUE));
        assert_eq!(var.resolve().as_ref().map(|v| v.as_slice()), Ok(VALUE));
        Ok(())
    }

    #[test]
    fn or() {
        let a = Variable::<i32, ()>::with_value(1);
        let b = Variable::<i32, ()>::with_value(2);
        assert_eq!(a.or(b).resolve(), Ok(1));
        let a = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        let b = Variable::<i32, VarError>::with_value(2);
        assert_eq!(a.or(b).resolve(), Ok(2));
        let a = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        let b = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        let c = Variable::<i32, VarError>::with_value(3);
        assert_eq!(a.or(b).or(c).resolve(), Ok(3));
        let a = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        let b = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        assert_eq!(a.or(b).resolve(), Err(VarError::NotPresent));
    }
}
<commit_msg>simplify match arm<commit_after>use std::convert::From;
use std::env::{var, VarError};
use std::fmt;
use std::sync::Arc;

/// Variable is an abstraction over parameters to credential providers, allowing to abstract on
/// how (source) and when (time) parameter values are resolved. A lot of credentials providers
/// use external information sources such as environment variables or files to obtain parameter
/// values needed to produce AWS credentials.
///
/// # Information Sources
///
/// - In memory values (static)
/// - Environment variables (dynamic)
/// - Files (dynamic)
/// - ...
///
/// # Resolving Behaviour
///
/// - Static variables always resolve to the same value.
/// - Dynamic variables can resolve to different values over time.
///
/// Most prominent examples for dynamic variables are parameters which read their value from
/// environment variables or files.
pub enum Variable<T, E = super::CredentialsError> {
    /// Static variable always resolving to the same given value.
    Static(T),
    /// Dynamic variable can resolve to different values over time.
    Dynamic(Arc<dyn Fn() -> Result<T, E> + Send + Sync>),
    /// Fallback try variables in given order returning the value of the first variable that
    /// does resolve.
    Fallback(Box<Variable<T, E>>, Box<Variable<T, E>>),
}

impl<T, E> From<T> for Variable<T, E>
where
    T: Clone,
{
    fn from(value: T) -> Self {
        Variable::with_value(value)
    }
}

impl<E> From<&str> for Variable<String, E> {
    fn from(value: &str) -> Self {
        Variable::with_value(value.to_owned())
    }
}

/*
impl<T, E, V> From<&V> for Variable<T, E>
where
    T: Clone + std::borrow::Borrow<V>,
    V: ToOwned<Owned = T> + ?Sized,
{
    fn from(value: &V) -> Self {
        Variable::with_value(value.to_owned())
    }
}*/

impl<T: fmt::Debug, E> fmt::Debug for Variable<T, E> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Static(t) => write!(f, "Variable::Static({:?})", t),
            Self::Dynamic(_) => write!(f, "Variable::Dynamic(...)"),
            Self::Fallback(a, b) => write!(f, "Variable::Fallback({:?}, {:?})", a, b),
        }
    }
}

/// Custom Clone implementation as type parameter E doesn't have to be cloneable.
impl<T: Clone, E> Clone for Variable<T, E> {
    fn clone(&self) -> Self {
        match self {
            Self::Static(t) => Self::Static(t.clone()),
            Self::Dynamic(f) => Self::Dynamic(f.clone()),
            Self::Fallback(a, b) => Self::Fallback(a.clone(), b.clone()),
        }
    }
}

impl<T: Clone, E> Variable<T, E> {
    /// Variable which statically resolves to a provided (in-memory) value.
    pub fn with_value<V: Into<T>>(value: V) -> Self {
        Self::Static(value.into())
    }

    /// Resolve the variable's value.
    pub fn resolve(&self) -> Result<T, E> {
        match self {
            Self::Static(t) => Ok(t.clone()),
            Self::Dynamic(f) => f(),
            Self::Fallback(a, b) => a.resolve().or_else(|_| b.resolve()),
        }
    }

    /// Combine this Variable with a fallback Variable. Resolving the variable's value will be
    /// done lazily, stopping on the first Variable that successfuly resolves.
    ///
    /// # Example Usage
    ///
    /// ```rust
    /// # use rusoto_credential::Variable;
    /// let primary: Variable<String> = Variable::from_env_var("AWS_SECRET_ACCESS_KEY");
    /// let fallback = Variable::from_env_var("AWS_SECRET_KEY");
    /// let aws_secret_access_key = primary.or(fallback);
    /// ```
    pub fn or(self, other: Variable<T, E>) -> Self {
        Self::Fallback(Box::new(self), Box::new(other))
    }
}

impl<T: 'static, E: 'static> Variable<T, E> {
    /// Variable which dynamically resolves to the value returned from the provided closure. Use
    /// this constructor function to create dynamically resolving Variables with custom logic.
    pub fn dynamic(f: impl Fn() -> Result<T, E> + Send + Sync + 'static) -> Self {
        Self::Dynamic(Arc::new(f))
    }
}

impl<T, E> Variable<T, E>
where
    T: From<String> + 'static,
    E: From<VarError> + 'static,
{
    /// Variable which dynamically resolves to the value of a given environment variable.
    pub fn from_env_var<K: AsRef<std::ffi::OsStr>>(key: K) -> Self {
        let tmp = key.as_ref().to_os_string();
        Self::dynamic(move || match var(&tmp) {
            Ok(ref v) if !v.trim().is_empty() => Ok(T::from(v.trim().to_string())),
            Ok(_) => Err(E::from(VarError::NotPresent)),
            Err(e) => Err(E::from(e)),
        })
    }
}

impl<T, E> Variable<Option<T>, E>
where
    T: From<String> + 'static,
    E: From<VarError> + 'static,
{
    /// Variable which dynamically resolves to the value of a given environment variable.
    pub fn from_env_var_optional<K: AsRef<std::ffi::OsStr>>(key: K) -> Self {
        let tmp = key.as_ref().to_os_string();
        Self::dynamic(move || match var(&tmp) {
            Ok(ref v) if !v.trim().is_empty() => Ok(Some(T::from(v.trim().to_string()))),
            Ok(_) | Err(VarError::NotPresent) => Ok(None),
            Err(e) => Err(E::from(e)),
        })
    }
}

impl<T, E> Variable<T, E>
where
    T: From<String> + 'static,
    E: From<std::io::Error> + From<std::string::FromUtf8Error> + 'static,
{
    /// Variable which dynamically resolves to the value of an UTF-8 encoded text file
    /// (removing all leading and trailing whitespaces.
    pub fn from_text_file<K: AsRef<std::path::Path>>(file: K) -> Self {
        use std::fs::read;
        let tmp = file.as_ref().to_path_buf();
        Self::dynamic(move || {
            Ok(T::from(
                String::from_utf8(read(&tmp)?)?.as_str().trim().to_string(),
            ))
        })
    }
}

impl<T, E> Variable<T, E>
where
    T: From<Vec<u8>> + 'static,
    E: From<std::io::Error> + 'static,
{
    /// Variable which dynamically resolves to the value of a binary file.
    pub fn from_binary_file<K: AsRef<std::path::Path>>(file: K) -> Self {
        use std::fs::read;
        let tmp = file.as_ref().to_path_buf();
        Self::dynamic(move || Ok(T::from(read(&tmp)?)))
    }
}

#[cfg(test)]
mod test {
    use super::super::CredentialsError;
    use super::*;
    use crate::test_utils::lock_env;
    use std::io::Write;
    use tempfile::NamedTempFile;

    #[test]
    fn api_ergonomics() {
        let _tmp: Variable<String> = "".to_string().into();
        let _tmp: Variable<String> = "".into();
        let _tmp: Variable<u32> = 1.into();
    }

    #[test]
    fn is_send() {
        fn _send<T: Send>(_t: T) {}
        let var = Variable::<i32, ()>::with_value(1);
        _send(var);
    }

    #[test]
    fn is_sync() {
        fn _sync<T: Sync>(_t: T) {}
        let var = Variable::<i32, ()>::with_value(1);
        _sync(var);
    }

    #[test]
    fn from_value() {
        let var = Variable::<i32, ()>::with_value(1);
        assert_eq!(var.resolve(), Ok(1));
        assert_eq!(var.resolve(), Ok(1));
    }

    #[test]
    fn dynamic() {
        fn xx() -> Result<i32, ()> {
            Ok(1)
        }
        let var = Variable::<i32, ()>::dynamic(|| Ok(1));
        assert_eq!(var.resolve(), Ok(1));
        assert_eq!(var.resolve(), Ok(1));
        let var = Variable::<i32, ()>::dynamic(xx);
        assert_eq!(var.resolve(), Ok(1));
        assert_eq!(var.resolve(), Ok(1));
    }

    #[test]
    fn from_env_var() {
        let _guard = lock_env();
        const VALUE: &str = "E6591691_C658_4C63_A7CF_C822D8FFC15B";
        std::env::set_var(VALUE, VALUE);
        let var = Variable::<String, CredentialsError>::from_env_var(VALUE);
        assert_eq!(var.resolve(), Ok(VALUE.to_string()));
        assert_eq!(var.resolve(), Ok(VALUE.to_string()));
        std::env::remove_var(VALUE);
        assert_eq!(var.resolve().is_ok(), false);
    }

    #[test]
    fn from_empty_env_var() {
        let _guard = lock_env();
        const VALUE: &str = "90E839DA_2254_4416_8295_AB82BD44D822";
        std::env::set_var(VALUE, "");
        let var = Variable::<String>::from_env_var(VALUE);
        assert_eq!(var.resolve().is_ok(), false);
        std::env::remove_var(VALUE);
    }

    #[test]
    fn from_text_file() -> Result<(), CredentialsError> {
        const VALUE: &str = "value";
        let mut file = NamedTempFile::new()?;
        writeln!(file, "{}", VALUE)?;
        let var = Variable::<String>::from_text_file(file.path());
        assert_eq!(var.resolve(), Ok(VALUE.to_string()));
        assert_eq!(var.resolve(), Ok(VALUE.to_string()));
        Ok(())
    }

    #[test]
    fn from_binary_file() -> Result<(), CredentialsError> {
        const VALUE: &[u8] = b"value";
        let mut file = NamedTempFile::new()?;
        file.write(VALUE)?;
        let var = Variable::<Vec<u8>>::from_binary_file(file.path());
        assert_eq!(var.resolve().as_ref().map(|v| v.as_slice()), Ok(VALUE));
        assert_eq!(var.resolve().as_ref().map(|v| v.as_slice()), Ok(VALUE));
        Ok(())
    }

    #[test]
    fn or() {
        let a = Variable::<i32, ()>::with_value(1);
        let b = Variable::<i32, ()>::with_value(2);
        assert_eq!(a.or(b).resolve(), Ok(1));
        let a = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        let b = Variable::<i32, VarError>::with_value(2);
        assert_eq!(a.or(b).resolve(), Ok(2));
        let a = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        let b = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        let c = Variable::<i32, VarError>::with_value(3);
        assert_eq!(a.or(b).or(c).resolve(), Ok(3));
        let a = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        let b = Variable::<i32, VarError>::dynamic(|| Err(VarError::NotPresent));
        assert_eq!(a.or(b).resolve(), Err(VarError::NotPresent));
    }
}
<|endoftext|>