<commit_before>use address::Address;
use messages::outgoing;
use mio;
use node;
use routing_table::{InsertOutcome, InsertionResult, RoutingTable};
use std::collections::HashMap;
use std::io::Cursor;
use std::sync::mpsc;
use std::thread;
use transaction::{TransactionId, TransactionIdGenerator};

pub enum ScheduledTask {
    ContinueBootstrap,
    ContinueHealthCheck,
    ContinueRefresh
}

#[derive(Debug)]
pub enum Event {
    ReceivedPacket(String)
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap,
    SendPacket(Address, String)
}

enum TableAction {
    Bootstrap(mio::Timeout),
    HealthCheck(mio::Timeout),
    RefreshBucket(mio::Timeout)
}

pub type TaskSender = mio::Sender<OneshotTask>;

enum Status {
    Bootstrapping,
    Idle
}

pub struct Network {
    port: u16,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>,
    event_listeners: Vec<mpsc::Sender<Event>>
}

impl Network {
    pub fn new<N: node::Node + 'static>(self_node: N, port: u16, routers: Vec<Box<node::Node>>) -> Network {
        let self_address = self_node.get_address().clone();
        let routing_table = RoutingTable::new(8, self_address, routers);

        Network {
            port: port,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new(),
            event_listeners: vec![]
        }
    }

    pub fn run(self) -> TaskSender {
        let mut event_loop_config = mio::EventLoopConfig::new();
        event_loop_config.notify_capacity(16384);
        let mut event_loop = mio::EventLoop::configured(event_loop_config).unwrap();

        create_incoming_udp_channel(self.port, event_loop.channel());
        event_loop.channel().send(OneshotTask::StartBootstrap).unwrap();
        let mut handler = Handler::new(self);
        let task_sender = event_loop.channel();
        thread::spawn(move|| event_loop.run(&mut handler).unwrap());
        task_sender
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming::{Message, Query, Response, self};
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();

        match message {
            Message::Query(transaction_id, origin, query) => {
                let origin_address = origin.get_address();
                match query {
                    Query::FindNode(target) => {
                        let response: Vec<u8> = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                self.routing_table.nearest_to(&target, false));
                        origin.send(response);

                        self.insert_node(origin).unwrap();
                        {
                            if let Some(origin) = self.routing_table.find_node(&origin_address) {
                                origin.received_query(transaction_id);
                            }
                        }
                    },
                    Query::Packet(payload) => {
                        for listener in &self.event_listeners {
                            listener.send(Event::ReceivedPacket(payload.clone()));
                        }
                        let response = outgoing::create_packet_response(
                            transaction_id, &self.self_node);
                        origin.send(response);
                    },
                    Query::Ping => {
                        let response = outgoing::create_ping_response(
                            transaction_id,
                            &self.self_node);
                        origin.send(response);

                        self.insert_node(origin).unwrap();
                        if let Some(origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_query(transaction_id);
                        }
                    }
                }
            }
            Message::Response(transaction_id, origin, response) => {
                let origin_address = origin.get_address();
                match response {
                    Response::FindNode(mut nodes) => {
                        let mut encounted_new_node = false;
                        let mut tail = vec![origin];
                        for node in nodes.drain(..).chain(tail.drain(..)) {
                            match self.insert_node(node) {
                                Ok(InsertOutcome::Inserted) => {
                                    encounted_new_node = true;
                                }
                                Err(error) => { panic!(error) }
                                _ => { }
                            }
                        }

                        {
                            let mut origin = self.routing_table
                                .find_node(&origin_address)
                                .expect("Got find node response from unknown node");
                            origin.received_response(transaction_id);
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                                if encounted_new_node {
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.continue_health_check(event_loop);
                                    self.continue_refresh(event_loop)
                                }
                            }
                            Some(TableAction::HealthCheck(_)) => {
                            },
                            Some(TableAction::RefreshBucket(_)) => {
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                self.status = Status::Idle;
                            }
                            _ => { }
                        }
                    }
                    Response::Packet => {
                        let mut origin = self.routing_table
                            .find_node(&origin_address)
                            .expect("Got packet response from unknown node");
                        origin.received_response(transaction_id);
                    }
                    Response::Ping => {
                        let mut origin = self.routing_table.find_node(&origin_address).expect("Got ping response from unknown node");
                        origin.received_response(transaction_id);
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let address = &self.self_node.get_address();
        let transaction_id = self.find_node(address);
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn continue_health_check(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let transaction_id = self.health_check();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueHealthCheck, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::HealthCheck(timeout));
    }

    fn continue_refresh(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueRefresh, 1000).unwrap();

        match self.refresh_bucket() {
            Some(transaction_id) => {
                self.pending_actions.insert(transaction_id, TableAction::RefreshBucket(timeout));
            }
            None => { }
        }
    }

    fn find_node(&mut self, address: &Address) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            address);
        for node in self.routing_table.nearest() {
            {
                node.send(query.clone());
            }
            node.sent_query(transaction_id);
        }
        transaction_id
    }

    fn health_check(&mut self) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        if let Some(node) = self.routing_table.questionable_nodes().get_mut(0) {
            let query = outgoing::create_ping_query(
                transaction_id, &self.self_node);
            node.send(query);
            node.sent_query(transaction_id);
        }
        transaction_id
    }

    fn refresh_bucket(&mut self) -> Option<TransactionId> {
        if let Some(address) = self.address_to_find_for_refresh() {
            Some(self.find_node(&address))
        } else {
            None
        }
    }

    fn address_to_find_for_refresh(&self) -> Option<Address> {
        match self.routing_table.bucket_needing_refresh() {
            Some(bucket) => {
                println!("refreshing {:?}", bucket);
                Some(bucket.random_address_in_space())
            }
            None => None
        }
    }

    fn insert_node(&mut self, node: Box<node::Node>) -> InsertionResult {
        self.routing_table.insert(node, &self.self_node, &mut self.transaction_ids)
    }

    fn send_packet(&mut self, recipient: Address, payload: String, event_loop: &mut mio::EventLoop<Handler>) {
        for node in self.routing_table.nearest_to(&recipient, false) {
            let transaction_id = self.transaction_ids.generate();
            let query = outgoing::create_packet_query(
                transaction_id, &self.self_node, payload.clone());
            node.send(query.clone());
            node.sent_query(transaction_id);
        }
    }
}

struct Handler {
    network: Network
}

impl Handler {
    fn new(network: Network) -> Handler {
        Handler {
            network: network
        }
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.network.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.network.start_bootstrap(event_loop),
            OneshotTask::SendPacket(recipient, payload) => {
                self.network.send_packet(recipient, payload, event_loop);
            }
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.network.continue_bootstrap(event_loop),
            ScheduledTask::ContinueHealthCheck => self.network.continue_health_check(event_loop),
            ScheduledTask::ContinueRefresh => self.network.continue_refresh(event_loop)
        }
    }
}

fn create_incoming_udp_channel(port: u16, sender: TaskSender) {
    use std::net::UdpSocket;
    thread::spawn(move || {
        let address = ("0.0.0.0", port);
        let socket = UdpSocket::bind(address).unwrap();
        loop {
            let mut buf = [0; 4096];
            match socket.recv_from(&mut buf) {
                Ok((size, _src)) => {
                    sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect())).unwrap();
                }
                Err(e) => panic!("Error receiving from server: {}", e)
            }
        }
    });
}
<commit_msg>Remove some debug printing<commit_after>use address::Address;
use messages::outgoing;
use mio;
use node;
use routing_table::{InsertOutcome, InsertionResult, RoutingTable};
use std::collections::HashMap;
use std::io::Cursor;
use std::sync::mpsc;
use std::thread;
use transaction::{TransactionId, TransactionIdGenerator};

pub enum ScheduledTask {
    ContinueBootstrap,
    ContinueHealthCheck,
    ContinueRefresh
}

#[derive(Debug)]
pub enum Event {
    ReceivedPacket(String)
}

pub enum OneshotTask {
    Incoming(Vec<u8>),
    StartBootstrap,
    SendPacket(Address, String)
}

enum TableAction {
    Bootstrap(mio::Timeout),
    HealthCheck(mio::Timeout),
    RefreshBucket(mio::Timeout)
}

pub type TaskSender = mio::Sender<OneshotTask>;

enum Status {
    Bootstrapping,
    Idle
}

pub struct Network {
    port: u16,
    routing_table: RoutingTable,
    self_node: Box<node::Node + 'static>,
    transaction_ids: TransactionIdGenerator,
    status: Status,
    pending_actions: HashMap<TransactionId, TableAction>,
    event_listeners: Vec<mpsc::Sender<Event>>
}

impl Network {
    pub fn new<N: node::Node + 'static>(self_node: N, port: u16, routers: Vec<Box<node::Node>>) -> Network {
        let self_address = self_node.get_address().clone();
        let routing_table = RoutingTable::new(8, self_address, routers);

        Network {
            port: port,
            routing_table: routing_table,
            self_node: Box::new(self_node),
            transaction_ids: TransactionIdGenerator::new(),
            status: Status::Idle,
            pending_actions: HashMap::new(),
            event_listeners: vec![]
        }
    }

    pub fn run(self) -> TaskSender {
        let mut event_loop_config = mio::EventLoopConfig::new();
        event_loop_config.notify_capacity(16384);
        let mut event_loop = mio::EventLoop::configured(event_loop_config).unwrap();

        create_incoming_udp_channel(self.port, event_loop.channel());
        event_loop.channel().send(OneshotTask::StartBootstrap).unwrap();
        let mut handler = Handler::new(self);
        let task_sender = event_loop.channel();
        thread::spawn(move|| event_loop.run(&mut handler).unwrap());
        task_sender
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_incoming(&mut self, data: Vec<u8>, event_loop: &mut mio::EventLoop<Handler>) {
        use messages::incoming::{Message, Query, Response, self};
        let mut data = Cursor::new(data);
        let message = incoming::parse_from_reader(&mut data).unwrap();

        match message {
            Message::Query(transaction_id, origin, query) => {
                let origin_address = origin.get_address();
                match query {
                    Query::FindNode(target) => {
                        let response: Vec<u8> = outgoing::create_find_node_response(
                                transaction_id,
                                &self.self_node,
                                self.routing_table.nearest_to(&target, false));
                        origin.send(response);

                        self.insert_node(origin).unwrap();
                        {
                            if let Some(origin) = self.routing_table.find_node(&origin_address) {
                                origin.received_query(transaction_id);
                            }
                        }
                    },
                    Query::Packet(payload) => {
                        for listener in &self.event_listeners {
                            listener.send(Event::ReceivedPacket(payload.clone()));
                        }
                        let response = outgoing::create_packet_response(
                            transaction_id, &self.self_node);
                        origin.send(response);
                    },
                    Query::Ping => {
                        let response = outgoing::create_ping_response(
                            transaction_id,
                            &self.self_node);
                        origin.send(response);

                        self.insert_node(origin).unwrap();
                        if let Some(origin) = self.routing_table.find_node(&origin_address) {
                            origin.received_query(transaction_id);
                        }
                    }
                }
            }
            Message::Response(transaction_id, origin, response) => {
                let origin_address = origin.get_address();
                match response {
                    Response::FindNode(mut nodes) => {
                        let mut encounted_new_node = false;
                        let mut tail = vec![origin];
                        for node in nodes.drain(..).chain(tail.drain(..)) {
                            match self.insert_node(node) {
                                Ok(InsertOutcome::Inserted) => {
                                    encounted_new_node = true;
                                }
                                Err(error) => { panic!(error) }
                                _ => { }
                            }
                        }

                        {
                            let mut origin = self.routing_table
                                .find_node(&origin_address)
                                .expect("Got find node response from unknown node");
                            origin.received_response(transaction_id);
                        }

                        match self.pending_actions.remove(&transaction_id) {
                            Some(TableAction::Bootstrap(timeout)) => {
                                event_loop.clear_timeout(timeout);
                                if encounted_new_node {
                                    self.continue_bootstrap(event_loop);
                                } else {
                                    self.continue_health_check(event_loop);
                                    self.continue_refresh(event_loop)
                                }
                            }
                            Some(TableAction::HealthCheck(_)) => {
                            },
                            Some(TableAction::RefreshBucket(_)) => {
                            }
                            None => { }
                        }

                        match self.status {
                            Status::Bootstrapping => {
                                self.status = Status::Idle;
                            }
                            _ => { }
                        }
                    }
                    Response::Packet => {
                        let mut origin = self.routing_table
                            .find_node(&origin_address)
                            .expect("Got packet response from unknown node");
                        origin.received_response(transaction_id);
                    }
                    Response::Ping => {
                        let mut origin = self.routing_table.find_node(&origin_address).expect("Got ping response from unknown node");
                        origin.received_response(transaction_id);
                    }
                }
            }
        }
    }

    fn start_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        self.status = Status::Bootstrapping;
        self.continue_bootstrap(event_loop);
    }

    fn continue_bootstrap(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let address = &self.self_node.get_address();
        let transaction_id = self.find_node(address);
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueBootstrap, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::Bootstrap(timeout));
    }

    fn continue_health_check(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let transaction_id = self.health_check();
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueHealthCheck, 1000).unwrap();
        self.pending_actions.insert(transaction_id, TableAction::HealthCheck(timeout));
    }

    fn continue_refresh(&mut self, event_loop: &mut mio::EventLoop<Handler>) {
        let timeout = event_loop.timeout_ms(ScheduledTask::ContinueRefresh, 1000).unwrap();

        match self.refresh_bucket() {
            Some(transaction_id) => {
                self.pending_actions.insert(transaction_id, TableAction::RefreshBucket(timeout));
            }
            None => { }
        }
    }

    fn find_node(&mut self, address: &Address) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        let query = outgoing::create_find_node_query(
            transaction_id,
            &self.self_node,
            address);
        for node in self.routing_table.nearest() {
            {
                node.send(query.clone());
            }
            node.sent_query(transaction_id);
        }
        transaction_id
    }

    fn health_check(&mut self) -> TransactionId {
        let transaction_id = self.transaction_ids.generate();
        if let Some(node) = self.routing_table.questionable_nodes().get_mut(0) {
            let query = outgoing::create_ping_query(
                transaction_id, &self.self_node);
            node.send(query);
            node.sent_query(transaction_id);
        }
        transaction_id
    }

    fn refresh_bucket(&mut self) -> Option<TransactionId> {
        if let Some(address) = self.address_to_find_for_refresh() {
            Some(self.find_node(&address))
        } else {
            None
        }
    }

    fn address_to_find_for_refresh(&self) -> Option<Address> {
        match self.routing_table.bucket_needing_refresh() {
            Some(bucket) => {
                Some(bucket.random_address_in_space())
            }
            None => None
        }
    }

    fn insert_node(&mut self, node: Box<node::Node>) -> InsertionResult {
        self.routing_table.insert(node, &self.self_node, &mut self.transaction_ids)
    }

    fn send_packet(&mut self, recipient: Address, payload: String, event_loop: &mut mio::EventLoop<Handler>) {
        for node in self.routing_table.nearest_to(&recipient, false) {
            let transaction_id = self.transaction_ids.generate();
            let query = outgoing::create_packet_query(
                transaction_id, &self.self_node, payload.clone());
            node.send(query.clone());
            node.sent_query(transaction_id);
        }
    }
}

struct Handler {
    network: Network
}

impl Handler {
    fn new(network: Network) -> Handler {
        Handler {
            network: network
        }
    }
}

impl mio::Handler for Handler {
    type Timeout = ScheduledTask;
    type Message = OneshotTask;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Handler>, task: OneshotTask) {
        match task {
            OneshotTask::Incoming(data) => self.network.handle_incoming(data, event_loop),
            OneshotTask::StartBootstrap => self.network.start_bootstrap(event_loop),
            OneshotTask::SendPacket(recipient, payload) => {
                self.network.send_packet(recipient, payload, event_loop);
            }
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Handler>, timeout: ScheduledTask) {
        match timeout {
            ScheduledTask::ContinueBootstrap => self.network.continue_bootstrap(event_loop),
            ScheduledTask::ContinueHealthCheck => self.network.continue_health_check(event_loop),
            ScheduledTask::ContinueRefresh => self.network.continue_refresh(event_loop)
        }
    }
}

fn create_incoming_udp_channel(port: u16, sender: TaskSender) {
    use std::net::UdpSocket;
    thread::spawn(move || {
        let address = ("0.0.0.0", port);
        let socket = UdpSocket::bind(address).unwrap();
        loop {
            let mut buf = [0; 4096];
            match socket.recv_from(&mut buf) {
                Ok((size, _src)) => {
                    sender.send(OneshotTask::Incoming(buf[..size].iter().cloned().collect())).unwrap();
                }
                Err(e) => panic!("Error receiving from server: {}", e)
            }
        }
    });
}
<|endoftext|>


<commit_before>extern crate irc;

use irc::client::prelude::*;
use std::default::Default;
use std::env;

fn main() {
    let repository_slug = env::var("TRAVIS_REPO_SLUG").unwrap();
    let branch = env::var("TRAVIS_BRANCH").unwrap();
    let commit = env::var("TRAVIS_COMMIT").unwrap();
    let commit_message = env::var("TRAVIS_COMMIT_MESSAGE").unwrap();

    let config = Config {
        nickname: Some("irc-crate-ci".to_owned()),
        server: Some("irc.pdgn.co".to_owned()),
        use_ssl: Some(true),
        ..Default::default()
    };

    let mut reactor = IrcReactor::new().unwrap();
    let client = reactor.prepare_client_and_connect(&config).unwrap();
    client.identify().unwrap();

    reactor.register_client_with_handler(client, move |client, message| {
        match message.command {
            Command::Response(Response::RPL_ISUPPORT, _, _) => {
                client.send_privmsg(
                    "#commits",
                    format!(
                        "Hello from Travis CI! {}/{} {}: {}",
                        repository_slug, branch, commit, commit_message
                    ),
                )?;
                client.send_quit("QUIT")?;
            }
            _ => (),
        };

        Ok(())
    });

    reactor.run().unwrap();
}
<commit_msg>Re-format ci bot message<commit_after>extern crate irc;

use irc::client::prelude::*;
use std::default::Default;
use std::env;

fn main() {
    let repository_slug = env::var("TRAVIS_REPO_SLUG").unwrap();
    let branch = env::var("TRAVIS_BRANCH").unwrap();
    let commit = env::var("TRAVIS_COMMIT").unwrap();
    let commit_message = env::var("TRAVIS_COMMIT_MESSAGE").unwrap();

    let config = Config {
        nickname: Some("irc-crate-ci".to_owned()),
        server: Some("irc.pdgn.co".to_owned()),
        use_ssl: Some(true),
        ..Default::default()
    };

    let mut reactor = IrcReactor::new().unwrap();
    let client = reactor.prepare_client_and_connect(&config).unwrap();
    client.identify().unwrap();

    reactor.register_client_with_handler(client, move |client, message| {
        match message.command {
            Command::Response(Response::RPL_ISUPPORT, _, _) => {
                client.send_privmsg(
                    "#commits",
                    format!(
                        "[{}/{}] ({}) {}",
                        repository_slug,
                        branch,
                        &commit[..7],
                        commit_message
                    ),
                )?;
                client.send_quit("QUIT")?;
            }
            _ => (),
        };

        Ok(())
    });

    reactor.run().unwrap();
}
<|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

#[macro_use]
extern crate log;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimir;
extern crate rs_es;

use std::collections::HashSet;
use std::collections::HashMap;
use mimirsbrunn::rubber::Rubber;
use mimirsbrunn::objects::{Polygon, MultiPolygon};

pub type AdminsVec = Vec<mimir::Admin>;
pub type StreetsVec = Vec<mimir::Street>;
pub type ParsedPbf = osmpbfreader::OsmPbfReader<std::fs::File>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
    flag_import_way: bool
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level> [--import-way]...

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -w, --import-way      By default, streets are not imported
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

#[derive(Debug)]
struct AdminMatcher {
    admin_levels: HashSet<u32>,
}
impl AdminMatcher {
    pub fn new(levels: HashSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

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

struct BoundaryPart {
    nodes: Vec<osmpbfreader::Node>,
}

impl BoundaryPart {
    pub fn new(nodes: Vec<osmpbfreader::Node>) -> BoundaryPart {
        BoundaryPart { nodes: nodes }
    }
    pub fn first(&self) -> i64 {
        self.nodes.first().unwrap().id
    }
    pub fn last(&self) -> i64 {
        self.nodes.last().unwrap().id
    }
}

fn get_nodes(way: &osmpbfreader::Way,
             objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
             -> Vec<osmpbfreader::Node> {
    way.nodes
       .iter()
       .filter_map(|node_id| objects.get(&osmpbfreader::OsmId::Node(*node_id)))
       .filter_map(|node_obj| if let &osmpbfreader::OsmObj::Node(ref node) = node_obj {
           Some(node.clone())
       } else {
           None
       })
       .collect()
}

fn build_boundary(relation: &osmpbfreader::Relation,
                  objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
                  -> Option<MultiPolygon> {
    let mut boundary_parts: Vec<BoundaryPart> =
        relation.refs
                .iter()
                .filter(|rf| rf.role == "outer" || rf.role == "" || rf.role == "enclave")
                .filter_map(|refe| {
                    objects.get(&refe.member).or_else(|| {
                        warn!("missing element for relation {}", relation.id);
                        None
                    })
                })
                .filter_map(|way_obj| if let &osmpbfreader::OsmObj::Way(ref way) = way_obj {
                    Some(way)
                } else {
                    None
                })
                .map(|way| get_nodes(&way, objects))
                .filter(|nodes| nodes.len() > 1)
                .map(|nodes| BoundaryPart::new(nodes))
                .collect();
    let mut multipoly = MultiPolygon { polygons: Vec::new() };
    // we want to try build a polygon for a least each way
    while !boundary_parts.is_empty() {
        let mut current = -1;
        let mut first = 0;
        let mut nb_try = 0;

        let mut outer: Vec<osmpbfreader::Node> = Vec::new();
        // we try to close the polygon, if we can't we want to at least have tried one time per
        // way. We could improve that latter by trying to attach the way to both side of the
        // polygon
        let max_try = boundary_parts.len();
        while current != first && nb_try < max_try {
            let mut i = 0;
            while i < boundary_parts.len() {
                if outer.is_empty() {
                    // our polygon is empty, we initialise it with the current way
                    first = boundary_parts[i].first();
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    // this way has been used, we remove it from the pool
                    boundary_parts.remove(i);
                    continue;
                }
                if current == boundary_parts[i].first() {
                    // the start of current way touch the polygon, we add it and remove it from the
                    // pool
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else if current == boundary_parts[i].last() {
                    // the end of the current way touch the polygon, we reverse the way and add it
                    current = boundary_parts[i].first();
                    boundary_parts[i].nodes.reverse();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else {
                    i += 1;
                    // didnt do anything, we want to explore the next way, if we had do something we
                    // will have removed the current way and there will be no need to increment
                }
                if current == first {
                    // our polygon is closed, we create it and add it to the multipolygon
                    let polygon = Polygon::new(outer.iter()
                                                    .map(|n| {
                                                        mimir::Coord {
                                                            lat: n.lat,
                                                            lon: n.lon,
                                                        }
                                                    })
                                                    .collect());
                    multipoly.polygons.push(polygon);
                    break;
                }
            }
            nb_try += 1;
        }
    }
    debug!("polygon for relation {};{}", relation.id, multipoly.to_wkt());
    if multipoly.polygons.is_empty() {
        None
    } else {
        Some(multipoly)
    }
}

fn parse_osm_pbf(path: &str) -> ParsedPbf {
    let path = std::path::Path::new(&path);
    osmpbfreader::OsmPbfReader::new(std::fs::File::open(&path).unwrap())
}

fn administrative_regions(pbf: &mut ParsedPbf, levels: HashSet<u32>) -> AdminsVec {
    let mut administrative_regions = AdminsVec::new();
    let matcher = AdminMatcher::new(levels);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_admin(o)).unwrap();
    // load administratives regions
    for (_, obj) in &objects {
        if !matcher.is_admin(&obj) {
            continue;
        }
        if let &osmpbfreader::OsmObj::Relation(ref relation) = obj {
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            // admininstrative region without coordinates
            let coord_centre = relation.refs
                                       .iter()
                                       .find(|rf| rf.role == "admin_centre")
                                       .and_then(|r| {
                                           objects.get(&r.member).and_then(|value| {
                                               match value {
                                                   &osmpbfreader::OsmObj::Node(ref node) => {
                                                       Some(mimir::Coord {
                                                           lat: node.lat,
                                                           lon: node.lon,
                                                       })
                                                   }
                                                   _ => None,
                                               }
                                           })
                                       });

            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val.trim_left_matches('0')),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let boundary = build_boundary(&relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: coord_centre,
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    return administrative_regions;
}

fn streets(pbf: &mut ParsedPbf) -> StreetsVec {

    let is_valid_street = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Way(ref way) => {
                way.tags.get("highway").map_or(false, |x: &String| !x.is_empty()) &&
                way.tags.get("name").map_or(false, |x: &String| !x.is_empty())
            }
            _ => false,
        }
    };

    let is_associated_street_relation = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("type").map_or(false, |v| v == "associatedStreet")
            }
            _ => false,
        }
    };

    let mut street_map = osmpbfreader::get_objs_and_deps(pbf, is_valid_street).unwrap();
    let relation_map = osmpbfreader::get_objs_and_deps(pbf, is_associated_street_relation).unwrap();

    // Sometimes, streets can be devided into several "way"s that still have the same street name.
    // The reason why a street is devided may be that a part of the street become a bridge/tunne/etc.
    // In this case, a "relation" tagged with (type = associatedStreet) is used to group all these "way"s.
    // In order not to have doublons in autocompleion, we should keep only one "way" in the relation
    // and remove all the rest way whose street name is the same.
    for (_, rel_obj) in &relation_map {
        if let &osmpbfreader::OsmObj::Relation(ref rel) = rel_obj {
            let mut found = false;
            for ref_obj in &rel.refs {
                if let &osmpbfreader::OsmId::Way(_) = &ref_obj.member {
                    if !found {
                        found = true;
                        continue;
                    };
                    street_map.remove(&ref_obj.member);
                };
            }
        };
    }

    street_map.iter()
              .filter_map(|(osm_id, obj)| {
                  if let &osmpbfreader::OsmObj::Way(ref way) = obj {
                      if let &osmpbfreader::OsmId::Way(ref way_id) = osm_id {
                          way.tags.get("name").and_then(|way_name| {
                              Some(mimirsbrunn::Street {
                                  id: way_id.to_string(),
                                  street_name: way_name.to_string(),
                                  name: way_name.to_string(),
                                  weight: 1,
                                  administrative_region: None,
                              })
                          })
                      } else {
                          None
                      }
                  } else {
                      None
                  }
              })
              .collect()

}
// TODO: template these two functions
fn index_admin(es_cnx_string: &str, admins: AdminsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    match rubber.bulk_index(admins.iter()) {
        Err(e) => panic!("failed to index admins of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed adminstrative regions: {}", nb),
    }
}

fn index_ways(es_cnx_string: &str, streets: StreetsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    match rubber.bulk_index(streets.iter()) {
        Err(e) => panic!("failed to index streets of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed street: {}", nb),
    }
}

fn index_settings(es_cnx_string: &str) {
    let mut rubber = Rubber::new(es_cnx_string);
    rubber.create_index();
}

fn main() {
    mimir::logger_init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());

    let levels = args.flag_level.iter().cloned().collect();
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);

    let admins = administrative_regions(&mut parsed_pbf, levels);

    index_settings(&args.flag_connection_string);
    index_admin(&args.flag_connection_string, admins);

    let mut optinoal_streets: Option<StreetsVec> = None;
    if args.flag_import_way  {
        optinoal_streets = Some(streets(&mut parsed_pbf));
    }

    if let Some(streets) = optinoal_streets {
	index_ways(&args.flag_connection_string, streets);
    }
}
<commit_msg>remove useless type info<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

#[macro_use]
extern crate log;
extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimir;
extern crate rs_es;

use std::collections::HashSet;
use std::collections::HashMap;
use mimirsbrunn::rubber::Rubber;
use mimirsbrunn::objects::{Polygon, MultiPolygon};

pub type AdminsVec = Vec<mimir::Admin>;
pub type StreetsVec = Vec<mimir::Street>;
pub type ParsedPbf = osmpbfreader::OsmPbfReader<std::fs::File>;

#[derive(RustcDecodable, Debug)]
struct Args {
    flag_input: String,
    flag_level: Vec<u32>,
    flag_connection_string: String,
    flag_import_way: bool
}

static USAGE: &'static str = "
Usage:
    osm2mimir --help
    osm2mimir --input=<file> [--connection-string=<connection-string>] --level=<level> [--import-way]...

Options:
    -h, --help            Show this message.
    -i, --input=<file>    OSM PBF file.
    -l, --level=<level>   Admin levels to keep.
    -w, --import-way      By default, streets are not imported
    -c, --connection-string=<connection-string>
                          Elasticsearch parameters, [default: http://localhost:9200/munin]
";

#[derive(Debug)]
struct AdminMatcher {
    admin_levels: HashSet<u32>,
}
impl AdminMatcher {
    pub fn new(levels: HashSet<u32>) -> AdminMatcher {
        AdminMatcher { admin_levels: levels }
    }

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

struct BoundaryPart {
    nodes: Vec<osmpbfreader::Node>,
}

impl BoundaryPart {
    pub fn new(nodes: Vec<osmpbfreader::Node>) -> BoundaryPart {
        BoundaryPart { nodes: nodes }
    }
    pub fn first(&self) -> i64 {
        self.nodes.first().unwrap().id
    }
    pub fn last(&self) -> i64 {
        self.nodes.last().unwrap().id
    }
}

fn get_nodes(way: &osmpbfreader::Way,
             objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
             -> Vec<osmpbfreader::Node> {
    way.nodes
       .iter()
       .filter_map(|node_id| objects.get(&osmpbfreader::OsmId::Node(*node_id)))
       .filter_map(|node_obj| if let &osmpbfreader::OsmObj::Node(ref node) = node_obj {
           Some(node.clone())
       } else {
           None
       })
       .collect()
}

fn build_boundary(relation: &osmpbfreader::Relation,
                  objects: &HashMap<osmpbfreader::OsmId, osmpbfreader::OsmObj>)
                  -> Option<MultiPolygon> {
    let mut boundary_parts: Vec<BoundaryPart> =
        relation.refs
                .iter()
                .filter(|rf| rf.role == "outer" || rf.role == "" || rf.role == "enclave")
                .filter_map(|refe| {
                    objects.get(&refe.member).or_else(|| {
                        warn!("missing element for relation {}", relation.id);
                        None
                    })
                })
                .filter_map(|way_obj| if let &osmpbfreader::OsmObj::Way(ref way) = way_obj {
                    Some(way)
                } else {
                    None
                })
                .map(|way| get_nodes(&way, objects))
                .filter(|nodes| nodes.len() > 1)
                .map(|nodes| BoundaryPart::new(nodes))
                .collect();
    let mut multipoly = MultiPolygon { polygons: Vec::new() };
    // we want to try build a polygon for a least each way
    while !boundary_parts.is_empty() {
        let mut current = -1;
        let mut first = 0;
        let mut nb_try = 0;

        let mut outer: Vec<osmpbfreader::Node> = Vec::new();
        // we try to close the polygon, if we can't we want to at least have tried one time per
        // way. We could improve that latter by trying to attach the way to both side of the
        // polygon
        let max_try = boundary_parts.len();
        while current != first && nb_try < max_try {
            let mut i = 0;
            while i < boundary_parts.len() {
                if outer.is_empty() {
                    // our polygon is empty, we initialise it with the current way
                    first = boundary_parts[i].first();
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    // this way has been used, we remove it from the pool
                    boundary_parts.remove(i);
                    continue;
                }
                if current == boundary_parts[i].first() {
                    // the start of current way touch the polygon, we add it and remove it from the
                    // pool
                    current = boundary_parts[i].last();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else if current == boundary_parts[i].last() {
                    // the end of the current way touch the polygon, we reverse the way and add it
                    current = boundary_parts[i].first();
                    boundary_parts[i].nodes.reverse();
                    outer.append(&mut boundary_parts[i].nodes);
                    boundary_parts.remove(i);
                } else {
                    i += 1;
                    // didnt do anything, we want to explore the next way, if we had do something we
                    // will have removed the current way and there will be no need to increment
                }
                if current == first {
                    // our polygon is closed, we create it and add it to the multipolygon
                    let polygon = Polygon::new(outer.iter()
                                                    .map(|n| {
                                                        mimir::Coord {
                                                            lat: n.lat,
                                                            lon: n.lon,
                                                        }
                                                    })
                                                    .collect());
                    multipoly.polygons.push(polygon);
                    break;
                }
            }
            nb_try += 1;
        }
    }
    debug!("polygon for relation {};{}", relation.id, multipoly.to_wkt());
    if multipoly.polygons.is_empty() {
        None
    } else {
        Some(multipoly)
    }
}

fn parse_osm_pbf(path: &str) -> ParsedPbf {
    let path = std::path::Path::new(&path);
    osmpbfreader::OsmPbfReader::new(std::fs::File::open(&path).unwrap())
}

fn administrative_regions(pbf: &mut ParsedPbf, levels: HashSet<u32>) -> AdminsVec {
    let mut administrative_regions = AdminsVec::new();
    let matcher = AdminMatcher::new(levels);
    let objects = osmpbfreader::get_objs_and_deps(pbf, |o| matcher.is_admin(o)).unwrap();
    // load administratives regions
    for (_, obj) in &objects {
        if !matcher.is_admin(&obj) {
            continue;
        }
        if let &osmpbfreader::OsmObj::Relation(ref relation) = obj {
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok());
            let level = match level {
                None => {
                    info!("invalid admin_level for relation {}: admin_level {:?}",
                          relation.id,
                          relation.tags.get("admin_level"));
                    continue;
                }
                Some(l) => l,
            };
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                    warn!("adminstrative region without name for relation {}:  admin_level {} \
                           ignored.",
                          relation.id,
                          level);
                    continue;
                }
            };
            // admininstrative region without coordinates
            let coord_centre = relation.refs
                                       .iter()
                                       .find(|rf| rf.role == "admin_centre")
                                       .and_then(|r| {
                                           objects.get(&r.member).and_then(|value| {
                                               match value {
                                                   &osmpbfreader::OsmObj::Node(ref node) => {
                                                       Some(mimir::Coord {
                                                           lat: node.lat,
                                                           lon: node.lon,
                                                       })
                                                   }
                                                   _ => None,
                                               }
                                           })
                                       });

            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val.trim_left_matches('0')),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let boundary = build_boundary(&relation, &objects);
            let admin = mimir::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: coord_centre,
                boundary: boundary,
            };
            administrative_regions.push(admin);
        }
    }
    return administrative_regions;
}

fn streets(pbf: &mut ParsedPbf) -> StreetsVec {

    let is_valid_street = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Way(ref way) => {
                way.tags.get("highway").map_or(false, |x| !x.is_empty()) &&
                way.tags.get("name").map_or(false, |x| !x.is_empty())
            }
            _ => false,
        }
    };

    let is_associated_street_relation = |obj: &osmpbfreader::OsmObj| -> bool {
        match *obj {
            osmpbfreader::OsmObj::Relation(ref rel) => {
                rel.tags.get("type").map_or(false, |v| v == "associatedStreet")
            }
            _ => false,
        }
    };

    let mut street_map = osmpbfreader::get_objs_and_deps(pbf, is_valid_street).unwrap();
    let relation_map = osmpbfreader::get_objs_and_deps(pbf, is_associated_street_relation).unwrap();

    // Sometimes, streets can be devided into several "way"s that still have the same street name.
    // The reason why a street is devided may be that a part of the street become a bridge/tunne/etc.
    // In this case, a "relation" tagged with (type = associatedStreet) is used to group all these "way"s.
    // In order not to have doublons in autocompleion, we should keep only one "way" in the relation
    // and remove all the rest way whose street name is the same.
    for (_, rel_obj) in &relation_map {
        if let &osmpbfreader::OsmObj::Relation(ref rel) = rel_obj {
            let mut found = false;
            for ref_obj in &rel.refs {
                if let &osmpbfreader::OsmId::Way(_) = &ref_obj.member {
                    if !found {
                        found = true;
                        continue;
                    };
                    street_map.remove(&ref_obj.member);
                };
            }
        };
    }

    street_map.iter()
              .filter_map(|(osm_id, obj)| {
                  if let &osmpbfreader::OsmObj::Way(ref way) = obj {
                      if let &osmpbfreader::OsmId::Way(ref way_id) = osm_id {
                          way.tags.get("name").and_then(|way_name| {
                              Some(mimirsbrunn::Street {
                                  id: way_id.to_string(),
                                  street_name: way_name.to_string(),
                                  name: way_name.to_string(),
                                  weight: 1,
                                  administrative_region: None,
                              })
                          })
                      } else {
                          None
                      }
                  } else {
                      None
                  }
              })
              .collect()

}
// TODO: template these two functions
fn index_admin(es_cnx_string: &str, admins: AdminsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    match rubber.bulk_index(admins.iter()) {
        Err(e) => panic!("failed to index admins of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed adminstrative regions: {}", nb),
    }
}

fn index_ways(es_cnx_string: &str, streets: StreetsVec) {
    let mut rubber = Rubber::new(es_cnx_string);
    match rubber.bulk_index(streets.iter()) {
        Err(e) => panic!("failed to index streets of osm because: {}", e),
        Ok(nb) => info!("Nb of indexed street: {}", nb),
    }
}

fn index_settings(es_cnx_string: &str) {
    let mut rubber = Rubber::new(es_cnx_string);
    rubber.create_index();
}

fn main() {
    mimir::logger_init().unwrap();
    debug!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());

    let levels = args.flag_level.iter().cloned().collect();
    let mut parsed_pbf = parse_osm_pbf(&args.flag_input);

    let admins = administrative_regions(&mut parsed_pbf, levels);

    index_settings(&args.flag_connection_string);
    index_admin(&args.flag_connection_string, admins);

    let mut optinoal_streets: Option<StreetsVec> = None;
    if args.flag_import_way  {
        optinoal_streets = Some(streets(&mut parsed_pbf));
    }

    if let Some(streets) = optinoal_streets {
	index_ways(&args.flag_connection_string, streets);
    }
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Binary_digits
#![cfg(not_tested)]

fn main() {
    for i in range(0, 16) {
        println!("{:t}", i)
    }
}
<commit_msg>binary digits, added tests<commit_after>// Implements http://rosettacode.org/wiki/Binary_digits
use std::vec::Vec;
use std::string::String;

#[cfg(not(test))]
fn main() {
    let bins=binaries(16u);
    for s in bins.iter() {
        println!("{}", s);
    }
}

fn binaries(n:uint) -> Vec<String> {
    let mut bins = Vec::<String>::with_capacity(n);
    for i in range(0u, n) {
        bins.push(format!("{:t}", i));
    }
    bins
}

#[test]
fn test_digits() {
    let bins=binaries(16u);
    assert_eq!(bins, vec![String::from_str("0")
                        ,String::from_str("1")
                        ,String::from_str("10")
                        ,String::from_str("11")
                        ,String::from_str("100")
                        ,String::from_str("101")
                        ,String::from_str("110")
                        ,String::from_str("111")
                        ,String::from_str("1000")
                        ,String::from_str("1001")
                        ,String::from_str("1010")
                        ,String::from_str("1011")
                        ,String::from_str("1100")
                        ,String::from_str("1101")
                        ,String::from_str("1110")
                        ,String::from_str("1111")]);
}<|endoftext|>


<commit_before>use bitboard::Board;
use bitboard::Position;
use bitboard::Move;
use bitboard::Turn;
use bitboard::empty_movelist;

use std::rc::Weak;
use std::time::Instant;
use std::time::Duration;
use std::thread;

use rand;
use rand::Rng;

use rayon::prelude::*;

#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
enum NodeState {
    INVALID,        // not a valid node.
    PROVEN_WIN,     // there is at least one child that is a proven loss for the other player
    PROVEN_DRAW,    // current player can force a draw
    EXPLORED,       // already expanded
    UNEXPLORED,     // hasn't been expanded yet
    PROVEN_LOSS,    // every move leads to a loss for the current player
}

const EXPLORATION : f32 = 4.0;
const SIMULATIONS_PER_NODE : i32 = 1064/8;

/// Represents a node in the game tree that has been or is to be explored
#[derive(Clone, PartialEq)]
struct SearchTreeNode {
    children    : Vec<SearchTreeNode>,
    position    : Position,
    state       : NodeState,
    results     : i32,
    simulations : i32,
    child_count : u32,
    prev_move   : Move,
}

impl SearchTreeNode {

    /// Creates a new SearchTreeNode at the given position from the board
    pub fn new(b : Board, pm : Move) -> SearchTreeNode {
        let pieces = b.pieces();

        let state = if b.is_done() {
            let c = b.count_pieces();
            if c.0 > c.1 {
                NodeState::PROVEN_WIN
            } else if c.0 == c.1 {
                NodeState::PROVEN_DRAW
            } else {
                NodeState::PROVEN_LOSS
            }
        } else {
            NodeState::UNEXPLORED
        };
        // TODO: add heuristic value,
        SearchTreeNode {
            children    : vec![],
            position    : Position::from_board(b),
            state       : state,
            results     : 0,
            simulations : 1,
            child_count : 0,
            prev_move   : pm,
        }
    }

    /// Construct an empty node that hasn't been initialized yet
    pub fn empty() -> SearchTreeNode {
        // TODO: add heuristic value,
        SearchTreeNode {
            children    : vec![],
            position    : Position::from_board(Board::new()),
            state       : NodeState::INVALID,
            results     : 0,
            simulations : 1,
            child_count : 0,
            prev_move   : Move::null(),
        }
    }

    /// Get a Board representation of the Position this node
    fn get_board(&self) -> Board {
        self.position.to_board()
    }

    /// calculate the score from the statistics on this node and the total number of simulations
    fn get_score(&self, n : i32) -> f32 {
        let r = self.results as f32;
        let s = self.simulations as f32;

        (r / s) + EXPLORATION * ((n as f32).log(2.718281828459045) / s).sqrt()
    }

    /// Expand this node, simulate the child nodes, and update this node.
    fn expand(&mut self) -> (i32, i32, u32) {
        self.state = NodeState::EXPLORED;
        let b = self.get_board();

        let mut ms = empty_movelist();
        let n = b.get_moves(&mut ms) as usize;

        self.children.reserve_exact(n);

        //run some simulations in parallel.
        let sims = ms[0..n].par_iter().map( |&m| {
            let mut bc = b.copy();
            bc.f_do_move(m);

            let mut r = 0;

            //simulate 1000 games
            let mut s = SIMULATIONS_PER_NODE;
            while s != 0 {
                r += fast_simulate(bc.copy());
                s -= 1;
            }

            let mut ch = SearchTreeNode::new(bc, m);
            ch.add_runs(r, SIMULATIONS_PER_NODE);

            (r, SIMULATIONS_PER_NODE, ch)
        });

        let mut tr = 0;
        let mut ts = 0;

        for (rs, ss, chs) in sims.collect::<Vec<_>>() {
            tr += rs;
            ts += ss;
            self.children.push(chs);
        }

        let c = self.children.len() as u32;
        self.add_children(c);

        self.add_runs(tr, ts);
        (tr, ts, c)
    }

    /// Select the most promising node in the explored game tree and expand it
    fn select_node(&mut self, sims : i32) -> (i32, i32, u32) {
        //find best child to expand.
        //ignore solved (propagated later)
        if NodeState::UNEXPLORED == self.state {
            let (r, s, c) = self.expand();

            return (-r, s, c);
        }

        use std::f32;
        let mut b = 0.0;
        let mut bi : i32 = -1;
        //find the subnode with the best score
        for i in 0..(self.children.len()) {
            match self.children[i].state {
                NodeState::EXPLORED | NodeState::UNEXPLORED => {
                    let score = self.children[i].get_score(sims);
                    if bi == -1 || b < score {
                        bi = i as i32;
                        b = score;
                    }
                },
                _ => {}
            }
        }

        if bi != -1 {

            // update results and simulations
            let (r, s, c) = self.children[bi as usize].select_node(sims);
            self.add_runs(r, s);
            self.add_children(c);

            self.update_proven_state();

            return (-r, s, c);
        } else {
            self.update_proven_state();
            return (0,0,0);

            panic!()
        }
    }

    /// Check children, determine if this node has a proven state, and update the state
    fn update_proven_state(&mut self) {
        let mut best_state = NodeState::INVALID;
        for i in 0..(self.children.len()) {
            if best_state < self.children[i].state {
                best_state = self.children[i].state;
            }
        }

        match best_state {
            NodeState::PROVEN_LOSS => {
                // if there is a proven loss for the opponent, this move is a proven win
                self.state = NodeState::PROVEN_WIN;
            },
            NodeState::PROVEN_DRAW => {
                // if the best is a proven draw (this implies that there are no unproven branches left)
                // then this node is also a proven draw
                self.state = NodeState::PROVEN_DRAW;
            },
            NodeState::PROVEN_WIN => {
                // if the best state is a proven win, then this node is a proven loss for the current player
                self.state = NodeState::PROVEN_LOSS;
            },
            //no other states matter:
            _ => {}
        }
    }

    /// Updates the number of results and simulations in the node and subnodes
    fn add_runs(&mut self, r : i32, s : i32) {
        self.results += r;
        self.simulations += s;
    }

    /// Updates the number of children in the node and subnodes
    fn add_children(&mut self, c : u32) {
        self.child_count += c;
    }

    /// Does an iteration of Monte Carlo Tree search
    fn search(&mut self) {
        let s = self.simulations;
        let mut tmp = [0; 60];
        self.select_node(s);

        // for i in tmp[0..60].iter() {
        //     eprint!("{} ", i);
        // }
        // eprintln!("");
    }
}

fn fast_simulate(mut b : Board) -> i32 {
    use std::i32;

    let mut mvs = empty_movelist();
    let mut e = b.total_empty();
    let mut r = rand::thread_rng();
    let mut c = 1;

    while e > 0 {
        let n = b.get_moves(&mut mvs);
        b.f_do_move(mvs[(r.gen::<u8>() % n) as usize]);
        e -= 1;
        c = -c;
    }
    while !b.is_done() {
        let n = b.get_moves(&mut mvs);
        b.f_do_move(mvs[(r.gen::<u8>() % n) as usize]);
        c = -c;
    }

    let p = b.count_pieces();
    (c * (p.0 as i32 - p.1 as i32).signum())
}

/// Struct used to keep track of the searched game tree and reuse it, etc.
pub struct MonteCarloSearch {
    root_node   : SearchTreeNode,
}

impl MonteCarloSearch {
    /// Creates a new Monte Carlo Tree search engine at the root node of an
    /// Othello game.
    pub fn new() -> MonteCarloSearch {
        MonteCarloSearch {
            root_node: SearchTreeNode::new(Board::new(), Move::null()),
        }
    }

    /// Prunes the monte Carlo Search Tree branches that are no longer relevant
    /// i.e. ones that represent moves not played.
    pub fn prune(&mut self, i : usize) {
        use std::mem;

        let tmp = mem::replace(&mut self.root_node.children[i],
                                SearchTreeNode::empty());

        self.root_node = tmp;
    }

    ///searches the
    pub fn search_for_millis(&mut self, b : Board, msleft : u64) -> Move {
        let start = Instant::now();

        //check if we already have information on this position
        let mut flag = true;
        for i in 0..(self.root_node.children.len()) {
            if self.root_node.children[i].position == Position::from_board(b) {
                self.prune(i);
                flag = false;

                eprintln!("[COIN]: Saved {} Game Tree Nodes and {} Simulations!",
                    self.root_node.child_count,
                    self.root_node.simulations
                );
                break;
            }
        }
        if flag {
            eprintln!("[COIN]: Discarded Previous Game Tree.");
            self.root_node = SearchTreeNode::new(b, Move::null());
        }

        eprintln!("[COIN]: Expanding Game Tree...");

        while start.elapsed() < Duration::from_millis(msleft) {
            self.root_node.search();

            match self.root_node.state {
                NodeState::PROVEN_DRAW | NodeState::PROVEN_WIN | NodeState::PROVEN_LOSS => {
                    eprintln!("[COIN]: Game Tree Solved: {:?}", self.root_node.state);
                    break;
                },
                _ => {}
            }
        }

        eprintln!("[COIN]: Searched {} Nodes with {} Simulations",
            self.root_node.child_count,
            self.root_node.simulations
        );

        let sims = self.root_node.simulations;

        let mut mvs = empty_movelist();
        let n = b.get_moves(&mut mvs) as usize;

        let mut bi = 0;
        let mut bs = 0;

        for i in 0..n {
            let sc = self.root_node.children[i].simulations;

            // eprintln!("{}, {}, {}, {:?}",
            //     self.root_node.children[i].prev_move,
            //     self.root_node.children[i].get_score(sims),
            //     self.root_node.children[i].simulations,
            //     self.root_node.children[i].state
            // );
            if sc > bs {
                bi = i;
                bs = sc;
            }

            if self.root_node.children[i].state == NodeState::PROVEN_LOSS {
                //if the opponent has a proven loss, take it!
                return mvs[i];
            }
        }

        eprintln!("[COIN]: Best Move: {}", mvs[bi]);

        self.prune(bi);

        eprintln!("[COIN]: {}/{} ({:.2})",
            self.root_node.results,
            self.root_node.simulations,
            self.root_node.results as f32 / self.root_node.simulations as f32
        );

        mvs[bi]
    }
}<commit_msg>added a parallel search version which adds some exploration bias. the monte carlo search still needs some proper parallelizations work currently<commit_after>use bitboard::Board;
use bitboard::Position;
use bitboard::Move;
use bitboard::Turn;
use bitboard::empty_movelist;

use std::rc::Weak;
use std::time::Instant;
use std::time::Duration;
use std::thread;

use rand;
use rand::Rng;

use rayon::prelude::*;

#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
enum NodeState {
    INVALID,        // not a valid node.
    PROVEN_WIN,     // there is at least one child that is a proven loss for the other player
    PROVEN_DRAW,    // current player can force a draw
    EXPLORED,       // already expanded
    UNEXPLORED,     // hasn't been expanded yet
    PROVEN_LOSS,    // every move leads to a loss for the current player
}

const EXPLORATION : f32 = 4.0;
const SIMULATIONS_PER_NODE : i32 = 1064/8;

/// Represents a node in the game tree that has been or is to be explored
#[derive(Clone, PartialEq)]
struct SearchTreeNode {
    children    : Vec<SearchTreeNode>,
    position    : Position,
    state       : NodeState,
    results     : i32,
    simulations : i32,
    child_count : u32,
    prev_move   : Move,
}

impl SearchTreeNode {

    /// Creates a new SearchTreeNode at the given position from the board
    pub fn new(b : Board, pm : Move) -> SearchTreeNode {
        let pieces = b.pieces();

        let state = if b.is_done() {
            let c = b.count_pieces();
            if c.0 > c.1 {
                NodeState::PROVEN_WIN
            } else if c.0 == c.1 {
                NodeState::PROVEN_DRAW
            } else {
                NodeState::PROVEN_LOSS
            }
        } else {
            NodeState::UNEXPLORED
        };
        // TODO: add heuristic value,
        SearchTreeNode {
            children    : vec![],
            position    : Position::from_board(b),
            state       : state,
            results     : 0,
            simulations : 1,
            child_count : 0,
            prev_move   : pm,
        }
    }

    /// Construct an empty node that hasn't been initialized yet
    pub fn empty() -> SearchTreeNode {
        // TODO: add heuristic value,
        SearchTreeNode {
            children    : vec![],
            position    : Position::from_board(Board::new()),
            state       : NodeState::INVALID,
            results     : 0,
            simulations : 1,
            child_count : 0,
            prev_move   : Move::null(),
        }
    }

    /// Get a Board representation of the Position this node
    fn get_board(&self) -> Board {
        self.position.to_board()
    }

    /// calculate the score from the statistics on this node and the total number of simulations
    fn get_score(&self, n : i32) -> f32 {
        let r = self.results as f32;
        let s = self.simulations as f32;

        (r / s) + EXPLORATION * ((n as f32).log(2.718281828459045) / s).sqrt()
    }

    /// Expand this node, simulate the child nodes, and update this node.
    fn expand(&mut self) -> (i32, i32, u32) {
        self.state = NodeState::EXPLORED;
        let b = self.get_board();

        let mut ms = empty_movelist();
        let n = b.get_moves(&mut ms) as usize;

        self.children.reserve_exact(n);

        //run some simulations in parallel.
        let sims = ms[0..n].par_iter().map( |&m| {
            let mut bc = b.copy();
            bc.f_do_move(m);

            let mut r = 0;

            //simulate 1000 games
            let mut s = SIMULATIONS_PER_NODE;
            while s != 0 {
                r += fast_simulate(bc.copy());
                s -= 1;
            }

            let mut ch = SearchTreeNode::new(bc, m);
            ch.add_runs(r, SIMULATIONS_PER_NODE);

            (r, SIMULATIONS_PER_NODE, ch)
        });

        let mut tr = 0;
        let mut ts = 0;

        for (rs, ss, chs) in sims.collect::<Vec<_>>() {
            tr += rs;
            ts += ss;
            self.children.push(chs);
        }

        let c = self.children.len() as u32;
        self.add_children(c);

        self.add_runs(tr, ts);
        (tr, ts, c)
    }

    /// Select the most promising node in the explored game tree and expand it
    fn select_node(&mut self, sims : i32) -> (i32, i32, u32) {
        //find best child to expand.
        //ignore solved (propagated later)
        if NodeState::UNEXPLORED == self.state {
            let (r, s, c) = self.expand();

            return (-r, s, c);
        }

        use std::f32;
        let mut b = 0.0;
        let mut bi : i32 = -1;
        //find the subnode with the best score
        for i in 0..(self.children.len()) {
            match self.children[i].state {
                NodeState::EXPLORED | NodeState::UNEXPLORED => {
                    let score = self.children[i].get_score(sims);
                    if bi == -1 || b < score {
                        bi = i as i32;
                        b = score;
                    }
                },
                _ => {}
            }
        }

        if bi != -1 {

            // update results and simulations
            let (r, s, c) = self.children[bi as usize].select_node(sims);
            self.add_runs(r, s);
            self.add_children(c);

            self.update_proven_state();

            return (-r, s, c);
        } else {
            self.update_proven_state();
            return (0,0,0);

            panic!()
        }
    }

    /// Check children, determine if this node has a proven state, and update the state
    fn update_proven_state(&mut self) {
        let mut best_state = NodeState::INVALID;
        for i in 0..(self.children.len()) {
            if best_state < self.children[i].state {
                best_state = self.children[i].state;
            }
        }

        match best_state {
            NodeState::PROVEN_LOSS => {
                // if there is a proven loss for the opponent, this move is a proven win
                self.state = NodeState::PROVEN_WIN;
            },
            NodeState::PROVEN_DRAW => {
                // if the best is a proven draw (this implies that there are no unproven branches left)
                // then this node is also a proven draw
                self.state = NodeState::PROVEN_DRAW;
            },
            NodeState::PROVEN_WIN => {
                // if the best state is a proven win, then this node is a proven loss for the current player
                self.state = NodeState::PROVEN_LOSS;
            },
            //no other states matter:
            _ => {}
        }
    }

    /// Updates the number of results and simulations in the node and subnodes
    fn add_runs(&mut self, r : i32, s : i32) {
        self.results += r;
        self.simulations += s;
    }

    /// Updates the number of children in the node and subnodes
    fn add_children(&mut self, c : u32) {
        self.child_count += c;
    }

    /// Does an iteration of Monte Carlo Tree search
    fn search(&mut self) {
        let s = self.simulations;
        self.select_node(s);

    }

    fn par_search(&mut self) {
        let s = self.simulations;
        let (r, s, c) = self.children.par_iter_mut().map( |c| {
            c.select_node(s)
        }).collect::<Vec<_>>().iter().fold((0, 0, 0), |(ra, sa, ca), &(r,s,c)| {
            (ra + r, sa + s, ca + c)
        });

        self.add_runs(r,s);
        self.add_children(c);

        self.update_proven_state();
    }
}

fn fast_simulate(mut b : Board) -> i32 {
    use std::i32;

    let mut mvs = empty_movelist();
    let mut e = b.total_empty()+2;
    let mut r = rand::thread_rng();
    let mut c = 1;

    while e > 0 {
        let n = b.get_moves(&mut mvs);
        b.f_do_move(mvs[(r.gen::<u8>() % n) as usize]);
        e -= 1;
        c = -c;
    }

    let p = b.count_pieces();
    (c * (p.0 as i32 - p.1 as i32).signum())
}

/// Struct used to keep track of the searched game tree and reuse it, etc.
pub struct MonteCarloSearch {
    root_node   : SearchTreeNode,
}

impl MonteCarloSearch {
    /// Creates a new Monte Carlo Tree search engine at the root node of an
    /// Othello game.
    pub fn new() -> MonteCarloSearch {
        MonteCarloSearch {
            root_node: SearchTreeNode::new(Board::new(), Move::null()),
        }
    }

    /// Prunes the monte Carlo Search Tree branches that are no longer relevant
    /// i.e. ones that represent moves not played.
    pub fn prune(&mut self, i : usize) {
        use std::mem;

        let tmp = mem::replace(&mut self.root_node.children[i],
                                SearchTreeNode::empty());

        self.root_node = tmp;
    }

    ///searches the
    pub fn search_for_millis(&mut self, b : Board, msleft : u64) -> Move {
        let start = Instant::now();

        //check if we already have information on this position
        let mut flag = true;
        for i in 0..(self.root_node.children.len()) {
            if self.root_node.children[i].position == Position::from_board(b) {
                self.prune(i);
                flag = false;

                eprintln!("[COIN]: Saved {} Game Tree Nodes and {} Simulations!",
                    self.root_node.child_count,
                    self.root_node.simulations
                );
                break;
            }
        }
        if flag {
            eprintln!("[COIN]: Discarded Previous Game Tree.");
            self.root_node = SearchTreeNode::new(b, Move::null());
        }

        eprintln!("[COIN]: Expanding Game Tree...");

        while start.elapsed() < Duration::from_millis(msleft) {
            self.root_node.search();
            self.root_node.search();
            self.root_node.par_search();

            match self.root_node.state {
                NodeState::PROVEN_DRAW | NodeState::PROVEN_WIN | NodeState::PROVEN_LOSS => {
                    eprintln!("[COIN]: Game Tree Solved: {:?}", self.root_node.state);
                    break;
                },
                _ => {}
            }
        }

        eprintln!("[COIN]: Searched {} Nodes with {} Simulations",
            self.root_node.child_count,
            self.root_node.simulations
        );
        let elapsed = {
            let d = start.elapsed();
            (d.as_secs() as f32) + (d.subsec_nanos() as f32)/1_000_000_000f32
        };
        eprintln!("[COIN]: Time elapsed: {} ({:.2} sims/s)", elapsed, self.root_node.simulations as f32 / elapsed);

        let mut mvs = empty_movelist();
        let n = b.get_moves(&mut mvs) as usize;

        let mut bi = 0;
        let mut bs = 0;

        //check which node seems best
        for i in 0..n {
            if self.root_node.children[i].state == NodeState::PROVEN_LOSS {
                //if the opponent has a proven loss, take it!
                return mvs[i];
            }

            let sc = self.root_node.children[i].simulations;

            if sc > bs {
                bi = i;
                bs = sc;
            }
        }

        eprintln!("[COIN]: Best Move: {}", mvs[bi]);

        self.prune(bi);

        eprintln!("[COIN]: {}/{} ({:.2})",
            self.root_node.results,
            self.root_node.simulations,
            self.root_node.results as f32 / self.root_node.simulations as f32
        );

        mvs[bi]
    }
}<|endoftext|>


<commit_before>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces,space, many, many1, sep_by, alpha_num, satisfy, string,Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let ident_start = satisfy(|c|
            c.is_alphabetic()
                || c == '='
                || c == '*'
                || c == '+'
                || c == '/'
                || c == '!'
                || c == '\\'
                || c == '?');
        let ident_body = satisfy(|c|
            c.is_alphanumeric()
                || c == '='
                || c == '*'
                || c == '+'
                || c == '/'
                || c == '!'
                || c == '\\'
                || c == '?');
        ident_start
            .and(many::<Vec<_>, _>(ident_body).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })

}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            (name as fn(_) -> _)
                .and(many(expr as fn(_) -> _))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: (x.1)
                    })
                })
                );
        spaces.clone().with(
            sexpr
                .or((name as fn(_) -> _).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::expr;
    use super::parser_combinators::{Parser, ParseResult};

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            (expr as fn (_) -> _).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

        #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            (expr as fn (_) -> _).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

}
<commit_msg>Clean up unused imports<commit_after>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, many, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let ident_start = satisfy(|c|
            c.is_alphabetic()
                || c == '='
                || c == '*'
                || c == '+'
                || c == '/'
                || c == '!'
                || c == '\\'
                || c == '?');
        let ident_body = satisfy(|c|
            c.is_alphanumeric()
                || c == '='
                || c == '*'
                || c == '+'
                || c == '/'
                || c == '!'
                || c == '\\'
                || c == '?');
        ident_start
            .and(many::<Vec<_>, _>(ident_body).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })

}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            (name as fn(_) -> _)
                .and(many(expr as fn(_) -> _))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: (x.1)
                    })
                })
                );
        spaces.clone().with(
            sexpr
                .or((name as fn(_) -> _).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::expr;
    use super::parser_combinators::Parser;

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            (expr as fn (_) -> _).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

        #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            (expr as fn (_) -> _).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

}
<|endoftext|>