<commit_before>// 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
#![recursion_limit = "128"]

#[macro_use]
extern crate slog;
#[macro_use]
extern crate slog_scope;
#[macro_use]
extern crate approx;
#[macro_use]
extern crate assert_float_eq;

mod bano2mimir_test;
mod bragi_bano_test;
mod bragi_filter_types_test;
mod bragi_ntfs_test;
mod bragi_osm_test;
mod bragi_poi_test;
mod bragi_stops_test;
mod bragi_synonyms_test;
mod bragi_three_cities_test;
mod canonical_import_process_test;
mod cosmogony2mimir_test;
mod openaddresses2mimir_test;
mod osm2mimir_bano2mimir_test;
mod osm2mimir_test;
mod rubber_test;
mod stops2mimir_test;

use actix_web::client::ClientResponse;
use docker_wrapper::*;
use failure::{format_err, Error};
use serde_json::value::Value;
use serde_json::Map;
use std::process::Command;

pub struct ElasticSearchWrapper<'a> {
    docker_wrapper: &'a DockerWrapper,
    pub rubber: mimir::rubber::Rubber,
}

impl<'a> ElasticSearchWrapper<'a> {
    pub fn host(&self) -> String {
        self.docker_wrapper.host()
    }

    pub fn init(&mut self) {
        self.rubber.delete_index(&"_all".to_string()).unwrap();
    }

    //    A way to watch if indexes are built might be curl http://localhost:9200/_stats
    //    then _all/total/segments/index_writer_memory_in_bytes( or version_map_memory_in_bytes)
    // 	  should be == 0 if indexes are ok (no refresh needed)
    pub fn refresh(&self) {
        info!("Refreshing ES indexes");

        let res = reqwest::Client::new()
            .get(&format!("{}/_refresh", self.host()))
            .send()
            .unwrap();
        assert!(
            res.status() == reqwest::StatusCode::OK,
            "Error ES refresh: {:?}",
            res
        );
    }

    pub fn new(docker_wrapper: &DockerWrapper) -> ElasticSearchWrapper<'_> {
        let mut es_wrapper = ElasticSearchWrapper {
            docker_wrapper: docker_wrapper,
            rubber: mimir::rubber::Rubber::new(&docker_wrapper.host()),
        };
        es_wrapper.init();
        es_wrapper
    }

    /// simple search on an index
    /// assert that the result is OK and transform it to a json Value
    pub fn search(&self, word: &str) -> serde_json::Value {
        let mut res = self
            .rubber
            .get(&format!("munin/_search?q={}", word))
            .unwrap();
        assert!(res.status() == reqwest::StatusCode::OK);
        res.json().unwrap()
    }

    pub fn search_on_global_stop_index(&self, word: &str) -> serde_json::Value {
        let mut res = self
            .rubber
            .get(&format!("munin_global_stops/_search?q={}", word))
            .unwrap();
        assert!(res.status() == reqwest::StatusCode::OK);
        res.json().unwrap()
    }

    pub fn search_and_filter<'b, F>(
        &self,
        word: &str,
        predicate: F,
    ) -> impl Iterator<Item = mimir::Place> + 'b
    where
        F: 'b + FnMut(&mimir::Place) -> bool,
    {
        self.search_and_filter_on_index(word, predicate, false)
    }

    pub fn search_and_filter_on_global_stop_index<'b, F>(
        &self,
        word: &str,
        predicate: F,
    ) -> impl Iterator<Item = mimir::Place> + 'b
    where
        F: 'b + FnMut(&mimir::Place) -> bool,
    {
        self.search_and_filter_on_index(word, predicate, true)
    }

    fn search_and_filter_on_index<'b, F>(
        &self,
        word: &str,
        predicate: F,
        search_on_global_stops: bool,
    ) -> impl Iterator<Item = mimir::Place> + 'b
    where
        F: 'b + FnMut(&mimir::Place) -> bool,
    {
        use serde_json::map::Entry;
        fn into_object(json: Value) -> Option<Map<String, Value>> {
            match json {
                Value::Object(o) => Some(o),
                _ => None,
            }
        }
        fn get(json: Value, key: &str) -> Option<Value> {
            into_object(json).and_then(|mut json| match json.entry(key.to_string()) {
                Entry::Occupied(o) => Some(o.remove()),
                _ => None,
            })
        }
        let json = if search_on_global_stops {
            self.search_on_global_stop_index(word)
        } else {
            self.search(word)
        };
        get(json, "hits")
            .and_then(|json| get(json, "hits"))
            .and_then(|hits| match hits {
                Value::Array(v) => Some(v),
                _ => None,
            })
            .unwrap_or_else(Vec::default)
            .into_iter()
            .filter_map(|json| {
                into_object(json).and_then(|obj| {
                    let doc_type = obj
                        .get("_type")
                        .and_then(|doc_type| doc_type.as_str())
                        .map(|doc_type| doc_type.into());

                    doc_type.and_then(|doc_type| {
                        // The real object is contained in the _source section.
                        obj.get("_source").and_then(|src| {
                            bragi::query::make_place(doc_type, Some(Box::new(src.clone())))
                        })
                    })
                })
            })
            .filter(predicate)
    }
}

fn launch_and_assert(
    cmd: &str,
    args: &[std::string::String],
    es_wrapper: &ElasticSearchWrapper<'_>,
) {
    let status = Command::new(cmd).args(args).status().unwrap();
    assert!(status.success(), "`{}` failed {}", cmd, &status);
    es_wrapper.refresh();
}

pub struct BragiHandler {
    app: actix_web::test::TestServer,
}

impl BragiHandler {
    pub fn new(url: String) -> BragiHandler {
        let make_server = move || {
            bragi::server::create_server(bragi::Context {
                es_cnx_string: url.clone(),
                max_es_timeout: None,
            })
        };

        BragiHandler {
            app: actix_web::test::TestServer::with_factory(make_server),
        }
    }

    pub fn raw_get(&mut self, q: &str) -> Result<ClientResponse, Error> {
        self.app
            .execute(
                self.app
                    .client(actix_web::http::Method::GET, q)
                    .finish()
                    .map_err(|e| format_err!("invalid query: {}", e))?
                    .send(),
            )
            .map_err(|e| format_err!("impossible to query bragi: {}", e))
    }

    pub fn get(&mut self, q: &str) -> Vec<Map<String, Value>> {
        let r = self.raw_get(q).unwrap();
        assert!(r.status().is_success(), "invalid status: {}", r.status());
        self.get_results(r, Some("/properties/geocoding".to_string()))
    }

    pub fn get_json(&mut self, q: &str) -> Value {
        let r = self.raw_get(q).unwrap();
        assert!(r.status().is_success(), "invalid status: {}", r.status());
        self.to_json(r)
    }

    pub fn get_unchecked_json(&mut self, q: &str) -> (actix_web::http::StatusCode, Value) {
        let r = self.raw_get(q).unwrap();
        (r.status(), self.to_json(r))
    }

    pub fn raw_post_shape(
        &mut self,
        q: &str,
        shape: &'static str,
    ) -> Result<ClientResponse, Error> {
        self.app
            .execute(
                self.app
                    .client(actix_web::http::Method::POST, q)
                    .header(actix_web::http::header::CONTENT_TYPE, "application/json")
                    .body(shape)
                    .map_err(|e| format_err!("invalid query: {}", e))?
                    .send(),
            )
            .map_err(|e| format_err!("impossible to query bragi: {}", e))
    }

    pub fn post_shape(&mut self, q: &str, shape: &'static str) -> Vec<Map<String, Value>> {
        let r = self.raw_post_shape(q, shape).unwrap();
        self.get_results(r, Some("/properties/geocoding".to_string()))
    }

    pub fn to_json(&mut self, r: ClientResponse) -> Value {
        use actix_web::HttpMessage;
        let bytes = self.app.execute(r.body()).unwrap();
        let body = std::str::from_utf8(&bytes).unwrap();
        serde_json::from_str(body).unwrap()
    }

    pub fn get_results(
        &mut self,
        r: ClientResponse,
        pointer: Option<String>,
    ) -> Vec<Map<String, Value>> {
        self.to_json(r)
            .pointer("/features")
            .expect("wrongly formated bragi response")
            .as_array()
            .expect("features must be array")
            .iter()
            .map(|f| {
                if let Some(p) = &pointer {
                    f.pointer(&p)
                        .expect("no field in bragi response")
                        .as_object()
                        .unwrap()
                        .clone()
                } else {
                    f.as_object().unwrap().clone()
                }
            })
            .collect()
    }
}

pub fn get_values<'a>(r: &'a [Map<String, Value>], val: &'a str) -> Vec<&'a str> {
    r.iter().map(|e| get_value(e, val)).collect()
}

pub fn get_value<'a>(e: &'a Map<String, Value>, val: &str) -> &'a str {
    e.get(val).and_then(|l| l.as_str()).unwrap_or_else(|| "")
}

pub fn get_types(r: &[Map<String, Value>]) -> Vec<&str> {
    get_values(r, "type")
}

pub fn filter_by(r: &[Map<String, Value>], key: &str, t: &str) -> Vec<Map<String, Value>> {
    r.iter()
        .filter(|e| e.get(key).and_then(|l| l.as_str()).unwrap_or_else(|| "") == t)
        .cloned()
        .collect()
}

pub fn filter_by_type(r: &[Map<String, Value>], t: &str) -> Vec<Map<String, Value>> {
    filter_by(r, "type", t)
}

pub fn count_types(types: &[&str], value: &str) -> usize {
    types.iter().filter(|&t| *t == value).count()
}

fn get_poi_type_ids(e: &Map<String, Value>) -> Vec<&str> {
    let array = match e.get("poi_types").and_then(|json| json.as_array()) {
        None => return vec![],
        Some(array) => array,
    };
    array
        .iter()
        .filter_map(|v| v.as_object().and_then(|o| o.get("id")))
        .filter_map(|o| o.as_str())
        .collect()
}

fn get_first_index_aliases(indexes: &serde_json::Map<String, Value>) -> Vec<String> {
    indexes
        .get(indexes.keys().next().unwrap())
        .and_then(Value::as_object)
        .and_then(|s| s.get("aliases"))
        .and_then(Value::as_object)
        .map(|s| s.keys().cloned().collect())
        .unwrap_or_else(Vec::new)
}

/// Main test method (regroups all tests)
/// All tests are done sequentially,
/// and use the same docker in order to avoid multiple inits
/// (ES cleanup is handled by `es_wrapper`)
#[test]
fn all_tests() {
    let _guard = mimir::logger_init();
    let docker_wrapper = DockerWrapper::new().unwrap();

    // we call all tests here
    bano2mimir_test::bano2mimir_sample_test(ElasticSearchWrapper::new(&docker_wrapper));
    osm2mimir_test::osm2mimir_sample_test(ElasticSearchWrapper::new(&docker_wrapper));
    stops2mimir_test::stops2mimir_sample_test(ElasticSearchWrapper::new(&docker_wrapper));
    osm2mimir_bano2mimir_test::osm2mimir_bano2mimir_test(ElasticSearchWrapper::new(
        &docker_wrapper,
    ));
    rubber_test::rubber_zero_downtime_test(ElasticSearchWrapper::new(&docker_wrapper));
    rubber_test::rubber_custom_id(ElasticSearchWrapper::new(&docker_wrapper));
    rubber_test::rubber_ghost_index_cleanup(ElasticSearchWrapper::new(&docker_wrapper));
    rubber_test::rubber_empty_bulk(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_bano_test::bragi_bano_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_osm_test::bragi_osm_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_poi_test::test_i18n_poi(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_three_cities_test::bragi_three_cities_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_poi_test::bragi_poi_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_stops_test::bragi_stops_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_ntfs_test::bragi_ntfs_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_filter_types_test::bragi_filter_types_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_synonyms_test::bragi_synonyms_test(ElasticSearchWrapper::new(&docker_wrapper));
    openaddresses2mimir_test::oa2mimir_simple_test(ElasticSearchWrapper::new(&docker_wrapper));
    cosmogony2mimir_test::cosmogony2mimir_test(ElasticSearchWrapper::new(&docker_wrapper));
    canonical_import_process_test::canonical_import_process_test(ElasticSearchWrapper::new(
        &docker_wrapper,
    ));
    canonical_import_process_test::bragi_invalid_es_test(ElasticSearchWrapper::new(
        &docker_wrapper,
    ));
}
<commit_msg>Fix warnings<commit_after>// 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
#![recursion_limit = "128"]

#[macro_use]
extern crate slog;
#[macro_use]
extern crate slog_scope;
#[macro_use]
extern crate approx;
#[macro_use]
extern crate assert_float_eq;

mod bano2mimir_test;
mod bragi_bano_test;
mod bragi_filter_types_test;
mod bragi_ntfs_test;
mod bragi_osm_test;
mod bragi_poi_test;
mod bragi_stops_test;
mod bragi_synonyms_test;
mod bragi_three_cities_test;
mod canonical_import_process_test;
mod cosmogony2mimir_test;
mod openaddresses2mimir_test;
mod osm2mimir_bano2mimir_test;
mod osm2mimir_test;
mod rubber_test;
mod stops2mimir_test;

use actix_web::client::ClientResponse;
use docker_wrapper::*;
use failure::{format_err, Error};
use serde_json::value::Value;
use serde_json::Map;
use std::process::Command;

pub struct ElasticSearchWrapper<'a> {
    docker_wrapper: &'a DockerWrapper,
    pub rubber: mimir::rubber::Rubber,
}

impl<'a> ElasticSearchWrapper<'a> {
    pub fn host(&self) -> String {
        self.docker_wrapper.host()
    }

    pub fn init(&mut self) {
        self.rubber.delete_index(&"_all".to_string()).unwrap();
    }

    //    A way to watch if indexes are built might be curl http://localhost:9200/_stats
    //    then _all/total/segments/index_writer_memory_in_bytes( or version_map_memory_in_bytes)
    // 	  should be == 0 if indexes are ok (no refresh needed)
    pub fn refresh(&self) {
        info!("Refreshing ES indexes");

        let res = reqwest::Client::new()
            .get(&format!("{}/_refresh", self.host()))
            .send()
            .unwrap();
        assert!(
            res.status() == reqwest::StatusCode::OK,
            "Error ES refresh: {:?}",
            res
        );
    }

    pub fn new(docker_wrapper: &DockerWrapper) -> ElasticSearchWrapper<'_> {
        let mut es_wrapper = ElasticSearchWrapper {
            docker_wrapper: docker_wrapper,
            rubber: mimir::rubber::Rubber::new(&docker_wrapper.host()),
        };
        es_wrapper.init();
        es_wrapper
    }

    /// simple search on an index
    /// assert that the result is OK and transform it to a json Value
    pub fn search(&self, word: &str) -> serde_json::Value {
        let mut res = self
            .rubber
            .get(&format!("munin/_search?q={}", word))
            .unwrap();
        assert!(res.status() == reqwest::StatusCode::OK);
        res.json().unwrap()
    }

    pub fn search_on_global_stop_index(&self, word: &str) -> serde_json::Value {
        let mut res = self
            .rubber
            .get(&format!("munin_global_stops/_search?q={}", word))
            .unwrap();
        assert!(res.status() == reqwest::StatusCode::OK);
        res.json().unwrap()
    }

    pub fn search_and_filter<'b, F>(
        &self,
        word: &str,
        predicate: F,
    ) -> impl Iterator<Item = mimir::Place> + 'b
    where
        F: 'b + FnMut(&mimir::Place) -> bool,
    {
        self.search_and_filter_on_index(word, predicate, false)
    }

    pub fn search_and_filter_on_global_stop_index<'b, F>(
        &self,
        word: &str,
        predicate: F,
    ) -> impl Iterator<Item = mimir::Place> + 'b
    where
        F: 'b + FnMut(&mimir::Place) -> bool,
    {
        self.search_and_filter_on_index(word, predicate, true)
    }

    fn search_and_filter_on_index<'b, F>(
        &self,
        word: &str,
        predicate: F,
        search_on_global_stops: bool,
    ) -> impl Iterator<Item = mimir::Place> + 'b
    where
        F: 'b + FnMut(&mimir::Place) -> bool,
    {
        use serde_json::map::Entry;

        fn into_object(json: Value) -> Option<Map<String, Value>> {
            match json {
                Value::Object(o) => Some(o),
                _ => None,
            }
        }
        fn get(json: Value, key: &str) -> Option<Value> {
            into_object(json).and_then(|mut json| match json.entry(key.to_string()) {
                Entry::Occupied(o) => Some(o.remove()),
                _ => None,
            })
        }
        let json = if search_on_global_stops {
            self.search_on_global_stop_index(word)
        } else {
            self.search(word)
        };
        get(json, "hits")
            .and_then(|json| get(json, "hits"))
            .and_then(|hits| match hits {
                Value::Array(v) => Some(v),
                _ => None,
            })
            .unwrap_or_else(Vec::default)
            .into_iter()
            .filter_map(|json| {
                into_object(json).and_then(|obj| {
                    let doc_type = obj
                        .get("_type")
                        .and_then(|doc_type| doc_type.as_str())
                        .map(|doc_type| doc_type.into());

                    doc_type.and_then(|doc_type| {
                        // The real object is contained in the _source section.
                        obj.get("_source").and_then(|src| {
                            bragi::query::make_place(doc_type, Some(Box::new(src.clone())))
                        })
                    })
                })
            })
            .filter(predicate)
    }
}

fn launch_and_assert(
    cmd: &str,
    args: &[std::string::String],
    es_wrapper: &ElasticSearchWrapper<'_>,
) {
    let status = Command::new(cmd).args(args).status().unwrap();
    assert!(status.success(), "`{}` failed {}", cmd, &status);
    es_wrapper.refresh();
}

pub struct BragiHandler {
    app: actix_web::test::TestServer,
}

impl BragiHandler {
    pub fn new(url: String) -> BragiHandler {
        let make_server = move || {
            bragi::server::create_server(bragi::Context {
                es_cnx_string: url.clone(),
                max_es_timeout: None,
            })
        };

        BragiHandler {
            app: actix_web::test::TestServer::with_factory(make_server),
        }
    }

    pub fn raw_get(&mut self, q: &str) -> Result<ClientResponse, Error> {
        self.app
            .execute(
                self.app
                    .client(actix_web::http::Method::GET, q)
                    .finish()
                    .map_err(|e| format_err!("invalid query: {}", e))?
                    .send(),
            )
            .map_err(|e| format_err!("impossible to query bragi: {}", e))
    }

    pub fn get(&mut self, q: &str) -> Vec<Map<String, Value>> {
        let r = self.raw_get(q).unwrap();
        assert!(r.status().is_success(), "invalid status: {}", r.status());
        self.get_results(r, Some("/properties/geocoding".to_string()))
    }

    pub fn get_json(&mut self, q: &str) -> Value {
        let r = self.raw_get(q).unwrap();
        assert!(r.status().is_success(), "invalid status: {}", r.status());
        self.to_json(r)
    }

    pub fn get_unchecked_json(&mut self, q: &str) -> (actix_web::http::StatusCode, Value) {
        let r = self.raw_get(q).unwrap();
        (r.status(), self.to_json(r))
    }

    pub fn raw_post_shape(
        &mut self,
        q: &str,
        shape: &'static str,
    ) -> Result<ClientResponse, Error> {
        self.app
            .execute(
                self.app
                    .client(actix_web::http::Method::POST, q)
                    .header(actix_web::http::header::CONTENT_TYPE, "application/json")
                    .body(shape)
                    .map_err(|e| format_err!("invalid query: {}", e))?
                    .send(),
            )
            .map_err(|e| format_err!("impossible to query bragi: {}", e))
    }

    pub fn post_shape(&mut self, q: &str, shape: &'static str) -> Vec<Map<String, Value>> {
        let r = self.raw_post_shape(q, shape).unwrap();
        self.get_results(r, Some("/properties/geocoding".to_string()))
    }

    pub fn to_json(&mut self, r: ClientResponse) -> Value {
        use actix_web::HttpMessage;
        let bytes = self.app.execute(r.body()).unwrap();
        let body = std::str::from_utf8(&bytes).unwrap();
        serde_json::from_str(body).unwrap()
    }

    pub fn get_results(
        &mut self,
        r: ClientResponse,
        pointer: Option<String>,
    ) -> Vec<Map<String, Value>> {
        self.to_json(r)
            .pointer("/features")
            .expect("wrongly formated bragi response")
            .as_array()
            .expect("features must be array")
            .iter()
            .map(|f| {
                if let Some(p) = &pointer {
                    f.pointer(&p)
                        .expect("no field in bragi response")
                        .as_object()
                        .unwrap()
                        .clone()
                } else {
                    f.as_object().unwrap().clone()
                }
            })
            .collect()
    }
}

pub fn get_values<'a>(r: &'a [Map<String, Value>], val: &'a str) -> Vec<&'a str> {
    r.iter().map(|e| get_value(e, val)).collect()
}

pub fn get_value<'a>(e: &'a Map<String, Value>, val: &str) -> &'a str {
    e.get(val).and_then(|l| l.as_str()).unwrap_or_else(|| "")
}

pub fn get_types(r: &[Map<String, Value>]) -> Vec<&str> {
    get_values(r, "type")
}

pub fn filter_by(r: &[Map<String, Value>], key: &str, t: &str) -> Vec<Map<String, Value>> {
    r.iter()
        .filter(|e| e.get(key).and_then(|l| l.as_str()).unwrap_or_else(|| "") == t)
        .cloned()
        .collect()
}

pub fn filter_by_type(r: &[Map<String, Value>], t: &str) -> Vec<Map<String, Value>> {
    filter_by(r, "type", t)
}

pub fn count_types(types: &[&str], value: &str) -> usize {
    types.iter().filter(|&t| *t == value).count()
}

fn get_poi_type_ids(e: &Map<String, Value>) -> Vec<&str> {
    let array = match e.get("poi_types").and_then(|json| json.as_array()) {
        None => return vec![],
        Some(array) => array,
    };
    array
        .iter()
        .filter_map(|v| v.as_object().and_then(|o| o.get("id")))
        .filter_map(|o| o.as_str())
        .collect()
}

fn get_first_index_aliases(indexes: &serde_json::Map<String, Value>) -> Vec<String> {
    indexes
        .get(indexes.keys().next().unwrap())
        .and_then(Value::as_object)
        .and_then(|s| s.get("aliases"))
        .and_then(Value::as_object)
        .map(|s| s.keys().cloned().collect())
        .unwrap_or_else(Vec::new)
}

/// Main test method (regroups all tests)
/// All tests are done sequentially,
/// and use the same docker in order to avoid multiple inits
/// (ES cleanup is handled by `es_wrapper`)
#[test]
fn all_tests() {
    let _guard = mimir::logger_init();
    let docker_wrapper = DockerWrapper::new().unwrap();

    // we call all tests here
    bano2mimir_test::bano2mimir_sample_test(ElasticSearchWrapper::new(&docker_wrapper));
    osm2mimir_test::osm2mimir_sample_test(ElasticSearchWrapper::new(&docker_wrapper));
    stops2mimir_test::stops2mimir_sample_test(ElasticSearchWrapper::new(&docker_wrapper));
    osm2mimir_bano2mimir_test::osm2mimir_bano2mimir_test(ElasticSearchWrapper::new(
        &docker_wrapper,
    ));
    rubber_test::rubber_zero_downtime_test(ElasticSearchWrapper::new(&docker_wrapper));
    rubber_test::rubber_custom_id(ElasticSearchWrapper::new(&docker_wrapper));
    rubber_test::rubber_ghost_index_cleanup(ElasticSearchWrapper::new(&docker_wrapper));
    rubber_test::rubber_empty_bulk(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_bano_test::bragi_bano_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_osm_test::bragi_osm_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_poi_test::test_i18n_poi(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_three_cities_test::bragi_three_cities_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_poi_test::bragi_poi_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_stops_test::bragi_stops_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_ntfs_test::bragi_ntfs_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_filter_types_test::bragi_filter_types_test(ElasticSearchWrapper::new(&docker_wrapper));
    bragi_synonyms_test::bragi_synonyms_test(ElasticSearchWrapper::new(&docker_wrapper));
    openaddresses2mimir_test::oa2mimir_simple_test(ElasticSearchWrapper::new(&docker_wrapper));
    cosmogony2mimir_test::cosmogony2mimir_test(ElasticSearchWrapper::new(&docker_wrapper));
    canonical_import_process_test::canonical_import_process_test(ElasticSearchWrapper::new(
        &docker_wrapper,
    ));
    canonical_import_process_test::bragi_invalid_es_test(ElasticSearchWrapper::new(
        &docker_wrapper,
    ));
}
<|endoftext|>


<commit_before>use super::nums;
use eventual::*;
use std::sync::mpsc::channel;

#[test]
pub fn test_stream_successfully_sending_all_values() {
    let (tx, rx) = Stream::<usize, ()>::pair();

    tx.send(1)
        .and_then(|tx| {
            tx.send_all(nums::<()>(2, 5))
                .map_err(|_| unreachable!())
        })
        .and_then(|tx| tx.send(5))
        .fire();

    let vals: Vec<usize> = rx.iter().collect();
    assert_eq!(&[1, 2, 3, 4, 5], &vals);
}

#[test]
pub fn test_stream_producer_fails() {
    let (tx, src) = Stream::<i32, &'static str>::pair();

    // Populate the source
    tx.and_then(|tx| tx.send(2))
        .and_then(|tx| tx.send(3))
        .and_then(|tx| tx.fail("nope"))
        .fire();

    let (tx, dst) = Stream::<i32, &'static str>::pair();

    tx.send(1)
        .and_then(move |tx| {
            tx.send_all(src)
                .or_else(|(err, tx)| {
                    assert_eq!("nope", err);
                    tx.send(10)
                })
        })
        .fire();

    let vals: Vec<i32> = dst.iter().collect();
    assert_eq!(&[1, 2, 3, 10], &vals);
}

#[test]
pub fn test_stream_consumer_loses_interest() {
    let (seen, rx) = channel();
    let (tx, dst) = Stream::<usize, ()>::pair();

    let src = nums::<()>(1, 5).map(move |v| {
        seen.send(v).unwrap();
        v
    });

    let _ = tx.send_all(src);

    let vals: Vec<usize> = dst.take(3).iter().collect();
    assert_eq!(&[1, 2, 3], &vals);
    assert_eq!(vals, rx.iter().collect());
}

#[test]
pub fn test_future_send_success() {
    let (tx, rx) = Stream::<usize, ()>::pair();

    tx.send(1)
        .and_then(|tx| {
            tx.send_all(Future::<usize, ()>::of(2))
                .map_err(|_| unreachable!())
        })
        .and_then(|tx| tx.send(3))
        .fire();

    let vals: Vec<usize> = rx.iter().collect();
    assert_eq!(&[1, 2, 3], &vals);
}

#[test]
pub fn test_future_send_fail() {
    let (tx, rx) = Stream::<usize, &'static str>::pair();

    tx.send(1)
        .and_then(|tx| {
            tx.send_all(Future::error("nope"))
                .or_else(|(err, tx)| {
                    assert_eq!("nope", err);
                    tx.send(10)
                })
        })
        .and_then(|tx| tx.send(3))
        .fire();

    let vals: Vec<usize> = rx.iter().collect();
    assert_eq!(&[1, 10, 3], &vals);
}
<commit_msg>Track Rust master<commit_after>use super::nums;
use eventual::*;
use std::sync::mpsc::channel;

#[test]
pub fn test_stream_successfully_sending_all_values() {
    let (tx, rx) = Stream::<usize, ()>::pair();

    tx.send(1)
        .and_then(|tx| {
            tx.send_all(nums::<()>(2, 5))
                .map_err(|_| unreachable!())
        })
        .and_then(|tx| tx.send(5))
        .fire();

    let vals: Vec<usize> = rx.iter().collect();
    assert_eq!(&[1, 2, 3, 4, 5], &vals);
}

#[test]
pub fn test_stream_producer_fails() {
    let (tx, src) = Stream::<i32, &'static str>::pair();

    // Populate the source
    tx.and_then(|tx| tx.send(2))
        .and_then(|tx| tx.send(3))
        .and_then(|tx| tx.fail("nope"))
        .fire();

    let (tx, dst) = Stream::<i32, &'static str>::pair();

    tx.send(1)
        .and_then(move |tx| {
            tx.send_all(src)
                .or_else(|(err, tx)| {
                    assert_eq!("nope", err);
                    tx.send(10)
                })
        })
        .fire();

    let vals: Vec<i32> = dst.iter().collect();
    assert_eq!(&[1, 2, 3, 10], &vals);
}

#[test]
pub fn test_stream_consumer_loses_interest() {
    let (seen, rx) = channel();
    let (tx, dst) = Stream::<usize, ()>::pair();

    let src = nums::<()>(1, 5).map(move |v| {
        seen.send(v).unwrap();
        v
    });

    let _ = tx.send_all(src);

    let vals: Vec<usize> = dst.take(3).iter().collect();
    assert_eq!(&[1, 2, 3], &vals);

    let vals: Vec<usize> = rx.iter().collect();
    assert_eq!(&[1, 2, 3], &vals);
}

#[test]
pub fn test_future_send_success() {
    let (tx, rx) = Stream::<usize, ()>::pair();

    tx.send(1)
        .and_then(|tx| {
            tx.send_all(Future::<usize, ()>::of(2))
                .map_err(|_| unreachable!())
        })
        .and_then(|tx| tx.send(3))
        .fire();

    let vals: Vec<usize> = rx.iter().collect();
    assert_eq!(&[1, 2, 3], &vals);
}

#[test]
pub fn test_future_send_fail() {
    let (tx, rx) = Stream::<usize, &'static str>::pair();

    tx.send(1)
        .and_then(|tx| {
            tx.send_all(Future::error("nope"))
                .or_else(|(err, tx)| {
                    assert_eq!("nope", err);
                    tx.send(10)
                })
        })
        .and_then(|tx| tx.send(3))
        .fire();

    let vals: Vec<usize> = rx.iter().collect();
    assert_eq!(&[1, 10, 3], &vals);
}
<|endoftext|>


<commit_before>use super::behaviors::{TextAction, TextBehavior};

use crate::{api::prelude::*, prelude::*, proc_macros::*, themes::theme_orbtk::*};

// --- KEYS --
pub static STYLE_TEXT_BOX: &str = "text_box";
static ID_CURSOR: &str = "id_cursor";
// --- KEYS --

widget!(
    /// The `TextBox` widget represents a single line text input widget.
    ///
    /// * style: `text_box`
    TextBox: ActivateHandler,
    KeyDownHandler,
    TextInputHandler {
        /// Sets or shares the text property.
        text: String,

        /// Sets or shares the water_mark text property.
        water_mark: String,

        /// Sets or shares the text selection property.
        selection: TextSelection,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or shares the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the focused property.
        focused: bool,

        /// Sets or shares ta value that describes if the TextBox should lose focus on activation (enter).
        lose_focus_on_activation: bool,

        /// Used to request focus from outside. Set to `true` tor request focus.
        request_focus: bool,

        /// If set to `true` all character will be focused when the widget gets focus. Default is `true`
        select_all_on_focus: bool,

        /// Indicates if the widget is hovered by the mouse cursor.
        hover: bool
    }
);

impl Template for TextBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let text_block = TextBlock::new()
            .v_align("center")
            .h_align("start")
            .foreground(id)
            .text(id)
            .water_mark(id)
            .font(id)
            .font_size(id)
            .localizable(false)
            .build(ctx);

        let cursor = Cursor::new().id(ID_CURSOR).selection(id).build(ctx);

        let text_behavior = TextBehavior::new()
            .cursor(cursor.0)
            .target(id.0)
            .text_block(text_block.0)
            .focused(id)
            .font(id)
            .font_size(id)
            .lose_focus_on_activation(id)
            .select_all_on_focus(id)
            .request_focus(id)
            .text(id)
            .selection(id)
            .build(ctx);

        self.name("TextBox")
            .style(STYLE_TEXT_BOX)
            .text("")
            .foreground(colors::LINK_WATER_COLOR)
            .font_size(orbtk_fonts::FONT_SIZE_12)
            .font("Roboto-Regular")
            .selection(TextSelection::default())
            .padding(4.0)
            .background(colors::LYNCH_COLOR)
            .border_brush("transparent")
            .border_width(0.0)
            .border_radius(2.0)
            .min_width(128.0)
            .height(32.0)
            .focused(false)
            .lose_focus_on_activation(true)
            .select_all_on_focus(true)
            .child(text_behavior)
            .child(
                Container::new()
                    .background(id)
                    .border_radius(id)
                    .border_width(id)
                    .border_brush(id)
                    .padding(id)
                    .child(
                        Grid::new()
                            .clip(true)
                            .child(cursor)
                            .child(text_block)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_changed("text", move |ctx, _| {
                ctx.send_message(TextAction::ForceUpdate(false), text_behavior);
            })
    }
}
<commit_msg>orbtk_widgets: text_box: reorder properties<commit_after>use super::behaviors::{TextAction, TextBehavior};

use crate::{api::prelude::*, prelude::*, proc_macros::*, themes::theme_orbtk::*};

// --- KEYS --
pub static STYLE_TEXT_BOX: &str = "text_box";
static ID_CURSOR: &str = "id_cursor";
// --- KEYS --

widget!(
    /// The `TextBox` widget represents a single line text input widget.
    ///
    /// * style: `text_box`
    TextBox: ActivateHandler,
    KeyDownHandler,
    TextInputHandler {
        /// Sets or shares the text property.
        text: String,

        /// Sets or shares the water_mark text property.
        water_mark: String,

        /// Sets or shares the text selection property.
        selection: TextSelection,

        /// Sets or shares the foreground property.
        foreground: Brush,

        /// Sets or shares the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the background property.
        background: Brush,

        /// Sets or shares the border radius property.
        border_radius: f64,

        /// Sets or shares the border thickness property.
        border_width: Thickness,

        /// Sets or shares the border brush property.
        border_brush: Brush,

        /// Sets or shares the padding property.
        padding: Thickness,

        /// Sets or shares the focused property.
        focused: bool,

        /// Sets or shares ta value that describes if the TextBox should lose focus on activation (enter).
        lose_focus_on_activation: bool,

        /// Used to request focus from outside. Set to `true` tor request focus.
        request_focus: bool,

        /// If set to `true` all character will be focused when the widget gets focus. Default is `true`
        select_all_on_focus: bool,

        /// Indicates if the widget is hovered by the mouse cursor.
        hover: bool
    }
);

impl Template for TextBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        let text_block = TextBlock::new()
            .v_align("center")
            .h_align("start")
            .foreground(id)
            .text(id)
            .water_mark(id)
            .font(id)
            .font_size(id)
            .localizable(false)
            .build(ctx);

        let cursor = Cursor::new().id(ID_CURSOR).selection(id).build(ctx);

        let text_behavior = TextBehavior::new()
            .cursor(cursor.0)
            .target(id.0)
            .text_block(text_block.0)
            .focused(id)
            .font(id)
            .font_size(id)
            .lose_focus_on_activation(id)
            .select_all_on_focus(id)
            .request_focus(id)
            .text(id)
            .selection(id)
            .build(ctx);

        self.name("TextBox")
            .style(STYLE_TEXT_BOX)
            .background(colors::LYNCH_COLOR)
            .border_brush("transparent")
            .border_width(0.0)
            .border_radius(2.0)
            .focused(false)
	    .font_size(orbtk_fonts::FONT_SIZE_12)
	    .font("Roboto-Regular")
	    .foreground(colors::LINK_WATER_COLOR)
	    .height(32.0)
            .lose_focus_on_activation(true)
	    .min_width(128.0)
	    .padding(4.0)
            .select_all_on_focus(true)
	    .selection(TextSelection::default())
	    .text("")
            .child(text_behavior)
            .child(
                Container::new()
                    .background(id)
                    .border_radius(id)
                    .border_width(id)
                    .border_brush(id)
                    .padding(id)
                    .child(
                        Grid::new()
                            .clip(true)
                            .child(cursor)
                            .child(text_block)
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_changed("text", move |ctx, _| {
                ctx.send_message(TextAction::ForceUpdate(false), text_behavior);
            })
    }
}
<|endoftext|>


<commit_before>// Copyright © 2016, 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 osmpbfreader;
extern crate mimir;

use boundaries::{build_boundary, make_centroid};
use std::cell::Cell;
use std::collections::BTreeSet;
use itertools::Itertools;
use super::OsmPbfReader;
pub type StreetsVec = Vec<mimir::Street>;

#[derive(Debug)]
pub struct AdminMatcher {
    admin_levels: BTreeSet<u32>,
}

impl AdminMatcher {
    pub fn new(levels: BTreeSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("boundary").map_or(false, |v| v == "administrative") &&
                rel.tags.get("admin_level").map_or(false, |lvl| {
                    self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                })
            }
            _ => false,
        }
    }
}

pub fn administrative_regions(pbf: &mut OsmPbfReader, levels: BTreeSet<u32>) -> Vec<mimir::Admin> {
    let mut administrative_regions = Vec::<mimir::Admin>::new();
    let matcher = AdminMatcher::new(levels);
    info!("reading pbf...");
    let objects = pbf.get_objs_and_deps(|o| matcher.is_admin(o)).unwrap();
    info!("reading pbf done.");
    // load administratives regions
    for obj in objects.values() {
        if !matcher.is_admin(obj) {
            continue;
        }
        if let osmpbfreader::OsmObj::Relation(ref relation) = *obj {
            let level = relation.tags.get("admin_level").and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id.0,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id.0,
                          level);
                    continue;
                }
            };

            // admininstrative region without coordinates
            let coord_center = relation.refs
                .iter()
                .find(|r| r.role == "admin_centre")
                .and_then(|r| objects.get(&r.member))
                .and_then(|o| o.node())
                .map(|node| mimir::Coord::new(node.lat(), node.lon()));
            let (admin_id, insee_id) = match relation.tags.get("ref:INSEE") {
                Some(val) => {
                    (format!("admin:fr:{}", val.trim_left_matches('0')), val.trim_left_matches('0'))
                }
                None => (format!("admin:osm:{}", relation.id.0), ""),
            };

            let zip_code = relation.tags
                .get("addr:postcode")
                .or_else(|| relation.tags.get("postal_code"))
                .map_or("", |val| &val[..]);
            let zip_codes = zip_code.split(';').map(|s| s.to_string()).sorted();
            let boundary = build_boundary(relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                insee: insee_id.to_string(),
                level: level,
                name: name.to_string(),
                label: format!("{}{}", name.to_string(), format_zip_codes(&zip_codes)),
                zip_codes: zip_codes,
                weight: Cell::new(0),
                coord: coord_center.unwrap_or_else(|| make_centroid(&boundary)),
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    administrative_regions
}

pub fn compute_admin_weight(streets: &mut StreetsVec) {
    for st in streets {
        for admin in &mut st.administrative_regions {
            admin.weight.set(admin.weight.get() + 1);
        }
    }
}

fn format_zip_codes(zip_codes: &[String]) -> String {
    match zip_codes.len() {
        0 => "".to_string(),
        1 => format!(" ({})", zip_codes.first().unwrap()),
        _ => {
            format!(" ({}-{})",
                    zip_codes.first().unwrap(),
                    zip_codes.last().unwrap())
        }
    }
}
<commit_msg>osm: handle no zip cleanly<commit_after>// Copyright © 2016, 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 osmpbfreader;
extern crate mimir;

use boundaries::{build_boundary, make_centroid};
use std::cell::Cell;
use std::collections::BTreeSet;
use itertools::Itertools;
use super::OsmPbfReader;
pub type StreetsVec = Vec<mimir::Street>;

#[derive(Debug)]
pub struct AdminMatcher {
    admin_levels: BTreeSet<u32>,
}

impl AdminMatcher {
    pub fn new(levels: BTreeSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

    pub fn is_admin(&self, obj: &osmpbfreader::OsmObj) -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("boundary").map_or(false, |v| v == "administrative") &&
                rel.tags.get("admin_level").map_or(false, |lvl| {
                    self.admin_levels.contains(&lvl.parse::<u32>().unwrap_or(0))
                })
            }
            _ => false,
        }
    }
}

pub fn administrative_regions(pbf: &mut OsmPbfReader, levels: BTreeSet<u32>) -> Vec<mimir::Admin> {
    let mut administrative_regions = Vec::<mimir::Admin>::new();
    let matcher = AdminMatcher::new(levels);
    info!("reading pbf...");
    let objects = pbf.get_objs_and_deps(|o| matcher.is_admin(o)).unwrap();
    info!("reading pbf done.");
    // load administratives regions
    for obj in objects.values() {
        if !matcher.is_admin(obj) {
            continue;
        }
        if let osmpbfreader::OsmObj::Relation(ref relation) = *obj {
            let level = relation.tags.get("admin_level").and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id.0,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id.0,
                          level);
                    continue;
                }
            };

            // admininstrative region without coordinates
            let coord_center = relation.refs
                .iter()
                .find(|r| r.role == "admin_centre")
                .and_then(|r| objects.get(&r.member))
                .and_then(|o| o.node())
                .map(|node| mimir::Coord::new(node.lat(), node.lon()));
            let (admin_id, insee_id) = match relation.tags.get("ref:INSEE") {
                Some(val) => {
                    (format!("admin:fr:{}", val.trim_left_matches('0')), val.trim_left_matches('0'))
                }
                None => (format!("admin:osm:{}", relation.id.0), ""),
            };

            let zip_code = relation.tags
                .get("addr:postcode")
                .or_else(|| relation.tags.get("postal_code"))
                .map_or("", |val| &val[..]);
            let zip_codes = zip_code.split(';')
                .filter(|s| !s.is_empty())
                .map(|s| s.to_string())
                .sorted();
            let boundary = build_boundary(relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                insee: insee_id.to_string(),
                level: level,
                name: name.to_string(),
                label: format!("{}{}", name.to_string(), format_zip_codes(&zip_codes)),
                zip_codes: zip_codes,
                weight: Cell::new(0),
                coord: coord_center.unwrap_or_else(|| make_centroid(&boundary)),
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    administrative_regions
}

pub fn compute_admin_weight(streets: &mut StreetsVec) {
    for st in streets {
        for admin in &mut st.administrative_regions {
            admin.weight.set(admin.weight.get() + 1);
        }
    }
}

fn format_zip_codes(zip_codes: &[String]) -> String {
    match zip_codes.len() {
        0 => "".to_string(),
        1 => format!(" ({})", zip_codes.first().unwrap()),
        _ => {
            format!(" ({}-{})",
                    zip_codes.first().unwrap(),
                    zip_codes.last().unwrap())
        }
    }
}
<|endoftext|>


<commit_before>// You are likely to be eaten by a grue.

use std::{io, path, ptr, mem, ffi, slice, time};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::collections::BTreeMap;
use libc::{c_void, c_int, c_schar, c_uchar, size_t, uid_t, sysctl, sysctlnametomib,
           getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in6, AF_INET, AF_INET6};
use data::*;
use super::common::*;
use super::bsd;

pub struct PlatformImpl;

macro_rules! sysctl_mib {
    ($len:expr, $name:expr) => {
        {
            let mut mib: [c_int; $len] = [0; $len];
            let mut sz: size_t = mib.len();
            let s = ffi::CString::new($name).unwrap();
            unsafe { sysctlnametomib(s.as_ptr(), &mut mib[0], &mut sz) };
            mib
        }
    }
}

macro_rules! sysctl {
    ($mib:expr, $dataptr:expr, $size:expr, $shouldcheck:expr) => {
        {
            let mib = &$mib;
            let mut size = $size;
            if unsafe { sysctl(&mib[0], mib.len() as u32,
                               $dataptr as *mut _ as *mut c_void, &mut size, ptr::null(), 0) } != 0 && $shouldcheck {
                return Err(io::Error::new(io::ErrorKind::Other, "sysctl() failed"))
            }
            size
        }
    };
    ($mib:expr, $dataptr:expr, $size:expr) => {
        sysctl!($mib, $dataptr, $size, true)
    }
}

lazy_static! {
    static ref KERN_CP_TIMES: [c_int; 2] = sysctl_mib!(2, "kern.cp_times");
    static ref V_ACTIVE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_active_count");
    static ref V_INACTIVE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_inactive_count");
    static ref V_WIRE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_wire_count");
    static ref V_CACHE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_cache_count");
    static ref V_FREE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_free_count");
    static ref BATTERY_LIFE: [c_int; 4] = sysctl_mib!(4, "hw.acpi.battery.life");
    static ref BATTERY_TIME: [c_int; 4] = sysctl_mib!(4, "hw.acpi.battery.time");
    static ref ACLINE: [c_int; 3] = sysctl_mib!(3, "hw.acpi.acline");

    static ref CP_TIMES_SIZE: usize = {
        let mut size: usize = 0;
        unsafe { sysctl(&KERN_CP_TIMES[0], KERN_CP_TIMES.len() as u32,
                        ptr::null_mut(), &mut size, ptr::null(), 0) };
        size
    };
}

/// An implementation of `Platform` for FreeBSD.
/// See `Platform` for documentation.
impl Platform for PlatformImpl {
    #[inline(always)]
    fn new() -> Self {
        PlatformImpl
    }

    fn cpu_load(&self) -> io::Result<DelayedMeasurement<Vec<CPULoad>>> {
        let loads = try!(measure_cpu());
        Ok(DelayedMeasurement::new(
                Box::new(move || Ok(loads.iter()
                               .zip(try!(measure_cpu()).iter())
                               .map(|(prev, now)| (*now - prev).to_cpuload())
                               .collect::<Vec<_>>()))))
    }

    fn load_average(&self) -> io::Result<LoadAverage> {
        bsd::load_average()
    }

    fn memory(&self) -> io::Result<Memory> {
        let mut active: usize = 0; sysctl!(V_ACTIVE_COUNT, &mut active, mem::size_of::<usize>());
        let mut inactive: usize = 0; sysctl!(V_INACTIVE_COUNT, &mut inactive, mem::size_of::<usize>());
        let mut wired: usize = 0; sysctl!(V_WIRE_COUNT, &mut wired, mem::size_of::<usize>());
        let mut cache: usize = 0; sysctl!(V_CACHE_COUNT, &mut cache, mem::size_of::<usize>(), false);
        let mut free: usize = 0; sysctl!(V_FREE_COUNT, &mut free, mem::size_of::<usize>());
        let pmem = PlatformMemory {
            active: ByteSize::kib(active << *bsd::PAGESHIFT),
            inactive: ByteSize::kib(inactive << *bsd::PAGESHIFT),
            wired: ByteSize::kib(wired << *bsd::PAGESHIFT),
            cache: ByteSize::kib(cache << *bsd::PAGESHIFT),
            free: ByteSize::kib(free << *bsd::PAGESHIFT),
        };
        Ok(Memory {
            total: pmem.active + pmem.inactive + pmem.wired + pmem.cache + pmem.free,
            free: pmem.inactive + pmem.cache + pmem.free,
            platform_memory: pmem,
        })
    }

    fn battery_life(&self) -> io::Result<BatteryLife> {
        let mut life: usize = 0; sysctl!(BATTERY_LIFE, &mut life, mem::size_of::<usize>());
        let mut time: i32 = 0; sysctl!(BATTERY_TIME, &mut time, mem::size_of::<i32>());
        Ok(BatteryLife {
            remaining_capacity: life as f32 / 100.0,
            remaining_time: time::Duration::from_secs(if time < 0 { 0 } else { time as u64 }),
        })
    }

    fn on_ac_power(&self) -> io::Result<bool> {
        let mut on: usize = 0; sysctl!(ACLINE, &mut on, mem::size_of::<usize>());
        Ok(on == 1)
    }

    fn mounts(&self) -> io::Result<Vec<Filesystem>> {
        let mut mptr: *mut statfs = ptr::null_mut();
        let len = unsafe { getmntinfo(&mut mptr, 1 as i32) };
        if len < 1 {
            return Err(io::Error::new(io::ErrorKind::Other, "getmntinfo() failed"))
        }
        let mounts = unsafe { slice::from_raw_parts(mptr, len as usize) };
        Ok(mounts.iter().map(|m| m.to_fs()).collect::<Vec<_>>())
    }

    fn mount_at<P: AsRef<path::Path>>(&self, path: P) -> io::Result<Filesystem> {
        let mut sfs: statfs = unsafe { mem::zeroed() };
        if unsafe { statfs(path.as_ref().to_string_lossy().as_ptr(), &mut sfs) } != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "statfs() failed"))
        }
        Ok(sfs.to_fs())
    }

    fn networks(&self) -> io::Result<BTreeMap<String, Network>> {
        let mut ifap: *mut ifaddrs = ptr::null_mut();
        if unsafe { getifaddrs(&mut ifap) } != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "getifaddrs() failed"))
        }
        let ifirst = ifap;
        let mut result = BTreeMap::new();
        while ifap != ptr::null_mut() {
            let ifa = unsafe { (*ifap) };
            let name = unsafe { ffi::CStr::from_ptr(ifa.ifa_name).to_string_lossy().into_owned() };
            let mut entry = result.entry(name.clone()).or_insert(Network {
                name: name,
                addrs: Vec::new(),
            });
            let addr = parse_addr(ifa.ifa_addr);
            if addr != IpAddr::Unsupported {
                entry.addrs.push(NetworkAddrs {
                    addr: addr,
                    netmask: parse_addr(ifa.ifa_netmask),
                });
            }
            ifap = unsafe { (*ifap).ifa_next };
        }
        unsafe { freeifaddrs(ifirst) };
        Ok(result)
    }
}

fn parse_addr(aptr: *const sockaddr) -> IpAddr {
    if aptr == ptr::null() {
        return IpAddr::Empty;
    }
    let addr = unsafe { *aptr };
    match addr.sa_family as i32 {
        AF_INET => IpAddr::V4(Ipv4Addr::new(addr.sa_data[2] as u8, addr.sa_data[3] as u8,
                                            addr.sa_data[4] as u8, addr.sa_data[5] as u8)),
        AF_INET6 => {
            // This is horrible.
            let addr6: *const sockaddr_in6 = unsafe { mem::transmute(aptr) };
            let mut a: [u8; 16] = unsafe { (*addr6).sin6_addr.s6_addr };
            &mut a[..].reverse();
            let a: [u16; 8] = unsafe { mem::transmute(a) };
            IpAddr::V6(Ipv6Addr::new(a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]))
        },
        _ => IpAddr::Unsupported,
    }
}

fn measure_cpu() -> io::Result<Vec<bsd::sysctl_cpu>> {
    let cpus = *CP_TIMES_SIZE / mem::size_of::<bsd::sysctl_cpu>();
    let mut data: Vec<bsd::sysctl_cpu> = Vec::with_capacity(cpus);
    unsafe { data.set_len(cpus) };
    sysctl!(KERN_CP_TIMES, &mut data[0], *CP_TIMES_SIZE);
    Ok(data)
}

#[repr(C)]
struct fsid_t {
    val: [i32; 2],
}

// FreeBSD's native struct. If you want to know what FreeBSD
// thinks about the POSIX statvfs struct, read man 3 statvfs :D
#[repr(C)]
struct statfs {
    f_version: u32,
    f_type: u32,
    f_flags: u64,
    f_bsize: u64,
    f_iosize: u64,
    f_blocks: u64,
    f_bfree: u64,
    f_bavail: i64,
    f_files: u64,
    f_ffree: i64,
    f_syncwrites: u64,
    f_asyncwrites: u64,
    f_syncreads: u64,
    f_asyncreads: u64,
    f_spare: [u64; 10],
    f_namemax: u32,
    f_owner: uid_t,
    f_fsid: fsid_t,
    f_charspare: [c_schar; 80],
    f_fstypename: [c_schar; 16],
    f_mntfromname: [c_schar; 88],
    f_mntonname: [c_schar; 88],
}

impl statfs {
    fn to_fs(&self) -> Filesystem {
        Filesystem {
            files: self.f_files as usize - self.f_ffree as usize,
            free: ByteSize::b(self.f_bfree as usize * self.f_bsize as usize),
            avail: ByteSize::b(self.f_bavail as usize * self.f_bsize as usize),
            total: ByteSize::b(self.f_blocks as usize * self.f_bsize as usize),
            name_max: self.f_namemax as usize,
            fs_type: unsafe { ffi::CStr::from_ptr(&self.f_fstypename[0]).to_string_lossy().into_owned() },
            fs_mounted_from: unsafe { ffi::CStr::from_ptr(&self.f_mntfromname[0]).to_string_lossy().into_owned() },
            fs_mounted_on: unsafe { ffi::CStr::from_ptr(&self.f_mntonname[0]).to_string_lossy().into_owned() },
        }
    }
}

#[link(name = "c")]
extern "C" {
    fn getloadavg(loadavg: *mut f64, nelem: c_int) -> c_int;
    fn getmntinfo(mntbufp: *mut *mut statfs, flags: c_int) -> c_int;
    fn statfs(path: *const c_uchar, buf: *mut statfs) -> c_int;
}
<commit_msg>remove extra extern<commit_after>// You are likely to be eaten by a grue.

use std::{io, path, ptr, mem, ffi, slice, time};
use std::net::{Ipv4Addr, Ipv6Addr};
use std::collections::BTreeMap;
use libc::{c_void, c_int, c_schar, c_uchar, size_t, uid_t, sysctl, sysctlnametomib,
           getifaddrs, freeifaddrs, ifaddrs, sockaddr, sockaddr_in6, AF_INET, AF_INET6};
use data::*;
use super::common::*;
use super::bsd;

pub struct PlatformImpl;

macro_rules! sysctl_mib {
    ($len:expr, $name:expr) => {
        {
            let mut mib: [c_int; $len] = [0; $len];
            let mut sz: size_t = mib.len();
            let s = ffi::CString::new($name).unwrap();
            unsafe { sysctlnametomib(s.as_ptr(), &mut mib[0], &mut sz) };
            mib
        }
    }
}

macro_rules! sysctl {
    ($mib:expr, $dataptr:expr, $size:expr, $shouldcheck:expr) => {
        {
            let mib = &$mib;
            let mut size = $size;
            if unsafe { sysctl(&mib[0], mib.len() as u32,
                               $dataptr as *mut _ as *mut c_void, &mut size, ptr::null(), 0) } != 0 && $shouldcheck {
                return Err(io::Error::new(io::ErrorKind::Other, "sysctl() failed"))
            }
            size
        }
    };
    ($mib:expr, $dataptr:expr, $size:expr) => {
        sysctl!($mib, $dataptr, $size, true)
    }
}

lazy_static! {
    static ref KERN_CP_TIMES: [c_int; 2] = sysctl_mib!(2, "kern.cp_times");
    static ref V_ACTIVE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_active_count");
    static ref V_INACTIVE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_inactive_count");
    static ref V_WIRE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_wire_count");
    static ref V_CACHE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_cache_count");
    static ref V_FREE_COUNT: [c_int; 4] = sysctl_mib!(4, "vm.stats.vm.v_free_count");
    static ref BATTERY_LIFE: [c_int; 4] = sysctl_mib!(4, "hw.acpi.battery.life");
    static ref BATTERY_TIME: [c_int; 4] = sysctl_mib!(4, "hw.acpi.battery.time");
    static ref ACLINE: [c_int; 3] = sysctl_mib!(3, "hw.acpi.acline");

    static ref CP_TIMES_SIZE: usize = {
        let mut size: usize = 0;
        unsafe { sysctl(&KERN_CP_TIMES[0], KERN_CP_TIMES.len() as u32,
                        ptr::null_mut(), &mut size, ptr::null(), 0) };
        size
    };
}

/// An implementation of `Platform` for FreeBSD.
/// See `Platform` for documentation.
impl Platform for PlatformImpl {
    #[inline(always)]
    fn new() -> Self {
        PlatformImpl
    }

    fn cpu_load(&self) -> io::Result<DelayedMeasurement<Vec<CPULoad>>> {
        let loads = try!(measure_cpu());
        Ok(DelayedMeasurement::new(
                Box::new(move || Ok(loads.iter()
                               .zip(try!(measure_cpu()).iter())
                               .map(|(prev, now)| (*now - prev).to_cpuload())
                               .collect::<Vec<_>>()))))
    }

    fn load_average(&self) -> io::Result<LoadAverage> {
        bsd::load_average()
    }

    fn memory(&self) -> io::Result<Memory> {
        let mut active: usize = 0; sysctl!(V_ACTIVE_COUNT, &mut active, mem::size_of::<usize>());
        let mut inactive: usize = 0; sysctl!(V_INACTIVE_COUNT, &mut inactive, mem::size_of::<usize>());
        let mut wired: usize = 0; sysctl!(V_WIRE_COUNT, &mut wired, mem::size_of::<usize>());
        let mut cache: usize = 0; sysctl!(V_CACHE_COUNT, &mut cache, mem::size_of::<usize>(), false);
        let mut free: usize = 0; sysctl!(V_FREE_COUNT, &mut free, mem::size_of::<usize>());
        let pmem = PlatformMemory {
            active: ByteSize::kib(active << *bsd::PAGESHIFT),
            inactive: ByteSize::kib(inactive << *bsd::PAGESHIFT),
            wired: ByteSize::kib(wired << *bsd::PAGESHIFT),
            cache: ByteSize::kib(cache << *bsd::PAGESHIFT),
            free: ByteSize::kib(free << *bsd::PAGESHIFT),
        };
        Ok(Memory {
            total: pmem.active + pmem.inactive + pmem.wired + pmem.cache + pmem.free,
            free: pmem.inactive + pmem.cache + pmem.free,
            platform_memory: pmem,
        })
    }

    fn battery_life(&self) -> io::Result<BatteryLife> {
        let mut life: usize = 0; sysctl!(BATTERY_LIFE, &mut life, mem::size_of::<usize>());
        let mut time: i32 = 0; sysctl!(BATTERY_TIME, &mut time, mem::size_of::<i32>());
        Ok(BatteryLife {
            remaining_capacity: life as f32 / 100.0,
            remaining_time: time::Duration::from_secs(if time < 0 { 0 } else { time as u64 }),
        })
    }

    fn on_ac_power(&self) -> io::Result<bool> {
        let mut on: usize = 0; sysctl!(ACLINE, &mut on, mem::size_of::<usize>());
        Ok(on == 1)
    }

    fn mounts(&self) -> io::Result<Vec<Filesystem>> {
        let mut mptr: *mut statfs = ptr::null_mut();
        let len = unsafe { getmntinfo(&mut mptr, 1 as i32) };
        if len < 1 {
            return Err(io::Error::new(io::ErrorKind::Other, "getmntinfo() failed"))
        }
        let mounts = unsafe { slice::from_raw_parts(mptr, len as usize) };
        Ok(mounts.iter().map(|m| m.to_fs()).collect::<Vec<_>>())
    }

    fn mount_at<P: AsRef<path::Path>>(&self, path: P) -> io::Result<Filesystem> {
        let mut sfs: statfs = unsafe { mem::zeroed() };
        if unsafe { statfs(path.as_ref().to_string_lossy().as_ptr(), &mut sfs) } != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "statfs() failed"))
        }
        Ok(sfs.to_fs())
    }

    fn networks(&self) -> io::Result<BTreeMap<String, Network>> {
        let mut ifap: *mut ifaddrs = ptr::null_mut();
        if unsafe { getifaddrs(&mut ifap) } != 0 {
            return Err(io::Error::new(io::ErrorKind::Other, "getifaddrs() failed"))
        }
        let ifirst = ifap;
        let mut result = BTreeMap::new();
        while ifap != ptr::null_mut() {
            let ifa = unsafe { (*ifap) };
            let name = unsafe { ffi::CStr::from_ptr(ifa.ifa_name).to_string_lossy().into_owned() };
            let mut entry = result.entry(name.clone()).or_insert(Network {
                name: name,
                addrs: Vec::new(),
            });
            let addr = parse_addr(ifa.ifa_addr);
            if addr != IpAddr::Unsupported {
                entry.addrs.push(NetworkAddrs {
                    addr: addr,
                    netmask: parse_addr(ifa.ifa_netmask),
                });
            }
            ifap = unsafe { (*ifap).ifa_next };
        }
        unsafe { freeifaddrs(ifirst) };
        Ok(result)
    }
}

fn parse_addr(aptr: *const sockaddr) -> IpAddr {
    if aptr == ptr::null() {
        return IpAddr::Empty;
    }
    let addr = unsafe { *aptr };
    match addr.sa_family as i32 {
        AF_INET => IpAddr::V4(Ipv4Addr::new(addr.sa_data[2] as u8, addr.sa_data[3] as u8,
                                            addr.sa_data[4] as u8, addr.sa_data[5] as u8)),
        AF_INET6 => {
            // This is horrible.
            let addr6: *const sockaddr_in6 = unsafe { mem::transmute(aptr) };
            let mut a: [u8; 16] = unsafe { (*addr6).sin6_addr.s6_addr };
            &mut a[..].reverse();
            let a: [u16; 8] = unsafe { mem::transmute(a) };
            IpAddr::V6(Ipv6Addr::new(a[7], a[6], a[5], a[4], a[3], a[2], a[1], a[0]))
        },
        _ => IpAddr::Unsupported,
    }
}

fn measure_cpu() -> io::Result<Vec<bsd::sysctl_cpu>> {
    let cpus = *CP_TIMES_SIZE / mem::size_of::<bsd::sysctl_cpu>();
    let mut data: Vec<bsd::sysctl_cpu> = Vec::with_capacity(cpus);
    unsafe { data.set_len(cpus) };
    sysctl!(KERN_CP_TIMES, &mut data[0], *CP_TIMES_SIZE);
    Ok(data)
}

#[repr(C)]
struct fsid_t {
    val: [i32; 2],
}

// FreeBSD's native struct. If you want to know what FreeBSD
// thinks about the POSIX statvfs struct, read man 3 statvfs :D
#[repr(C)]
struct statfs {
    f_version: u32,
    f_type: u32,
    f_flags: u64,
    f_bsize: u64,
    f_iosize: u64,
    f_blocks: u64,
    f_bfree: u64,
    f_bavail: i64,
    f_files: u64,
    f_ffree: i64,
    f_syncwrites: u64,
    f_asyncwrites: u64,
    f_syncreads: u64,
    f_asyncreads: u64,
    f_spare: [u64; 10],
    f_namemax: u32,
    f_owner: uid_t,
    f_fsid: fsid_t,
    f_charspare: [c_schar; 80],
    f_fstypename: [c_schar; 16],
    f_mntfromname: [c_schar; 88],
    f_mntonname: [c_schar; 88],
}

impl statfs {
    fn to_fs(&self) -> Filesystem {
        Filesystem {
            files: self.f_files as usize - self.f_ffree as usize,
            free: ByteSize::b(self.f_bfree as usize * self.f_bsize as usize),
            avail: ByteSize::b(self.f_bavail as usize * self.f_bsize as usize),
            total: ByteSize::b(self.f_blocks as usize * self.f_bsize as usize),
            name_max: self.f_namemax as usize,
            fs_type: unsafe { ffi::CStr::from_ptr(&self.f_fstypename[0]).to_string_lossy().into_owned() },
            fs_mounted_from: unsafe { ffi::CStr::from_ptr(&self.f_mntfromname[0]).to_string_lossy().into_owned() },
            fs_mounted_on: unsafe { ffi::CStr::from_ptr(&self.f_mntonname[0]).to_string_lossy().into_owned() },
        }
    }
}

#[link(name = "c")]
extern "C" {
    fn getmntinfo(mntbufp: *mut *mut statfs, flags: c_int) -> c_int;
    fn statfs(path: *const c_uchar, buf: *mut statfs) -> c_int;
}
<|endoftext|>


<commit_before>use irc::client::prelude::*;
use irc::error::Error as IrcError;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct KeepNick;

impl KeepNick {
    pub fn new() -> KeepNick {
        KeepNick {}
    }

    fn check_nick(&self, server: &IrcServer) -> Result<(), IrcError> {
        let cfg_nick = match server.config().nickname {
            Some(ref nick) => nick.clone(),
            None => return Ok(()),
        };

        let server_nick = server.current_nickname();

        if server_nick != cfg_nick {
            info!("Trying to switch nick from {} to {}", server_nick, cfg_nick);
            server.send(Command::NICK(cfg_nick))

        } else {
            Ok(())
        }
    }
}

impl Plugin for KeepNick {
    fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool {
        match message.command {
            Command::QUIT(_) => true,
            _ => false,
        }
    }

    fn execute(&self, server: &IrcServer, _: &Message) -> Result<(), IrcError> {
        self.check_nick(server)
    }

    fn command(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {
        server.send_notice(&command.source,
                           "This Plugin does not implement any commands.")
    }
}

#[cfg(test)]
mod tests {}
<commit_msg>Check who left before trying to get the nick<commit_after>use irc::client::prelude::*;
use irc::error::Error as IrcError;

use plugin::*;

#[derive(PluginName, Debug)]
pub struct KeepNick;

impl KeepNick {
    pub fn new() -> KeepNick {
        KeepNick {}
    }

    fn check_nick(&self, server: &IrcServer, leaver: &str) -> Result<(), IrcError> {
        let cfg_nick = match server.config().nickname {
            Some(ref nick) => nick.clone(),
            None => return Ok(()),
        };

        if leaver != cfg_nick {
            return Ok(());
        }

        let server_nick = server.current_nickname();

        if server_nick != cfg_nick {
            info!("Trying to switch nick from {} to {}", server_nick, cfg_nick);
            server.send(Command::NICK(cfg_nick))

        } else {
            Ok(())
        }
    }
}

impl Plugin for KeepNick {
    fn is_allowed(&self, _: &IrcServer, message: &Message) -> bool {
        match message.command {
            Command::QUIT(_) => true,
            _ => false,
        }
    }

    fn execute(&self, server: &IrcServer, message: &Message) -> Result<(), IrcError> {
        match message.command {
            Command::QUIT(ref nick) => {
                self.check_nick(server, &nick.clone().unwrap_or(String::from("")))
            }
            _ => Ok(()),
        }
    }

    fn command(&self, server: &IrcServer, command: PluginCommand) -> Result<(), IrcError> {
        server.send_notice(&command.source,
                           "This Plugin does not implement any commands.")
    }
}

#[cfg(test)]
mod tests {}
<|endoftext|>


<commit_before>//! Sphere primitives.
//!
//! # Examples
//!
//! ```rust
//! # extern crate decorum;
//! # extern crate nalgebra;
//! # extern crate plexus;
//! #
//! use decorum::N64;
//! use nalgebra::Point3;
//! use plexus::graph::MeshGraph;
//! use plexus::index::HashIndexer;
//! use plexus::prelude::*;
//! use plexus::primitive::sphere::UvSphere;
//!
//! # fn main() {
//! let mut graph = UvSphere::new(16, 8)
//!     .polygons_with_position::<Point3<N64>>()
//!     .collect_with_indexer::<MeshGraph<Point3<N64>>, _>(HashIndexer::default())
//!     .unwrap();
//! # }
//! ```

use decorum::Real;
use num::traits::FloatConst;
use num::{NumCast, One, ToPrimitive};
use std::cmp;
use theon::space::{EuclideanSpace, FiniteDimensional, Scalar};
use typenum::U3;

use crate::primitive::generate::{
    PolygonGenerator, PolygonsWithPosition, PositionGenerator, PositionIndexGenerator,
    PositionPolygonGenerator, PositionVertexGenerator, VerticesWithPosition,
};
use crate::primitive::Polygon;

#[derive(Clone, Copy)]
pub struct Bounds<S>
where
    S: EuclideanSpace,
{
    radius: Scalar<S>,
}

impl<S> Bounds<S>
where
    S: EuclideanSpace,
{
    pub fn with_radius(radius: Scalar<S>) -> Self {
        Bounds { radius }
    }

    pub fn with_width(width: Scalar<S>) -> Self {
        Self::with_radius(width / (Scalar::<S>::one() + One::one()))
    }

    pub fn unit_radius() -> Self {
        Self::with_radius(One::one())
    }

    pub fn unit_width() -> Self {
        Self::with_width(One::one())
    }
}

impl<S> Default for Bounds<S>
where
    S: EuclideanSpace,
{
    fn default() -> Self {
        Self::unit_radius()
    }
}

#[derive(Clone, Copy)]
pub struct UvSphere {
    nu: usize, // Meridians.
    nv: usize, // Parallels.
}

impl UvSphere {
    pub fn new(nu: usize, nv: usize) -> Self {
        UvSphere {
            nu: cmp::max(3, nu),
            nv: cmp::max(2, nv),
        }
    }

    fn vertex_with_position_from<S>(
        &self,
        state: &<Self as PositionGenerator<S>>::State,
        u: usize,
        v: usize,
    ) -> S
    where
        Self: PositionGenerator<S, State = Bounds<S>>,
        S: EuclideanSpace + FiniteDimensional<N = U3>,
        Scalar<S>: FloatConst,
    {
        let one = Scalar::<S>::one();
        let pi = Scalar::<S>::PI();
        let u = (into_scalar::<_, S>(u) / into_scalar::<_, S>(self.nu)) * pi * (one + one);
        let v = (into_scalar::<_, S>(v) / into_scalar::<_, S>(self.nv)) * pi;
        S::from_xyz(
            state.radius * u.cos() * v.sin(),
            state.radius * u.sin() * v.sin(),
            state.radius * v.cos(),
        )
    }

    fn index_for_position(&self, u: usize, v: usize) -> usize {
        if v == 0 {
            0
        }
        else if v == self.nv {
            ((self.nv - 1) * self.nu) + 1
        }
        else {
            ((v - 1) * self.nu) + (u % self.nu) + 1
        }
    }

    fn map_polygon_index(&self, index: usize) -> (usize, usize) {
        (index % self.nu, index / self.nu)
    }
}

impl Default for UvSphere {
    fn default() -> Self {
        UvSphere::new(16, 16)
    }
}

impl PolygonGenerator for UvSphere {
    fn polygon_count(&self) -> usize {
        self.nu * self.nv
    }
}

impl<S> PositionGenerator<S> for UvSphere
where
    S: EuclideanSpace + FiniteDimensional<N = U3>,
{
    type State = Bounds<S>;
}

impl<S> PositionVertexGenerator<S> for UvSphere
where
    S: EuclideanSpace + FiniteDimensional<N = U3>,
    Scalar<S>: FloatConst,
{
    fn vertex_with_position_from(&self, state: &Self::State, index: usize) -> S {
        let count = <Self as PositionVertexGenerator<S>>::vertex_with_position_count(self);
        if index == 0 {
            self.vertex_with_position_from::<S>(state, 0, 0)
        }
        else if index == (count - 1) {
            self.vertex_with_position_from::<S>(state, 0, self.nv)
        }
        else {
            let index = index - 1;
            self.vertex_with_position_from::<S>(state, index % self.nu, (index / self.nu) + 1)
        }
    }

    fn vertex_with_position_count(&self) -> usize {
        (self.nv - 1) * self.nu + 2
    }
}

impl<S> PositionPolygonGenerator<S> for UvSphere
where
    S: EuclideanSpace + FiniteDimensional<N = U3>,
    Scalar<S>: FloatConst,
{
    type Output = Polygon<S>;

    fn polygon_with_position_from(&self, state: &Self::State, index: usize) -> Self::Output {
        // Prevent floating point rounding errors by wrapping the incremented
        // values for `(u, v)` into `(p, q)`. This is important for indexing
        // geometry, because small differences in the computation of spatial
        // vertices will produce redundant output vertices. There should be
        // exactly `(nv - 1) * nu + 2` unique values of `(u, v)` used to
        // generate positions.
        //
        // There are two important observations:
        //
        //   1. `u` must wrap, but `v` need not. There are `nu` meridians of
        //      points and polygons, but there are `nv` parallels of polygons
        //      and `nv + 1` parallels of points.
        //   2. `u`, which represents a meridian, is meaningless at the poles,
        //      and can be normalized to zero.
        let (u, v) = self.map_polygon_index(index);
        let (p, q) = ((u + 1) % self.nu, v + 1);

        // Generate the vertices at the requested meridian and parallel. The
        // lower bound of `(u, v)` is always used, so compute that in advance
        // (`lower`). Emit triangles at the poles, otherwise quads.
        let lower = self.vertex_with_position_from(state, u, v);
        if v == 0 {
            Polygon::triangle(
                lower,
                self.vertex_with_position_from(state, u, q),
                self.vertex_with_position_from(state, p, q),
            )
        }
        else if v == self.nv - 1 {
            Polygon::triangle(
                // Normalize `u` at the pole, using `(0, nv)` in place of
                // `(p, q)`.
                self.vertex_with_position_from(state, 0, self.nv),
                self.vertex_with_position_from(state, p, v),
                lower,
            )
        }
        else {
            Polygon::quad(
                lower,
                self.vertex_with_position_from(state, u, q),
                self.vertex_with_position_from(state, p, q),
                self.vertex_with_position_from(state, p, v),
            )
        }
    }
}

impl PositionIndexGenerator for UvSphere {
    type Output = Polygon<usize>;

    fn index_for_position(&self, index: usize) -> Self::Output {
        let (u, v) = self.map_polygon_index(index);
        let (p, q) = (u + 1, v + 1);

        let low = self.index_for_position(u, v);
        let high = self.index_for_position(p, q);
        if v == 0 {
            Polygon::triangle(low, self.index_for_position(u, q), high)
        }
        else if v == self.nv - 1 {
            Polygon::triangle(high, self.index_for_position(p, v), low)
        }
        else {
            Polygon::quad(
                low,
                self.index_for_position(u, q),
                high,
                self.index_for_position(p, v),
            )
        }
    }
}

impl VerticesWithPosition for UvSphere {}

impl PolygonsWithPosition for UvSphere {}

fn into_scalar<T, S>(value: T) -> Scalar<S>
where
    T: ToPrimitive,
    S: EuclideanSpace,
{
    <Scalar<S> as NumCast>::from(value).unwrap()
}

#[cfg(test)]
mod tests {
    use nalgebra::Point3;
    use std::collections::BTreeSet;
    use std::iter::FromIterator;

    use crate::prelude::*;
    use crate::primitive::sphere::UvSphere;

    type E3 = Point3<f64>;

    #[test]
    fn vertex_count() {
        assert_eq!(
            5,
            UvSphere::new(3, 2)
                .vertices_with_position::<E3>() // 5 conjoint vertices.
                .count()
        );
    }

    #[test]
    fn polygon_vertex_count() {
        assert_eq!(
            18,
            UvSphere::new(3, 2)
                .polygons_with_position::<E3>() // 6 triangles, 18 vertices.
                .vertices()
                .count()
        );
    }

    #[test]
    fn position_index_to_vertex_mapping() {
        assert_eq!(
            5,
            BTreeSet::from_iter(
                UvSphere::new(3, 2)
                    .indices_for_position() // 18 vertices, 5 indices.
                    .vertices()
            )
            .len()
        )
    }
}
<commit_msg>Use conversions to construct `Polygon`s.<commit_after>//! Sphere primitives.
//!
//! # Examples
//!
//! ```rust
//! # extern crate decorum;
//! # extern crate nalgebra;
//! # extern crate plexus;
//! #
//! use decorum::N64;
//! use nalgebra::Point3;
//! use plexus::graph::MeshGraph;
//! use plexus::index::HashIndexer;
//! use plexus::prelude::*;
//! use plexus::primitive::sphere::UvSphere;
//!
//! # fn main() {
//! let mut graph = UvSphere::new(16, 8)
//!     .polygons_with_position::<Point3<N64>>()
//!     .collect_with_indexer::<MeshGraph<Point3<N64>>, _>(HashIndexer::default())
//!     .unwrap();
//! # }
//! ```

use decorum::Real;
use num::traits::FloatConst;
use num::{NumCast, One, ToPrimitive};
use std::cmp;
use theon::space::{EuclideanSpace, FiniteDimensional, Scalar};
use typenum::U3;

use crate::primitive::generate::{
    PolygonGenerator, PolygonsWithPosition, PositionGenerator, PositionIndexGenerator,
    PositionPolygonGenerator, PositionVertexGenerator, VerticesWithPosition,
};
use crate::primitive::{Polygon, Quad, Triangle};

#[derive(Clone, Copy)]
pub struct Bounds<S>
where
    S: EuclideanSpace,
{
    radius: Scalar<S>,
}

impl<S> Bounds<S>
where
    S: EuclideanSpace,
{
    pub fn with_radius(radius: Scalar<S>) -> Self {
        Bounds { radius }
    }

    pub fn with_width(width: Scalar<S>) -> Self {
        Self::with_radius(width / (Scalar::<S>::one() + One::one()))
    }

    pub fn unit_radius() -> Self {
        Self::with_radius(One::one())
    }

    pub fn unit_width() -> Self {
        Self::with_width(One::one())
    }
}

impl<S> Default for Bounds<S>
where
    S: EuclideanSpace,
{
    fn default() -> Self {
        Self::unit_radius()
    }
}

#[derive(Clone, Copy)]
pub struct UvSphere {
    nu: usize, // Meridians.
    nv: usize, // Parallels.
}

impl UvSphere {
    pub fn new(nu: usize, nv: usize) -> Self {
        UvSphere {
            nu: cmp::max(3, nu),
            nv: cmp::max(2, nv),
        }
    }

    fn vertex_with_position_from<S>(
        &self,
        state: &<Self as PositionGenerator<S>>::State,
        u: usize,
        v: usize,
    ) -> S
    where
        Self: PositionGenerator<S, State = Bounds<S>>,
        S: EuclideanSpace + FiniteDimensional<N = U3>,
        Scalar<S>: FloatConst,
    {
        let one = Scalar::<S>::one();
        let pi = Scalar::<S>::PI();
        let u = (into_scalar::<_, S>(u) / into_scalar::<_, S>(self.nu)) * pi * (one + one);
        let v = (into_scalar::<_, S>(v) / into_scalar::<_, S>(self.nv)) * pi;
        S::from_xyz(
            state.radius * u.cos() * v.sin(),
            state.radius * u.sin() * v.sin(),
            state.radius * v.cos(),
        )
    }

    fn index_for_position(&self, u: usize, v: usize) -> usize {
        if v == 0 {
            0
        }
        else if v == self.nv {
            ((self.nv - 1) * self.nu) + 1
        }
        else {
            ((v - 1) * self.nu) + (u % self.nu) + 1
        }
    }

    fn map_polygon_index(&self, index: usize) -> (usize, usize) {
        (index % self.nu, index / self.nu)
    }
}

impl Default for UvSphere {
    fn default() -> Self {
        UvSphere::new(16, 16)
    }
}

impl PolygonGenerator for UvSphere {
    fn polygon_count(&self) -> usize {
        self.nu * self.nv
    }
}

impl<S> PositionGenerator<S> for UvSphere
where
    S: EuclideanSpace + FiniteDimensional<N = U3>,
{
    type State = Bounds<S>;
}

impl<S> PositionVertexGenerator<S> for UvSphere
where
    S: EuclideanSpace + FiniteDimensional<N = U3>,
    Scalar<S>: FloatConst,
{
    fn vertex_with_position_from(&self, state: &Self::State, index: usize) -> S {
        let count = <Self as PositionVertexGenerator<S>>::vertex_with_position_count(self);
        if index == 0 {
            self.vertex_with_position_from::<S>(state, 0, 0)
        }
        else if index == (count - 1) {
            self.vertex_with_position_from::<S>(state, 0, self.nv)
        }
        else {
            let index = index - 1;
            self.vertex_with_position_from::<S>(state, index % self.nu, (index / self.nu) + 1)
        }
    }

    fn vertex_with_position_count(&self) -> usize {
        (self.nv - 1) * self.nu + 2
    }
}

impl<S> PositionPolygonGenerator<S> for UvSphere
where
    S: EuclideanSpace + FiniteDimensional<N = U3>,
    Scalar<S>: FloatConst,
{
    type Output = Polygon<S>;

    fn polygon_with_position_from(&self, state: &Self::State, index: usize) -> Self::Output {
        // Prevent floating point rounding errors by wrapping the incremented
        // values for `(u, v)` into `(p, q)`. This is important for indexing
        // geometry, because small differences in the computation of spatial
        // vertices will produce redundant output vertices. There should be
        // exactly `(nv - 1) * nu + 2` unique values of `(u, v)` used to
        // generate positions.
        //
        // There are two important observations:
        //
        //   1. `u` must wrap, but `v` need not. There are `nu` meridians of
        //      points and polygons, but there are `nv` parallels of polygons
        //      and `nv + 1` parallels of points.
        //   2. `u`, which represents a meridian, is meaningless at the poles,
        //      and can be normalized to zero.
        let (u, v) = self.map_polygon_index(index);
        let (p, q) = ((u + 1) % self.nu, v + 1);

        // Generate the vertices at the requested meridian and parallel. The
        // lower bound of `(u, v)` is always used, so compute that in advance
        // (`lower`). Emit triangles at the poles, otherwise quads.
        let lower = self.vertex_with_position_from(state, u, v);
        if v == 0 {
            Triangle::new(
                lower,
                self.vertex_with_position_from(state, u, q),
                self.vertex_with_position_from(state, p, q),
            )
            .into()
        }
        else if v == self.nv - 1 {
            Triangle::new(
                // Normalize `u` at the pole, using `(0, nv)` in place of
                // `(p, q)`.
                self.vertex_with_position_from(state, 0, self.nv),
                self.vertex_with_position_from(state, p, v),
                lower,
            )
            .into()
        }
        else {
            Quad::new(
                lower,
                self.vertex_with_position_from(state, u, q),
                self.vertex_with_position_from(state, p, q),
                self.vertex_with_position_from(state, p, v),
            )
            .into()
        }
    }
}

impl PositionIndexGenerator for UvSphere {
    type Output = Polygon<usize>;

    fn index_for_position(&self, index: usize) -> Self::Output {
        let (u, v) = self.map_polygon_index(index);
        let (p, q) = (u + 1, v + 1);

        let low = self.index_for_position(u, v);
        let high = self.index_for_position(p, q);
        if v == 0 {
            Triangle::new(low, self.index_for_position(u, q), high).into()
        }
        else if v == self.nv - 1 {
            Triangle::new(high, self.index_for_position(p, v), low).into()
        }
        else {
            Quad::new(
                low,
                self.index_for_position(u, q),
                high,
                self.index_for_position(p, v),
            )
            .into()
        }
    }
}

impl VerticesWithPosition for UvSphere {}

impl PolygonsWithPosition for UvSphere {}

fn into_scalar<T, S>(value: T) -> Scalar<S>
where
    T: ToPrimitive,
    S: EuclideanSpace,
{
    <Scalar<S> as NumCast>::from(value).unwrap()
}

#[cfg(test)]
mod tests {
    use nalgebra::Point3;
    use std::collections::BTreeSet;
    use std::iter::FromIterator;

    use crate::prelude::*;
    use crate::primitive::sphere::UvSphere;

    type E3 = Point3<f64>;

    #[test]
    fn vertex_count() {
        assert_eq!(
            5,
            UvSphere::new(3, 2)
                .vertices_with_position::<E3>() // 5 conjoint vertices.
                .count()
        );
    }

    #[test]
    fn polygon_vertex_count() {
        assert_eq!(
            18,
            UvSphere::new(3, 2)
                .polygons_with_position::<E3>() // 6 triangles, 18 vertices.
                .vertices()
                .count()
        );
    }

    #[test]
    fn position_index_to_vertex_mapping() {
        assert_eq!(
            5,
            BTreeSet::from_iter(
                UvSphere::new(3, 2)
                    .indices_for_position() // 18 vertices, 5 indices.
                    .vertices()
            )
            .len()
        )
    }
}
<|endoftext|>


<commit_before>use rsh::State;

pub fn set(s: &mut State) -> i32 {

    let var_name = s.argv.get(1);
    let value = s.argv.get(2);

    if var_name.is_none() || value.is_none() {
        println!("set: not enough arguments to set");
        return 0;
    }

    let var = var_name.unwrap().clone();
    let val = value.unwrap().clone();

    s.variables.insert(var.to_string(), val.to_string());

    0
}

pub fn unset(s: &mut State) -> i32 {
    match s.argv.get(1) {
        Some(var) => {
            s.variables.remove(var);
            0
        }
        None => {
            println!("unset: not enough arguments");
            1
        }
    }
}

pub fn get(s: &mut State) -> i32 {
    match s.argv.get(1) {
        Some(var) => {
            s.variables
                .get(var)
                .map(|val| {
                    println!("{}", val);
                });

            0
        }
        None => {
            println!("get: not enough arguments");
            1
        }
    }
}
<commit_msg>update to use proper environment variables<commit_after>use std::env;

use rsh::State;

pub fn set(s: &mut State) -> i32 {

    let var_name = s.argv.get(1);
    let value = s.argv.get(2);

    if var_name.is_none() || value.is_none() {
        println!("set: not enough arguments to set");
        return 0;
    }

    let var = var_name.unwrap().clone();
    let val = value.unwrap().clone();

    env::set_var(var, val);

    0
}

pub fn unset(s: &mut State) -> i32 {
    match s.argv.get(1) {
        Some(var) => {
            env::remove_var(var);
            0
        }
        None => {
            println!("unset: not enough arguments");
            1
        }
    }
}

pub fn get(s: &mut State) -> i32 {
    match s.argv.get(1) {
        Some(var) => {
            if let Ok(val) = env::var(var) {
                println!("{}", val);
            }

            0
        }
        None => {
            println!("get: not enough arguments");
            1
        }
    }
}
<|endoftext|>