<commit_before>#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))]

use std::error::Error;
use tokio::net::{TcpListener, TcpStream};
use tokio::runtime::{Builder, Runtime};

mod support {
    pub mod panic;
}
use support::panic::test_panic;

#[test]
fn udp_socket_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    use std::net::SocketAddr;
    use tokio::net::UdpSocket;

    let addr = "127.0.0.1:8080".parse::<SocketAddr>().unwrap();
    let std_sock = std::net::UdpSocket::bind(addr).unwrap();
    std_sock.set_nonblocking(true).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _sock = UdpSocket::from_std(std_sock);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
fn tcp_listener_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    let std_listener = std::net::TcpListener::bind("127.0.0.1:8080").unwrap();
    std_listener.set_nonblocking(true).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = TcpListener::from_std(std_listener);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
fn tcp_stream_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    let std_listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();

    let std_stream = std::net::TcpStream::connect(std_listener.local_addr().unwrap()).unwrap();
    std_stream.set_nonblocking(true).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = TcpStream::from_std(std_stream);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(unix)]
fn unix_listener_bind_panic_caller() -> Result<(), Box<dyn Error>> {
    use tokio::net::UnixListener;

    let dir = tempfile::tempdir().unwrap();
    let sock_path = dir.path().join("socket");

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = UnixListener::bind(&sock_path);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(unix)]
fn unix_listener_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    use tokio::net::UnixListener;

    let dir = tempfile::tempdir().unwrap();
    let sock_path = dir.path().join("socket");
    let std_listener = std::os::unix::net::UnixListener::bind(&sock_path).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = UnixListener::from_std(std_listener);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(unix)]
fn unix_stream_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    use tokio::net::UnixStream;

    let dir = tempfile::tempdir().unwrap();
    let sock_path = dir.path().join("socket");
    let _std_listener = std::os::unix::net::UnixListener::bind(&sock_path).unwrap();
    let std_stream = std::os::unix::net::UnixStream::connect(&sock_path).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = UnixStream::from_std(std_stream);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(unix)]
fn unix_datagram_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    use std::os::unix::net::UnixDatagram as StdUDS;
    use tokio::net::UnixDatagram;

    let dir = tempfile::tempdir().unwrap();
    let sock_path = dir.path().join("socket");

    // Bind the socket to a filesystem path
    // /let socket_path = tmp.path().join("socket");
    let std_socket = StdUDS::bind(&sock_path).unwrap();
    std_socket.set_nonblocking(true).unwrap();

    let panic_location_file = test_panic(move || {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = UnixDatagram::from_std(std_socket);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(windows)]
fn server_options_max_instances_panic_caller() -> Result<(), Box<dyn Error>> {
    use tokio::net::windows::named_pipe::ServerOptions;

    let panic_location_file = test_panic(move || {
        let rt = runtime_without_io();
        rt.block_on(async {
            let mut options = ServerOptions::new();
            options.max_instances(255);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

// Runtime without `enable_io` so it has no IO driver set.
fn runtime_without_io() -> Runtime {
    Builder::new_current_thread().build().unwrap()
}
<commit_msg>net: don't use port 8080 in tests (#5062)<commit_after>#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(tokio_wasi)))]

use std::error::Error;
use tokio::net::{TcpListener, TcpStream};
use tokio::runtime::{Builder, Runtime};

mod support {
    pub mod panic;
}
use support::panic::test_panic;

#[test]
fn udp_socket_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    use std::net::SocketAddr;
    use tokio::net::UdpSocket;

    let addr = "127.0.0.1:0".parse::<SocketAddr>().unwrap();
    let std_sock = std::net::UdpSocket::bind(addr).unwrap();
    std_sock.set_nonblocking(true).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _sock = UdpSocket::from_std(std_sock);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
fn tcp_listener_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    let std_listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
    std_listener.set_nonblocking(true).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = TcpListener::from_std(std_listener);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
fn tcp_stream_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    let std_listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();

    let std_stream = std::net::TcpStream::connect(std_listener.local_addr().unwrap()).unwrap();
    std_stream.set_nonblocking(true).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = TcpStream::from_std(std_stream);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(unix)]
fn unix_listener_bind_panic_caller() -> Result<(), Box<dyn Error>> {
    use tokio::net::UnixListener;

    let dir = tempfile::tempdir().unwrap();
    let sock_path = dir.path().join("socket");

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = UnixListener::bind(&sock_path);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(unix)]
fn unix_listener_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    use tokio::net::UnixListener;

    let dir = tempfile::tempdir().unwrap();
    let sock_path = dir.path().join("socket");
    let std_listener = std::os::unix::net::UnixListener::bind(&sock_path).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = UnixListener::from_std(std_listener);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(unix)]
fn unix_stream_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    use tokio::net::UnixStream;

    let dir = tempfile::tempdir().unwrap();
    let sock_path = dir.path().join("socket");
    let _std_listener = std::os::unix::net::UnixListener::bind(&sock_path).unwrap();
    let std_stream = std::os::unix::net::UnixStream::connect(&sock_path).unwrap();

    let panic_location_file = test_panic(|| {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = UnixStream::from_std(std_stream);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(unix)]
fn unix_datagram_from_std_panic_caller() -> Result<(), Box<dyn Error>> {
    use std::os::unix::net::UnixDatagram as StdUDS;
    use tokio::net::UnixDatagram;

    let dir = tempfile::tempdir().unwrap();
    let sock_path = dir.path().join("socket");

    // Bind the socket to a filesystem path
    // /let socket_path = tmp.path().join("socket");
    let std_socket = StdUDS::bind(&sock_path).unwrap();
    std_socket.set_nonblocking(true).unwrap();

    let panic_location_file = test_panic(move || {
        let rt = runtime_without_io();
        rt.block_on(async {
            let _ = UnixDatagram::from_std(std_socket);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

#[test]
#[cfg(windows)]
fn server_options_max_instances_panic_caller() -> Result<(), Box<dyn Error>> {
    use tokio::net::windows::named_pipe::ServerOptions;

    let panic_location_file = test_panic(move || {
        let rt = runtime_without_io();
        rt.block_on(async {
            let mut options = ServerOptions::new();
            options.max_instances(255);
        });
    });

    // The panic location should be in this file
    assert_eq!(&panic_location_file.unwrap(), file!());

    Ok(())
}

// Runtime without `enable_io` so it has no IO driver set.
fn runtime_without_io() -> Runtime {
    Builder::new_current_thread().build().unwrap()
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-win32
// Passing enums by value

pub enum void { }

mod bindgen {
    use super::void;

    #[nolink]
    extern {
        pub fn printf(v: void);
    }
}

pub fn main() { }
<commit_msg>test: un-xfail now working run-pass/foreign-struct.rs, close #2334.<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Passing enums by value

pub enum void { }

mod bindgen {
    use super::void;

    #[nolink]
    extern {
        pub fn printf(v: void);
    }
}

pub fn main() { }
<|endoftext|>


<commit_before>#![feature(inner_deref)]
#![allow(clippy::match_bool)]

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

#[macro_use] extern crate failure;

#[macro_use]
extern crate clap;
use clap::{App, AppSettings, SubCommand, Arg, ArgMatches};

#[cfg(windows)]
mod embed;

mod typelib;
mod generators;

/// Main entry point.
fn main() {

    // Define the command line arguments using clap.
    let app = App::new( "Rust COM utility" )
            .version( crate_version!() )
            .author( "Mikko Rantanen <rantanen@jubjubnest.net>" )
            .setting( AppSettings::SubcommandRequiredElseHelp )
            .subcommand( SubCommand::with_name( "read-typelib" )
                .about( "Reads the type library." )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the type library." )
                   .index( 1 )
                )
            )
            .subcommand( SubCommand::with_name( "idl" )
                .about( "Generates IDL file from the Rust crate" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
                .arg( Arg::with_name( "all" )
                    .long( "all" )
                    .help( "Include both Automation and Raw type systems in the IDL.{n}\
                           Normally the IDL only includes the Automation type system interfaces." )
                )
            )
            .subcommand( SubCommand::with_name( "manifest" )
                .about( "Generates a manifest file for the Rust crate for \
                            registration free COM" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
            )
            .subcommand( SubCommand::with_name( "cpp" )
                .about( "Generates C++ header files from the Rust crate" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
                .arg( Arg::with_name( "source" )
                   .long( "source" )
                   .value_name( "source_file" )
                   .help( "File path for the generated source file. '-' for stdout." )
                )
                .arg( Arg::with_name( "header" )
                   .long( "header" )
                   .value_name( "header_file" )
                   .help( "File path for the generated header file. '-' for stdout." )
                )
                .arg( Arg::with_name( "all" )
                    .long( "all" )
                    .help( "Include both Automation and Raw type systems in the C++ implementation.{n}\
                           Normally the implementation only includes the Raw type system interfaces." )
                )
            );

    #[cfg(windows)]
    let app = app.subcommand( SubCommand::with_name( "embed-typelib" )
            .about( "Builds and embeds the typelib into a DLL" )
            .arg( Arg::with_name( "path" )
               .help( "Path to the DLL." )
               .index( 1 )
            )
        );

    // Run the command and report possible errors.
    if let Err( e ) = run_cmd( &app.get_matches() ) {
        eprintln!( "{}", e );
    }
}

fn run_cmd( matches : &ArgMatches ) -> Result<(), failure::Error>
{
    let opts = generators::ModelOptions {
        type_systems: vec![
            generators::TypeSystemOptions {
                ts: intercom::type_system::TypeSystemName::Automation,
                use_full_name: true,
            },
            generators::TypeSystemOptions {
                ts: intercom::type_system::TypeSystemName::Raw,
                use_full_name: true,
            },
        ]
    };

    match matches.subcommand() {
        ( "read-typelib", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            println!( "{:#?}", typelib::read_typelib( path )? );
        },
        #[cfg(windows)]
        ( "embed-typelib", Some( args ) ) => {
            embed::embed_typelib( Path::new( args.value_of("path").unwrap() ), opts )?;
        },
        ( "idl", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let lib = typelib::read_typelib( path )?;
            generators::idl::write( lib, opts, &mut io::stdout() )?;
        },
        ( "cpp", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let lib = typelib::read_typelib( path )?;

            let header_writer : Result<_, failure::Error>
                = args.value_of("header").map(|path|
                    if path == "-" {
                        Ok(Box::new(io::stdout()) as Box<dyn io::Write>)
                    } else {
                        Ok(Box::new(File::create(path)?) as Box<dyn io::Write>)
                    })
                    .map_or(Ok(None), |v| v.map(Some));
            let source_writer : Result<_, failure::Error>
                = args.value_of("source").map(|path|
                    if path == "-" {
                        Ok(Box::new(io::stdout()) as Box<dyn io::Write>)
                    } else {
                        Ok(Box::new(File::create(path)?) as Box<dyn io::Write>)
                    })
                    .map_or(Ok(None), |v| v.map(Some));

            {
                let mut header_writer = header_writer?;
                let mut source_writer = source_writer?;
                return Ok( generators::cpp::write(
                    lib, opts,
                    header_writer.as_mut().map(|b| b as &mut dyn io::Write),
                    source_writer.as_mut().map(|b| b as &mut dyn io::Write),
                )? );
            }
        },
        _ => unreachable!(),
    }

    Ok(())
}
<commit_msg>Return failed exit code on CLI error<commit_after>#![feature(inner_deref)]
#![allow(clippy::match_bool)]

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

#[macro_use] extern crate failure;

#[macro_use]
extern crate clap;
use clap::{App, AppSettings, SubCommand, Arg, ArgMatches};

#[cfg(windows)]
mod embed;

mod typelib;
mod generators;

/// Main entry point.
fn main() {

    // Define the command line arguments using clap.
    let app = App::new( "Rust COM utility" )
            .version( crate_version!() )
            .author( "Mikko Rantanen <rantanen@jubjubnest.net>" )
            .setting( AppSettings::SubcommandRequiredElseHelp )
            .subcommand( SubCommand::with_name( "read-typelib" )
                .about( "Reads the type library." )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the type library." )
                   .index( 1 )
                )
            )
            .subcommand( SubCommand::with_name( "idl" )
                .about( "Generates IDL file from the Rust crate" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
                .arg( Arg::with_name( "all" )
                    .long( "all" )
                    .help( "Include both Automation and Raw type systems in the IDL.{n}\
                           Normally the IDL only includes the Automation type system interfaces." )
                )
            )
            .subcommand( SubCommand::with_name( "manifest" )
                .about( "Generates a manifest file for the Rust crate for \
                            registration free COM" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
            )
            .subcommand( SubCommand::with_name( "cpp" )
                .about( "Generates C++ header files from the Rust crate" )
                .arg( Arg::with_name( "path" )
                   .help( "Path to the crate to process" )
                   .default_value( "." )
                   .index( 1 )
                )
                .arg( Arg::with_name( "source" )
                   .long( "source" )
                   .value_name( "source_file" )
                   .help( "File path for the generated source file. '-' for stdout." )
                )
                .arg( Arg::with_name( "header" )
                   .long( "header" )
                   .value_name( "header_file" )
                   .help( "File path for the generated header file. '-' for stdout." )
                )
                .arg( Arg::with_name( "all" )
                    .long( "all" )
                    .help( "Include both Automation and Raw type systems in the C++ implementation.{n}\
                           Normally the implementation only includes the Raw type system interfaces." )
                )
            );

    #[cfg(windows)]
    let app = app.subcommand( SubCommand::with_name( "embed-typelib" )
            .about( "Builds and embeds the typelib into a DLL" )
            .arg( Arg::with_name( "path" )
               .help( "Path to the DLL." )
               .index( 1 )
            )
        );

    // Run the command and report possible errors.
    if let Err( e ) = run_cmd( &app.get_matches() ) {
        eprintln!( "{}", e );
        std::process::exit(1);
    }
}

fn run_cmd( matches : &ArgMatches ) -> Result<(), failure::Error>
{
    let opts = generators::ModelOptions {
        type_systems: vec![
            generators::TypeSystemOptions {
                ts: intercom::type_system::TypeSystemName::Automation,
                use_full_name: true,
            },
            generators::TypeSystemOptions {
                ts: intercom::type_system::TypeSystemName::Raw,
                use_full_name: true,
            },
        ]
    };

    match matches.subcommand() {
        ( "read-typelib", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            println!( "{:#?}", typelib::read_typelib( path )? );
        },
        #[cfg(windows)]
        ( "embed-typelib", Some( args ) ) => {
            embed::embed_typelib( Path::new( args.value_of("path").unwrap() ), opts )?;
        },
        ( "idl", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let lib = typelib::read_typelib( path )?;
            generators::idl::write( lib, opts, &mut io::stdout() )?;
        },
        ( "cpp", Some( args ) ) => {
            let path = Path::new( args.value_of( "path" ).unwrap() );
            let lib = typelib::read_typelib( path )?;

            let header_writer : Result<_, failure::Error>
                = args.value_of("header").map(|path|
                    if path == "-" {
                        Ok(Box::new(io::stdout()) as Box<dyn io::Write>)
                    } else {
                        Ok(Box::new(File::create(path)?) as Box<dyn io::Write>)
                    })
                    .map_or(Ok(None), |v| v.map(Some));
            let source_writer : Result<_, failure::Error>
                = args.value_of("source").map(|path|
                    if path == "-" {
                        Ok(Box::new(io::stdout()) as Box<dyn io::Write>)
                    } else {
                        Ok(Box::new(File::create(path)?) as Box<dyn io::Write>)
                    })
                    .map_or(Ok(None), |v| v.map(Some));

            {
                let mut header_writer = header_writer?;
                let mut source_writer = source_writer?;
                return Ok( generators::cpp::write(
                    lib, opts,
                    header_writer.as_mut().map(|b| b as &mut dyn io::Write),
                    source_writer.as_mut().map(|b| b as &mut dyn io::Write),
                )? );
            }
        },
        _ => unreachable!(),
    }

    Ok(())
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{GLint, GLchar, GLuint, GLenum};
use cgmath::matrix::Matrix4;
use error_context;
use core::types::MInt;
use core::misc::read_file;
use visualizer::types::{MatId, MFloat, ColorId, Color4};

pub struct Shader {
    id: GLuint,
}

impl Shader {
    pub fn new(vs_path: &Path, fs_path: &Path) -> Shader {
        set_error_context!("loading shader", vs_path.as_str().unwrap()); // TODO
        compile_program(
            read_file(vs_path).as_slice(),
            read_file(fs_path).as_slice(),
        )
    }

    pub fn activate(&self) {
        verify!(gl::UseProgram(self.id));
    }

    pub fn enable_attr(&self, name: &str, components_count: MInt) {
        let mut attr_id = 0;
        name.with_c_str(|name| {
            unsafe {
                attr_id = verify!(gl::GetAttribLocation(self.id, name));
            }
        });
        verify!(gl::EnableVertexAttribArray(attr_id as GLuint));
        let normalized = gl::FALSE;
        let stride = 0;
        unsafe {
            verify!(gl::VertexAttribPointer(
                attr_id as GLuint,
                components_count,
                gl::FLOAT,
                normalized,
                stride,
                std::ptr::null(),
            ));
        }
    }

    pub fn uniform_mat4f(&self, mat_id: MatId, mat: &Matrix4<MFloat>) {
        unsafe {
            let matrix_ptr = std::mem::transmute(mat);
            verify!(gl::UniformMatrix4fv(
                mat_id.id as MInt, 1, gl::FALSE, matrix_ptr));
        }
    }

    pub fn uniform_color(&self, color_id: ColorId, color: Color4) {
        unsafe {
            let data_ptr = std::mem::transmute(&color);
            verify!(gl::Uniform4fv(color_id.id as MInt, 1, data_ptr));
        }
    }

    pub fn get_uniform(&self, name: &str) -> GLuint {
        name.with_c_str(|name| {
            unsafe {
                verify!(gl::GetUniformLocation(self.id, name) as GLuint)
            }
        })
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        verify!(gl::DeleteProgram(self.id));
    }
}

fn compile_shader(src: &str, shader_type: GLenum) -> GLuint {
    let shader = verify!(gl::CreateShader(shader_type));
    unsafe {
        src.with_c_str(|src| {
            verify!(gl::ShaderSource(shader, 1, &src, std::ptr::null()));
        });
        verify!(gl::CompileShader(shader));
        let mut status = gl::FALSE as GLint;
        verify!(gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status));
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            verify!(gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len));
            // subtract 1 to skip the trailing null character
            let mut buf = Vec::from_elem(len as uint - 1, 0u8);
            verify!(gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
                buf.as_mut_ptr() as *mut GLchar));
            fail!(
                "compile_shader: {}",
                std::str::raw::from_utf8(buf.as_slice())
            );
        }
    }
    shader
}

fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
    let program = verify!(gl::CreateProgram());
    verify!(gl::AttachShader(program, vertex_shader));
    verify!(gl::AttachShader(program, fragment_shader));
    verify!(gl::LinkProgram(program));
    unsafe {
        let mut status = gl::FALSE as GLint;
        verify!(gl::GetProgramiv(program, gl::LINK_STATUS, &mut status));
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            verify!(gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len));
            // subtract 1 to skip the trailing null character
            let mut buf = Vec::from_elem(len as uint - 1, 0u8);
            verify!(gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
                buf.as_mut_ptr() as *mut GLchar));
            fail!(
                "link_program: {}",
                std::str::raw::from_utf8(buf.as_slice())
            );
        }
    }
    program
}

fn compile_program(vertex_shader_src: &str, frag_shader_src: &str) -> Shader {
    let vertex_shader = compile_shader(
        vertex_shader_src, gl::VERTEX_SHADER);
    let fragment_shader = compile_shader(
        frag_shader_src, gl::FRAGMENT_SHADER);
    let program = link_program(vertex_shader, fragment_shader);
    // mark shaders for deletion after program deletion
    verify!(gl::DeleteShader(fragment_shader));
    verify!(gl::DeleteShader(vertex_shader));
    Shader{id: program}
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Shader: Simplified unitform_mat4<commit_after>// See LICENSE file for copyright and license details.

use std;
use gl;
use gl::types::{GLint, GLchar, GLuint, GLenum};
use cgmath::matrix::Matrix4;
use cgmath::array::Array2;
use error_context;
use core::types::MInt;
use core::misc::read_file;
use visualizer::types::{MatId, MFloat, ColorId, Color4};

pub struct Shader {
    id: GLuint,
}

impl Shader {
    pub fn new(vs_path: &Path, fs_path: &Path) -> Shader {
        set_error_context!("loading shader", vs_path.as_str().unwrap()); // TODO
        compile_program(
            read_file(vs_path).as_slice(),
            read_file(fs_path).as_slice(),
        )
    }

    pub fn activate(&self) {
        verify!(gl::UseProgram(self.id));
    }

    pub fn enable_attr(&self, name: &str, components_count: MInt) {
        let mut attr_id = 0;
        name.with_c_str(|name| {
            unsafe {
                attr_id = verify!(gl::GetAttribLocation(self.id, name));
            }
        });
        verify!(gl::EnableVertexAttribArray(attr_id as GLuint));
        let normalized = gl::FALSE;
        let stride = 0;
        unsafe {
            verify!(gl::VertexAttribPointer(
                attr_id as GLuint,
                components_count,
                gl::FLOAT,
                normalized,
                stride,
                std::ptr::null(),
            ));
        }
    }

    pub fn uniform_mat4f(&self, mat_id: MatId, mat: &Matrix4<MFloat>) {
        unsafe {
            verify!(gl::UniformMatrix4fv(
                mat_id.id as MInt, 1, gl::FALSE, mat.ptr()));
        }
    }

    pub fn uniform_color(&self, color_id: ColorId, color: Color4) {
        unsafe {
            let data_ptr = std::mem::transmute(&color);
            verify!(gl::Uniform4fv(color_id.id as MInt, 1, data_ptr));
        }
    }

    pub fn get_uniform(&self, name: &str) -> GLuint {
        name.with_c_str(|name| {
            unsafe {
                verify!(gl::GetUniformLocation(self.id, name) as GLuint)
            }
        })
    }
}

impl Drop for Shader {
    fn drop(&mut self) {
        verify!(gl::DeleteProgram(self.id));
    }
}

fn compile_shader(src: &str, shader_type: GLenum) -> GLuint {
    let shader = verify!(gl::CreateShader(shader_type));
    unsafe {
        src.with_c_str(|src| {
            verify!(gl::ShaderSource(shader, 1, &src, std::ptr::null()));
        });
        verify!(gl::CompileShader(shader));
        let mut status = gl::FALSE as GLint;
        verify!(gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status));
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            verify!(gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len));
            // subtract 1 to skip the trailing null character
            let mut buf = Vec::from_elem(len as uint - 1, 0u8);
            verify!(gl::GetShaderInfoLog(shader, len, std::ptr::mut_null(),
                buf.as_mut_ptr() as *mut GLchar));
            fail!(
                "compile_shader: {}",
                std::str::raw::from_utf8(buf.as_slice())
            );
        }
    }
    shader
}

fn link_program(vertex_shader: GLuint, fragment_shader: GLuint) -> GLuint {
    let program = verify!(gl::CreateProgram());
    verify!(gl::AttachShader(program, vertex_shader));
    verify!(gl::AttachShader(program, fragment_shader));
    verify!(gl::LinkProgram(program));
    unsafe {
        let mut status = gl::FALSE as GLint;
        verify!(gl::GetProgramiv(program, gl::LINK_STATUS, &mut status));
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            verify!(gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len));
            // subtract 1 to skip the trailing null character
            let mut buf = Vec::from_elem(len as uint - 1, 0u8);
            verify!(gl::GetProgramInfoLog(program, len, std::ptr::mut_null(),
                buf.as_mut_ptr() as *mut GLchar));
            fail!(
                "link_program: {}",
                std::str::raw::from_utf8(buf.as_slice())
            );
        }
    }
    program
}

fn compile_program(vertex_shader_src: &str, frag_shader_src: &str) -> Shader {
    let vertex_shader = compile_shader(
        vertex_shader_src, gl::VERTEX_SHADER);
    let fragment_shader = compile_shader(
        frag_shader_src, gl::FRAGMENT_SHADER);
    let program = link_program(vertex_shader, fragment_shader);
    // mark shaders for deletion after program deletion
    verify!(gl::DeleteShader(fragment_shader));
    verify!(gl::DeleteShader(vertex_shader));
    Shader{id: program}
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimirsbrunn;

use std::collections::HashSet;

use std::collections::BTreeMap;
use osmpbfreader::{OsmObj, OsmId};

pub type AdminsMap = BTreeMap<OsmId, mimirsbrunn::Admin>;

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

static USAGE: &'static str = "
Usage:
    osm2mimir --input=<pbf-file> --level=<admin-level>...

Options:
    -h, --help                               Show this message.
    -i <pbf-file>, --input=<pbf-file>        OSM PBF file.
    -l <admin-level>, --level=<admin-level>  Admin levels to keep.
";

fn get_osm_id(obj: &OsmObj) -> OsmId {
    match *obj {
        OsmObj::Node(ref node) => OsmId::Node(node.id),
        OsmObj::Way(ref way) => OsmId::Way(way.id),
        OsmObj::Relation(ref rel) => OsmId::Relation(rel.id),
    }
}

fn update_coordinates(filename: &String, admins: &mut AdminsMap) {
	if admins.is_empty() {
		return;
	}
    // load coord for administratives regions
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Node(ref node) = obj {
            let mut adm = match admins.get_mut(&get_osm_id(&obj)) {
                Some(val) => val,
                None => continue,
            };
            adm.coord.lat = node.lat;
            adm.coord.lon = node.lon;
        }
    }
}

fn administartive_regions(filename: &String, levels: &HashSet<u32>) -> AdminsMap {
    let mut administrative_regions = AdminsMap::new();
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    // load administratives regions
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Relation(relation) = obj {
            // not administartive region
            if !relation.tags
                        .get("boundary")
                        .map(|s| s == "administrative")
                        .unwrap_or(false) {
                continue;
            }
            // admininstrative region without coordinates
            let admin_centre = match relation.refs.iter().find(|rf| rf.role == "admin_centre") {
                Some(val) => val.member,
                None => continue,

            };
            let level = relation.tags
                                .get("admin_level")
                                .and_then(|s| s.parse().ok())
                                .unwrap_or(0);
            // administrative region without levelval
            if !levels.contains(&level) {
                continue;
            }
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => continue,
            };
            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let admin = mimirsbrunn::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: mimirsbrunn::Coord {
                    lat: 0.0,
                    lon: 0.0,
                },
            };
            administrative_regions.insert(admin_centre, admin);
        }
    }
    return administrative_regions;
}

fn main() {
    println!("importing adminstrative region into Mimir");
    let args: Args = docopt::Docopt::new(USAGE)
                         .and_then(|d| d.decode())
                         .unwrap_or_else(|e| e.exit());
    let map = args.flag_level.iter().cloned().collect();
    let mut res = administartive_regions(&args.flag_input, &map);
    update_coordinates(&args.flag_input, &mut res);
}
<commit_msg>mimirsbrunn: corrections<commit_after>#[macro_use] extern crate log;
extern crate env_logger;

extern crate osmpbfreader;
extern crate rustc_serialize;
extern crate docopt;
extern crate mimirsbrunn;

use std::collections::HashSet;

use std::collections::BTreeMap;
use osmpbfreader::{OsmObj, OsmId};

pub type AdminsMap = BTreeMap<OsmId, mimirsbrunn::Admin>;

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

static USAGE: &'static str = "
Usage:
    osm2mimir --input=<pbf-file> --level=<admin-level>...

Options:
    -h, --help                               Show this message.
    -i <pbf-file>, --input=<pbf-file>        OSM PBF file.
    -l <admin-level>, --level=<admin-level>  Admin levels to keep.
";

fn get_osm_id(obj: &OsmObj) -> OsmId {
    match *obj {
        OsmObj::Node(ref node) => OsmId::Node(node.id),
        OsmObj::Way(ref way) => OsmId::Way(way.id),
        OsmObj::Relation(ref rel) => OsmId::Relation(rel.id),
    }
}

fn update_coordinates(filename: &String, admins: &mut AdminsMap) {
	if admins.is_empty() {
		return;
	}
    // load coord for administratives regions
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Node(ref node) = obj {
            let mut adm = match admins.get_mut(&get_osm_id(&obj)) {
                Some(val) => val,
                None => continue,
            };
            adm.coord.lat = node.lat;
            adm.coord.lon = node.lon;
        }
    }
}

fn administartive_regions(filename: &String, levels: &HashSet<u32>) -> AdminsMap {
    let mut administrative_regions = AdminsMap::new();
    let path = std::path::Path::new(&filename);
    let r = std::fs::File::open(&path).unwrap();
    let mut pbf = osmpbfreader::OsmPbfReader::new(r);
    // load administratives regions
    for obj in pbf.iter() {
        if let osmpbfreader::OsmObj::Relation(relation) = obj {
            // not administartive region
            if !relation.tags
                        .get("boundary")
                        .map(|s| s == "administrative")
                        .unwrap_or(false) {
                continue;
            }
            // admininstrative region without coordinates
            let admin_centre = match relation.refs.iter().find(|rf| rf.role == "admin_centre") {
                Some(val) => val.member,
                None => {
                	info!("adminstrative regione without coordinates for relation {}.", relation.id);
                	continue;
                }
            };
            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 without levelval
            //println!("level: {:?}", level);
            if !levels.contains(&level) {
            	info!("admin_level ignored for relation {}:  admin_level {:?} .", relation.id, level);
                continue;
            }
            // administrative region with name ?
            let name = match relation.tags.get("name") {
                Some(val) => val,
                None => {
                	info!("adminstrative regione without name for relation {}:  admin_level {:?} ignored .", relation.id, level);
                	continue;
                }
            };
            let admin_id = match relation.tags.get("ref:INSEE") {
                Some(val) => format!("admin:fr:{}", val),
                None => format!("admin:osm:{}", relation.id),
            };
            let zip_code = match relation.tags.get("addr:postcode") {
                Some(val) => &val[..],
                None => "",
            };
            let admin = mimirsbrunn::Admin {
                id: admin_id,
                level: level,
                name: name.to_string(),
                zip_code: zip_code.to_string(),
                // TODO weight value ?
                weight: 1,
                coord: mimirsbrunn::Coord {
                    lat: 0.0,
                    lon: 0.0,
                },
            };
            administrative_regions.insert(admin_centre, admin);
        }
    }
    return administrative_regions;
}

fn main() {
	env_logger::init().unwrap();

	debug!("importing adminstrative region into Mimir");
    //println!("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 res = administartive_regions(&args.flag_input, &levels);
    update_coordinates(&args.flag_input, &mut res);
}
<|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: &String) -> 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>minor fix<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: &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);
    }
}
<|endoftext|>