<commit_before>// FIXME Remove once not dev anymore
#![allow(dead_code, unused_imports)]
#[macro_use]
extern crate slog;
extern crate slog_term;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate hyper_tls;
extern crate time;

use std::env;
use std::io::{self, Write};

use serde::{Serialize, Serializer, Deserialize, Deserializer};
use futures::{Future, Stream};
use futures::future;
use slog::*;
use hyper::{Client, Uri, Method, Chunk, Error, StatusCode};
use hyper::header::{Authorization, Accept, UserAgent, qitem};
use hyper::client::{Request, Response, FutureResponse};
use hyper_tls::HttpsConnector;
use tokio_core::reactor::{Core, Handle};
mod utils;

///
/// 'Main' struct which have relevant parts which are use as core elements of the application
///
struct Main {
    core: Core,
    endpoint: HnNews,
    client: Client<hyper_tls::HttpsConnector>,
    logger: Logger,
}

fn create_main() -> Main {
    let logger = create_loggers();
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let client = configure_client(&handle);
    let endpoint = HnNews::build_default();
    let mut main = Main {
        core: core,
        endpoint: endpoint,
        client: client,
        logger: logger,
    };
    main
}
fn configure_client(handle: &Handle) -> Client<hyper_tls::HttpsConnector> {
    Client::configure()
        // Does not check the validity of certificate
        .connector(HttpsConnector::new(4, &handle))
        .build(&handle)
}

fn main() {
    let mut main = create_main();
    info!(&main.logger, "Application started");
    let response = get_top_story_ids(&mut main);
    println!("{}", response.unwrap());
}

fn get_comments_for_a_story(main: &mut Main, story_id: i32) {}

fn get_top_story_ids(main: &mut Main) -> Result<String, hyper::Error> {
    let logger = &main.logger; // These need to be here as otherwise it'll cause mutable<>immutable borrow error
    let endpoint = &main.endpoint;
    let client = &main.client;
    let work = request_top_story_ids(&client, &endpoint)
        .and_then(|res| {
            log_response_status(&logger, &endpoint.get_top_stories_path(), &res.status());
            res.body()
                .fold(Vec::new(), |mut v, chunk| {
                    v.extend(&chunk[..]);
                    future::ok::<_, Error>(v)
                })
        })
        .map(|chunks| String::from_utf8(chunks).unwrap());
    let result = main.core.run(work);
    result
}

fn get_item_by_id(item: &str, main: &mut Main) -> Result<HnItem, hyper::Error> {
    let logger = &main.logger; // These need to be here as otherwise it'll cause mutable<>immutable borrow error
    let endpoint = &main.endpoint;
    let client = &main.client;
    let work = request_item(&item, &client, &endpoint)
        .and_then(|res| {
            log_response_status(&logger, &endpoint.get_item_path(&item), &res.status());
            res.body()
                .fold(Vec::new(), |mut v, chunk| {
                    v.extend(&chunk[..]);
                    future::ok::<_, Error>(v)
                })
        })
        .map(|chunks| {
            let s = String::from_utf8(chunks).unwrap();
            let deserialized: HnItem = serde_json::from_str(&s).unwrap();
            deserialized
        });
    let result = main.core.run(work);
    result
}

fn log_response_status(logger: &Logger, url: &str, status: &StatusCode) {
    info!(logger,
          format!("Request to {} finished with status {}", url, status));
}

fn common_headers(req: &mut Request) {
    req.headers_mut().set(UserAgent::new("hyper"));
}
fn consume_request(client: &Client<hyper_tls::HttpsConnector>, request: Request) -> FutureResponse {
    client.request(request)
}

fn create_loggers() -> Logger {
    let drain = slog_term::streamer().build().fuse();
    let root_logger = Logger::root(drain, o!());
    root_logger
}

fn request_top_story_ids(client: &Client<hyper_tls::HttpsConnector>,
                         endpoints: &HnNews)
                         -> FutureResponse {
    let url = utils::parse_url_from_str(&endpoints.get_top_stories_path());
    let mut request = Request::new(Method::Get, url);
    common_headers(&mut request);
    client.request(request)
}
fn request_item(item: &str,
                client: &Client<hyper_tls::HttpsConnector>,
                endpoints: &HnNews)
                -> FutureResponse {
    let url = utils::parse_url_from_str(&endpoints.get_item_path(item));
    let mut request = Request::new(Method::Get, url);
    common_headers(&mut request);
    client.request(request)
}

struct HnNews {
    base_url: String,
    top_news_suffix: String,
    item_suffix: String,
    max_item_suffix: String,
    json_suffix: String,
}

impl HnNews {
    pub fn build_default() -> HnNews {
        let e = HnNews {
            base_url: String::from("https://hacker-news.firebaseio.com/v0/"),
            top_news_suffix: String::from("topstories"),
            item_suffix: String::from("item/"),
            max_item_suffix: String::from("maxitem"),
            json_suffix: String::from(".json"),
        };
        e
    }

    pub fn get_top_stories_path(&self) -> String {
        utils::combine_strings(vec![&self.base_url, &self.top_news_suffix, &self.json_suffix])
    }
    pub fn get_max_item_path(&self) -> String {
        utils::combine_strings(vec![&self.base_url, &self.max_item_suffix, &self.json_suffix])
    }
    pub fn get_item_path(&self, id: &str) -> String {
        utils::combine_strings(vec![&self.base_url, &self.item_suffix, id, &self.json_suffix])
    }
}

#[derive(Serialize)]
struct HnTopStories {
    values: Vec<i32>,
}

impl Deserialize for HnTopStories {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer
    {
        Deserialize::deserialize(deserializer).map(|arr: Vec<i32>| HnTopStories { values: arr })
    }
}

#[derive(Serialize, Deserialize)]
struct HnItem {
    by: String,
    descendants: i32,
    id: i32,
    kids: Vec<i32>,
    title: String,
    score: i32,
    time: f64,
    #[serde(rename(deserialize = "type"))]
    type_str: String,
    url: String,
}

#[derive(Serialize, Deserialize)]
struct HnUser {
    about: String,
    created: f64,
    id: String,
    karma: i32,
    submitted: Vec<i32>,
}

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

    #[test]
    fn hn_item_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/item.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnItem = serde_json::from_str(&contents).unwrap();
        assert_eq!(71, deserialized.descendants);
        assert_eq!("dhouston", deserialized.by);
        assert_eq!(8863, deserialized.id);
        assert_eq!(111, deserialized.score);
        assert_eq!(1175714200.0f64, deserialized.time);
        assert_eq!("My YC app: Dropbox - Throw away your USB drive",
                   deserialized.title);
        assert_eq!("story", deserialized.type_str);
        assert_eq!("http://www.getdropbox.com/u/2/screencast.html",
                   deserialized.url);
    }
    #[test]
    fn hn_top_stories_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/top-stories.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnTopStories = serde_json::from_str(&contents).unwrap();
        assert!(deserialized.values.len() > 3);
    }
    #[test]
    fn hn_user_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/user.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnUser = serde_json::from_str(&contents).unwrap();
        assert_eq!("This is a test", deserialized.about);
        assert_eq!(1173923446.0f64, deserialized.created);
        assert_eq!("jl", deserialized.id);
        assert_eq!(3496, deserialized.karma);
        assert!(deserialized.submitted.len() > 3);
    }

    #[test]
    fn request_item_test() {
        let mut main = create_main();
        let s = String::from("8000");
        let response = main.core.run(request_item(&s, &main.client, &main.endpoint)).unwrap();
        assert_eq!(StatusCode::Ok, response.status());
    }

}
<commit_msg>added tests for getter<commit_after>// FIXME Remove once not dev anymore
#![allow(dead_code, unused_imports)]
#[macro_use]
extern crate slog;
extern crate slog_term;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate hyper_tls;
extern crate time;

use std::env;
use std::io::{self, Write};

use serde::{Serialize, Serializer, Deserialize, Deserializer};
use futures::{Future, Stream};
use futures::future;
use slog::*;
use hyper::{Client, Uri, Method, Chunk, Error, StatusCode};
use hyper::header::{Authorization, Accept, UserAgent, qitem};
use hyper::client::{Request, Response, FutureResponse};
use hyper_tls::HttpsConnector;
use tokio_core::reactor::{Core, Handle};
mod utils;

///
/// 'Main' struct which have relevant parts which are use as core elements of the application
///
struct Main {
    core: Core,
    endpoint: HnNews,
    client: Client<hyper_tls::HttpsConnector>,
    logger: Logger,
}

fn create_main() -> Main {
    let logger = create_loggers();
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let client = configure_client(&handle);
    let endpoint = HnNews::build_default();
    let mut main = Main {
        core: core,
        endpoint: endpoint,
        client: client,
        logger: logger,
    };
    main
}
fn configure_client(handle: &Handle) -> Client<hyper_tls::HttpsConnector> {
    Client::configure()
        // Does not check the validity of certificate
        .connector(HttpsConnector::new(4, &handle))
        .build(&handle)
}

fn main() {
    let mut main = create_main();
    info!(&main.logger, "Application started");
    let response = get_top_story_ids(&mut main);
    println!("{}", response.unwrap());
}

fn get_comments_for_a_story(main: &mut Main, story_id: i32) {}

fn get_top_story_ids(main: &mut Main) -> Result<String, hyper::Error> {
    let logger = &main.logger; // These need to be here as otherwise it'll cause mutable<>immutable borrow error
    let endpoint = &main.endpoint;
    let client = &main.client;
    let work = request_top_story_ids(&client, &endpoint)
        .and_then(|res| {
            log_response_status(&logger, &endpoint.get_top_stories_path(), &res.status());
            res.body()
                .fold(Vec::new(), |mut v, chunk| {
                    v.extend(&chunk[..]);
                    future::ok::<_, Error>(v)
                })
        })
        .map(|chunks| String::from_utf8(chunks).unwrap());
    let result = main.core.run(work);
    result
}

fn get_item_by_id(item: &str, main: &mut Main) -> Result<HnItem, hyper::Error> {
    let logger = &main.logger; // These need to be here as otherwise it'll cause mutable<>immutable borrow error
    let endpoint = &main.endpoint;
    let client = &main.client;
    let work = request_item(&item, &client, &endpoint)
        .and_then(|res| {
            log_response_status(&logger, &endpoint.get_item_path(&item), &res.status());
            res.body()
                .fold(Vec::new(), |mut v, chunk| {
                    v.extend(&chunk[..]);
                    future::ok::<_, Error>(v)
                })
        })
        .map(|chunks| {
            let s = String::from_utf8(chunks).unwrap();
            let deserialized: HnItem = serde_json::from_str(&s).unwrap();
            deserialized
        });
    let result = main.core.run(work);
    result
}

fn log_response_status(logger: &Logger, url: &str, status: &StatusCode) {
    info!(logger,
          format!("Request to {} finished with status {}", url, status));
}

fn common_headers(req: &mut Request) {
    req.headers_mut().set(UserAgent::new("hyper"));
}
fn consume_request(client: &Client<hyper_tls::HttpsConnector>, request: Request) -> FutureResponse {
    client.request(request)
}

fn create_loggers() -> Logger {
    let drain = slog_term::streamer().build().fuse();
    let root_logger = Logger::root(drain, o!());
    root_logger
}

fn request_top_story_ids(client: &Client<hyper_tls::HttpsConnector>,
                         endpoints: &HnNews)
                         -> FutureResponse {
    let url = utils::parse_url_from_str(&endpoints.get_top_stories_path());
    let mut request = Request::new(Method::Get, url);
    common_headers(&mut request);
    client.request(request)
}
fn request_item(item: &str,
                client: &Client<hyper_tls::HttpsConnector>,
                endpoints: &HnNews)
                -> FutureResponse {
    let url = utils::parse_url_from_str(&endpoints.get_item_path(item));
    let mut request = Request::new(Method::Get, url);
    common_headers(&mut request);
    client.request(request)
}

struct HnNews {
    base_url: String,
    top_news_suffix: String,
    item_suffix: String,
    max_item_suffix: String,
    json_suffix: String,
}

impl HnNews {
    pub fn build_default() -> HnNews {
        let e = HnNews {
            base_url: String::from("https://hacker-news.firebaseio.com/v0/"),
            top_news_suffix: String::from("topstories"),
            item_suffix: String::from("item/"),
            max_item_suffix: String::from("maxitem"),
            json_suffix: String::from(".json"),
        };
        e
    }

    pub fn get_top_stories_path(&self) -> String {
        utils::combine_strings(vec![&self.base_url, &self.top_news_suffix, &self.json_suffix])
    }
    pub fn get_max_item_path(&self) -> String {
        utils::combine_strings(vec![&self.base_url, &self.max_item_suffix, &self.json_suffix])
    }
    pub fn get_item_path(&self, id: &str) -> String {
        utils::combine_strings(vec![&self.base_url, &self.item_suffix, id, &self.json_suffix])
    }
}

#[derive(Serialize)]
struct HnTopStories {
    values: Vec<i32>,
}

impl Deserialize for HnTopStories {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer
    {
        Deserialize::deserialize(deserializer).map(|arr: Vec<i32>| HnTopStories { values: arr })
    }
}

#[derive(Serialize, Deserialize)]
struct HnItem {
    by: String,
    #[serde(skip_serializing_if="Option::is_none")]
    descendants: Option<i32>,
    id: i32,
    #[serde(skip_serializing_if="Option::is_none")]
    kids: Option<Vec<i32>>,
    title: String,
    score: i32,
    time: f64,
    #[serde(rename(deserialize = "type"))]
    type_str: String,
    #[serde(skip_serializing_if="Option::is_none")]
    url: Option<String>,
}

#[derive(Serialize, Deserialize)]
struct HnUser {
    about: String,
    created: f64,
    id: String,
    karma: i32,
    submitted: Vec<i32>,
}

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

    #[test]
    fn hn_item_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/item.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnItem = serde_json::from_str(&contents).unwrap();
        assert_eq!(71, deserialized.descendants.unwrap());
        assert_eq!("dhouston", deserialized.by);
        assert_eq!(8863, deserialized.id);
        assert_eq!(111, deserialized.score);
        assert_eq!(1175714200.0f64, deserialized.time);
        assert_eq!("My YC app: Dropbox - Throw away your USB drive",
                   deserialized.title);
        assert_eq!("story", deserialized.type_str);
        assert_eq!("http://www.getdropbox.com/u/2/screencast.html",
                   deserialized.url.unwrap());
    }
    #[test]
    fn hn_top_stories_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/top-stories.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnTopStories = serde_json::from_str(&contents).unwrap();
        assert!(deserialized.values.len() > 3);
    }
    #[test]
    fn hn_user_serde_test() {
        use std::fs::File;
        use std::io::prelude::*;
        let mut contents = String::new();
        File::open("res/test/user.json")
            .and_then(|mut file| file.read_to_string(&mut contents))
            .unwrap();
        let deserialized: HnUser = serde_json::from_str(&contents).unwrap();
        assert_eq!("This is a test", deserialized.about);
        assert_eq!(1173923446.0f64, deserialized.created);
        assert_eq!("jl", deserialized.id);
        assert_eq!(3496, deserialized.karma);
        assert!(deserialized.submitted.len() > 3);
    }

    #[test]
    fn request_item_test() {
        let mut main = create_main();
        let s = String::from("8000");
        let response = main.core.run(request_item(&s, &main.client, &main.endpoint)).unwrap();
        assert_eq!(StatusCode::Ok, response.status());
    }

    #[test]
    fn get_item_by_id_test() {
        let mut main = create_main();
        let s = String::from("126809");
        let hnitem: HnItem = get_item_by_id(&s, &mut main).unwrap();
        assert!(hnitem.score != 0);
        assert!(hnitem.id != 0);
        assert!(!hnitem.type_str.is_empty());
        assert!(!hnitem.title.is_empty());
        assert_eq!(126809, hnitem.id);

    }
}
<|endoftext|>


<commit_before>use crate::action_client::comm_state_machine::{CommStateMachine, State};
use crate::goal_status::{GoalID, GoalState};
use crate::static_messages::MUTEX_LOCK_FAIL;
use crate::{Action, ResultBody};
use std::convert::TryInto;
use std::sync::{Arc, Mutex};

pub struct ClientGoalHandle<T: Action> {
    state_machine: Arc<Mutex<CommStateMachine<T>>>,
}

impl<T: Action> ClientGoalHandle<T> {
    pub(crate) fn new(state_machine: Arc<Mutex<CommStateMachine<T>>>) -> Self {
        Self { state_machine }
    }

    pub fn cancel(&self) {
        let mut state_machine = self.state_machine.lock().expect(MUTEX_LOCK_FAIL);
        let cancel_message = GoalID {
            stamp: rosrust::Time::new(),
            id: state_machine.action_goal().id.id.clone(),
        };
        state_machine.send_cancel(cancel_message);
        state_machine.transition_to(State::WaitingForCancelAck)
    }

    #[inline]
    pub fn comm_state(&self) -> State {
        self.state_machine.lock().expect(MUTEX_LOCK_FAIL).state()
    }

    #[inline]
    pub fn goal_status(&self) -> GoalState {
        self.state_machine
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .latest_goal_status()
            .status
            .try_into()
            .unwrap_or(GoalState::Lost)
    }

    #[inline]
    pub fn result(&self) -> Option<ResultBody<T>> {
        self.state_machine
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .latest_result()
            .as_ref()
            .map(|result| result.body.clone())
    }

    #[inline]
    pub fn get_terminal_state(&self) -> GoalState {
        let state_machine = self.state_machine.lock().expect(MUTEX_LOCK_FAIL);
        if state_machine.state() != State::Done {
            rosrust::ros_warn!(
                "Asking for the terminal state when we're in [{:?}]",
                state_machine.state(),
            );
        }
        let goal_state: GoalState = state_machine
            .latest_goal_status()
            .status
            .try_into()
            .unwrap_or(GoalState::Lost);
        match goal_state {
            GoalState::Preempted
            | GoalState::Succeeded
            | GoalState::Aborted
            | GoalState::Rejected
            | GoalState::Recalled
            | GoalState::Lost => goal_state,
            GoalState::Pending
            | GoalState::Active
            | GoalState::Preempting
            | GoalState::Recalling => {
                rosrust::ros_err!(
                    "Asking for a terminal state, but the goal status is {:?}",
                    goal_state
                );
                GoalState::Lost
            }
        }
    }
}
<commit_msg>Add missing method to client goal handle<commit_after>use crate::action_client::comm_state_machine::{CommStateMachine, State};
use crate::goal_status::{GoalID, GoalState};
use crate::static_messages::MUTEX_LOCK_FAIL;
use crate::{Action, ResultBody};
use std::convert::TryInto;
use std::sync::{Arc, Mutex};

pub struct ClientGoalHandle<T: Action> {
    state_machine: Arc<Mutex<CommStateMachine<T>>>,
}

impl<T: Action> ClientGoalHandle<T> {
    pub(crate) fn new(state_machine: Arc<Mutex<CommStateMachine<T>>>) -> Self {
        Self { state_machine }
    }

    pub fn cancel(&self) {
        let mut state_machine = self.state_machine.lock().expect(MUTEX_LOCK_FAIL);
        let cancel_message = GoalID {
            stamp: rosrust::Time::new(),
            id: state_machine.action_goal().id.id.clone(),
        };
        state_machine.send_cancel(cancel_message);
        state_machine.transition_to(State::WaitingForCancelAck)
    }

    #[inline]
    pub fn comm_state(&self) -> State {
        self.state_machine.lock().expect(MUTEX_LOCK_FAIL).state()
    }

    #[inline]
    pub fn goal_status(&self) -> GoalState {
        self.state_machine
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .latest_goal_status()
            .status
            .try_into()
            .unwrap_or(GoalState::Lost)
    }

    #[inline]
    pub fn goal_status_text(&self) -> String {
        self.state_machine
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .latest_goal_status()
            .text
            .clone()
    }

    #[inline]
    pub fn result(&self) -> Option<ResultBody<T>> {
        self.state_machine
            .lock()
            .expect(MUTEX_LOCK_FAIL)
            .latest_result()
            .as_ref()
            .map(|result| result.body.clone())
    }

    #[inline]
    pub fn get_terminal_state(&self) -> GoalState {
        let state_machine = self.state_machine.lock().expect(MUTEX_LOCK_FAIL);
        if state_machine.state() != State::Done {
            rosrust::ros_warn!(
                "Asking for the terminal state when we're in [{:?}]",
                state_machine.state(),
            );
        }
        let goal_state: GoalState = state_machine
            .latest_goal_status()
            .status
            .try_into()
            .unwrap_or(GoalState::Lost);
        match goal_state {
            GoalState::Preempted
            | GoalState::Succeeded
            | GoalState::Aborted
            | GoalState::Rejected
            | GoalState::Recalled
            | GoalState::Lost => goal_state,
            GoalState::Pending
            | GoalState::Active
            | GoalState::Preempting
            | GoalState::Recalling => {
                rosrust::ros_err!(
                    "Asking for a terminal state, but the goal status is {:?}",
                    goal_state
                );
                GoalState::Lost
            }
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use] extern crate log;
extern crate semver;
extern crate toml;

extern crate libimagrt;
#[macro_use] extern crate libimagstore;
extern crate libimagentrytag;

module_entry_path_mod!("notes", "0.1.0");

pub mod error;
pub mod note;
pub mod result;

<commit_msg>Enable lints<commit_after>#![deny(
    dead_code,
    non_camel_case_types,
    non_snake_case,
    path_statements,
    trivial_numeric_casts,
    unstable_features,
    unused_allocation,
    unused_import_braces,
    unused_imports,
    unused_must_use,
    unused_mut,
    unused_qualifications,
    while_true,
)]

#[macro_use] extern crate log;
extern crate semver;
extern crate toml;

extern crate libimagrt;
#[macro_use] extern crate libimagstore;
extern crate libimagentrytag;

module_entry_path_mod!("notes", "0.1.0");

pub mod error;
pub mod note;
pub mod result;

<|endoftext|>


<commit_before>use std::io::Write;
use std::io::stderr;

use log::{Log, LogLevel, LogRecord, LogMetadata};

pub struct ImagLogger {
    lvl: LogLevel,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            lvl: lvl,
        }
    }

}

impl Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            // TODO: This is just simple logging. Maybe we can enhance this lateron
            writeln!(stderr(), "[imag][{: <5}]: {}", record.level(), record.args());
        }
    }
}

<commit_msg>Make result used<commit_after>use std::io::Write;
use std::io::stderr;

use log::{Log, LogLevel, LogRecord, LogMetadata};

pub struct ImagLogger {
    lvl: LogLevel,
}

impl ImagLogger {

    pub fn new(lvl: LogLevel) -> ImagLogger {
        ImagLogger {
            lvl: lvl,
        }
    }

}

impl Log for ImagLogger {

    fn enabled(&self, metadata: &LogMetadata) -> bool {
        metadata.level() <= self.lvl
    }

    fn log(&self, record: &LogRecord) {
        if self.enabled(record.metadata()) {
            // TODO: This is just simple logging. Maybe we can enhance this lateron
            writeln!(stderr(), "[imag][{: <5}]: {}", record.level(), record.args()).ok();
        }
    }
}

<|endoftext|>


<commit_before>//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![allow(incomplete_features)]
#![feature(control_flow_enum)]
#![feature(in_band_lifetimes)]
#![feature(unboxed_closures)]
#![feature(generators)]
#![feature(generator_trait)]
#![feature(fn_traits)]
#![feature(min_specialization)]
#![feature(optin_builtin_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
#![feature(stmt_expr_attributes)]
#![feature(core_intrinsics)]
#![feature(test)]
#![feature(associated_type_bounds)]
#![feature(thread_id_value)]
#![feature(extend_one)]
#![feature(const_panic)]
#![feature(const_generics)]
#![feature(once_cell)]
#![allow(rustc::default_hash_types)]

#[macro_use]
extern crate tracing;
#[macro_use]
extern crate cfg_if;
#[macro_use]
extern crate rustc_macros;

#[inline(never)]
#[cold]
pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
    f()
}

#[macro_export]
macro_rules! likely {
    ($e:expr) => {
        #[allow(unused_unsafe)]
        {
            unsafe { std::intrinsics::likely($e) }
        }
    };
}

#[macro_export]
macro_rules! unlikely {
    ($e:expr) => {
        #[allow(unused_unsafe)]
        {
            unsafe { std::intrinsics::unlikely($e) }
        }
    };
}

pub mod base_n;
pub mod binary_search_util;
pub mod box_region;
pub mod captures;
pub mod const_cstr;
pub mod flock;
pub mod fx;
pub mod graph;
pub mod jobserver;
pub mod macros;
pub mod map_in_place;
pub mod obligation_forest;
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_c_str;
pub mod snapshot_map;
pub mod stable_map;
pub mod svh;
pub use ena::snapshot_vec;
pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
pub mod sharded;
pub mod stack;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub use ena::undo_log;
pub use ena::unify;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
    /// Forgets the function which prevents it from running.
    /// Ensure that the function owns no memory, otherwise it will be leaked.
    #[inline]
    pub fn disable(self) {
        std::mem::forget(self);
    }
}

impl<F: Fn()> Drop for OnDrop<F> {
    #[inline]
    fn drop(&mut self) {
        (self.0)();
    }
}

// See comments in src/librustc_middle/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
<commit_msg>Replace const_generics feature gate with min_const_generics<commit_after>//! Various data structures used by the Rust compiler. The intention
//! is that code in here should be not be *specific* to rustc, so that
//! it can be easily unit tested and so forth.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![allow(incomplete_features)]
#![feature(control_flow_enum)]
#![feature(in_band_lifetimes)]
#![feature(unboxed_closures)]
#![feature(generators)]
#![feature(generator_trait)]
#![feature(fn_traits)]
#![feature(min_specialization)]
#![feature(optin_builtin_traits)]
#![feature(nll)]
#![feature(allow_internal_unstable)]
#![feature(hash_raw_entry)]
#![feature(stmt_expr_attributes)]
#![feature(core_intrinsics)]
#![feature(test)]
#![feature(associated_type_bounds)]
#![feature(thread_id_value)]
#![feature(extend_one)]
#![feature(const_panic)]
#![feature(min_const_generics)]
#![feature(once_cell)]
#![allow(rustc::default_hash_types)]

#[macro_use]
extern crate tracing;
#[macro_use]
extern crate cfg_if;
#[macro_use]
extern crate rustc_macros;

#[inline(never)]
#[cold]
pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R {
    f()
}

#[macro_export]
macro_rules! likely {
    ($e:expr) => {
        #[allow(unused_unsafe)]
        {
            unsafe { std::intrinsics::likely($e) }
        }
    };
}

#[macro_export]
macro_rules! unlikely {
    ($e:expr) => {
        #[allow(unused_unsafe)]
        {
            unsafe { std::intrinsics::unlikely($e) }
        }
    };
}

pub mod base_n;
pub mod binary_search_util;
pub mod box_region;
pub mod captures;
pub mod const_cstr;
pub mod flock;
pub mod fx;
pub mod graph;
pub mod jobserver;
pub mod macros;
pub mod map_in_place;
pub mod obligation_forest;
pub mod owning_ref;
pub mod ptr_key;
pub mod sip128;
pub mod small_c_str;
pub mod snapshot_map;
pub mod stable_map;
pub mod svh;
pub use ena::snapshot_vec;
pub mod sorted_map;
pub mod stable_set;
#[macro_use]
pub mod stable_hasher;
pub mod sharded;
pub mod stack;
pub mod sync;
pub mod thin_vec;
pub mod tiny_list;
pub mod transitive_relation;
pub use ena::undo_log;
pub use ena::unify;
mod atomic_ref;
pub mod fingerprint;
pub mod profiling;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
pub mod frozen;
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;

pub struct OnDrop<F: Fn()>(pub F);

impl<F: Fn()> OnDrop<F> {
    /// Forgets the function which prevents it from running.
    /// Ensure that the function owns no memory, otherwise it will be leaked.
    #[inline]
    pub fn disable(self) {
        std::mem::forget(self);
    }
}

impl<F: Fn()> Drop for OnDrop<F> {
    #[inline]
    fn drop(&mut self) {
        (self.0)();
    }
}

// See comments in src/librustc_middle/lib.rs
#[doc(hidden)]
pub fn __noop_fix_for_27438() {}
<|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
use super::model;
use regex;
use rs_es;
use rs_es::query::Query as rs_q;
use rs_es::operations::search::SearchResult;
use rs_es::units as rs_u;
use mimir;
use serde_json;
use serde;

fn build_rs_client(cnx: &String) -> rs_es::Client {
    let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
    let cap = re.captures(&cnx).unwrap();
    let host = cap.name("host").unwrap().as_str();
    let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();

    rs_es::Client::new(&host, port)
}

/// takes a ES json blob and build a Place from it
/// it uses the _type field of ES to know which type of the Place enum to fill
pub fn make_place(doc_type: String, value: Option<Box<serde_json::Value>>) -> Option<mimir::Place> {
    value.and_then(|v| {
        fn convert<T: serde::Deserialize>(v: serde_json::Value,
                                          f: fn(T) -> mimir::Place)
                                          -> Option<mimir::Place> {
            serde_json::from_value::<T>(v)
                .map_err(|err| warn!("Impossible to load ES result: {}", err))
                .ok()
                .map(f)
        }
        match doc_type.as_ref() {
            "addr" => convert(*v, mimir::Place::Addr),
            "street" => convert(*v, mimir::Place::Street),
            "admin" => convert(*v, mimir::Place::Admin),
            "poi" => convert(*v, mimir::Place::Poi),
            "stop" => convert(*v, mimir::Place::Stop),
            _ => {
                warn!("unknown ES return value, _type field = {}", doc_type);
                None
            }
        }
    })
}

#[derive(Debug, Eq, PartialEq)]
enum MatchType {
    Prefix,
    Fuzzy,
}

fn build_query(q: &str,
               match_type: MatchType,
               coord: &Option<model::Coord>,
               shape: Option<Vec<rs_es::units::Location>>)
               -> rs_es::query::Query {
    use rs_es::query::functions::Function;
    // we order the type of object we want
    // Note: the addresses are boosted more because even if we don't want them first
    // because they are more severely filtered
    let boost_addr = rs_q::build_term("_type", "addr").with_boost(5000).build();
    let boost_admin = rs_q::build_term("_type", "admin").with_boost(3000).build();
    let boost_stop = rs_q::build_term("_type", "stop").with_boost(2000).build();

    let main_match_type = match match_type {
        MatchType::Prefix => "label.prefix",
        MatchType::Fuzzy => "label.ngram",
    };

    let boost_main_match_query = rs_q::build_multi_match(vec![main_match_type.to_string()],
                                                         q.to_string())
        .with_boost(100)
        .build();
    let boost_zipcode_match_query = rs_q::build_multi_match(vec!["zip_codes.prefix".to_string()],
                                                            q.to_string())
        .with_boost(500)
        .build();

    let mut should_query = vec![boost_addr,
                                boost_admin,
                                boost_stop,
                                boost_main_match_query,
                                boost_zipcode_match_query];

    // for fuzzy search we also search by the prefix index (with a greater boost than ngram)
    // to have better results
    if match_type == MatchType::Fuzzy {
        should_query.push(rs_q::build_match("label.prefix", q.to_string())
            .with_boost(1000)
            .build());
    }

    if let &Some(ref c) = coord {
        // if we have coordinate, we boost we result near this coordinate
        let boost_on_proximity =
            rs_q::build_function_score()
                .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
                .with_boost(500)
                .with_function(Function::build_decay("coord",
                                           rs_u::Location::LatLon(c.lat, c.lon),
                                           rs_u::Distance::new(50f64,
                                                               rs_u::DistanceUnit::Kilometer))
                                   .build_exp())
                .build();
        should_query.push(boost_on_proximity);
    } else {
        // if we don't have coords, we take the field `weight` into account
        let boost_on_weight = rs_q::build_function_score()
            .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
            .with_boost(300)
            .with_query(rs_q::build_match_all().build())
            .with_function(Function::build_field_value_factor("weight")
                .with_factor(1)
                .with_modifier(rs_es::query::functions::Modifier::Log1p)
                .build())
            .build();
        should_query.push(boost_on_weight);
    }

    let sub_query = rs_q::build_bool()
        .with_should(should_query)
        .build();

    use rs_es::query::{CombinationMinimumShouldMatch, MinimumShouldMatch};
    let min_match = |min, threshold| {
        CombinationMinimumShouldMatch::new(MinimumShouldMatch::from(min),
                                           MinimumShouldMatch::from(threshold))
    };

    let minimum_should_match = match match_type {
        MatchType::Prefix => {
            // when we search [0, 2] fields, we need to match 100% of them
            // when we search [3, 4] fields, we need to match 90% of them
            // when we search [5, +] fields, we only need to match 70% on them
            // this way if the input has more fields than the documents
            // (additional information like the country, the region, ...)
            // they can be ignored
            MinimumShouldMatch::from(vec![min_match(2, 90f64), min_match(4, 70f64)])
        }
        // for fuzzy search we lower our expectation and we accept 50% of token match
        MatchType::Fuzzy => MinimumShouldMatch::from(50f64),
    };

    let mut must = vec![rs_q::build_multi_match(vec![main_match_type.to_string(),
                                                     "zip_codes.prefix".to_string()],
                                                q.to_string())
                            .with_minimum_should_match(minimum_should_match)
                            .build()];

    if let Some(s) = shape {
        must.push(rs_q::build_geo_polygon("coord", s).build());
    }

    // filter to handle house number
    // we either want:
    // * to exactly match the document house_number
    // * or that the document has no house_number
    let filter = rs_q::build_bool()
        .with_should(vec![rs_q::build_bool()
                              .with_must_not(rs_q::build_exists("house_number").build())
                              .build(),
                          rs_q::build_match("house_number", q.to_string()).build()])
        .with_must(must)
        .build();

    rs_q::build_bool()
        .with_must(vec![sub_query])
        .with_filter(filter)
        .build()
}

fn make_indexes<'a>(all_data: bool,
                    pt_dataset_index: &'a String,
                    client: &mut rs_es::Client)
                    -> Vec<&'a str> {
    if all_data {
        return vec!["munin"];
    }

    let mut result: Vec<&str> = vec![];

    if !pt_dataset_index.is_empty() {
        if client.open_index(&pt_dataset_index).is_ok() {
            result.push(pt_dataset_index);
        }
    }
    if client.open_index(&"munin_geo_data".to_string()).is_ok() {
        result.push("munin_geo_data");
    }
    return result;
}

fn query(q: &str,
         pt_dataset: &Option<&str>,
         all_data: bool,
         cnx: &str,
         match_type: MatchType,
         offset: u64,
         limit: u64,
         coord: &Option<model::Coord>,
         shape: Option<Vec<rs_es::units::Location>>)
         -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    let query = build_query(q, match_type, coord, shape);

    let mut client = build_rs_client(&cnx.to_string());

    let pt_dataset_index = pt_dataset.map(|d| format!("munin_stop_{}", d))
        .unwrap_or("".to_string());
    let indexes = make_indexes(all_data, &pt_dataset_index, &mut client);

    let result: SearchResult<serde_json::Value> = try!(client.search_query()
        .with_indexes(&indexes)
        .with_query(&query)
        .with_from(offset)
        .with_size(limit)
        .send());

    debug!("{} documents found", result.hits.total);

    // for the moment rs-es does not handle enum Document,
    // so we need to convert the ES glob to a Place
    Ok(result.hits
        .hits
        .into_iter()
        .filter_map(|hit| make_place(hit.doc_type, hit.source))
        .collect())
}

pub fn autocomplete(q: &str,
                    pt_dataset: &Option<&str>,
                    all_data: bool,
                    offset: u64,
                    limit: u64,
                    coord: Option<model::Coord>,
                    cnx: &str,
                    shape: Option<Vec<(f64, f64)>>)
                    -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    fn make_shape(shape: &Option<Vec<(f64, f64)>>) -> Option<Vec<rs_es::units::Location>> {
        shape.as_ref().map(|v| v.iter().map(|&l| l.into()).collect())
    }

    // First we try a prety exact match on the prefix.
    // If there are no results then we do a new fuzzy search (matching ngrams)
    let results = try!(query(&q,
                             &pt_dataset,
                             all_data,
                             cnx,
                             MatchType::Prefix,
                             offset,
                             limit,
                             &coord,
                             make_shape(&shape)));
    if results.is_empty() {
        query(&q,
              &pt_dataset,
              all_data,
              cnx,
              MatchType::Fuzzy,
              offset,
              limit,
              &coord,
              make_shape(&shape))
    } else {
        Ok(results)
    }
}
<commit_msg>refactoring<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
use super::model;
use regex;
use rs_es;
use rs_es::query::Query as rs_q;
use rs_es::operations::search::SearchResult;
use rs_es::units as rs_u;
use mimir;
use serde_json;
use serde;

fn build_rs_client(cnx: &String) -> rs_es::Client {
    let re = regex::Regex::new(r"(?:https?://)?(?P<host>.+?):(?P<port>\d+)").unwrap();
    let cap = re.captures(&cnx).unwrap();
    let host = cap.name("host").unwrap().as_str();
    let port = cap.name("port").unwrap().as_str().parse::<u32>().unwrap();

    rs_es::Client::new(&host, port)
}

/// takes a ES json blob and build a Place from it
/// it uses the _type field of ES to know which type of the Place enum to fill
pub fn make_place(doc_type: String, value: Option<Box<serde_json::Value>>) -> Option<mimir::Place> {
    value.and_then(|v| {
        fn convert<T: serde::Deserialize>(v: serde_json::Value,
                                          f: fn(T) -> mimir::Place)
                                          -> Option<mimir::Place> {
            serde_json::from_value::<T>(v)
                .map_err(|err| warn!("Impossible to load ES result: {}", err))
                .ok()
                .map(f)
        }
        match doc_type.as_ref() {
            "addr" => convert(*v, mimir::Place::Addr),
            "street" => convert(*v, mimir::Place::Street),
            "admin" => convert(*v, mimir::Place::Admin),
            "poi" => convert(*v, mimir::Place::Poi),
            "stop" => convert(*v, mimir::Place::Stop),
            _ => {
                warn!("unknown ES return value, _type field = {}", doc_type);
                None
            }
        }
    })
}

#[derive(Debug, Eq, PartialEq)]
enum MatchType {
    Prefix,
    Fuzzy,
}

fn build_query(q: &str,
               match_type: MatchType,
               coord: &Option<model::Coord>,
               shape: Option<Vec<rs_es::units::Location>>)
               -> rs_es::query::Query {
    use rs_es::query::functions::Function;
    // we order the type of object we want
    // Note: the addresses are boosted more because even if we don't want them first
    // because they are more severely filtered
    let boost_addr = rs_q::build_term("_type", "addr").with_boost(5000).build();
    let boost_admin = rs_q::build_term("_type", "admin").with_boost(3000).build();
    let boost_stop = rs_q::build_term("_type", "stop").with_boost(2000).build();

    let main_match_type = match match_type {
        MatchType::Prefix => "label.prefix",
        MatchType::Fuzzy => "label.ngram",
    };

    let boost_main_match_query = rs_q::build_multi_match(vec![main_match_type.to_string()],
                                                         q.to_string())
        .with_boost(100)
        .build();
    let boost_zipcode_match_query = rs_q::build_multi_match(vec!["zip_codes.prefix".to_string()],
                                                            q.to_string())
        .with_boost(500)
        .build();

    let mut should_query = vec![boost_addr,
                                boost_admin,
                                boost_stop,
                                boost_main_match_query,
                                boost_zipcode_match_query];

    // for fuzzy search we also search by the prefix index (with a greater boost than ngram)
    // to have better results
    if match_type == MatchType::Fuzzy {
        should_query.push(rs_q::build_match("label.prefix", q.to_string())
            .with_boost(1000)
            .build());
    }

    if let &Some(ref c) = coord {
        // if we have coordinate, we boost we result near this coordinate
        let boost_on_proximity =
            rs_q::build_function_score()
                .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
                .with_boost(500)
                .with_function(Function::build_decay("coord",
                                           rs_u::Location::LatLon(c.lat, c.lon),
                                           rs_u::Distance::new(50f64,
                                                               rs_u::DistanceUnit::Kilometer))
                                   .build_exp())
                .build();
        should_query.push(boost_on_proximity);
    } else {
        // if we don't have coords, we take the field `weight` into account
        let boost_on_weight = rs_q::build_function_score()
            .with_boost_mode(rs_es::query::compound::BoostMode::Multiply)
            .with_boost(300)
            .with_query(rs_q::build_match_all().build())
            .with_function(Function::build_field_value_factor("weight")
                .with_factor(1)
                .with_modifier(rs_es::query::functions::Modifier::Log1p)
                .build())
            .build();
        should_query.push(boost_on_weight);
    }

    let sub_query = rs_q::build_bool()
        .with_should(should_query)
        .build();

    use rs_es::query::{CombinationMinimumShouldMatch, MinimumShouldMatch};
    let min_match = |min, threshold| {
        CombinationMinimumShouldMatch::new(MinimumShouldMatch::from(min),
                                           MinimumShouldMatch::from(threshold))
    };

    let minimum_should_match = match match_type {
        MatchType::Prefix => {
            // when we search [0, 2] fields, we need to match 100% of them
            // when we search [3, 4] fields, we need to match 90% of them
            // when we search [5, +] fields, we only need to match 70% on them
            // this way if the input has more fields than the documents
            // (additional information like the country, the region, ...)
            // they can be ignored
            MinimumShouldMatch::from(vec![min_match(2, 90f64), min_match(4, 70f64)])
        }
        // for fuzzy search we lower our expectation and we accept 50% of token match
        MatchType::Fuzzy => MinimumShouldMatch::from(50f64),
    };

    let mut must = vec![rs_q::build_multi_match(vec![main_match_type.to_string(),
                                                     "zip_codes.prefix".to_string()],
                                                q.to_string())
                            .with_minimum_should_match(minimum_should_match)
                            .build()];

    if let Some(s) = shape {
        must.push(rs_q::build_geo_polygon("coord", s).build());
    }

    // filter to handle house number
    // we either want:
    // * to exactly match the document house_number
    // * or that the document has no house_number
    let filter = rs_q::build_bool()
        .with_should(vec![rs_q::build_bool()
                              .with_must_not(rs_q::build_exists("house_number").build())
                              .build(),
                          rs_q::build_match("house_number", q.to_string()).build()])
        .with_must(must)
        .build();

    rs_q::build_bool()
        .with_must(vec![sub_query])
        .with_filter(filter)
        .build()
}

fn is_existing_index(client: &mut rs_es::Client, index: &String) -> bool {
    !index.is_empty() && client.open_index(&index).is_ok()
}
fn make_indexes<'a>(all_data: bool,
                    pt_dataset_index: &'a Option<String>,
                    client: &mut rs_es::Client)
                    -> Vec<&'a str> {
    if all_data {
        return vec!["munin"];
    }

    let mut result: Vec<&str> = vec![];
    if is_existing_index(client, &"munin_geo_data".to_string()) {
        result.push("munin_geo_data");
    }
    match *pt_dataset_index {
        Some(ref dataset) => {
            if is_existing_index(client, dataset) {
                result.push(dataset);
            }
                result
        },
        _ => result
    }

}

fn query(q: &str,
         pt_dataset: &Option<&str>,
         all_data: bool,
         cnx: &str,
         match_type: MatchType,
         offset: u64,
         limit: u64,
         coord: &Option<model::Coord>,
         shape: Option<Vec<rs_es::units::Location>>)
         -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    let query = build_query(q, match_type, coord, shape);

    let mut client = build_rs_client(&cnx.to_string());

    let pt_dataset_index = pt_dataset.map(|d| format!("munin_stop_{}", d));
    let indexes = make_indexes(all_data, &pt_dataset_index, &mut client);

    let result: SearchResult<serde_json::Value> = try!(client.search_query()
        .with_indexes(&indexes)
        .with_query(&query)
        .with_from(offset)
        .with_size(limit)
        .send());

    debug!("{} documents found", result.hits.total);

    // for the moment rs-es does not handle enum Document,
    // so we need to convert the ES glob to a Place
    Ok(result.hits
        .hits
        .into_iter()
        .filter_map(|hit| make_place(hit.doc_type, hit.source))
        .collect())
}

pub fn autocomplete(q: &str,
                    pt_dataset: &Option<&str>,
                    all_data: bool,
                    offset: u64,
                    limit: u64,
                    coord: Option<model::Coord>,
                    cnx: &str,
                    shape: Option<Vec<(f64, f64)>>)
                    -> Result<Vec<mimir::Place>, rs_es::error::EsError> {
    fn make_shape(shape: &Option<Vec<(f64, f64)>>) -> Option<Vec<rs_es::units::Location>> {
        shape.as_ref().map(|v| v.iter().map(|&l| l.into()).collect())
    }

    // First we try a prety exact match on the prefix.
    // If there are no results then we do a new fuzzy search (matching ngrams)
    let results = try!(query(&q,
                             &pt_dataset,
                             all_data,
                             cnx,
                             MatchType::Prefix,
                             offset,
                             limit,
                             &coord,
                             make_shape(&shape)));
    if results.is_empty() {
        query(&q,
              &pt_dataset,
              all_data,
              cnx,
              MatchType::Fuzzy,
              offset,
              limit,
              &coord,
              make_shape(&shape))
    } else {
        Ok(results)
    }
}
<|endoftext|>


<commit_before>//! Support for mock HTTP servers that verify pacts.

use pact_matching::models::*;
use pact_mock_server::*;
use pact_mock_server::matching::MatchResult;
use std::{
  fmt::Write as FmtWrite,
  env,
  io::{self, prelude::*},
  thread
};
use url::Url;
use futures::future::*;

/// This trait is implemented by types which allow us to start a mock server.
pub trait StartMockServer {
    /// Start a mock server running in a background thread.
    fn start_mock_server(&self) -> BackgroundMockServer;

    /// Asynchronously spawn a mock server onto the current tokio runtime.
    fn spawn_mock_server(&self) -> BoxFuture<'static, SpawnedMockServer>;
}

impl StartMockServer for Pact {
    fn start_mock_server(&self) -> BackgroundMockServer {
        BackgroundMockServer::new(self.clone())
    }

    fn spawn_mock_server(&self) -> BoxFuture<'static, SpawnedMockServer> {
        SpawnedMockServer::new(self.clone()).boxed()
    }
}

pub trait ValidatingMockServer {
    /// The URL of our mock server. You can make normal HTTP requests using this
    /// as the base URL.
    fn url(&self) -> &Url;

    /// Given a path string, return a URL pointing to that path on the mock
    /// server. If the `path` cannot be parsed as URL, **this function will
    /// panic**. For a non-panicking version, call `.url()` instead and build
    /// this path yourself.
    fn path<P: AsRef<str>>(&self, path: P) -> Url;

    /// Returns the current status of the mock server
    fn status(&self) -> Vec<MatchResult>;
}

struct InnerServer {
    // A description of our mock server, for use in error messages.
    description: String,
    // The URL of our mock server.
    url: Url,
    // The mock server instance
    mock_server: mock_server::MockServer,
    // The running server's asynchronous join handle
    server_handle: Option<tokio::task::JoinHandle<()>>,
}

impl InnerServer {
    fn new(
        mock_server: mock_server::MockServer,
        server_handle: tokio::task::JoinHandle<()>
    ) -> InnerServer {
        let description = format!("{}/{}", mock_server.pact.consumer.name, mock_server.pact.provider.name);
        let url_str = mock_server.url();
        InnerServer {
            description,
            url: url_str.parse().expect("invalid mock server URL"),
            mock_server,
            server_handle: Some(server_handle)
        }
    }

    // Initialize the inner mock server instance
    async fn init_mock_server(
        pact: Pact
    ) -> Result<(mock_server::MockServer, impl std::future::Future<Output = ()>), String> {
        mock_server::MockServer::new(
            "".into(),
            pact,
            ([0, 0, 0, 0], 0 as u16).into()
        ).await
    }

    /// Helper function called by our `drop` implementation. This basically exists
    /// so that it can return `Err(message)` whenever needed without making the
    /// flow control in `drop` ultra-complex.
    fn drop_helper(&mut self) -> Result<(), String> {
        // Look up any mismatches which occurred.
        let mismatches = self.mock_server.mismatches();

        if mismatches.is_empty() {
            // Success! Write out the generated pact file.
            self.mock_server.write_pact(&Some(env::var("PACT_OUTPUT_DIR").unwrap_or("target/pacts".to_owned())))
                .map_err(|err| format!("error writing pact: {}", err))?;
            Ok(())
        } else {
            // Failure. Format our errors.
            let mut msg = format!(
                "mock server {} failed verification:\n",
                self.description,
            );
            for mismatch in mismatches {
                match mismatch {
                    MatchResult::RequestMatch(_) => {
                        unreachable!("list of mismatches contains a match");
                    }
                    MatchResult::RequestMismatch(interaction, mismatches) => {
                        let _ = writeln!(
                            &mut msg,
                            "- interaction {:?}:",
                            interaction.description,
                        );
                        for m in mismatches {
                            let _ = writeln!(&mut msg, "  - {}", m.description());
                        }
                    }
                    MatchResult::RequestNotFound(request) => {
                        let _ = writeln!(&mut msg, "- received unexpected request:");
                        let _ = writeln!(&mut msg, "{:#?}", request);
                    }
                    MatchResult::MissingRequest(interaction) => {
                        let _ = writeln!(
                            &mut msg,
                            "- interaction {:?} expected, but never occurred",
                            interaction.description,
                        );
                        let _ = writeln!(&mut msg, "{:#?}", interaction.request);
                    }
                }
            }
            Err(msg)
        }
    }
}

pub struct BackgroundMockServer {
    inner: InnerServer,
    runtime: tokio::runtime::Runtime
}

impl BackgroundMockServer {
    /// Create a new mock server which handles requests as described in the
    /// pact, and runs in a background thread
    pub fn new(pact: Pact) -> BackgroundMockServer {
        let mut runtime = tokio::runtime::Builder::new()
            .threaded_scheduler()
            .num_threads(1)
            .enable_all()
            .build()
            .unwrap();

        let (mock_server, future) = runtime.block_on(InnerServer::init_mock_server(pact))
            .expect("error initializing mock server");

        let server_handle = runtime.spawn(future);

        BackgroundMockServer {
            inner: InnerServer::new(mock_server, server_handle),
            runtime,
        }
    }

    fn drop_helper(&mut self) -> Result<(), String> {
        let server_handle = self.inner.server_handle
            .take()
            .expect("Server was already shut down");
        self.inner.mock_server.shutdown().ok();

        self.runtime.block_on(server_handle).unwrap();

        self.inner.drop_helper()
    }
}

impl ValidatingMockServer for BackgroundMockServer {
    fn url(&self) -> &Url {
        &self.inner.url
    }

    fn path<P: AsRef<str>>(&self, path: P) -> Url {
        // We panic here because this a _test_ library, the `?` operator is
        // useless in tests, and filling up our test code with piles of `unwrap`
        // calls is ugly.
        self.inner.url.join(path.as_ref()).expect("could not parse URL")
    }

    fn status(&self) -> Vec<MatchResult> {
        self.inner.mock_server.mismatches()
    }
}

impl Drop for BackgroundMockServer {
    fn drop(&mut self) {
        let result = self.drop_helper();
        if let Err(msg) = result {
            panic_or_print_error(&msg);
        }
    }
}

///
/// A mock server version that is spawned onto the implicit current
/// tokio runtime, which is outside our control.
/// After use, the server must be explitcly and asynchronously disposed by a call to
/// shutdown(). If not, the runtime might end up deadlocked.
///
#[must_use = "Remember to call shutdown().await"]
pub struct SpawnedMockServer {
    inner: InnerServer
}

impl SpawnedMockServer {
    /// Asynchronously create and spawn a new mock server
    pub async fn new(pact: Pact) -> SpawnedMockServer {
        let (mock_server, future) = InnerServer::init_mock_server(pact)
            .await
            .expect("error initializing mock server");

        let server_handle = tokio::spawn(future);

        SpawnedMockServer {
            inner: InnerServer::new(mock_server, server_handle)
        }
    }

    /// Asynchronously shut down the server. Only needed for "spawned" mode.
    pub async fn shutdown(mut self) {
        self.inner.mock_server.shutdown().unwrap();
        if let Some(server_handle) = self.inner.server_handle.take() {
            server_handle.await.unwrap();
        }
    }

    fn drop_helper(&mut self) -> Result<(), String> {
        if self.inner.server_handle.is_some() {
            panic!("Running in spawned mode, the server should be shut down using shutdown().await");
        }
        self.inner.drop_helper()
    }
}

impl ValidatingMockServer for SpawnedMockServer {
    fn url(&self) -> &Url {
        &self.inner.url
    }

    fn path<P: AsRef<str>>(&self, path: P) -> Url {
        // We panic here because this a _test_ library, the `?` operator is
        // useless in tests, and filling up our test code with piles of `unwrap`
        // calls is ugly.
        self.inner.url.join(path.as_ref()).expect("could not parse URL")
    }

    fn status(&self) -> Vec<MatchResult> {
        self.inner.mock_server.mismatches()
    }
}

impl Drop for SpawnedMockServer {
    fn drop(&mut self) {
        let result = self.drop_helper();
        if let Err(msg) = result {
            panic_or_print_error(&msg);
        }
    }
}

/// Either panic with `msg`, or if we're already in the middle of a panic,
/// just print `msg` to standard error.
fn panic_or_print_error(msg: &str) {
    if thread::panicking() {
        // The current thread is panicking, so don't try to panic again, because
        // double panics don't print useful explanations of why the test failed.
        // Instead, just print to `stderr`. Ignore any errors, because there's
        // not much we can do if we can't panic and we can't write to `stderr`.
        let _ = writeln!(io::stderr(), "{}", msg);
    } else {
        panic!("{}", msg);
    }
}
<commit_msg>pact_consumer: Better mock server documentation<commit_after>//! Support for mock HTTP servers that verify pacts.

use pact_matching::models::*;
use pact_mock_server::*;
use pact_mock_server::matching::MatchResult;
use std::{
  fmt::Write as FmtWrite,
  env,
  io::{self, prelude::*},
  thread
};
use url::Url;
use futures::future::*;

/// This trait is implemented by types which allow us to start a mock server.
pub trait StartMockServer {
    /// Start a mock server running in a background thread.
    fn start_mock_server(&self) -> BackgroundMockServer;

    /// Asynchronously spawn a mock server onto the current tokio runtime.
    fn spawn_mock_server(&self) -> BoxFuture<'static, SpawnedMockServer>;
}

impl StartMockServer for Pact {
    fn start_mock_server(&self) -> BackgroundMockServer {
        BackgroundMockServer::new(self.clone())
    }

    fn spawn_mock_server(&self) -> BoxFuture<'static, SpawnedMockServer> {
        SpawnedMockServer::new(self.clone()).boxed()
    }
}

///
/// A trait for accessing the properties of a mock server.
///
pub trait ValidatingMockServer {
    /// The URL of our mock server. You can make normal HTTP requests using this
    /// as the base URL.
    fn url(&self) -> &Url;

    /// Given a path string, return a URL pointing to that path on the mock
    /// server. If the `path` cannot be parsed as URL, **this function will
    /// panic**. For a non-panicking version, call `.url()` instead and build
    /// this path yourself.
    fn path<P: AsRef<str>>(&self, path: P) -> Url;

    /// Returns the current status of the mock server
    fn status(&self) -> Vec<MatchResult>;
}

/// Inner struct for shared data and behaviour of mock servers
struct InnerServer {
    // A description of our mock server, for use in error messages.
    description: String,
    // The URL of our mock server.
    url: Url,
    // The mock server instance
    mock_server: mock_server::MockServer,
    // The running server's asynchronous join handle
    server_handle: Option<tokio::task::JoinHandle<()>>,
}

impl InnerServer {
    fn new(
        mock_server: mock_server::MockServer,
        server_handle: tokio::task::JoinHandle<()>
    ) -> InnerServer {
        let description = format!("{}/{}", mock_server.pact.consumer.name, mock_server.pact.provider.name);
        let url_str = mock_server.url();
        InnerServer {
            description,
            url: url_str.parse().expect("invalid mock server URL"),
            mock_server,
            server_handle: Some(server_handle)
        }
    }

    /// Initialize the inner mock server instance
    async fn init_mock_server(
        pact: Pact
    ) -> Result<(mock_server::MockServer, impl std::future::Future<Output = ()>), String> {
        mock_server::MockServer::new(
            "".into(),
            pact,
            ([0, 0, 0, 0], 0 as u16).into()
        ).await
    }

    /// Helper function called by our `drop` implementation. This basically exists
    /// so that it can return `Err(message)` whenever needed without making the
    /// flow control in `drop` ultra-complex.
    fn drop_helper(&mut self) -> Result<(), String> {
        // Look up any mismatches which occurred.
        let mismatches = self.mock_server.mismatches();

        if mismatches.is_empty() {
            // Success! Write out the generated pact file.
            self.mock_server.write_pact(&Some(env::var("PACT_OUTPUT_DIR").unwrap_or("target/pacts".to_owned())))
                .map_err(|err| format!("error writing pact: {}", err))?;
            Ok(())
        } else {
            // Failure. Format our errors.
            let mut msg = format!(
                "mock server {} failed verification:\n",
                self.description,
            );
            for mismatch in mismatches {
                match mismatch {
                    MatchResult::RequestMatch(_) => {
                        unreachable!("list of mismatches contains a match");
                    }
                    MatchResult::RequestMismatch(interaction, mismatches) => {
                        let _ = writeln!(
                            &mut msg,
                            "- interaction {:?}:",
                            interaction.description,
                        );
                        for m in mismatches {
                            let _ = writeln!(&mut msg, "  - {}", m.description());
                        }
                    }
                    MatchResult::RequestNotFound(request) => {
                        let _ = writeln!(&mut msg, "- received unexpected request:");
                        let _ = writeln!(&mut msg, "{:#?}", request);
                    }
                    MatchResult::MissingRequest(interaction) => {
                        let _ = writeln!(
                            &mut msg,
                            "- interaction {:?} expected, but never occurred",
                            interaction.description,
                        );
                        let _ = writeln!(&mut msg, "{:#?}", interaction.request);
                    }
                }
            }
            Err(msg)
        }
    }
}

///
/// A mock server running synchronously, in a background thread.
/// Convenient when used with synchronous code.
///
pub struct BackgroundMockServer {
    inner: InnerServer,
    runtime: tokio::runtime::Runtime
}

impl BackgroundMockServer {
    /// Create a new mock server which handles requests as described in the
    /// pact, and runs in a background thread
    pub fn new(pact: Pact) -> BackgroundMockServer {
        let mut runtime = tokio::runtime::Builder::new()
            .threaded_scheduler()
            .num_threads(1)
            .enable_all()
            .build()
            .unwrap();

        let (mock_server, future) = runtime.block_on(InnerServer::init_mock_server(pact))
            .expect("error initializing mock server");

        BackgroundMockServer {
            inner: InnerServer::new(mock_server, runtime.spawn(future)),
            runtime,
        }
    }

    fn drop_helper(&mut self) -> Result<(), String> {
        let server_handle = self.inner.server_handle
            .take()
            .expect("Server was already shut down");
        self.inner.mock_server.shutdown().ok();

        self.runtime.block_on(server_handle).unwrap();

        self.inner.drop_helper()
    }
}

impl ValidatingMockServer for BackgroundMockServer {
    fn url(&self) -> &Url {
        &self.inner.url
    }

    fn path<P: AsRef<str>>(&self, path: P) -> Url {
        // We panic here because this a _test_ library, the `?` operator is
        // useless in tests, and filling up our test code with piles of `unwrap`
        // calls is ugly.
        self.inner.url.join(path.as_ref()).expect("could not parse URL")
    }

    fn status(&self) -> Vec<MatchResult> {
        self.inner.mock_server.mismatches()
    }
}

impl Drop for BackgroundMockServer {
    fn drop(&mut self) {
        let result = self.drop_helper();
        if let Err(msg) = result {
            panic_or_print_error(&msg);
        }
    }
}

///
/// A mock server implementation that is spawned onto the implicit current
/// tokio runtime that drives the current unit test via tokio::test.
/// After use, the server must be explitcly and asynchronously disposed by a call to
/// shutdown(). If not, the test runtime might end up deadlocked.
///
#[must_use = "Remember to call shutdown().await"]
pub struct SpawnedMockServer {
    inner: InnerServer
}

impl SpawnedMockServer {
    /// Asynchronously create and spawn a new mock server
    pub async fn new(pact: Pact) -> SpawnedMockServer {
        let (mock_server, future) = InnerServer::init_mock_server(pact)
            .await
            .expect("error initializing mock server");

        SpawnedMockServer {
            inner: InnerServer::new(mock_server, tokio::spawn(future))
        }
    }

    /// Asynchronously shut down the server.
    /// This is necessary before the test runtime gets destroyed.
    /// The reason is that the mock server is spawned as a background task.
    /// When the tokio test runtime tries to shut down, it will wait for
    /// all its running tasks to complete. Only by first awaiting the server's
    /// JoinHandle can the shutdown procedure be properly executed.
    pub async fn shutdown(mut self) {
        // Send the server shutdown signal
        self.inner.mock_server.shutdown().unwrap();

        let server_handle = self.inner.server_handle
            .take()
            .expect("Server was already shut down");

        // Await the running server's task's join handle
        server_handle.await.unwrap();
    }

    fn drop_helper(&mut self) -> Result<(), String> {
        if self.inner.server_handle.is_some() {
            panic!("Running in spawned mode, the server should be shut down using shutdown().await");
        }
        self.inner.drop_helper()
    }
}

impl ValidatingMockServer for SpawnedMockServer {
    fn url(&self) -> &Url {
        &self.inner.url
    }

    fn path<P: AsRef<str>>(&self, path: P) -> Url {
        // We panic here because this a _test_ library, the `?` operator is
        // useless in tests, and filling up our test code with piles of `unwrap`
        // calls is ugly.
        self.inner.url.join(path.as_ref()).expect("could not parse URL")
    }

    fn status(&self) -> Vec<MatchResult> {
        self.inner.mock_server.mismatches()
    }
}

impl Drop for SpawnedMockServer {
    fn drop(&mut self) {
        let result = self.drop_helper();
        if let Err(msg) = result {
            panic_or_print_error(&msg);
        }
    }
}

/// Either panic with `msg`, or if we're already in the middle of a panic,
/// just print `msg` to standard error.
fn panic_or_print_error(msg: &str) {
    if thread::panicking() {
        // The current thread is panicking, so don't try to panic again, because
        // double panics don't print useful explanations of why the test failed.
        // Instead, just print to `stderr`. Ignore any errors, because there's
        // not much we can do if we can't panic and we can't write to `stderr`.
        let _ = writeln!(io::stderr(), "{}", msg);
    } else {
        panic!("{}", msg);
    }
}
<|endoftext|>


<commit_before>//! Code to trace out a single lane, collecting information into the
//! lane table as we go.

use collections::Set;
use grammar::repr::*;
use lr1::core::*;
use lr1::first::FirstSets;
use lr1::lookahead::*;
use lr1::state_graph::StateGraph;

use super::table::{ConflictIndex, LaneTable};

pub struct LaneTracer<'trace, 'grammar: 'trace> {
    grammar: &'grammar Grammar,
    states: &'trace [LR0State<'grammar>],
    first_sets: FirstSets,
    state_graph: StateGraph,
    table: LaneTable<'grammar>,
}

impl<'trace, 'grammar> LaneTracer<'trace, 'grammar> {
    pub fn new(grammar: &'grammar Grammar,
               states: &'trace [LR0State<'grammar>],
               conflicts: usize)
               -> Self {
        LaneTracer {
            grammar: grammar,
            states: states,
            first_sets: FirstSets::new(grammar),
            state_graph: StateGraph::new(states),
            table: LaneTable::new(grammar, conflicts),
        }
    }

    pub fn into_table(self) -> LaneTable<'grammar> {
        self.table
    }

    pub fn start_trace(&mut self,
                       state: StateIndex,
                       conflict: ConflictIndex,
                       item: LR0Item<'grammar>) {
        let mut visited_set = Set::default();
        self.continue_trace(state, conflict, item, &mut visited_set);
    }

    fn continue_trace(&mut self,
                      state: StateIndex,
                      conflict: ConflictIndex,
                      item: LR0Item<'grammar>,
                      visited: &mut Set<(StateIndex, LR0Item<'grammar>)>) {
        if !visited.insert((state, item)) {
            return;
        }

        if item.index > 0 {
            // This item was reached by shifting some symbol.  We need
            // to unshift that symbol, which means we walk backwards
            // to predecessors of `state` in the state graph.
            //
            // Example:
            //
            //     X = ...p T (*) ...s
            //
            // Here we would be "unshifting" T, which means we will
            // walk to predecessors of the current state that were
            // reached by shifting T. Those predecessors will contain
            // an item like `X = ...p (*) T ...s`, which we will then
            // process in turn.
            let shifted_symbol = item.production.symbols[item.index - 1];
            let unshifted_item = Item { index: item.index - 1, ..item };
            let predecessors = self.state_graph.predecessors(state, shifted_symbol);
            for predecessor in predecessors {
                self.table.add_successor(state, predecessor);
                self.continue_trace(predecessor, conflict, unshifted_item, visited);
            }
            return;
        }

        // Either: we are in the start state, or this item was
        // reached by an epsilon transition. We have to
        // "unepsilon", which means that we search elsewhere in
        // the state for where the epsilon transition could have
        // come from.
        //
        // Example:
        //
        //     X = (*) ...
        //
        // We will search for other items in the same state like:
        //
        //     Y = ...p (*) X ...s
        //
        // We can then insert `FIRST(...s)` as lookahead for
        // `conflict`. If `...s` may derive epsilon, though, we
        // have to recurse and search with the previous item.

        let state_items = &self.states[state.0].items.vec;
        let nonterminal = item.production.nonterminal;
        for &pred_item in state_items.iter()
                                     .filter(|i| i.can_shift_nonterminal(nonterminal)) {
            let symbol_sets = pred_item.symbol_sets();
            let mut first = self.first_sets.first0(self.grammar, symbol_sets.suffix);
            let derives_epsilon = first.take_eof(self.grammar);
            self.table.add_lookahead(state, conflict, &first);
            if derives_epsilon {
                self.continue_trace(state, conflict, pred_item, visited);
            }
        }
    }
}
<commit_msg>shift conflicts do not need to be traced<commit_after>//! Code to trace out a single lane, collecting information into the
//! lane table as we go.

use collections::Set;
use grammar::repr::*;
use lr1::core::*;
use lr1::first::FirstSets;
use lr1::lookahead::*;
use lr1::state_graph::StateGraph;

use super::table::{ConflictIndex, LaneTable};

pub struct LaneTracer<'trace, 'grammar: 'trace> {
    grammar: &'grammar Grammar,
    states: &'trace [LR0State<'grammar>],
    first_sets: FirstSets,
    state_graph: StateGraph,
    table: LaneTable<'grammar>,
}

impl<'trace, 'grammar> LaneTracer<'trace, 'grammar> {
    pub fn new(grammar: &'grammar Grammar,
               states: &'trace [LR0State<'grammar>],
               conflicts: usize)
               -> Self {
        LaneTracer {
            grammar: grammar,
            states: states,
            first_sets: FirstSets::new(grammar),
            state_graph: StateGraph::new(states),
            table: LaneTable::new(grammar, conflicts),
        }
    }

    pub fn into_table(self) -> LaneTable<'grammar> {
        self.table
    }

    pub fn start_trace(&mut self,
                       state: StateIndex,
                       conflict: ConflictIndex,
                       item: LR0Item<'grammar>) {
        let mut visited_set = Set::default();

        // if the conflict item is a "shift" item, then the context
        // is always the termianl to shift (and conflicts only arise
        // around shifting terminal, so it must be a terminal)
        match item.shift_symbol() {
            Some((Symbol::Terminal(term), _)) => {
                let mut token_set = TokenSet::new(self.grammar);
                token_set.insert(self.grammar, Token::Terminal(term));
                self.table.add_lookahead(state, conflict, &token_set);
            }

            Some((Symbol::Nonterminal(_), _)) => {
                panic!("invalid conflict item `{:?}`: shifts nonterminal",
                       item);
            }

            None => {
                self.continue_trace(state, conflict, item, &mut visited_set);
            }
        }
    }

    fn continue_trace(&mut self,
                      state: StateIndex,
                      conflict: ConflictIndex,
                      item: LR0Item<'grammar>,
                      visited: &mut Set<(StateIndex, LR0Item<'grammar>)>) {
        if !visited.insert((state, item)) {
            return;
        }

        if item.index > 0 {
            // This item was reached by shifting some symbol.  We need
            // to unshift that symbol, which means we walk backwards
            // to predecessors of `state` in the state graph.
            //
            // Example:
            //
            //     X = ...p T (*) ...s
            //
            // Here we would be "unshifting" T, which means we will
            // walk to predecessors of the current state that were
            // reached by shifting T. Those predecessors will contain
            // an item like `X = ...p (*) T ...s`, which we will then
            // process in turn.
            let shifted_symbol = item.production.symbols[item.index - 1];
            let unshifted_item = Item { index: item.index - 1, ..item };
            let predecessors = self.state_graph.predecessors(state, shifted_symbol);
            for predecessor in predecessors {
                self.table.add_successor(state, predecessor);
                self.continue_trace(predecessor, conflict, unshifted_item, visited);
            }
            return;
        }

        // Either: we are in the start state, or this item was
        // reached by an epsilon transition. We have to
        // "unepsilon", which means that we search elsewhere in
        // the state for where the epsilon transition could have
        // come from.
        //
        // Example:
        //
        //     X = (*) ...
        //
        // We will search for other items in the same state like:
        //
        //     Y = ...p (*) X ...s
        //
        // We can then insert `FIRST(...s)` as lookahead for
        // `conflict`. If `...s` may derive epsilon, though, we
        // have to recurse and search with the previous item.

        let state_items = &self.states[state.0].items.vec;
        let nonterminal = item.production.nonterminal;
        for &pred_item in state_items.iter()
                                     .filter(|i| i.can_shift_nonterminal(nonterminal)) {
            let symbol_sets = pred_item.symbol_sets();
            let mut first = self.first_sets.first0(self.grammar, symbol_sets.suffix);
            let derives_epsilon = first.take_eof(self.grammar);
            self.table.add_lookahead(state, conflict, &first);
            if derives_epsilon {
                self.continue_trace(state, conflict, pred_item, visited);
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::collections::BTreeMap;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;

use toml::Value;

use error::GPSErrorKind as GPSEK;
use error::GPSError as GPSE;
use error::Result;
use error::ResultExt;

pub trait FromValue : Sized {
    fn from_value(v: &Value) -> Result<Self>;
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct GPSValue {
    pub degree:  i8,
    pub minutes: i8,
    pub seconds: i8
}

impl GPSValue {

    pub fn new(d: i8, m: i8, s: i8) -> GPSValue {
        GPSValue {
            degree:  d,
            minutes: m,
            seconds: s
        }
    }
}

impl Into<Value> for GPSValue {

    fn into(self) -> Value {
        let mut map = BTreeMap::new();
        let _ = map.insert("degree".to_owned(),  Value::Integer(self.degree as i64));
        let _ = map.insert("minutes".to_owned(), Value::Integer(self.minutes as i64));
        let _ = map.insert("seconds".to_owned(), Value::Integer(self.seconds as i64));
        Value::Table(map)
    }

}

impl FromValue for GPSValue {
    fn from_value(v: &Value) -> Result<Self> {
        match *v {
            Value::Table(ref map) => {
                Ok(GPSValue::new(
                    map.get("degree")
                        .ok_or_else(|| GPSE::from_kind(GPSEK::DegreeMissing))
                        .and_then(|v| match *v {
                            Value::Integer(i) => i64_to_i8(i),
                            _ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
                        })?,

                    map
                        .get("minutes")
                        .ok_or_else(|| GPSE::from_kind(GPSEK::MinutesMissing))
                        .and_then(|v| match *v {
                            Value::Integer(i) => i64_to_i8(i),
                            _ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
                        })?,

                    map
                        .get("seconds")
                        .ok_or_else(|| GPSE::from_kind(GPSEK::SecondsMissing))
                        .and_then(|v| match *v {
                            Value::Integer(i) => i64_to_i8(i),
                            _ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
                        })?
                ))
            }
            _ => Err(GPSE::from_kind(GPSEK::TypeError))
        }
    }

}

impl Display for GPSValue {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}° {}\" {}'", self.degree, self.minutes, self.seconds)
    }
}

/// Data-transfer type for transfering longitude-latitude-pairs
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct Coordinates {
    pub longitude: GPSValue,
    pub latitude:  GPSValue,
}

impl Coordinates {
    pub fn new(long: GPSValue, lat: GPSValue) -> Coordinates {
        Coordinates {
            longitude: long,
            latitude:  lat,
        }
    }
}

impl Into<Value> for Coordinates {

    fn into(self) -> Value {
        let mut map = BTreeMap::new();
        let _ = map.insert("longitude".to_owned(), self.longitude.into());
        let _ = map.insert("latitude".to_owned(), self.latitude.into());
        Value::Table(map)
    }

}

impl FromValue for Coordinates {
    fn from_value(v: &Value) -> Result<Self> {
        match *v {
            Value::Table(ref map) => {
                Ok(Coordinates::new(
                    match map.get("longitude") {
                        Some(v) => GPSValue::from_value(v),
                        None    => Err(GPSE::from_kind(GPSEK::LongitudeMissing)),
                    }?,

                    match map.get("latitude") {
                        Some(v) => GPSValue::from_value(v),
                        None    => Err(GPSE::from_kind(GPSEK::LongitudeMissing)),
                    }?
                ))
            }
            _ => Err(GPSE::from_kind(GPSEK::TypeError))
        }
    }

}

impl Display for Coordinates {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "longitude = {}\nlatitude = {}", self.longitude, self.latitude)
    }
}

/// Helper to convert a i64 to i8 or return an error if this doesn't work.
fn i64_to_i8(i: i64) -> Result<i8> {
    if i > (<i8>::max_value() as i64) {
        Err(GPSE::from_kind(GPSEK::NumberConversionError))
    } else {
        Ok(i as i8)
    }
}

<commit_msg>Add getters<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::collections::BTreeMap;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;

use toml::Value;

use error::GPSErrorKind as GPSEK;
use error::GPSError as GPSE;
use error::Result;
use error::ResultExt;

pub trait FromValue : Sized {
    fn from_value(v: &Value) -> Result<Self>;
}

#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct GPSValue {
    pub degree:  i8,
    pub minutes: i8,
    pub seconds: i8
}

impl GPSValue {

    pub fn new(d: i8, m: i8, s: i8) -> GPSValue {
        GPSValue {
            degree:  d,
            minutes: m,
            seconds: s
        }
    }

    pub fn degree(&self) -> i8 {
        self.degree
    }

    pub fn minutes(&self) -> i8 {
        self.minutes
    }

    pub fn seconds(&self) -> i8 {
        self.seconds
    }

}

impl Into<Value> for GPSValue {

    fn into(self) -> Value {
        let mut map = BTreeMap::new();
        let _ = map.insert("degree".to_owned(),  Value::Integer(self.degree as i64));
        let _ = map.insert("minutes".to_owned(), Value::Integer(self.minutes as i64));
        let _ = map.insert("seconds".to_owned(), Value::Integer(self.seconds as i64));
        Value::Table(map)
    }

}

impl FromValue for GPSValue {
    fn from_value(v: &Value) -> Result<Self> {
        match *v {
            Value::Table(ref map) => {
                Ok(GPSValue::new(
                    map.get("degree")
                        .ok_or_else(|| GPSE::from_kind(GPSEK::DegreeMissing))
                        .and_then(|v| match *v {
                            Value::Integer(i) => i64_to_i8(i),
                            _ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
                        })?,

                    map
                        .get("minutes")
                        .ok_or_else(|| GPSE::from_kind(GPSEK::MinutesMissing))
                        .and_then(|v| match *v {
                            Value::Integer(i) => i64_to_i8(i),
                            _ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
                        })?,

                    map
                        .get("seconds")
                        .ok_or_else(|| GPSE::from_kind(GPSEK::SecondsMissing))
                        .and_then(|v| match *v {
                            Value::Integer(i) => i64_to_i8(i),
                            _ => Err(GPSE::from_kind(GPSEK::HeaderTypeError)),
                        })?
                ))
            }
            _ => Err(GPSE::from_kind(GPSEK::TypeError))
        }
    }

}

impl Display for GPSValue {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "{}° {}\" {}'", self.degree, self.minutes, self.seconds)
    }
}

/// Data-transfer type for transfering longitude-latitude-pairs
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct Coordinates {
    pub longitude: GPSValue,
    pub latitude:  GPSValue,
}

impl Coordinates {
    pub fn new(long: GPSValue, lat: GPSValue) -> Coordinates {
        Coordinates {
            longitude: long,
            latitude:  lat,
        }
    }

    pub fn longitude(&self) -> &GPSValue {
        &self.longitude
    }

    pub fn latitude(&self) -> &GPSValue {
        &self.latitude
    }
}

impl Into<Value> for Coordinates {

    fn into(self) -> Value {
        let mut map = BTreeMap::new();
        let _ = map.insert("longitude".to_owned(), self.longitude.into());
        let _ = map.insert("latitude".to_owned(), self.latitude.into());
        Value::Table(map)
    }

}

impl FromValue for Coordinates {
    fn from_value(v: &Value) -> Result<Self> {
        match *v {
            Value::Table(ref map) => {
                Ok(Coordinates::new(
                    match map.get("longitude") {
                        Some(v) => GPSValue::from_value(v),
                        None    => Err(GPSE::from_kind(GPSEK::LongitudeMissing)),
                    }?,

                    match map.get("latitude") {
                        Some(v) => GPSValue::from_value(v),
                        None    => Err(GPSE::from_kind(GPSEK::LongitudeMissing)),
                    }?
                ))
            }
            _ => Err(GPSE::from_kind(GPSEK::TypeError))
        }
    }

}

impl Display for Coordinates {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "longitude = {}\nlatitude = {}", self.longitude, self.latitude)
    }
}

/// Helper to convert a i64 to i8 or return an error if this doesn't work.
fn i64_to_i8(i: i64) -> Result<i8> {
    if i > (<i8>::max_value() as i64) {
        Err(GPSE::from_kind(GPSEK::NumberConversionError))
    } else {
        Ok(i as i8)
    }
}

<|endoftext|>


<commit_before>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate rand;
extern crate rpsrtsrs;
#[cfg(feature = "include_sdl2")] extern crate sdl2_window;
#[cfg(feature = "include_glfw")] extern crate glfw_window;
#[cfg(feature = "include_glutin")] extern crate glutin_window;

use std::f64::consts::PI;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::*;
use piston::event_loop::*;
#[cfg(feature = "include_sdl2")] use sdl2_window::Sdl2Window as Window;
#[cfg(feature = "include_glfw")] use glfw_window::GlfwWindow as Window;
#[cfg(feature = "include_glutin")] use glutin_window::GlutinWindow as Window;
use rpsrtsrs::shapes::Unit;
use rpsrtsrs::client::*;

fn main() {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let mut window : Window = WindowSettings::new(
        "rpsrtsrs",
        [640, 480]
    ).exit_on_esc(true).samples(8).build().unwrap();

    // Create a new game and run it.
    let mut app = App::new(GlGraphics::new(opengl));
    let world_state = app.world_state.clone();
    let commands = app.commands.clone();
    let mut network_client = NetworkClient::new(("127.0.0.1", 8080), world_state.clone(), commands);

    network_client.connect();
    network_client.update();

    let mut cursor = [0.0,0.0];

    let mut events = Events::new(EventSettings::new().lazy(true));
    while let Some(e) = events.next(&mut window) {

        let world_lock = world_state.lock().unwrap();
        //app.units = vec![];
        if let Some(player) = world_lock.game.players.get(0) {
            for unit in player.units.iter() {
                app.units.get_mut(unit.id.0 as usize)
                    .map(|app_unit| app_unit.position = unit.position)
                    .or_else(|| {
                        app.units.push(Unit::new(unit.position.clone(), 0.0f64));
                        None
                    }
                    );
            }
        }

        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<commit_msg>client: Don't use 'lazy' event handling<commit_after>extern crate piston;
extern crate graphics;
extern crate opengl_graphics;
extern crate rand;
extern crate rpsrtsrs;
#[cfg(feature = "include_sdl2")] extern crate sdl2_window;
#[cfg(feature = "include_glfw")] extern crate glfw_window;
#[cfg(feature = "include_glutin")] extern crate glutin_window;

use std::f64::consts::PI;
use piston::window::WindowSettings;
use opengl_graphics::{ GlGraphics, OpenGL };
use piston::input::*;
use piston::event_loop::*;
#[cfg(feature = "include_sdl2")] use sdl2_window::Sdl2Window as Window;
#[cfg(feature = "include_glfw")] use glfw_window::GlfwWindow as Window;
#[cfg(feature = "include_glutin")] use glutin_window::GlutinWindow as Window;
use rpsrtsrs::shapes::Unit;
use rpsrtsrs::client::*;

fn main() {
    let opengl = OpenGL::V3_2;

    // Create an Glutin window.
    let mut window : Window = WindowSettings::new(
        "rpsrtsrs",
        [640, 480]
    ).exit_on_esc(true).samples(8).build().unwrap();

    // Create a new game and run it.
    let mut app = App::new(GlGraphics::new(opengl));
    let world_state = app.world_state.clone();
    let commands = app.commands.clone();
    let mut network_client = NetworkClient::new(("127.0.0.1", 8080), world_state.clone(), commands);

    network_client.connect();
    network_client.update();

    let mut cursor = [0.0,0.0];

    let mut events = Events::new(EventSettings::new());
    while let Some(e) = events.next(&mut window) {

        let world_lock = world_state.lock().unwrap();
        //app.units = vec![];
        if let Some(player) = world_lock.game.players.get(0) {
            for unit in player.units.iter() {
                app.units.get_mut(unit.id.0 as usize)
                    .map(|app_unit| app_unit.position = unit.position)
                    .or_else(|| {
                        app.units.push(Unit::new(unit.position.clone(), 0.0f64));
                        None
                    }
                    );
            }
        }

        if let Some(r) = e.render_args() {
            app.render(&r);
        }
        if let Some(Button::Mouse(button)) = e.press_args() {
            match button {
                MouseButton::Left  => app.select(cursor),
                MouseButton::Right => app.move_selected(cursor),
                _ => println!("Pressed mouse button '{:?}'", button),
            }
        }
        e.mouse_cursor(|x, y| {
            cursor = [x, y];
        });

        if let Some(u) = e.update_args() {
            app.update(&u);
        }
    }
}
<|endoftext|>