<commit_before>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate iron_test;
extern crate serde_json;
use super::BragiHandler;
use super::get_values;

pub fn bragi_bano_test(es_wrapper: ::ElasticSearchWrapper) {
    let bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // *********************************
    // We load bano files
    // *********************************
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    status_test(&bragi);
    simple_bano_autocomplete_test(&bragi);
    simple_bano_shape_filter_test(&bragi);
    simple_bano_lon_lat_test(&bragi);
}

fn status_test(bragi: &BragiHandler) {
    let resp = bragi.raw_get("/status").unwrap();
    assert_eq!(to_json(resp).find("status"),
               Some(&Value::String("good".to_string())));
}

fn simple_bano_autocomplete_test(bragi: &BragiHandler) {
    let resp = bragi.raw_get("/autocomplete?q=15 Rue Hector Malot, (Paris)").unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.376379,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot (Paris)","#,
                         r#""name":"15 Rue Hector Malot","housenumber":"15","#,
                         r#""street":"Rue Hector Malot","postcode":"75012","#,
                         r#""city":null,"city_code":null,"citycode":null,"level":null,"#,
                         r#""administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);
}

// A(48.846431 2.376488)
// B(48.846430 2.376306)
// C(48.846606 2.376309)
// D(48.846603 2.376486)
// R(48.846495 2.376378) : 15 Rue Hector Malot, (Paris)
// E(48.846452 2.376580) : 18 Rue Hector Malot, (Paris)
//
//             E
//
//      A ---------------------D
//      |                      |
//      |         R            |
//      |                      |
//      |                      |
//      B ---------------------C
fn simple_bano_shape_filter_test(bragi: &BragiHandler) {
    // Search with shape where house number in shape
    let shape = r#"{"geometry":{"type":"Polygon","coordinates":[[[2.376488, 48.846431],
        [2.376306, 48.846430],[2.376309, 48.846606],[ 2.376486, 48.846603]]]}}"#;
    let resp = bragi.raw_post_shape("/autocomplete?q=15 Rue Hector Malot, (Paris)", shape).unwrap();

    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.376379,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot (Paris)","#,
                         r#""name":"15 Rue Hector Malot","housenumber":"15","#,
                         r#""street":"Rue Hector Malot","postcode":"75012","#,
                         r#""city":null,"city_code":null,"citycode":null,"level":null,"#,
                         r#""administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);

    // Search with shape where house number out of shape
    let resp = bragi.raw_post_shape("/autocomplete?q=18 Rue Hector Malot, (Paris)", shape).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"features":[]}"#);
    assert_eq!(result_body, result);
}

fn simple_bano_lon_lat_test(bragi: &BragiHandler) {
    // test with a lon/lat priorisation
    // in the dataset there are two '20 rue hector malot',
    // one in paris and one in trifouilli-les-Oies
    // in the mean time we test our prefix search_query
    let all_20 = bragi.get("/autocomplete?q=20 rue hect mal");
    assert_eq!(all_20.len(), 2);
    // the first one is paris (since Paris has more streets, it is prioritized first)
    // TODO uncomment this test, for the moment since osm is not loaded, the order is random
    // assert_eq!(get_labels(&all_20),
    //            vec!["20 Rue Hector Malot (Paris)", "20 Rue Hector Malot (Trifouilli-les-Oies)"]);

    // if we give a lon/lat near trifouilli-les-Oies, we'll have another sort
    let all_20 = bragi.get("/autocomplete?q=20 rue hector malot&lat=50.2&lon=2.0");
    assert_eq!(get_values(&all_20, "label"),
               vec!["20 Rue Hector Malot (Trifouilli-les-Oies)", "20 Rue Hector Malot (Paris)"]);
    // and when we're in paris, we get paris first
    let all_20 = bragi.get("/autocomplete?q=20 rue hector malot&lat=48&lon=2.4");
    assert_eq!(get_values(&all_20, "label"),
               vec!["20 Rue Hector Malot (Paris)", "20 Rue Hector Malot (Trifouilli-les-Oies)"]);
}
<commit_msg>missing use after rebase<commit_after>// Copyright © 2017, Canal TP and/or its affiliates. All rights reserved.
//
// This file is part of Navitia,
//     the software to build cool stuff with public transport.
//
// Hope you'll enjoy and contribute to this project,
//     powered by Canal TP (www.canaltp.fr).
// Help us simplify mobility and open public transport:
//     a non ending quest to the responsive locomotion way of traveling!
//
// LICENCE: This program is free software; you can redistribute it
// and/or modify it under the terms of the GNU Affero General Public
// License as published by the Free Software Foundation, either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public
// License along with this program. If not, see
// <http://www.gnu.org/licenses/>.
//
// Stay tuned using
// twitter @navitia
// IRC #navitia on freenode
// https://groups.google.com/d/forum/navitia
// www.navitia.io

extern crate bragi;
extern crate iron_test;
extern crate serde_json;
use super::BragiHandler;
use super::get_values;
use super::to_json;
use serde_json::Value;

pub fn bragi_bano_test(es_wrapper: ::ElasticSearchWrapper) {
    let bragi = BragiHandler::new(format!("{}/munin", es_wrapper.host()));

    // *********************************
    // We load bano files
    // *********************************
    let bano2mimir = concat!(env!("OUT_DIR"), "/../../../bano2mimir");
    info!("Launching {}", bano2mimir);
    ::launch_and_assert(bano2mimir,
                        vec!["--input=./tests/fixtures/sample-bano.csv".into(),
                             format!("--connection-string={}", es_wrapper.host())],
                        &es_wrapper);

    status_test(&bragi);
    simple_bano_autocomplete_test(&bragi);
    simple_bano_shape_filter_test(&bragi);
    simple_bano_lon_lat_test(&bragi);
}

fn status_test(bragi: &BragiHandler) {
    let resp = bragi.raw_get("/status").unwrap();
    assert_eq!(to_json(resp).find("status"),
               Some(&Value::String("good".to_string())));
}

fn simple_bano_autocomplete_test(bragi: &BragiHandler) {
    let resp = bragi.raw_get("/autocomplete?q=15 Rue Hector Malot, (Paris)").unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.376379,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot (Paris)","#,
                         r#""name":"15 Rue Hector Malot","housenumber":"15","#,
                         r#""street":"Rue Hector Malot","postcode":"75012","#,
                         r#""city":null,"city_code":null,"citycode":null,"level":null,"#,
                         r#""administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);
}

// A(48.846431 2.376488)
// B(48.846430 2.376306)
// C(48.846606 2.376309)
// D(48.846603 2.376486)
// R(48.846495 2.376378) : 15 Rue Hector Malot, (Paris)
// E(48.846452 2.376580) : 18 Rue Hector Malot, (Paris)
//
//             E
//
//      A ---------------------D
//      |                      |
//      |         R            |
//      |                      |
//      |                      |
//      B ---------------------C
fn simple_bano_shape_filter_test(bragi: &BragiHandler) {
    // Search with shape where house number in shape
    let shape = r#"{"geometry":{"type":"Polygon","coordinates":[[[2.376488, 48.846431],
        [2.376306, 48.846430],[2.376309, 48.846606],[ 2.376486, 48.846603]]]}}"#;
    let resp = bragi.raw_post_shape("/autocomplete?q=15 Rue Hector Malot, (Paris)", shape).unwrap();

    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"#,
                         r#""features":[{"type":"Feature","geometry":{"coordinates":"#,
                         r#"[2.376379,48.846495],"type":"Point"},"#,
                         r#""properties":{"geocoding":{"id":"addr:2.376379;48.846495","#,
                         r#""type":"house","label":"15 Rue Hector Malot (Paris)","#,
                         r#""name":"15 Rue Hector Malot","housenumber":"15","#,
                         r#""street":"Rue Hector Malot","postcode":"75012","#,
                         r#""city":null,"city_code":null,"citycode":null,"level":null,"#,
                         r#""administrative_regions":[]}}}]}"#);
    assert_eq!(result_body, result);

    // Search with shape where house number out of shape
    let resp = bragi.raw_post_shape("/autocomplete?q=18 Rue Hector Malot, (Paris)", shape).unwrap();
    let result_body = iron_test::response::extract_body_to_string(resp);
    let result = concat!(r#"{"type":"FeatureCollection","#,
                         r#""geocoding":{"version":"0.1.0","query":""},"features":[]}"#);
    assert_eq!(result_body, result);
}

fn simple_bano_lon_lat_test(bragi: &BragiHandler) {
    // test with a lon/lat priorisation
    // in the dataset there are two '20 rue hector malot',
    // one in paris and one in trifouilli-les-Oies
    // in the mean time we test our prefix search_query
    let all_20 = bragi.get("/autocomplete?q=20 rue hect mal");
    assert_eq!(all_20.len(), 2);
    // the first one is paris (since Paris has more streets, it is prioritized first)
    // TODO uncomment this test, for the moment since osm is not loaded, the order is random
    // assert_eq!(get_labels(&all_20),
    //            vec!["20 Rue Hector Malot (Paris)", "20 Rue Hector Malot (Trifouilli-les-Oies)"]);

    // if we give a lon/lat near trifouilli-les-Oies, we'll have another sort
    let all_20 = bragi.get("/autocomplete?q=20 rue hector malot&lat=50.2&lon=2.0");
    assert_eq!(get_values(&all_20, "label"),
               vec!["20 Rue Hector Malot (Trifouilli-les-Oies)", "20 Rue Hector Malot (Paris)"]);
    // and when we're in paris, we get paris first
    let all_20 = bragi.get("/autocomplete?q=20 rue hector malot&lat=48&lon=2.4");
    assert_eq!(get_values(&all_20, "label"),
               vec!["20 Rue Hector Malot (Paris)", "20 Rue Hector Malot (Trifouilli-les-Oies)"]);
}
<|endoftext|>


<commit_before><commit_msg>Disable relevant lints in generated source<commit_after><|endoftext|>


<commit_before>#![feature(test)]
extern crate test;

use std::ops::{Mul, Add};

extern crate nalgebra;
use self::nalgebra::{DMat, Transpose};

extern crate rblas;
use rblas::matrix::ops::{Gemm};
use rblas::math::mat::Mat;
use rblas::attribute::Transpose as BlasTranspose;

const NSAMPLES: usize = 6 * 1000;
const NOBSERVED: usize = 10 * 10;
const NHIDDEN: usize = 20;

#[bench]
fn bench_ortho_nmf_weights_dividend_nalgebra(bencher: &mut test::Bencher) {
    let samples = DMat::<f64>::new_ones(NSAMPLES, NOBSERVED);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        samples.clone().mul(hidden.transpose())
    });
}

#[bench]
fn bench_ortho_nmf_weights_dividend_rblas(bencher: &mut test::Bencher) {
    let samples = Mat::<f64>::fill(1., NSAMPLES, NOBSERVED);
    let hidden = Mat::<f64>::fill(1., NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        let mut result = Mat::<f64>::fill(1., NSAMPLES, NHIDDEN);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &samples,
            BlasTranspose::Trans, &hidden,
            &0.,
            &mut result);
        result
    });
}

#[bench]
fn bench_ortho_nmf_weights_divisor_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        weights.clone().mul(&hidden).mul(hidden.transpose())
    });
}

#[bench]
fn bench_ortho_nmf_weights_divisor_rblas(bencher: &mut test::Bencher) {
    let weights = Mat::<f64>::fill(1., NSAMPLES, NHIDDEN);
    let hidden = Mat::<f64>::fill(1., NHIDDEN, NOBSERVED);
    let mut reconstruction = Mat::<f64>::new(NSAMPLES, NOBSERVED);
    bencher.iter(|| {
        let mut result = Mat::<f64>::fill(1., NSAMPLES, NHIDDEN);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &weights,
            BlasTranspose::NoTrans, &hidden,
            &0.,
            &mut reconstruction);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &reconstruction,
            BlasTranspose::Trans, &hidden,
            &0.,
            &mut result);
        result
    });
}

// TODO why is this so much faster than the other ones
// when it does so much more ?
// is the clone so expensive ?
#[bench]
fn bench_ortho_nmf_hidden_divisor_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        let gamma = DMat::<f64>::new_ones(NHIDDEN, NHIDDEN);
        weights.transpose().mul(&weights).mul(&hidden)
            .add(gamma.mul(&hidden))
    });
}
<commit_msg>complete benches for ortho nmf parts and use ndarray there<commit_after>#![feature(test)]
extern crate test;

use std::ops::{Mul, Add};

extern crate nalgebra;
use self::nalgebra::{DMat, Transpose};

extern crate rblas;
use rblas::{Gemm};
use rblas::attribute::Transpose as BlasTranspose;

extern crate ndarray;
use ndarray::ArrayBase;
use ndarray::blas::AsBlas;

const NSAMPLES: usize = 6 * 1000;
const NOBSERVED: usize = 10 * 10;
const NHIDDEN: usize = 20;

#[bench]
fn bench_ortho_nmf_weights_dividend_nalgebra(bencher: &mut test::Bencher) {
    let samples = DMat::<f64>::new_ones(NSAMPLES, NOBSERVED);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        samples.clone().mul(hidden.transpose())
    });
}

#[bench]
fn bench_ortho_nmf_weights_dividend_rblas(bencher: &mut test::Bencher) {
    let mut samples = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &samples.blas(),
            BlasTranspose::Trans, &hidden.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

#[bench]
fn bench_ortho_nmf_weights_divisor_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        weights.clone().mul(&hidden).mul(hidden.transpose())
    });
}

#[bench]
fn bench_ortho_nmf_weights_divisor_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    let mut reconstruction = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &weights.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &0.,
            &mut reconstruction.blas());
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &reconstruction.blas(),
            BlasTranspose::Trans, &hidden.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

#[bench]
fn bench_ortho_nmf_hidden_dividend_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let samples = DMat::<f64>::new_ones(NSAMPLES, NOBSERVED);
    bencher.iter(|| {
        weights.transpose().mul(&samples);
    });
}

#[bench]
fn bench_ortho_nmf_hidden_dividend_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut samples = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NOBSERVED), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
        Gemm::gemm(
            &1.,
            BlasTranspose::Trans, &weights.blas(),
            BlasTranspose::NoTrans, &samples.blas(),
            &0.,
            &mut result.blas());
        result
    });
}

// TODO why is this so much faster than the other ones
// when it does so much more ?
// is the clone so expensive ?
#[bench]
fn bench_ortho_nmf_hidden_divisor_nalgebra(bencher: &mut test::Bencher) {
    let weights = DMat::<f64>::new_ones(NSAMPLES, NHIDDEN);
    let hidden = DMat::<f64>::new_ones(NHIDDEN, NOBSERVED);
    bencher.iter(|| {
        // TODO this is surprisingly weirdly fast
        let gamma = DMat::<f64>::new_ones(NHIDDEN, NHIDDEN);
        weights.transpose().mul(&weights).mul(&hidden)
            .add(gamma.mul(&hidden))
    });
}

#[bench]
fn bench_ortho_nmf_hidden_divisor_rblas(bencher: &mut test::Bencher) {
    let mut weights = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut weights_copy = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NSAMPLES, NHIDDEN), 1.);
    let mut hidden = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
    let mut gamma = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NHIDDEN), 1.);
    // this is really small
    let mut tmp = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NHIDDEN), 1.);
    bencher.iter(|| {
        let mut result = ArrayBase::<Vec<f64>, (usize, usize)>::from_elem((NHIDDEN, NOBSERVED), 1.);
        // we must make a copy here because we need two mutable
        // references to weights at the same time for .blas()
        // weights_copy.clone_from(&weights);
        let mut weights_copy = weights.clone();
        Gemm::gemm(
            &1.,
            BlasTranspose::Trans, &weights.blas(),
            BlasTranspose::NoTrans, &weights_copy.blas(),
            &0.,
            &mut tmp.blas());
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &gamma.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &0.,
            &mut result.blas());
        // add to previous result
        Gemm::gemm(
            &1.,
            BlasTranspose::NoTrans, &tmp.blas(),
            BlasTranspose::NoTrans, &hidden.blas(),
            &1.,
            &mut result.blas());
        result
    });
}
<|endoftext|>


<commit_before>#![feature(nll)]

trait S: Sized {
    fn tpb(&mut self, _s: Self) {}
}

impl S for i32 {}

fn two_phase1() {
    let mut x = 3;
    x.tpb(x);
}

fn two_phase2() {
    let mut v = vec![];
    v.push(v.len());
}

fn two_phase3(b: bool) {
    let mut x = &mut vec![];
    let mut y = vec![];
    x.push((
        {
            if b { x = &mut y };
            22
        },
        x.len(),
    ));
}

/*
fn two_phase_overlapping1() {
    let mut x = vec![];
    let p = &x;
    x.push(p.len());
}

fn two_phase_overlapping2() {
    use std::ops::AddAssign;
    let mut x = 1;
    let l = &x;
    x.add_assign(x + *l);
}
*/

fn with_interior_mutability() {
    use std::cell::Cell;

    trait Thing: Sized {
        fn do_the_thing(&mut self, _s: i32) {}
    }

    impl<T> Thing for Cell<T> {}

    let mut x = Cell::new(1);
    let l = &x;
    x
        .do_the_thing({
            x.set(3);
            l.set(4);
            x.get() + l.get()
        })
    ;
}

fn main() {
    two_phase1();
    two_phase2();
    two_phase3(false);
    two_phase3(true);
    with_interior_mutability();
    //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved
    //two_phase_overlapping1();
    //two_phase_overlapping2();
}
<commit_msg>Use edition flag for 2phase test<commit_after>// edition:2018

trait S: Sized {
    fn tpb(&mut self, _s: Self) {}
}

impl S for i32 {}

fn two_phase1() {
    let mut x = 3;
    x.tpb(x);
}

fn two_phase2() {
    let mut v = vec![];
    v.push(v.len());
}

fn two_phase3(b: bool) {
    let mut x = &mut vec![];
    let mut y = vec![];
    x.push((
        {
            if b { x = &mut y };
            22
        },
        x.len(),
    ));
}

/*
fn two_phase_overlapping1() {
    let mut x = vec![];
    let p = &x;
    x.push(p.len());
}

fn two_phase_overlapping2() {
    use std::ops::AddAssign;
    let mut x = 1;
    let l = &x;
    x.add_assign(x + *l);
}
*/

fn with_interior_mutability() {
    use std::cell::Cell;

    trait Thing: Sized {
        fn do_the_thing(&mut self, _s: i32) {}
    }

    impl<T> Thing for Cell<T> {}

    let mut x = Cell::new(1);
    let l = &x;

    #[allow(unknown_lints, mutable_borrow_reservation_conflict)]
    x
        .do_the_thing({
            x.set(3);
            l.set(4);
            x.get() + l.get()
        })
    ;
}

fn main() {
    two_phase1();
    two_phase2();
    two_phase3(false);
    two_phase3(true);
    with_interior_mutability();
    //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved
    //two_phase_overlapping1();
    //two_phase_overlapping2();
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::fmt;
use std::fmt::{Display, Formatter, Error as E};
use std::error;
use std::result;
use std::convert::From;

use ::env::Env;

pub type Kfloat = f32;
pub type Kint = isize;
pub type Result<T> = result::Result<T, Error>;

#[derive(PartialEq, Clone, Debug)]
pub enum Expr {
    Int(Kint),
    Float(Kfloat),
    Cons(Rc<Expr>, Rc<Expr>),
    Nil,
    Sym(String),
    Str(String),
    Proc(Proc),
    EOF
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Type {
    Int,
    Float,
    Cons,
    Nil,
    Sym,
    Str,
    Proc,
    Any
}

#[derive(Clone)]
pub enum Proc {
    Lambda(Rc<Expr>, Rc<Expr>),
    Prim(String, Rc<Fn(&mut Env, &Expr) -> Result<Expr>>)
}

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidArgument(Expr),
    Type(Type, Expr),
    ArityShort,
    ArityExceed,
    Form(Expr),
    NotFunction(Expr),
    Unbound(String),
    User(String)
}

impl From<Kint> for Expr {fn from(i: Kint) -> Self {Expr::Int(i)}}
impl From<Kfloat> for Expr {fn from(f: Kfloat) -> Self {Expr::Float(f)}}
impl <'a >From<&'a str> for Expr {fn from(s: &str) -> Self {Expr::Str(s.to_string())}}
impl From<String> for Expr {fn from(s: String) -> Self {Expr::Str(s)}}

impl PartialEq for Proc {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Proc::Lambda(ref param1, ref body1), &Proc::Lambda(ref param2, ref body2)) => param1 == param2 && body1 == body2,
            _ => false
        }
    }
}

impl fmt::Debug for Proc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Proc::Lambda(ref param, ref body) => write!(f, "Lambda({}, {})", param, body),
            &Proc::Prim(ref name, _) => write!(f, "Prim(#<native function {}>)", name)
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self.clone() {
            Expr::Int(i) => write!(f, "{}", i),
            Expr::Float(fl) => write!(f, "{}", fl),
            // :TODO: pretty print for lists
            Expr::Cons(ref car,ref cdr) => write!(f, "({} . {})", car, cdr),
            Expr::Nil => write!(f, "nil"),
            Expr::Sym(ref s) => write!(f, "{}", s),
            Expr::Str(ref s) => write!(f, "\"{}\"", s),
            Expr::Proc(p) => write!(f, "{}", p),
            Expr::EOF => write!(f, "<EOF>")
        }
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self.clone() {
            Type::Int   => write!(f, "integer"),
            Type::Float => write!(f, "float"),
            Type::Cons  => write!(f, "cons"),
            Type::Nil   => write!(f, "nil"),
            Type::Sym   => write!(f, "symbol"),
            Type::Str   => write!(f, "string"),
            Type::Proc  => write!(f, "procedure"),
            Type::Any   => write!(f, "any")
        }
    }
}

impl fmt::Display for Proc {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self.clone() {
            Proc::Lambda(args, body) => write!(f, "(lambda {} {})", args, body),
            Proc::Prim(name, _) => write!(f, "{}", name)
        }
    }
}

impl Display for Error {
    fn fmt(&self,  f:&mut Formatter) -> result::Result<(), E> {
        let res = match self {
            &Error::InvalidArgument(ref args) => write!(f, "invalid argument: {}", args),
            &Error::Type(ref t, ref args) => write!(f, "type mismatch: expected: {}, got: {}", t, args),
            &Error::ArityShort => write!(f, "too few argument"),
            &Error::ArityExceed => write!(f, "too many argument"),
            &Error::Form(ref e) => write!(f, "invalid form: {}", e),
            &Error::NotFunction(ref e) => write!(f, "not a function: {}", e),
            &Error::Unbound(ref s) => write!(f, "unbound variable: {}", s),
            &Error::User(ref s) => write!(f, "user error: {}", s)

        };
        try!(res);
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        "Lisp Error"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

<commit_msg>don't clone if not need<commit_after>use std::rc::Rc;
use std::fmt;
use std::fmt::{Display, Formatter, Error as E};
use std::error;
use std::result;
use std::convert::From;

use ::env::Env;

pub type Kfloat = f32;
pub type Kint = isize;
pub type Result<T> = result::Result<T, Error>;

#[derive(PartialEq, Clone, Debug)]
pub enum Expr {
    Int(Kint),
    Float(Kfloat),
    Cons(Rc<Expr>, Rc<Expr>),
    Nil,
    Sym(String),
    Str(String),
    Proc(Proc),
    EOF
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub enum Type {
    Int,
    Float,
    Cons,
    Nil,
    Sym,
    Str,
    Proc,
    Any
}

#[derive(Clone)]
pub enum Proc {
    Lambda(Rc<Expr>, Rc<Expr>),
    Prim(String, Rc<Fn(&mut Env, &Expr) -> Result<Expr>>)
}

#[derive(Debug, PartialEq)]
pub enum Error {
    InvalidArgument(Expr),
    Type(Type, Expr),
    ArityShort,
    ArityExceed,
    Form(Expr),
    NotFunction(Expr),
    Unbound(String),
    User(String)
}

impl From<Kint> for Expr {fn from(i: Kint) -> Self {Expr::Int(i)}}
impl From<Kfloat> for Expr {fn from(f: Kfloat) -> Self {Expr::Float(f)}}
impl <'a >From<&'a str> for Expr {fn from(s: &str) -> Self {Expr::Str(s.to_string())}}
impl From<String> for Expr {fn from(s: String) -> Self {Expr::Str(s)}}

impl PartialEq for Proc {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (&Proc::Lambda(ref param1, ref body1), &Proc::Lambda(ref param2, ref body2)) => param1 == param2 && body1 == body2,
            _ => false
        }
    }
}

impl fmt::Debug for Proc {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Proc::Lambda(ref param, ref body) => write!(f, "Lambda({}, {})", param, body),
            &Proc::Prim(ref name, _) => write!(f, "Prim(#<native function {}>)", name)
        }
    }
}

impl fmt::Display for Expr {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Expr::Int(i) => write!(f, "{}", i),
            &Expr::Float(fl) => write!(f, "{}", fl),
            // :TODO: pretty print for lists
            &Expr::Cons(ref car,ref cdr) => write!(f, "({} . {})", car, cdr),
            &Expr::Nil => write!(f, "nil"),
            &Expr::Sym(ref s) => write!(f, "{}", s),
            &Expr::Str(ref s) => write!(f, "\"{}\"", s),
            &Expr::Proc(ref p) => write!(f, "{}", p),
            &Expr::EOF => write!(f, "<EOF>")
        }
    }
}

impl fmt::Display for Type {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Type::Int   => write!(f, "integer"),
            &Type::Float => write!(f, "float"),
            &Type::Cons  => write!(f, "cons"),
            &Type::Nil   => write!(f, "nil"),
            &Type::Sym   => write!(f, "symbol"),
            &Type::Str   => write!(f, "string"),
            &Type::Proc  => write!(f, "procedure"),
            &Type::Any   => write!(f, "any")
        }
    }
}

impl fmt::Display for Proc {
    fn fmt(&self, f:&mut fmt::Formatter) -> fmt::Result {
        match self {
            &Proc::Lambda(ref args, ref body) => write!(f, "(lambda {} {})", args, body),
            &Proc::Prim(ref name, _) => write!(f, "{}", name)
        }
    }
}

impl Display for Error {
    fn fmt(&self,  f:&mut Formatter) -> result::Result<(), E> {
        let res = match self {
            &Error::InvalidArgument(ref args) => write!(f, "invalid argument: {}", args),
            &Error::Type(ref t, ref args) => write!(f, "type mismatch: expected: {}, got: {}", t, args),
            &Error::ArityShort => write!(f, "too few argument"),
            &Error::ArityExceed => write!(f, "too many argument"),
            &Error::Form(ref e) => write!(f, "invalid form: {}", e),
            &Error::NotFunction(ref e) => write!(f, "not a function: {}", e),
            &Error::Unbound(ref s) => write!(f, "unbound variable: {}", s),
            &Error::User(ref s) => write!(f, "user error: {}", s)

        };
        try!(res);
        Ok(())
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        "Lisp Error"
    }

    fn cause(&self) -> Option<&error::Error> {
        None
    }
}

<|endoftext|>


<commit_before>use ffi::h5::{hsize_t, hbool_t};
use ffi::h5i::{hid_t, H5I_INVALID_HID};
use ffi::h5p::{H5Pcreate, H5Pset_userblock, H5Pget_userblock};
use ffi::h5f::{H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_EXCL, H5F_ACC_TRUNC,
               H5Fopen, H5Fcreate, H5Fget_filesize, H5Fget_intent,
               H5Fget_access_plist, H5Fget_create_plist, H5Fget_freespace};
use ffi::h5fd::{H5Pset_fapl_sec2, H5Pset_fapl_stdio, H5Pset_fapl_core};

use globals::{H5P_FILE_CREATE, H5P_FILE_ACCESS};

use container::Container;
use error::Result;
use location::Location;
use object::{Handle, Object};
use plist::PropertyList;
use util::to_cstring;

use std::path::Path;
use std::process::Command;

use libc::{size_t, c_uint};

#[derive(Clone)]
pub struct File {
    handle: Handle,
}

impl Object for File {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> File {
        File { handle: Handle::new(id) }
    }
}

impl Location for File {}

impl Container for File {}

impl File {
    /// Create a new file object.
    ///
    /// | `mode`    | File access mode
    /// |-----------|-----------------
    /// | `r`       | Read-only, file must exist
    /// | `r+`      | Read/write, file must exist
    /// | `w`       | Create file, truncate if exists
    /// | `w-`, `x` | Create file, fail if exists
    /// | `a`       | Read/write if exists, create otherwise
    pub fn open<P: AsRef<Path>, S: Into<String>>(filename: P, mode: S) -> Result<File> {
        FileBuilder::new().mode(mode).open(filename)
    }

    /// Returns the file size in bytes (or 0 if the file handle is invalid).
    pub fn size(&self) -> u64 {
        unsafe {
            let size: *mut hsize_t = &mut 0;
            h5lock_s!(H5Fget_filesize(self.id(), size));
            if *size > 0 { *size as u64 } else { 0 }
        }
    }

    /// Returns the free space in the file in bytes (or 0 if the file handle is invalid).
    pub fn free_space(&self) -> u64 {
        match h5call!(H5Fget_freespace(self.id())) {
            Ok(size) => size as u64,
            _        => 0,
        }
    }

    /// Returns true if the file was opened in a read-only mode.
    pub fn is_read_only(&self) -> bool {
        unsafe {
            let mode: *mut c_uint = &mut 0;
            h5lock_s!(H5Fget_intent(self.id(), mode));
            *mode != H5F_ACC_RDWR
        }
    }

    #[allow(dead_code)]
    fn fapl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_access_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    fn fcpl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_create_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    /// Returns the output of the `h5dump` tool. Note that this wouldn't work with core driver.
    pub fn dump(&self) -> Option<String> {
        self.flush(true).ok().and(Command::new("h5dump").arg(self.filename()).output().ok()
                                  .map(|out| String::from_utf8_lossy(&out.stdout).to_string()))
    }

    /// Returns the userblock size in bytes (or 0 if the file handle is invalid).
    pub fn userblock(&self) -> size_t {
        unsafe {
            let userblock: *mut hsize_t = &mut 0;
            h5lock_s!(H5Pget_userblock(self.fcpl().id(), userblock));
            *userblock as size_t
        }
    }
}

pub struct FileBuilder {
    driver: String,
    mode: String,
    userblock: size_t,
    filebacked: bool,
    increment: size_t,
}

impl FileBuilder {
    pub fn new() -> FileBuilder {
        FileBuilder {
            driver: "sec2".to_string(),
            mode: "r".to_string(),
            userblock: 0,
            filebacked: false,
            increment: 64 * 1024 * 1024,
        }
    }

    pub fn driver<S: Into<String>>(&mut self, driver: S) -> &mut FileBuilder {
        self.driver = driver.into(); self
    }

    pub fn mode<S: Into<String>>(&mut self, mode: S) -> &mut FileBuilder {
        self.mode = mode.into(); self
    }

    pub fn userblock(&mut self, userblock: size_t) -> &mut FileBuilder {
        self.userblock = userblock; self
    }

    pub fn filebacked(&mut self, filebacked: bool) -> &mut FileBuilder {
        self.filebacked = filebacked; self
    }

    pub fn increment(&mut self, increment: size_t) -> &mut FileBuilder {
        self.increment = increment; self
    }

    fn make_fapl(&self) -> Result<PropertyList> {
        h5lock_s!({
            let fapl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS)));
            match self.driver.as_ref() {
                "sec2"  => h5try!(H5Pset_fapl_sec2(fapl.id())),
                "stdio" => h5try!(H5Pset_fapl_stdio(fapl.id())),
                "core"  => h5try!(H5Pset_fapl_core(fapl.id(), self.increment,
                                                   self.filebacked as hbool_t)),
                _       => fail!(format!("Invalid file driver: {}", self.driver)),
            };
            Ok(fapl)
        })
    }

    fn open_file<P: AsRef<Path>>(&self, filename: P, write: bool) -> Result<File> {
        ensure!(self.userblock == 0, "Cannot specify userblock when opening a file");
        h5lock_s!({
            let fapl = try!(self.make_fapl());
            let flags = if write { H5F_ACC_RDWR } else { H5F_ACC_RDONLY };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = to_cstring(filename).as_ptr();
                    let file = File::from_id(h5try!(H5Fopen(c_filename, flags, fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for opened file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    fn create_file<P: AsRef<Path>>(&self, filename: P, exclusive: bool) -> Result<File> {
        h5lock_s!({
            let fcpl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)));
            h5try!(H5Pset_userblock(fcpl.id(), self.userblock));
            let fapl = try!(self.make_fapl());
            let flags = if exclusive { H5F_ACC_EXCL } else { H5F_ACC_TRUNC };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = to_cstring(filename).as_ptr();
                    let file = File::from_id(h5try!(H5Fcreate(c_filename, flags,
                                                              fcpl.id(), fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for created file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    pub fn open<P: AsRef<Path>>(&self, filename: P) -> Result<File> {
        match self.mode.as_ref() {
            "r"        => self.open_file(&filename, false),
            "r+"       => self.open_file(&filename, true),
            "w"        => self.create_file(&filename, false),
            "w-" | "x" => self.create_file(&filename, true),
            "a"        => match self.open_file(&filename, true) {
                            Ok(file) => Ok(file),
                            _        => self.create_file(&filename, true),
                          },
            _          => fail!("Invalid file access mode, expected r|r+|w|w-|x|a"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::File;
    use std::fs;
    use std::io::Write;
    use test::{with_tmp_dir, with_tmp_path};
    use container::Container;
    use error::silence_errors;

    #[test]
    pub fn test_invalid_mode() {
        silence_errors();
        with_tmp_dir(|dir| {
            assert_err!(File::open(&dir, "foo"), "Invalid file access mode");
        })
    }

    #[test]
    pub fn test_is_read_only() {
        silence_errors();
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "w").unwrap().is_read_only());
            assert!(File::open(&path, "r").unwrap().is_read_only());
            assert!(!File::open(&path, "r+").unwrap().is_read_only());
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "x").unwrap().is_read_only());
        });
    }

    #[test]
    pub fn test_unable_to_open() {
        silence_errors();
        with_tmp_dir(|dir| {
            assert_err!(File::open(&dir, "r"), "unable to open file");
            assert_err!(File::open(&dir, "r+"), "unable to open file");
            assert_err!(File::open(&dir, "x"), "unable to create file");
            assert_err!(File::open(&dir, "w-"), "unable to create file");
            assert_err!(File::open(&dir, "w"), "unable to create file");
            assert_err!(File::open(&dir, "a"), "unable to create file");
        });

        with_tmp_path("foo.h5", |path| {
            fs::File::create(&path).unwrap().write_all(b"foo").unwrap();
            assert!(fs::metadata(&path).is_ok());
            assert_err!(File::open(&path, "r"), "unable to open file");
        })
    }

    #[test]
    pub fn test_access_modes() {
        silence_errors();

        // "w" means overwrite
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "w").unwrap().create_group("foo").unwrap();
            assert_err!(File::open(&path, "w").unwrap().group("foo"), "unable to open group");
        });

        // "w-"/"x-" means exclusive write
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "w-").unwrap();
            assert_err!(File::open(&path, "w-"), "unable to create file");
        });
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "x").unwrap();
            assert_err!(File::open(&path, "x"), "unable to create file");
        });

        // "a" means append
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "a").unwrap().create_group("foo").unwrap();
            File::open(&path, "a").unwrap().group("foo").unwrap();
        });

        // "r" means read-only
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "w").unwrap().create_group("foo").unwrap();
            let file = File::open(&path, "r").unwrap();
            file.group("foo").unwrap();
            assert_err!(file.create_group("bar"),
                        "unable to create group: no write intent on file");
        });

        // "r+" means read-write
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "w").unwrap().create_group("foo").unwrap();
            let file = File::open(&path, "r+").unwrap();
            file.group("foo").unwrap();
            file.create_group("bar").unwrap();
        });
    }
}
<commit_msg>Added userblock tests<commit_after>use ffi::h5::{hsize_t, hbool_t};
use ffi::h5i::{hid_t, H5I_INVALID_HID};
use ffi::h5p::{H5Pcreate, H5Pset_userblock, H5Pget_userblock};
use ffi::h5f::{H5F_ACC_RDONLY, H5F_ACC_RDWR, H5F_ACC_EXCL, H5F_ACC_TRUNC,
               H5Fopen, H5Fcreate, H5Fget_filesize, H5Fget_intent,
               H5Fget_access_plist, H5Fget_create_plist, H5Fget_freespace};
use ffi::h5fd::{H5Pset_fapl_sec2, H5Pset_fapl_stdio, H5Pset_fapl_core};

use globals::{H5P_FILE_CREATE, H5P_FILE_ACCESS};

use container::Container;
use error::Result;
use location::Location;
use object::{Handle, Object};
use plist::PropertyList;
use util::to_cstring;

use std::path::Path;
use std::process::Command;

use libc::{size_t, c_uint};

#[derive(Clone)]
pub struct File {
    handle: Handle,
}

impl Object for File {
    fn id(&self) -> hid_t {
        self.handle.id()
    }

    fn from_id(id: hid_t) -> File {
        File { handle: Handle::new(id) }
    }
}

impl Location for File {}

impl Container for File {}

impl File {
    /// Create a new file object.
    ///
    /// | `mode`    | File access mode
    /// |-----------|-----------------
    /// | `r`       | Read-only, file must exist
    /// | `r+`      | Read/write, file must exist
    /// | `w`       | Create file, truncate if exists
    /// | `w-`, `x` | Create file, fail if exists
    /// | `a`       | Read/write if exists, create otherwise
    pub fn open<P: AsRef<Path>, S: Into<String>>(filename: P, mode: S) -> Result<File> {
        FileBuilder::new().mode(mode).open(filename)
    }

    /// Returns the file size in bytes (or 0 if the file handle is invalid).
    pub fn size(&self) -> u64 {
        unsafe {
            let size: *mut hsize_t = &mut 0;
            h5lock_s!(H5Fget_filesize(self.id(), size));
            if *size > 0 { *size as u64 } else { 0 }
        }
    }

    /// Returns the free space in the file in bytes (or 0 if the file handle is invalid).
    pub fn free_space(&self) -> u64 {
        match h5call!(H5Fget_freespace(self.id())) {
            Ok(size) => size as u64,
            _        => 0,
        }
    }

    /// Returns true if the file was opened in a read-only mode.
    pub fn is_read_only(&self) -> bool {
        unsafe {
            let mode: *mut c_uint = &mut 0;
            h5lock_s!(H5Fget_intent(self.id(), mode));
            *mode != H5F_ACC_RDWR
        }
    }

    #[allow(dead_code)]
    fn fapl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_access_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    fn fcpl(&self) -> PropertyList {
        PropertyList::from_id(h5call!(H5Fget_create_plist(self.id())).unwrap_or(H5I_INVALID_HID))
    }

    /// Returns the output of the `h5dump` tool. Note that this wouldn't work with core driver.
    pub fn dump(&self) -> Option<String> {
        self.flush(true).ok().and(Command::new("h5dump").arg(self.filename()).output().ok()
                                  .map(|out| String::from_utf8_lossy(&out.stdout).to_string()))
    }

    /// Returns the userblock size in bytes (or 0 if the file handle is invalid).
    pub fn userblock(&self) -> size_t {
        unsafe {
            let userblock: *mut hsize_t = &mut 0;
            h5lock_s!(H5Pget_userblock(self.fcpl().id(), userblock));
            *userblock as size_t
        }
    }
}

pub struct FileBuilder {
    driver: String,
    mode: String,
    userblock: size_t,
    filebacked: bool,
    increment: size_t,
}

impl FileBuilder {
    pub fn new() -> FileBuilder {
        FileBuilder {
            driver: "sec2".to_string(),
            mode: "r".to_string(),
            userblock: 0,
            filebacked: false,
            increment: 64 * 1024 * 1024,
        }
    }

    pub fn driver<S: Into<String>>(&mut self, driver: S) -> &mut FileBuilder {
        self.driver = driver.into(); self
    }

    pub fn mode<S: Into<String>>(&mut self, mode: S) -> &mut FileBuilder {
        self.mode = mode.into(); self
    }

    pub fn userblock(&mut self, userblock: size_t) -> &mut FileBuilder {
        self.userblock = userblock; self
    }

    pub fn filebacked(&mut self, filebacked: bool) -> &mut FileBuilder {
        self.filebacked = filebacked; self
    }

    pub fn increment(&mut self, increment: size_t) -> &mut FileBuilder {
        self.increment = increment; self
    }

    fn make_fapl(&self) -> Result<PropertyList> {
        h5lock_s!({
            let fapl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_ACCESS)));
            match self.driver.as_ref() {
                "sec2"  => h5try!(H5Pset_fapl_sec2(fapl.id())),
                "stdio" => h5try!(H5Pset_fapl_stdio(fapl.id())),
                "core"  => h5try!(H5Pset_fapl_core(fapl.id(), self.increment,
                                                   self.filebacked as hbool_t)),
                _       => fail!(format!("Invalid file driver: {}", self.driver)),
            };
            Ok(fapl)
        })
    }

    fn open_file<P: AsRef<Path>>(&self, filename: P, write: bool) -> Result<File> {
        ensure!(self.userblock == 0, "Cannot specify userblock when opening a file");
        h5lock_s!({
            let fapl = try!(self.make_fapl());
            let flags = if write { H5F_ACC_RDWR } else { H5F_ACC_RDONLY };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = to_cstring(filename).as_ptr();
                    let file = File::from_id(h5try!(H5Fopen(c_filename, flags, fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for opened file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    fn create_file<P: AsRef<Path>>(&self, filename: P, exclusive: bool) -> Result<File> {
        h5lock_s!({
            let fcpl = PropertyList::from_id(h5try!(H5Pcreate(*H5P_FILE_CREATE)));
            h5try!(H5Pset_userblock(fcpl.id(), self.userblock));
            let fapl = try!(self.make_fapl());
            let flags = if exclusive { H5F_ACC_EXCL } else { H5F_ACC_TRUNC };
            let filename = filename.as_ref();
            match filename.to_str() {
                Some(filename) => {
                    let c_filename = to_cstring(filename).as_ptr();
                    let file = File::from_id(h5try!(H5Fcreate(c_filename, flags,
                                                              fcpl.id(), fapl.id())));
                    ensure!(file.is_valid(), "Invalid id for created file");
                    Ok(file)
                },
                None          => fail!("Invalid UTF-8 in file name: {:?}", filename)
            }
        })
    }

    pub fn open<P: AsRef<Path>>(&self, filename: P) -> Result<File> {
        match self.mode.as_ref() {
            "r"        => self.open_file(&filename, false),
            "r+"       => self.open_file(&filename, true),
            "w"        => self.create_file(&filename, false),
            "w-" | "x" => self.create_file(&filename, true),
            "a"        => match self.open_file(&filename, true) {
                            Ok(file) => Ok(file),
                            _        => self.create_file(&filename, true),
                          },
            _          => fail!("Invalid file access mode, expected r|r+|w|w-|x|a"),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::{File, FileBuilder};
    use std::fs;
    use std::io::{Read, Write};
    use container::Container;
    use test::{with_tmp_dir, with_tmp_path, with_tmp_file};
    use error::silence_errors;

    #[test]
    pub fn test_invalid_mode() {
        silence_errors();
        with_tmp_dir(|dir| {
            assert_err!(File::open(&dir, "foo"), "Invalid file access mode");
        })
    }

    #[test]
    pub fn test_is_read_only() {
        silence_errors();
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "w").unwrap().is_read_only());
            assert!(File::open(&path, "r").unwrap().is_read_only());
            assert!(!File::open(&path, "r+").unwrap().is_read_only());
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "a").unwrap().is_read_only());
        });
        with_tmp_path("foo.h5", |path| {
            assert!(!File::open(&path, "x").unwrap().is_read_only());
        });
    }

    #[test]
    pub fn test_unable_to_open() {
        silence_errors();
        with_tmp_dir(|dir| {
            assert_err!(File::open(&dir, "r"), "unable to open file");
            assert_err!(File::open(&dir, "r+"), "unable to open file");
            assert_err!(File::open(&dir, "x"), "unable to create file");
            assert_err!(File::open(&dir, "w-"), "unable to create file");
            assert_err!(File::open(&dir, "w"), "unable to create file");
            assert_err!(File::open(&dir, "a"), "unable to create file");
        });

        with_tmp_path("foo.h5", |path| {
            fs::File::create(&path).unwrap().write_all(b"foo").unwrap();
            assert!(fs::metadata(&path).is_ok());
            assert_err!(File::open(&path, "r"), "unable to open file");
        })
    }

    #[test]
    pub fn test_access_modes() {
        silence_errors();

        // "w" means overwrite
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "w").unwrap().create_group("foo").unwrap();
            assert_err!(File::open(&path, "w").unwrap().group("foo"), "unable to open group");
        });

        // "w-"/"x-" means exclusive write
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "w-").unwrap();
            assert_err!(File::open(&path, "w-"), "unable to create file");
        });
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "x").unwrap();
            assert_err!(File::open(&path, "x"), "unable to create file");
        });

        // "a" means append
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "a").unwrap().create_group("foo").unwrap();
            File::open(&path, "a").unwrap().group("foo").unwrap();
        });

        // "r" means read-only
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "w").unwrap().create_group("foo").unwrap();
            let file = File::open(&path, "r").unwrap();
            file.group("foo").unwrap();
            assert_err!(file.create_group("bar"),
                        "unable to create group: no write intent on file");
            assert_err!(File::open("/foo/bar/baz", "r"), "unable to open file");
        });

        // "r+" means read-write
        with_tmp_path("foo.h5", |path| {
            File::open(&path, "w").unwrap().create_group("foo").unwrap();
            let file = File::open(&path, "r+").unwrap();
            file.group("foo").unwrap();
            file.create_group("bar").unwrap();
            assert_err!(File::open("/foo/bar/baz", "r+"), "unable to open file");
        });
    }

    #[test]
    pub fn test_userblock() {
        with_tmp_file(|file| {
            assert_eq!(file.userblock(), 0);
        });
        with_tmp_path("foo.h5", |path| {
            assert_err!(FileBuilder::new().userblock(512).mode("r").open(&path),
                        "Cannot specify userblock when opening a file");
            assert_err!(FileBuilder::new().userblock(512).mode("r+").open(&path),
                        "Cannot specify userblock when opening a file");
            assert_err!(FileBuilder::new().userblock(1).mode("w").open(&path),
                        "userblock size is non-zero and less than 512");
            FileBuilder::new().userblock(512).mode("w").open(&path).unwrap();
            assert_eq!(File::open(&path, "r").unwrap().userblock(), 512);

            // writing to userblock doesn't corrupt the file
            File::open(&path, "r+").unwrap().create_group("foo").unwrap();
            {
                let mut file = fs::OpenOptions::new().read(true).write(true)
                                                     .create(false).open(&path).unwrap();
                for i in 0usize..512usize {
                    file.write_all(&[(i % 256) as u8]).unwrap();
                }
                file.flush().unwrap();
            }
            File::open(&path, "r").unwrap().group("foo").unwrap();

            // writing to file doesn't corrupt the userblock
            File::open(&path, "r+").unwrap().create_group("bar").unwrap();
            {
                let mut reader = fs::File::open(&path).unwrap().take(512);
                let mut data: Vec<u8> = Vec::new();
                assert_eq!(reader.read_to_end(&mut data).unwrap(), 512);
                for i in 0usize..512usize {
                    assert_eq!(data[i], (i % 256) as u8);
                }
            }
        })
    }
}
<|endoftext|>


<commit_before>// Copyright © 2014, Peter Atashian
//! Stuff for working with NX files

use mmap::{MapError, MemoryMap};
use mmap::MapOption::{self, MapFd, MapReadable};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter};
use std::fmt::Error as FmtError;
use std::fs::File as FsFile;
use std::io::Error as IoError;
use std::mem::{size_of, transmute};
use std::path::{Path};
use std::result::{Result};
use std::slice::{from_raw_parts};

use repr::{self, Header};

pub use node::{Node};
pub use node::{GenericNode};
pub use node::{Type};

/// An error occuring anywhere in the library.
#[derive(Debug)]
pub enum Error {
    /// An internal IoError.
    Io(IoError),
    /// An internal MapError.
    Map(MapError),
    /// Magic value in header was incorrect.
    InvalidMagic,
    /// File was too short.
    TooShort,
}
impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            &Error::Io(ref e) => e.description(),
            &Error::Map(ref e) => e.description(),
            &Error::InvalidMagic => "Header magic value was invalid",
            &Error::TooShort => "File was too short for header",
        }
    }
    fn cause(&self) -> Option<&StdError> {
        match self {
            &Error::Io(ref e) => Some(e),
            &Error::Map(ref e) => Some(e),
            _ => None,
        }
    }
}
impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        match self.cause() {
            Some(cause) => write!(fmt, "{} ({})", self.description(), cause),
            None => write!(fmt, "{}", self.description()),
        }
    }
}
impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
impl From<MapError> for Error {
    fn from(err: MapError) -> Error {
        Error::Map(err)
    }
}

/// A memory-mapped NX file.
pub struct File {
    _map: MemoryMap,
    data: *const u8,
    header: *const Header,
    nodetable: *const repr::Node,
    stringtable: *const u64,
    audiotable: *const u64,
}

impl File {
    /// Opens an NX file via memory-mapping. This also checks the magic bytes in the header.
    pub fn open(path: &Path) -> Result<File, Error> {
        let file = try!(FsFile::open(path));
        let meta = try!(file.metadata());
        #[cfg(not(windows))]
        fn get_fd(file: &FsFile) -> MapOption {
            use std::os::unix::io::AsRawFd;
            MapFd(file.as_raw_fd())
        }
        #[cfg(windows)]
        fn get_fd(file: &FsFile) -> MapOption {
            use std::os::windows::io::AsRawHandle;
            MapFd(file.as_raw_handle() as *mut _)
        }
        let map = try!(MemoryMap::new(meta.len() as usize, &[MapReadable, get_fd(&file)]));
        if map.len() < size_of::<Header>() {
            return Err(Error::TooShort)
        }
        let data = map.data() as *const u8;
        let header = data as *const Header;
        if unsafe { (*header).magic } != 0x34474B50 {
            return Err(Error::InvalidMagic)
        }
        let nodetable = unsafe { data.offset((*header).nodeoffset as isize) as *const repr::Node };
        let stringtable = unsafe { data.offset((*header).stringoffset as isize) as *const u64 };
        let audiotable = unsafe { data.offset((*header).audiooffset as isize) as *const u64 };
        Ok(File {
            _map: map,
            data: data,
            header: header,
            nodetable: nodetable,
            stringtable: stringtable,
            audiotable: audiotable,
        })
    }
    /// Gets the file header.
    #[inline]
    fn header(&self) -> &Header {
        unsafe { &*self.header }
    }
    /// Number of nodes in the file
    #[inline]
    pub fn node_count(&self) -> u32 {
        self.header().nodecount
    }
    /// Gets the root node of the file.
    #[inline]
    pub fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node::construct(&*self.nodetable, self) }
    }
    /// Gets the string at the specified index in the string table.
    #[inline]
    pub unsafe fn get_str(&self, index: u32) -> &str {
        let off = *self.stringtable.offset(index as isize);
        let ptr = self.data.offset(off as isize);
        let size = ptr as *const u16;
        transmute(from_raw_parts(ptr.offset(2), (*size) as usize))
    }
    /// Gets the node data at the specified index in the node table.
    #[inline]
    pub unsafe fn get_node(&self, index: u32) -> &repr::Node {
        &*self.nodetable.offset(index as isize)
    }
    /// Gets the audio data at the specified index in the node table.
    #[inline]
    pub unsafe fn get_audio(&self, index: u32, length: u32) -> &[u8] {
        let off = *self.audiotable.offset(index as isize);
        let ptr = self.data.offset(off as isize);
        transmute(from_raw_parts(ptr, length as usize))
    }
}
<commit_msg>Make Files Send+Sync<commit_after>// Copyright © 2014, Peter Atashian
//! Stuff for working with NX files

use mmap::{MapError, MemoryMap};
use mmap::MapOption::{self, MapFd, MapReadable};
use std::error::Error as StdError;
use std::fmt::{Display, Formatter};
use std::fmt::Error as FmtError;
use std::fs::File as FsFile;
use std::io::Error as IoError;
use std::mem::{size_of, transmute};
use std::path::{Path};
use std::result::{Result};
use std::slice::{from_raw_parts};

use repr::{self, Header};

pub use node::{Node};
pub use node::{GenericNode};
pub use node::{Type};

/// An error occuring anywhere in the library.
#[derive(Debug)]
pub enum Error {
    /// An internal IoError.
    Io(IoError),
    /// An internal MapError.
    Map(MapError),
    /// Magic value in header was incorrect.
    InvalidMagic,
    /// File was too short.
    TooShort,
}
impl StdError for Error {
    fn description(&self) -> &str {
        match self {
            &Error::Io(ref e) => e.description(),
            &Error::Map(ref e) => e.description(),
            &Error::InvalidMagic => "Header magic value was invalid",
            &Error::TooShort => "File was too short for header",
        }
    }
    fn cause(&self) -> Option<&StdError> {
        match self {
            &Error::Io(ref e) => Some(e),
            &Error::Map(ref e) => Some(e),
            _ => None,
        }
    }
}
impl Display for Error {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        match self.cause() {
            Some(cause) => write!(fmt, "{} ({})", self.description(), cause),
            None => write!(fmt, "{}", self.description()),
        }
    }
}
impl From<IoError> for Error {
    fn from(err: IoError) -> Error {
        Error::Io(err)
    }
}
impl From<MapError> for Error {
    fn from(err: MapError) -> Error {
        Error::Map(err)
    }
}

/// A memory-mapped NX file.
pub struct File {
    _map: MemoryMap,
    data: *const u8,
    header: *const Header,
    nodetable: *const repr::Node,
    stringtable: *const u64,
    audiotable: *const u64,
}

impl File {
    /// Opens an NX file via memory-mapping. This also checks the magic bytes in the header.
    pub fn open(path: &Path) -> Result<File, Error> {
        let file = try!(FsFile::open(path));
        let meta = try!(file.metadata());
        #[cfg(not(windows))]
        fn get_fd(file: &FsFile) -> MapOption {
            use std::os::unix::io::AsRawFd;
            MapFd(file.as_raw_fd())
        }
        #[cfg(windows)]
        fn get_fd(file: &FsFile) -> MapOption {
            use std::os::windows::io::AsRawHandle;
            MapFd(file.as_raw_handle() as *mut _)
        }
        let map = try!(MemoryMap::new(meta.len() as usize, &[MapReadable, get_fd(&file)]));
        if map.len() < size_of::<Header>() {
            return Err(Error::TooShort)
        }
        let data = map.data() as *const u8;
        let header = data as *const Header;
        if unsafe { (*header).magic } != 0x34474B50 {
            return Err(Error::InvalidMagic)
        }
        let nodetable = unsafe { data.offset((*header).nodeoffset as isize) as *const repr::Node };
        let stringtable = unsafe { data.offset((*header).stringoffset as isize) as *const u64 };
        let audiotable = unsafe { data.offset((*header).audiooffset as isize) as *const u64 };
        Ok(File {
            _map: map,
            data: data,
            header: header,
            nodetable: nodetable,
            stringtable: stringtable,
            audiotable: audiotable,
        })
    }
    /// Gets the file header.
    #[inline]
    fn header(&self) -> &Header {
        unsafe { &*self.header }
    }
    /// Number of nodes in the file
    #[inline]
    pub fn node_count(&self) -> u32 {
        self.header().nodecount
    }
    /// Gets the root node of the file.
    #[inline]
    pub fn root<'a>(&'a self) -> Node<'a> {
        unsafe { Node::construct(&*self.nodetable, self) }
    }
    /// Gets the string at the specified index in the string table.
    #[inline]
    pub unsafe fn get_str(&self, index: u32) -> &str {
        let off = *self.stringtable.offset(index as isize);
        let ptr = self.data.offset(off as isize);
        let size = ptr as *const u16;
        transmute(from_raw_parts(ptr.offset(2), (*size) as usize))
    }
    /// Gets the node data at the specified index in the node table.
    #[inline]
    pub unsafe fn get_node(&self, index: u32) -> &repr::Node {
        &*self.nodetable.offset(index as isize)
    }
    /// Gets the audio data at the specified index in the node table.
    #[inline]
    pub unsafe fn get_audio(&self, index: u32, length: u32) -> &[u8] {
        let off = *self.audiotable.offset(index as isize);
        let ptr = self.data.offset(off as isize);
        transmute(from_raw_parts(ptr, length as usize))
    }
}
unsafe impl Send for File {}
unsafe impl Sync for File {}
<|endoftext|>


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

#![feature(test)]
extern crate parquet;
extern crate test;

use std::fs::File;
use std::path::Path;

use parquet::file::reader::{FileReader, SerializedFileReader};
use test::Bencher;

#[bench]
fn record_reader_10k_collect(bench: &mut Bencher) {
  let path = Path::new("data/10k-v2.parquet");
  let file = File::open(&path).unwrap();
  let len = file.metadata().unwrap().len();
  let parquet_reader = SerializedFileReader::new(file).unwrap();

  bench.bytes = len;
  bench.iter(|| {
    let iter = parquet_reader.get_row_iter(None).unwrap();
    let _ = iter.collect::<Vec<_>>();
  })
}
<commit_msg>add two benchmark test with new data file (#155)<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

#![feature(test)]
extern crate parquet;
extern crate test;

use std::collections::HashMap;
use std::fs::File;
use std::path::Path;

use parquet::column::reader::{ColumnReader, get_typed_column_reader};
use parquet::data_type::*;
use parquet::file::reader::{FileReader, SerializedFileReader};
use parquet::schema::types::ColumnPath;

use test::Bencher;

#[bench]
fn record_reader_10k_collect(bench: &mut Bencher) {
  let path = Path::new("data/10k-v2.parquet");
  let file = File::open(&path).unwrap();
  let len = file.metadata().unwrap().len();
  let parquet_reader = SerializedFileReader::new(file).unwrap();

  bench.bytes = len;
  bench.iter(|| {
    let iter = parquet_reader.get_row_iter(None).unwrap();
    let _ = iter.collect::<Vec<_>>();
  })
}

#[bench]
fn record_reader_stock_simulated_collect(bench: &mut Bencher) {
  let path = Path::new("data/stock_simulated.parquet");
  let file = File::open(&path).unwrap();
  let len = file.metadata().unwrap().len();
  let parquet_reader = SerializedFileReader::new(file).unwrap();

  bench.bytes = len;
  bench.iter(|| {
    let iter = parquet_reader.get_row_iter(None).unwrap();
    let _ = iter.collect::<Vec<_>>();
  })
}

#[bench]
fn record_reader_stock_simulated_column(bench: &mut Bencher) {
  // WARNING THIS BENCH IS INTENDED FOR THIS DATA FILE ONLY
  // COPY OR CHANGE THE DATA FILE MAY NOT WORK AS YOU WISH
  let path = Path::new("data/stock_simulated.parquet");
  let file = File::open(&path).unwrap();
  let len = file.metadata().unwrap().len();
  let parquet_reader = SerializedFileReader::new(file).unwrap();

  let descr = parquet_reader.metadata().file_metadata().schema_descr_ptr();
  let num_row_groups = parquet_reader.num_row_groups();
  let batch_size = 256;

  bench.bytes = len;
  bench.iter(|| {
    let mut current_row_group = 0;

    while current_row_group < num_row_groups {

      let row_group_reader = parquet_reader.get_row_group(current_row_group).unwrap();
      let num_rows = row_group_reader.metadata().num_rows() as usize;

      let mut paths = HashMap::new();
      let row_group_metadata = row_group_reader.metadata();

      for col_index in 0..row_group_reader.num_columns() {
        let col_meta = row_group_metadata.column(col_index);
        let col_path = col_meta.column_path().clone();
        paths.insert(col_path, col_index);
      }

      let mut readers = Vec::new();
      for field in descr.root_schema().get_fields() {
        let col_path = ColumnPath::new(vec![field.name().to_owned()]);
        let orig_index = *paths.get(&col_path).unwrap();
        let col_reader = row_group_reader.get_column_reader(orig_index).unwrap();
        readers.push(col_reader);
      }

      let mut def_levels = Some(vec![0; batch_size]);
      let mut rep_levels = None::<Vec<i16>>;

      for col_reader in readers.into_iter() {
        match col_reader {
          r @ ColumnReader::Int64ColumnReader(..) => {
            let mut data_collected = Vec::with_capacity(num_rows);
            let mut val = vec![0; batch_size];
            let mut typed_reader = get_typed_column_reader::<Int64Type>(r);
            while let Ok((values_read, _levels_read)) = typed_reader.read_batch(
                batch_size,
                def_levels.as_mut().map(|x| &mut x[..]),
                rep_levels.as_mut().map(|x| &mut x[..]),
                &mut val)
            {
                data_collected.extend_from_slice(&val);
                if values_read < batch_size { break }
            }
          },
          r @ ColumnReader::DoubleColumnReader(..) => {
            let mut data_collected = Vec::with_capacity(num_rows);
            let mut val = vec![0.0; batch_size];
            let mut typed_reader = get_typed_column_reader::<DoubleType>(r);
            while let Ok((values_read, _levels_read)) = typed_reader.read_batch(
                batch_size,
                def_levels.as_mut().map(|x| &mut x[..]),
                rep_levels.as_mut().map(|x| &mut x[..]),
                &mut val)
            {
                data_collected.extend_from_slice(&val);
                if values_read < batch_size { break }
            }
          },
          _ => unimplemented!(),
        }
      }
      current_row_group += 1;
    }
  })
}
<|endoftext|>


<commit_before>use artano::Annotation;
use config::resource::Resource;
use error::Cause;
use std::borrow::Cow;
use std::error;
use std::fmt;
use std::path::{Path, PathBuf};
use std::result;

// How the hell do you make a path buffer from command line input if command line input is a
// string but a path buffer itself is technically not because it isn't validated UTF8?

type Result<T> = result::Result<T, BuildOptionsError>;

#[derive(Debug)]
pub struct Options {
    pub base_image: Resource,
    pub annotations: Vec<Annotation>,
    pub output_path: PathBuf,
    pub output_format: OutputFormat,
    pub scale_mult: f32,
    pub font_path: PathBuf,
    pub debug: bool,
}

#[derive(Copy, Clone, Debug)]
pub enum OutputFormat {
    Jpg,
    Png,
}

impl Options {
    pub fn from_args() -> Result<Self> {
        read_command()
    }
}

pub struct OptionsBuilder {
    base_image: Option<String>,
    annotations: Vec<Annotation>,
    output_path: Option<String>,
    output_format: OutputFormat,
    scale_mult: f32,
    font_path: Cow<'static, str>,
    debug: bool,
}

impl OptionsBuilder {
    fn new() -> OptionsBuilder {
        OptionsBuilder {
            base_image: None,
            annotations: Vec::new(),
            output_path: None,
            output_format: OutputFormat::Jpg,
            scale_mult: 1.0,
            font_path: default_font(),
            debug: false,
        }
    }
}

impl OptionsBuilder {
    fn build(self) -> Result<Options> {
        let input_path: PathBuf = self.base_image.as_ref().unwrap().into();
        if input_path.file_name().is_none() {
            return Err(BuildOptionsError {
                kind: BuildOptionsErrorKind::ImagePath,
                description: Cow::from(
                    "The provided image path does not appear to have a filename",
                ),
                cause: None,
            });
        }

        let output_format = self.output_format;
        let output_path = self.output_path
            .map(|s| s.into())
            .unwrap_or_else(|| create_output_file_path(&input_path, output_format));

        let annotations = if self.annotations.is_empty() {
            return Err(BuildOptionsError {
                kind: BuildOptionsErrorKind::Annotations,
                description: Cow::from("No annotations provided"),
                cause: None,
            });
        } else {
            self.annotations
        };

        Ok(Options {
            base_image: Resource::new(self.base_image.unwrap()),
            annotations,
            output_path,
            output_format,
            scale_mult: self.scale_mult,
            font_path: self.font_path.to_string().into(),
            debug: self.debug,
        })
    }
}

#[derive(Debug)]
pub struct BuildOptionsError {
    kind: BuildOptionsErrorKind,
    description: Cow<'static, str>,
    cause: Option<Cause>,
}

#[derive(Debug)]
enum BuildOptionsErrorKind {
    Annotations,
    ImagePath,
    ScalingMultiplier,
}

impl fmt::Display for BuildOptionsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.description)
    }
}

impl error::Error for BuildOptionsError {
    fn description(&self) -> &str {
        &self.description
    }

    fn cause(&self) -> Option<&error::Error> {
        self.cause.as_ref().map(|cause| cause.as_ref())
    }
}

fn read_command() -> Result<Options> {
    use clap::ArgGroup;

    let text_group = ArgGroup::with_name("text_group")
        .args(&["caption", "bottom", "top", "middle"])
        .multiple(true);

    let encoding_group = ArgGroup::with_name("enc_group").args(&["encoding", "jpg", "png"]);

    let app = clap_app!(annatar =>
        (version: crate_version!())
        (author: crate_authors!())
        (about: crate_description!())
        (@arg image: +required "Path to an image to be annotated")
        (@arg caption: "A message to be added to the bottom of the image")
        (@arg bottom: -b --bottom +takes_value "A message to be added to the bottom of the image")
        (@arg top: -t --top +takes_value "A message to be added to the top of the image")
        (@arg middle: -m --middle +takes_value "A message to be added to the middle of the image")
        (@arg output: -o --output +takes_value
            "Sets an output path for the new image (default: <image path>/<image name>.ann.<ext>)")
        (@arg scale: -s --scale +takes_value "Sets the scale multiplier for annotations")
        (@arg font: -f --font +takes_value "Sets the path of the font to be used (default: Impact)")
        (@arg debug: -d --debug "Save edge detection ... thing to disk")
        (@arg jpg: --jpg "Set JPG mode (default)")
        (@arg png: --png "Set PNG mode")
    );

    // Much easier to set up argument groups outside macro.
    let app = app.group(text_group).group(encoding_group);

    let matches = app.get_matches();
    let mut options = OptionsBuilder::new();

    options.base_image = Some(matches.value_of("image").unwrap().to_string());
    options.output_path = matches.value_of("output").map(|s| s.to_string());

    if let Some(scale_multiplier) = matches.value_of("scale") {
        let multiplier = scale_multiplier.parse::<f32>().map_err(|e| {
            BuildOptionsError {
                kind: BuildOptionsErrorKind::ScalingMultiplier,
                description: Cow::from("Scaling multiplier must be a decimal value"),
                cause: Some(Box::new(e)),
            }
        })?;
        options.scale_mult = multiplier;
    }

    if let Some(font_path) = matches.value_of("font") {
        options.font_path = Cow::from(font_path.to_string());
    }

    if let Some(caption) = matches.value_of("caption") {
        options.annotations.push(Annotation::bottom(caption));
    }

    if let Some(caption) = matches.value_of("top") {
        options.annotations.push(Annotation::top(caption));
    }

    if let Some(caption) = matches.value_of("middle") {
        options.annotations.push(Annotation::middle(caption));
    }

    if let Some(caption) = matches.value_of("bottom") {
        options.annotations.push(Annotation::bottom(caption));
    }

    options.output_format = {
        if matches.is_present("jpg") {
            OutputFormat::Jpg
        } else {
            OutputFormat::Png
        }
    };

    options.debug = matches.is_present("debug");

    options.build()
}

#[cfg(target_os = "windows")]
fn default_font() -> Cow<'static, str> {
    Cow::from("C:/Windows/Fonts/Impact.ttf")
}

#[cfg(target_os = "macos")]
fn default_font() -> Cow<'static, str> {
    Cow::from("/Library/Fonts/Impact.ttf")
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn default_font() -> Cow<'static, str> {
    unimplemented!("Honestly, getting a font on Linux is going to be an adventure.");
}

fn create_output_file_path(input_path: &Path, output_format: OutputFormat) -> PathBuf {
    // I unwrap this because clap already converted it to a string, implying it's valid utf-8.
    let mut file_name = input_path
        .file_name()
        .unwrap()
        .to_str()
        .unwrap()
        .to_string();

    if let Some(last_segment_idx) = file_name.rfind('.') {
        file_name.truncate(last_segment_idx);
    }

    match output_format {
        OutputFormat::Png => file_name.push_str("-annotated.png"),
        _ => file_name.push_str("-annotated.jpg"),
    }

    file_name.into()
}
<commit_msg>Remove unused option<commit_after>use artano::Annotation;
use config::resource::Resource;
use error::Cause;
use std::borrow::Cow;
use std::error;
use std::fmt;
use std::path::{Path, PathBuf};
use std::result;

// How the hell do you make a path buffer from command line input if command line input is a
// string but a path buffer itself is technically not because it isn't validated UTF8?

type Result<T> = result::Result<T, BuildOptionsError>;

#[derive(Debug)]
pub struct Options {
    pub base_image: Resource,
    pub annotations: Vec<Annotation>,
    pub output_path: PathBuf,
    pub output_format: OutputFormat,
    pub scale_mult: f32,
    pub font_path: PathBuf,
    pub debug: bool,
}

#[derive(Copy, Clone, Debug)]
pub enum OutputFormat {
    Jpg,
    Png,
}

impl Options {
    pub fn from_args() -> Result<Self> {
        read_command()
    }
}

pub struct OptionsBuilder {
    base_image: Option<String>,
    annotations: Vec<Annotation>,
    output_path: Option<String>,
    output_format: OutputFormat,
    scale_mult: f32,
    font_path: Cow<'static, str>,
    debug: bool,
}

impl OptionsBuilder {
    fn new() -> OptionsBuilder {
        OptionsBuilder {
            base_image: None,
            annotations: Vec::new(),
            output_path: None,
            output_format: OutputFormat::Jpg,
            scale_mult: 1.0,
            font_path: default_font(),
            debug: false,
        }
    }
}

impl OptionsBuilder {
    fn build(self) -> Result<Options> {
        let input_path: PathBuf = self.base_image.as_ref().unwrap().into();
        if input_path.file_name().is_none() {
            return Err(BuildOptionsError {
                kind: BuildOptionsErrorKind::ImagePath,
                description: Cow::from(
                    "The provided image path does not appear to have a filename",
                ),
                cause: None,
            });
        }

        let output_format = self.output_format;
        let output_path = self.output_path
            .map(|s| s.into())
            .unwrap_or_else(|| create_output_file_path(&input_path, output_format));

        let annotations = if self.annotations.is_empty() {
            return Err(BuildOptionsError {
                kind: BuildOptionsErrorKind::Annotations,
                description: Cow::from("No annotations provided"),
                cause: None,
            });
        } else {
            self.annotations
        };

        Ok(Options {
            base_image: Resource::new(self.base_image.unwrap()),
            annotations,
            output_path,
            output_format,
            scale_mult: self.scale_mult,
            font_path: self.font_path.to_string().into(),
            debug: self.debug,
        })
    }
}

#[derive(Debug)]
pub struct BuildOptionsError {
    kind: BuildOptionsErrorKind,
    description: Cow<'static, str>,
    cause: Option<Cause>,
}

#[derive(Debug)]
enum BuildOptionsErrorKind {
    Annotations,
    ImagePath,
    ScalingMultiplier,
}

impl fmt::Display for BuildOptionsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(&self.description)
    }
}

impl error::Error for BuildOptionsError {
    fn description(&self) -> &str {
        &self.description
    }

    fn cause(&self) -> Option<&error::Error> {
        self.cause.as_ref().map(|cause| cause.as_ref())
    }
}

fn read_command() -> Result<Options> {
    use clap::ArgGroup;

    let text_group = ArgGroup::with_name("text_group")
        .args(&["caption", "bottom", "top", "middle"])
        .multiple(true);

    let encoding_group = ArgGroup::with_name("enc_group").args(&["jpg", "png"]);

    let app = clap_app!(annatar =>
        (version: crate_version!())
        (author: crate_authors!())
        (about: crate_description!())
        (@arg image: +required "Path to an image to be annotated")
        (@arg caption: "A message to be added to the bottom of the image")
        (@arg bottom: -b --bottom +takes_value "A message to be added to the bottom of the image")
        (@arg top: -t --top +takes_value "A message to be added to the top of the image")
        (@arg middle: -m --middle +takes_value "A message to be added to the middle of the image")
        (@arg output: -o --output +takes_value
            "Sets an output path for the new image (default: <image path>/<image name>.ann.<ext>)")
        (@arg scale: -s --scale +takes_value "Sets the scale multiplier for annotations")
        (@arg font: -f --font +takes_value "Sets the path of the font to be used (default: Impact)")
        (@arg debug: -d --debug "Save edge detection ... thing to disk")
        (@arg jpg: --jpg "Set JPG mode (default)")
        (@arg png: --png "Set PNG mode")
    );

    // Much easier to set up argument groups outside macro.
    let app = app.group(text_group).group(encoding_group);

    let matches = app.get_matches();
    let mut options = OptionsBuilder::new();

    options.base_image = Some(matches.value_of("image").unwrap().to_string());
    options.output_path = matches.value_of("output").map(|s| s.to_string());

    if let Some(scale_multiplier) = matches.value_of("scale") {
        let multiplier = scale_multiplier.parse::<f32>().map_err(|e| {
            BuildOptionsError {
                kind: BuildOptionsErrorKind::ScalingMultiplier,
                description: Cow::from("Scaling multiplier must be a decimal value"),
                cause: Some(Box::new(e)),
            }
        })?;
        options.scale_mult = multiplier;
    }

    if let Some(font_path) = matches.value_of("font") {
        options.font_path = Cow::from(font_path.to_string());
    }

    if let Some(caption) = matches.value_of("caption") {
        options.annotations.push(Annotation::bottom(caption));
    }

    if let Some(caption) = matches.value_of("top") {
        options.annotations.push(Annotation::top(caption));
    }

    if let Some(caption) = matches.value_of("middle") {
        options.annotations.push(Annotation::middle(caption));
    }

    if let Some(caption) = matches.value_of("bottom") {
        options.annotations.push(Annotation::bottom(caption));
    }

    options.output_format = {
        if matches.is_present("jpg") {
            OutputFormat::Jpg
        } else {
            OutputFormat::Png
        }
    };

    options.debug = matches.is_present("debug");

    options.build()
}

#[cfg(target_os = "windows")]
fn default_font() -> Cow<'static, str> {
    Cow::from("C:/Windows/Fonts/Impact.ttf")
}

#[cfg(target_os = "macos")]
fn default_font() -> Cow<'static, str> {
    Cow::from("/Library/Fonts/Impact.ttf")
}

#[cfg(not(any(target_os = "windows", target_os = "macos")))]
fn default_font() -> Cow<'static, str> {
    unimplemented!("Honestly, getting a font on Linux is going to be an adventure.");
}

fn create_output_file_path(input_path: &Path, output_format: OutputFormat) -> PathBuf {
    // I unwrap this because clap already converted it to a string, implying it's valid utf-8.
    let mut file_name = input_path
        .file_name()
        .unwrap()
        .to_str()
        .unwrap()
        .to_string();

    if let Some(last_segment_idx) = file_name.rfind('.') {
        file_name.truncate(last_segment_idx);
    }

    match output_format {
        OutputFormat::Png => file_name.push_str("-annotated.png"),
        _ => file_name.push_str("-annotated.jpg"),
    }

    file_name.into()
}
<|endoftext|>


<commit_before>use core::*;

/// Given some cards create sets of possible groups of cards.
#[derive(Debug)]
pub struct CardIter<'a> {
    /// All the possible cards that can be dealt
    possible_cards: &'a [Card],

    /// Set of current offsets being used to create card sets.
    idx: Vec<usize>,

    /// size of card sets requested.
    num_cards: usize,
}

/// `CardIter` is a container for cards and current state.
impl<'a> CardIter<'a> {
    /// Create a new `CardIter` from a slice of cards.
    /// `num_cards` represents how many cards should be in the resulting vector.
    pub fn new(possible_cards: &[Card], num_cards: usize) -> CardIter {
        let mut idx: Vec<usize> = (0..(num_cards as usize)).collect();
        idx[num_cards - 1] -= 1;
        CardIter {
            possible_cards: possible_cards,
            idx: idx,
            num_cards: num_cards,
        }
    }
}

/// The actual `Iterator` for `Card`'s.
impl<'a> Iterator for CardIter<'a> {
    type Item = Vec<Card>;
    fn next(&mut self) -> Option<Vec<Card>> {
        // Keep track of where we are mutating
        let mut current_level: usize = self.num_cards - 1;

        while current_level < self.num_cards {
            // Move the current level forward one.
            self.idx[current_level] += 1;

            // Now check if moving this level forward means that
            // We will need more cards to fill out the rest of the hand
            // then are there.
            let cards_needed_after = self.num_cards - (current_level + 1);
            if self.idx[current_level] + cards_needed_after >= self.possible_cards.len() {
                if current_level == 0 {
                    return None;
                }
                current_level -= 1;
            } else {
                // If we aren't at the end then
                if current_level < self.num_cards - 1 {
                    self.idx[current_level + 1] = self.idx[current_level];
                }
                // Move forward one level
                current_level += 1;
            }
        }

        let result_cards: Vec<Card> = self.idx
            .iter()
            .map(|i| self.possible_cards[*i as usize])
            .collect();
        Some(result_cards)
    }
}

/// This is useful for trying every possible 5 card hand
///
/// Probably not something that's going to be done in real
/// use cases, but still not bad.
impl<'a> IntoIterator for &'a FlatDeck {
    type Item = Vec<Card>;
    type IntoIter = CardIter<'a>;

    fn into_iter(self) -> CardIter<'a> {
        CardIter::new(&self[..], 5)
    }
}

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

    #[test]
    fn test_iter_one() {
        let mut h = Hand::default();
        h.push(Card {
            value: Value::Two,
            suit: Suit::Spade,
        });

        for cards in CardIter::new(&h[..], 1) {
            assert_eq!(1, cards.len());
        }

        assert_eq!(1, CardIter::new(&h[..], 1).count());
    }

    #[test]
    fn test_iter_two() {
        let mut h = Hand::default();
        h.push(Card {
            value: Value::Two,
            suit: Suit::Spade,
        });
        h.push(Card {
            value: Value::Three,
            suit: Suit::Spade,
        });
        h.push(Card {
            value: Value::Four,
            suit: Suit::Spade,
        });

        // Make sure that we get the correct number back.
        assert_eq!(3, CardIter::new(&h[..], 2).count());

        // Make sure that everything has two cards and they are different.
        //
        for cards in CardIter::new(&h[..], 2) {
            assert_eq!(2, cards.len());
            assert!(cards[0] != cards[1]);
        }
    }

    #[test]
    fn test_iter_deck() {
        let d: FlatDeck = Deck::default().flatten();
        assert_eq!(2598960, d.into_iter().count());
    }
}
<commit_msg>Fix compilation of tests<commit_after>use core::*;

/// Given some cards create sets of possible groups of cards.
#[derive(Debug)]
pub struct CardIter<'a> {
    /// All the possible cards that can be dealt
    possible_cards: &'a [Card],

    /// Set of current offsets being used to create card sets.
    idx: Vec<usize>,

    /// size of card sets requested.
    num_cards: usize,
}

/// `CardIter` is a container for cards and current state.
impl<'a> CardIter<'a> {
    /// Create a new `CardIter` from a slice of cards.
    /// `num_cards` represents how many cards should be in the resulting vector.
    pub fn new(possible_cards: &[Card], num_cards: usize) -> CardIter {
        let mut idx: Vec<usize> = (0..(num_cards as usize)).collect();
        idx[num_cards - 1] -= 1;
        CardIter {
            possible_cards: possible_cards,
            idx: idx,
            num_cards: num_cards,
        }
    }
}

/// The actual `Iterator` for `Card`'s.
impl<'a> Iterator for CardIter<'a> {
    type Item = Vec<Card>;
    fn next(&mut self) -> Option<Vec<Card>> {
        // Keep track of where we are mutating
        let mut current_level: usize = self.num_cards - 1;

        while current_level < self.num_cards {
            // Move the current level forward one.
            self.idx[current_level] += 1;

            // Now check if moving this level forward means that
            // We will need more cards to fill out the rest of the hand
            // then are there.
            let cards_needed_after = self.num_cards - (current_level + 1);
            if self.idx[current_level] + cards_needed_after >= self.possible_cards.len() {
                if current_level == 0 {
                    return None;
                }
                current_level -= 1;
            } else {
                // If we aren't at the end then
                if current_level < self.num_cards - 1 {
                    self.idx[current_level + 1] = self.idx[current_level];
                }
                // Move forward one level
                current_level += 1;
            }
        }

        let result_cards: Vec<Card> = self.idx
            .iter()
            .map(|i| self.possible_cards[*i as usize].clone())
            .collect();
        Some(result_cards)
    }
}

/// This is useful for trying every possible 5 card hand
///
/// Probably not something that's going to be done in real
/// use cases, but still not bad.
impl<'a> IntoIterator for &'a FlatDeck {
    type Item = Vec<Card>;
    type IntoIter = CardIter<'a>;

    fn into_iter(self) -> CardIter<'a> {
        CardIter::new(&self[..], 5)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use core::card::*;
    use core::hand::*;
    use core::deck::*;
    use core::flat_deck::*;

    #[test]
    fn test_iter_one() {
        let mut h = Hand::default();
        h.push(Card {
            value: Value::Two,
            suit: Suit::Spade,
        });

        for cards in CardIter::new(&h[..], 1) {
            assert_eq!(1, cards.len());
        }

        assert_eq!(1, CardIter::new(&h[..], 1).count());
    }

    #[test]
    fn test_iter_two() {
        let mut h = Hand::default();
        h.push(Card {
            value: Value::Two,
            suit: Suit::Spade,
        });
        h.push(Card {
            value: Value::Three,
            suit: Suit::Spade,
        });
        h.push(Card {
            value: Value::Four,
            suit: Suit::Spade,
        });

        // Make sure that we get the correct number back.
        assert_eq!(3, CardIter::new(&h[..], 2).count());

        // Make sure that everything has two cards and they are different.
        //
        for cards in CardIter::new(&h[..], 2) {
            assert_eq!(2, cards.len());
            assert!(cards[0] != cards[1]);
        }
    }

    #[test]
    fn test_iter_deck() {
        let d: FlatDeck = Deck::default().into();
        assert_eq!(2598960, d.into_iter().count());
    }
}
<|endoftext|>