<commit_before>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

use crate::core::config::ApplicationCfg;
use crate::mvt_service::MvtService;
use crate::runtime_config::{config_from_args, service_from_args};
use crate::static_files::StaticFiles;
use actix_cors::Cors;
use actix_files as fs;
use actix_web::dev::BodyEncoding;
use actix_web::http::{header, ContentEncoding};
use actix_web::middleware::Compress;
use actix_web::{guard, middleware, web, App, HttpRequest, HttpResponse, HttpServer, Result};
use clap::ArgMatches;
use log::Level;
use num_cpus;
use open;
use std::collections::HashMap;
use std::convert::Infallible;
use std::str;
use std::str::FromStr;

static DINO: &'static str = "             xxxxxxxxx
        xxxxxxxxxxxxxxxxxxxxxxxx
      xxxxxxxxxxxxxxxxxxxxxxxxxxxx
     xxxxxxxxxxxxxxxxxxxxxxxxx xxxx
     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  xxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   xxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   xxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx     xxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx    xxxxxxxxxxx
xxxxxxxxxxxxxx                   xxxxxx
xxxxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxx
xxxxxxxxx
xxxxxxx
xxxxxx
xxxxxxx";

async fn mvt_metadata(service: web::Data<MvtService>) -> Result<HttpResponse> {
    let json = service.get_mvt_metadata().unwrap();
    Ok(HttpResponse::Ok().json(json))
}

/// Font list for Maputnik
async fn fontstacks() -> Result<HttpResponse> {
    Ok(HttpResponse::Ok().json(["Roboto Medium", "Roboto Regular"]))
}

// Include method fonts() which returns HashMap with embedded font files
include!(concat!(env!("OUT_DIR"), "/fonts.rs"));

/// Fonts for Maputnik
/// Example: /fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/0-255.pbf
async fn fonts_pbf(params: web::Path<(String, String)>) -> Result<HttpResponse> {
    let fontpbfs = fonts();
    let fontlist = &params.as_ref().0;
    let range = &params.as_ref().1;
    let mut fonts = fontlist.split(",").collect::<Vec<_>>();
    fonts.push("Roboto Regular"); // Fallback
    let mut resp = HttpResponse::NotFound().finish();
    for font in fonts {
        let key = format!("fonts/{}/{}.pbf", font.replace("%20", " "), range);
        debug!("Font lookup: {}", key);
        if let Some(pbf) = fontpbfs.get(&key as &str) {
            resp = HttpResponse::Ok()
                .content_type("application/x-protobuf")
                // data is already gzip compressed
                .encoding(ContentEncoding::Identity)
                .header(header::CONTENT_ENCODING, "gzip")
                .body(*pbf); // TODO: chunked response
            break;
        }
    }
    Ok(resp)
}

fn req_baseurl(req: &HttpRequest) -> String {
    let conninfo = req.connection_info();
    format!("{}://{}", conninfo.scheme(), conninfo.host())
}

async fn tileset_tilejson(
    service: web::Data<MvtService>,
    tileset: web::Path<String>,
    req: HttpRequest,
) -> Result<HttpResponse> {
    let url = req_baseurl(&req);
    let json =
        web::block::<_, _, Infallible>(move || Ok(service.get_tilejson(&url, &tileset).unwrap()))
            .await
            .unwrap();
    Ok(HttpResponse::Ok().json(json))
}

async fn tileset_style_json(
    service: web::Data<MvtService>,
    tileset: web::Path<String>,
    req: HttpRequest,
) -> Result<HttpResponse> {
    let json = service.get_stylejson(&req_baseurl(&req), &tileset).unwrap();
    Ok(HttpResponse::Ok().json(json))
}

async fn tileset_metadata_json(
    service: web::Data<MvtService>,
    tileset: web::Path<String>,
) -> Result<HttpResponse> {
    let json =
        web::block::<_, _, Infallible>(move || Ok(service.get_mbtiles_metadata(&tileset).unwrap()))
            .await
            .unwrap();
    Ok(HttpResponse::Ok().json(json))
}

async fn tile_pbf(
    config: web::Data<ApplicationCfg>,
    service: web::Data<MvtService>,
    params: web::Path<(String, u8, u32, u32)>,
    req: HttpRequest,
) -> Result<HttpResponse> {
    let params = params.into_inner();
    let tileset = params.0;
    let z = params.1;
    let x = params.2;
    let y = params.3;
    let gzip = req
        .headers()
        .get(header::ACCEPT_ENCODING)
        .and_then(|headerval| {
            headerval
                .to_str()
                .ok()
                .and_then(|headerstr| Some(headerstr.contains("gzip")))
        })
        .unwrap_or(false);
    let tile = web::block::<_, _, Infallible>(move || {
        Ok(service.tile_cached(&tileset, x, y, z, gzip, None))
    })
    .await;

    let resp = match tile {
        Ok(Some(tile)) => {
            let mut r = HttpResponse::Ok();
            r.content_type("application/x-protobuf");
            if gzip {
                // data is already gzip compressed
                r.encoding(ContentEncoding::Identity)
                    .header(header::CONTENT_ENCODING, "gzip");
            }
            let cache_max_age = config.webserver.cache_control_max_age.unwrap_or(300);
            r.header(header::CACHE_CONTROL, format!("max-age={}", cache_max_age));
            r.body(tile) // TODO: chunked response
        }
        Ok(None) => HttpResponse::NoContent().finish(),
        Err(e) => {
            error!("{}", e);
            HttpResponse::InternalServerError().finish()
        }
    };
    Ok(resp)
}

lazy_static! {
    static ref STATIC_FILES: StaticFiles = StaticFiles::init();
}

async fn static_file_handler(req: HttpRequest) -> Result<HttpResponse> {
    let key = req.path()[1..].to_string();
    let resp = if let Some(ref content) = STATIC_FILES.content(None, key) {
        HttpResponse::Ok()
            .header(header::ACCESS_CONTROL_ALLOW_ORIGIN, "*") // TOOD: use Actix middleware
            .content_type(content.1)
            .body(content.0) // TODO: chunked response
    } else {
        HttpResponse::NotFound().finish()
    };
    Ok(resp)
}

#[derive(Deserialize)]
struct DrilldownParams {
    minzoom: Option<u8>,
    maxzoom: Option<u8>,
    points: String, //x1,y1,x2,y2,..
}

async fn drilldown_handler(
    service: web::Data<MvtService>,
    params: web::Query<DrilldownParams>,
) -> Result<HttpResponse> {
    let tileset = None; // all tilesets
    let progress = false;
    let points: Vec<f64> = params
        .points
        .split(",")
        .map(|v| {
            v.parse()
                .expect("Error parsing 'point' as pair of float values")
            //FIXME: map_err(|_| error::ErrorInternalServerError("...")
        })
        .collect();
    let stats = service.drilldown(tileset, params.minzoom, params.maxzoom, points, progress);
    let json = stats.as_json().unwrap();
    Ok(HttpResponse::Ok().json(json))
}

#[actix_web::main]
pub async fn webserver(args: ArgMatches<'static>) -> std::io::Result<()> {
    let config = config_from_args(&args);
    let host = config
        .webserver
        .bind
        .clone()
        .unwrap_or("127.0.0.1".to_string());
    let port = config.webserver.port.unwrap_or(6767);
    let bind_addr = format!("{}:{}", host, port);
    let workers = config.webserver.threads.unwrap_or(num_cpus::get() as u8);
    let mvt_viewer = config.service.mvt.viewer;
    let openbrowser =
        bool::from_str(args.value_of("openbrowser").unwrap_or("true")).unwrap_or(false);
    let static_dirs = config.webserver.static_.clone();

    let mut service = service_from_args(&config, &args);
    let service = web::block::<_, _, Infallible>(|| {
        service.prepare_feature_queries();
        service.init_cache();
        Ok(service)
    })
    .await
    .unwrap();

    let server = HttpServer::new(move || {
        let mut app = App::new()
            .data(config.clone())
            .data(service.clone())
            .wrap(middleware::Logger::new("%r %s %b %Dms %a"))
            .wrap(Compress::default())
            .wrap(
                Cors::new()
                    .send_wildcard()
                    .allowed_methods(vec!["GET"])
                    .finish(),
            )
            .service(
                web::resource("/index.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(mvt_metadata),
                ),
            )
            .service(
                web::resource("/fontstacks.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(fontstacks),
                ),
            )
            .service(
                web::resource("/fonts.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(fontstacks),
                ),
            )
            .service(
                web::resource("/fonts/{fonts}/{range}.pbf").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(fonts_pbf),
                ),
            );
        for static_dir in &static_dirs {
            let dir = &static_dir.dir;
            if std::path::Path::new(dir).is_dir() {
                info!("Serving static files from directory '{}'", dir);
                app = app.service(fs::Files::new(&static_dir.path, dir));
            } else {
                warn!("Static file directory '{}' not found", dir);
            }
        }
        app = app
            .service(
                web::resource("/{tileset}.style.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(tileset_style_json),
                ),
            )
            .service(
                web::resource("/{tileset}/metadata.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(tileset_metadata_json),
                ),
            )
            .service(
                web::resource("/{tileset}.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(tileset_tilejson),
                ),
            )
            .service(
                web::resource("/{tileset}/{z}/{x}/{y}.pbf").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(tile_pbf),
                ),
            );
        if mvt_viewer {
            app = app.service(
                web::resource("/drilldown").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(drilldown_handler),
                ),
            );
            app = app.default_service(web::to(static_file_handler));
        }
        app
    })
    .workers(workers as usize)
    .bind(&bind_addr)
    .expect("Can not start server on given IP/Port")
    .shutdown_timeout(3) // default: 30s
    .run();

    if log_enabled!(Level::Info) {
        println!("{}", DINO);
    }

    if openbrowser && mvt_viewer {
        let _res = open::that(format!("http://{}:{}", &host, port));
    }

    server.await
}
<commit_msg>Call service_from_args in web::block<commit_after>//
// Copyright (c) Pirmin Kalberer. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//

use crate::core::config::ApplicationCfg;
use crate::mvt_service::MvtService;
use crate::runtime_config::{config_from_args, service_from_args};
use crate::static_files::StaticFiles;
use actix_cors::Cors;
use actix_files as fs;
use actix_web::dev::BodyEncoding;
use actix_web::http::{header, ContentEncoding};
use actix_web::middleware::Compress;
use actix_web::{guard, middleware, web, App, HttpRequest, HttpResponse, HttpServer, Result};
use clap::ArgMatches;
use log::Level;
use num_cpus;
use open;
use std::collections::HashMap;
use std::convert::Infallible;
use std::str;
use std::str::FromStr;

static DINO: &'static str = "             xxxxxxxxx
        xxxxxxxxxxxxxxxxxxxxxxxx
      xxxxxxxxxxxxxxxxxxxxxxxxxxxx
     xxxxxxxxxxxxxxxxxxxxxxxxx xxxx
     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
   xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  xxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   xxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   xxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx     xxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx      x
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxx    xxxxxxxxxxx
xxxxxxxxxxxxxx                   xxxxxx
xxxxxxxxxxxx
xxxxxxxxxxx
xxxxxxxxxx
xxxxxxxxx
xxxxxxx
xxxxxx
xxxxxxx";

async fn mvt_metadata(service: web::Data<MvtService>) -> Result<HttpResponse> {
    let json = service.get_mvt_metadata().unwrap();
    Ok(HttpResponse::Ok().json(json))
}

/// Font list for Maputnik
async fn fontstacks() -> Result<HttpResponse> {
    Ok(HttpResponse::Ok().json(["Roboto Medium", "Roboto Regular"]))
}

// Include method fonts() which returns HashMap with embedded font files
include!(concat!(env!("OUT_DIR"), "/fonts.rs"));

/// Fonts for Maputnik
/// Example: /fonts/Open%20Sans%20Regular,Arial%20Unicode%20MS%20Regular/0-255.pbf
async fn fonts_pbf(params: web::Path<(String, String)>) -> Result<HttpResponse> {
    let fontpbfs = fonts();
    let fontlist = &params.as_ref().0;
    let range = &params.as_ref().1;
    let mut fonts = fontlist.split(",").collect::<Vec<_>>();
    fonts.push("Roboto Regular"); // Fallback
    let mut resp = HttpResponse::NotFound().finish();
    for font in fonts {
        let key = format!("fonts/{}/{}.pbf", font.replace("%20", " "), range);
        debug!("Font lookup: {}", key);
        if let Some(pbf) = fontpbfs.get(&key as &str) {
            resp = HttpResponse::Ok()
                .content_type("application/x-protobuf")
                // data is already gzip compressed
                .encoding(ContentEncoding::Identity)
                .header(header::CONTENT_ENCODING, "gzip")
                .body(*pbf); // TODO: chunked response
            break;
        }
    }
    Ok(resp)
}

fn req_baseurl(req: &HttpRequest) -> String {
    let conninfo = req.connection_info();
    format!("{}://{}", conninfo.scheme(), conninfo.host())
}

async fn tileset_tilejson(
    service: web::Data<MvtService>,
    tileset: web::Path<String>,
    req: HttpRequest,
) -> Result<HttpResponse> {
    let url = req_baseurl(&req);
    let json =
        web::block::<_, _, Infallible>(move || Ok(service.get_tilejson(&url, &tileset).unwrap()))
            .await
            .unwrap();
    Ok(HttpResponse::Ok().json(json))
}

async fn tileset_style_json(
    service: web::Data<MvtService>,
    tileset: web::Path<String>,
    req: HttpRequest,
) -> Result<HttpResponse> {
    let json = service.get_stylejson(&req_baseurl(&req), &tileset).unwrap();
    Ok(HttpResponse::Ok().json(json))
}

async fn tileset_metadata_json(
    service: web::Data<MvtService>,
    tileset: web::Path<String>,
) -> Result<HttpResponse> {
    let json =
        web::block::<_, _, Infallible>(move || Ok(service.get_mbtiles_metadata(&tileset).unwrap()))
            .await
            .unwrap();
    Ok(HttpResponse::Ok().json(json))
}

async fn tile_pbf(
    config: web::Data<ApplicationCfg>,
    service: web::Data<MvtService>,
    params: web::Path<(String, u8, u32, u32)>,
    req: HttpRequest,
) -> Result<HttpResponse> {
    let params = params.into_inner();
    let tileset = params.0;
    let z = params.1;
    let x = params.2;
    let y = params.3;
    let gzip = req
        .headers()
        .get(header::ACCEPT_ENCODING)
        .and_then(|headerval| {
            headerval
                .to_str()
                .ok()
                .and_then(|headerstr| Some(headerstr.contains("gzip")))
        })
        .unwrap_or(false);
    let tile = web::block::<_, _, Infallible>(move || {
        Ok(service.tile_cached(&tileset, x, y, z, gzip, None))
    })
    .await;

    let resp = match tile {
        Ok(Some(tile)) => {
            let mut r = HttpResponse::Ok();
            r.content_type("application/x-protobuf");
            if gzip {
                // data is already gzip compressed
                r.encoding(ContentEncoding::Identity)
                    .header(header::CONTENT_ENCODING, "gzip");
            }
            let cache_max_age = config.webserver.cache_control_max_age.unwrap_or(300);
            r.header(header::CACHE_CONTROL, format!("max-age={}", cache_max_age));
            r.body(tile) // TODO: chunked response
        }
        Ok(None) => HttpResponse::NoContent().finish(),
        Err(e) => {
            error!("{}", e);
            HttpResponse::InternalServerError().finish()
        }
    };
    Ok(resp)
}

lazy_static! {
    static ref STATIC_FILES: StaticFiles = StaticFiles::init();
}

async fn static_file_handler(req: HttpRequest) -> Result<HttpResponse> {
    let key = req.path()[1..].to_string();
    let resp = if let Some(ref content) = STATIC_FILES.content(None, key) {
        HttpResponse::Ok()
            .header(header::ACCESS_CONTROL_ALLOW_ORIGIN, "*") // TOOD: use Actix middleware
            .content_type(content.1)
            .body(content.0) // TODO: chunked response
    } else {
        HttpResponse::NotFound().finish()
    };
    Ok(resp)
}

#[derive(Deserialize)]
struct DrilldownParams {
    minzoom: Option<u8>,
    maxzoom: Option<u8>,
    points: String, //x1,y1,x2,y2,..
}

async fn drilldown_handler(
    service: web::Data<MvtService>,
    params: web::Query<DrilldownParams>,
) -> Result<HttpResponse> {
    let tileset = None; // all tilesets
    let progress = false;
    let points: Vec<f64> = params
        .points
        .split(",")
        .map(|v| {
            v.parse()
                .expect("Error parsing 'point' as pair of float values")
            //FIXME: map_err(|_| error::ErrorInternalServerError("...")
        })
        .collect();
    let stats = service.drilldown(tileset, params.minzoom, params.maxzoom, points, progress);
    let json = stats.as_json().unwrap();
    Ok(HttpResponse::Ok().json(json))
}

#[actix_web::main]
pub async fn webserver(args: ArgMatches<'static>) -> std::io::Result<()> {
    let config = config_from_args(&args);
    let host = config
        .webserver
        .bind
        .clone()
        .unwrap_or("127.0.0.1".to_string());
    let port = config.webserver.port.unwrap_or(6767);
    let bind_addr = format!("{}:{}", host, port);
    let workers = config.webserver.threads.unwrap_or(num_cpus::get() as u8);
    let mvt_viewer = config.service.mvt.viewer;
    let openbrowser =
        bool::from_str(args.value_of("openbrowser").unwrap_or("true")).unwrap_or(false);
    let static_dirs = config.webserver.static_.clone();

    let svc_config = config.clone();
    let service = web::block::<_, _, Infallible>(move || {
        let mut service = service_from_args(&svc_config, &args);
        service.prepare_feature_queries();
        service.init_cache();
        Ok(service)
    })
    .await
    .unwrap();

    let server = HttpServer::new(move || {
        let mut app = App::new()
            .data(config.clone())
            .data(service.clone())
            .wrap(middleware::Logger::new("%r %s %b %Dms %a"))
            .wrap(Compress::default())
            .wrap(
                Cors::new()
                    .send_wildcard()
                    .allowed_methods(vec!["GET"])
                    .finish(),
            )
            .service(
                web::resource("/index.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(mvt_metadata),
                ),
            )
            .service(
                web::resource("/fontstacks.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(fontstacks),
                ),
            )
            .service(
                web::resource("/fonts.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(fontstacks),
                ),
            )
            .service(
                web::resource("/fonts/{fonts}/{range}.pbf").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(fonts_pbf),
                ),
            );
        for static_dir in &static_dirs {
            let dir = &static_dir.dir;
            if std::path::Path::new(dir).is_dir() {
                info!("Serving static files from directory '{}'", dir);
                app = app.service(fs::Files::new(&static_dir.path, dir));
            } else {
                warn!("Static file directory '{}' not found", dir);
            }
        }
        app = app
            .service(
                web::resource("/{tileset}.style.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(tileset_style_json),
                ),
            )
            .service(
                web::resource("/{tileset}/metadata.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(tileset_metadata_json),
                ),
            )
            .service(
                web::resource("/{tileset}.json").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(tileset_tilejson),
                ),
            )
            .service(
                web::resource("/{tileset}/{z}/{x}/{y}.pbf").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(tile_pbf),
                ),
            );
        if mvt_viewer {
            app = app.service(
                web::resource("/drilldown").route(
                    web::route()
                        .guard(guard::Any(guard::Get()).or(guard::Head()))
                        .to(drilldown_handler),
                ),
            );
            app = app.default_service(web::to(static_file_handler));
        }
        app
    })
    .workers(workers as usize)
    .bind(&bind_addr)
    .expect("Can not start server on given IP/Port")
    .shutdown_timeout(3) // default: 30s
    .run();

    if log_enabled!(Level::Info) {
        println!("{}", DINO);
    }

    if openbrowser && mvt_viewer {
        let _res = open::that(format!("http://{}:{}", &host, port));
    }

    server.await
}
<|endoftext|>


<commit_before>// copyright 2017 Kaz Wesley

//! Classic Blake in a Rustic setting

#![no_std]

extern crate block_buffer;
extern crate byte_tools;
pub extern crate digest;

mod consts;

use core::mem;
use digest::generic_array::GenericArray;
pub use digest::Digest;

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct State<T> {
    h: [T; 8],
    s: [T; 4],
    t: [T; 2],
    nullt: bool,
}

macro_rules! define_compressor {
    ($compressor:ident, $word:ident, $buf:expr, $deserializer:ident, $uval:expr,
     $rounds:expr, $shift0:expr, $shift1:expr, $shift2: expr, $shift3: expr) => {
        #[derive(Clone, Copy, Debug)]
        struct $compressor {
            state: State<$word>
        }

        impl $compressor {
            fn increase_count(&mut self, count: $word) {
                let (new_t0, carry) = self.state.t[0].overflowing_add(count * 8);
                self.state.t[0] = new_t0;
                if carry { self.state.t[1] += 1; }
            }

            fn put_block(&mut self, block: &[u8; $buf]) {
                const U: [$word; 16] = $uval;

                #[inline(always)]
                fn g(v: &mut [$word; 16], m: &[$word; 16], sigma: &[u8; 16],
                    a: usize, b: usize, c: usize, d: usize, e: usize) {
                    v[a] = v[a].wrapping_add(m[sigma[e] as usize] ^ U[sigma[e+1] as usize])
                        .wrapping_add(v[b]);
                    v[d] = (v[d] ^ v[a]).rotate_right($shift0);
                    v[c] = v[c].wrapping_add(v[d]);
                    v[b] = (v[b] ^ v[c]).rotate_right($shift1);
                    v[a] = v[a].wrapping_add(m[sigma[e+1] as usize] ^ U[sigma[e] as usize])
                        .wrapping_add(v[b]);
                    v[d] = (v[d] ^ v[a]).rotate_right($shift2);
                    v[c] = v[c].wrapping_add(v[d]);
                    v[b] = (v[b] ^ v[c]).rotate_right($shift3);
                }

                let mut m = [0; 16];
                for (mx, b) in m.iter_mut().zip(block.chunks(mem::size_of::<$word>())) {
                    *mx = $deserializer(b);
                }

                let mut v = [0; 16];
                &v[..8].copy_from_slice(&self.state.h);
                &v[8..].copy_from_slice(&U[..8]);
                for (vx, sx) in v[8..11].iter_mut().zip(&self.state.s) {
                    *vx ^= sx;
                }

                // don't xor t when the block is only padding
                if !self.state.nullt {
                    v[12] ^= self.state.t[0];
                    v[13] ^= self.state.t[0];
                    v[14] ^= self.state.t[1];
                    v[15] ^= self.state.t[1];
                }

                for sigma in &SIGMA[..$rounds] {
                    // column step
                    g(&mut v, &m, sigma, 0,  4,  8, 12,  0 );
                    g(&mut v, &m, sigma, 1,  5,  9, 13,  2 );
                    g(&mut v, &m, sigma, 2,  6, 10, 14,  4 );
                    g(&mut v, &m, sigma, 3,  7, 11, 15,  6 );
                    // diagonal step
                    g(&mut v, &m, sigma, 0,  5, 10, 15,  8 );
                    g(&mut v, &m, sigma, 1,  6, 11, 12, 10 );
                    g(&mut v, &m, sigma, 2,  7,  8, 13, 12 );
                    g(&mut v, &m, sigma, 3,  4,  9, 14, 14 );
                }

                for (i, vx) in v.iter().enumerate() {
                    self.state.h[i % 8] ^= vx;
                }

                for (i, hx) in self.state.h.iter_mut().enumerate() {
                    *hx ^= self.state.s[i % 4];
                }
            }
        }
    }
}

macro_rules! define_hasher {
    ($name:ident, $word:ident, $buf:expr, $Buffer:ident, $bits:expr, $Bytes:ident,
     $serializer:ident, $compressor:ident, $iv:expr) => {
        #[derive(Clone, Copy)]
        pub struct $name {
            compressor: $compressor,
            buffer: $Buffer
        }

        impl core::fmt::Debug for $name {
            fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
                f.debug_struct("Blake")
                    .field("compressor", &self.compressor)
                    .field("buffer.position()", &self.buffer.position())
                    .finish()
            }
        }

        impl Default for $name {
            fn default() -> Self {
                Self {
                    compressor: $compressor {
                        state: State::<$word> {
                            h: $iv,
                            s: [0; 4],
                            t: [0; 2],
                            nullt: false,
                        }
                    },
                    buffer: $Buffer::default()
                }
            }
        }

        impl digest::BlockInput for $name {
            type BlockSize = $Bytes;
        }

        impl digest::Input for $name {
            fn process(&mut self, data: &[u8]) {
                let compressor = &mut self.compressor;
                self.buffer.input(data, |block| {
                    compressor.increase_count((mem::size_of::<$word>() * 16) as $word);
                    compressor.put_block(block);
                });
            }
        }

        impl digest::FixedOutput for $name {
            type OutputSize = $Bytes;

            fn fixed_result(self) -> GenericArray<u8, $Bytes> {
                let mut compressor = self.compressor;
                let mut buffer = self.buffer;

                compressor.increase_count(buffer.position() as $word);

                let mut msglen = [0u8; $buf/8];
                $serializer(&mut msglen[..$buf/16], compressor.state.t[1]);
                $serializer(&mut msglen[$buf/16..], compressor.state.t[0]);

                let footerlen = 1 + 2 * mem::size_of::<$word>();

                // low bit indicates full-length variant
                let isfull = ($bits == 8 * mem::size_of::<[$word; 8]>()) as u8;
                // high bit indicates fit with no padding
                let exactfit = if buffer.position() + footerlen != $buf { 0x00 } else { 0x80 };
                let magic = isfull | exactfit;

                // if header won't fit in last data block, pad to the end and start a new one
                let extra_block = buffer.position() + footerlen > $buf;
                if extra_block {
                    let pad = $buf - buffer.position();
                    buffer.input(&PADDING[..pad], |block| compressor.put_block(block));
                    debug_assert_eq!(buffer.position(), 0);
                }

                // pad last block up to footer start point
                compressor.state.nullt = buffer.position() == 0;
                // skip begin-padding byte if continuing padding
                let x = extra_block as usize;
                let (start, end) = (x, x + ($buf - footerlen - buffer.position()));
                buffer.input(&PADDING[start..end], |_| unreachable!());
                buffer.input(&[magic], |_| unreachable!());
                buffer.input(&msglen, |block| compressor.put_block(block));
                debug_assert_eq!(buffer.position(), 0);

                let mut out = GenericArray::default();
                for (h, out) in compressor.state.h.iter()
                    .zip(out.chunks_mut(mem::size_of::<$word>())) {
                    $serializer(out, *h);
                }
                out
            }
        }
    }
}

use block_buffer::{BlockBuffer1024, BlockBuffer512};
use byte_tools::{read_u32_be, read_u64_be, write_u32_be, write_u64_be};
use consts::{BLAKE224_IV, BLAKE256_IV, BLAKE256_U, BLAKE384_IV, BLAKE512_IV, BLAKE512_U, PADDING,
             SIGMA};
use digest::generic_array::typenum::{U28, U32, U48, U64};

#[cfg_attr(rustfmt, rustfmt_skip)]
define_compressor!(Compressor256, u32, 64, read_u32_be, BLAKE256_U, 14, 16, 12, 8, 7);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_hasher!(
    Blake224, u32, 64, BlockBuffer512, 224, U28, write_u32_be, Compressor256, BLAKE224_IV);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_hasher!(
    Blake256, u32, 64, BlockBuffer512, 256, U32, write_u32_be, Compressor256, BLAKE256_IV);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_compressor!(Compressor512, u64, 128, read_u64_be, BLAKE512_U, 16, 32, 25, 16, 11);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_hasher!(
    Blake384, u64, 128, BlockBuffer1024, 384, U48, write_u64_be, Compressor512, BLAKE384_IV);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_hasher!(
    Blake512, u64, 128, BlockBuffer1024, 512, U64, write_u64_be, Compressor512, BLAKE512_IV);
<commit_msg>blake: 1.21-compatible syntax<commit_after>// copyright 2017 Kaz Wesley

//! Classic Blake in a Rustic setting

#![no_std]

extern crate block_buffer;
extern crate byte_tools;
pub extern crate digest;

mod consts;

use core::mem;
use digest::generic_array::GenericArray;
pub use digest::Digest;

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct State<T> {
    h: [T; 8],
    s: [T; 4],
    t: [T; 2],
    nullt: bool,
}

macro_rules! define_compressor {
    ($compressor:ident, $word:ident, $buf:expr, $deserializer:ident, $uval:expr,
     $rounds:expr, $shift0:expr, $shift1:expr, $shift2: expr, $shift3: expr) => {
        #[derive(Clone, Copy, Debug)]
        struct $compressor {
            state: State<$word>
        }

        impl $compressor {
            fn increase_count(&mut self, count: $word) {
                let (new_t0, carry) = self.state.t[0].overflowing_add(count * 8);
                self.state.t[0] = new_t0;
                if carry { self.state.t[1] += 1; }
            }

            fn put_block(&mut self, block: &[u8; $buf]) {
                const U: [$word; 16] = $uval;

                #[inline(always)]
                fn g(v: &mut [$word; 16], m: &[$word; 16], sigma: &[u8; 16],
                    a: usize, b: usize, c: usize, d: usize, e: usize) {
                    v[a] = v[a].wrapping_add(m[sigma[e] as usize] ^ U[sigma[e+1] as usize])
                        .wrapping_add(v[b]);
                    v[d] = (v[d] ^ v[a]).rotate_right($shift0);
                    v[c] = v[c].wrapping_add(v[d]);
                    v[b] = (v[b] ^ v[c]).rotate_right($shift1);
                    v[a] = v[a].wrapping_add(m[sigma[e+1] as usize] ^ U[sigma[e] as usize])
                        .wrapping_add(v[b]);
                    v[d] = (v[d] ^ v[a]).rotate_right($shift2);
                    v[c] = v[c].wrapping_add(v[d]);
                    v[b] = (v[b] ^ v[c]).rotate_right($shift3);
                }

                let mut m = [0; 16];
                for (mx, b) in m.iter_mut().zip(block.chunks(mem::size_of::<$word>())) {
                    *mx = $deserializer(b);
                }

                let mut v = [0; 16];
                &v[..8].copy_from_slice(&self.state.h);
                &v[8..].copy_from_slice(&U[..8]);
                for (vx, sx) in v[8..11].iter_mut().zip(&self.state.s) {
                    *vx ^= *sx;
                }

                // don't xor t when the block is only padding
                if !self.state.nullt {
                    v[12] ^= self.state.t[0];
                    v[13] ^= self.state.t[0];
                    v[14] ^= self.state.t[1];
                    v[15] ^= self.state.t[1];
                }

                for sigma in &SIGMA[..$rounds] {
                    // column step
                    g(&mut v, &m, sigma, 0,  4,  8, 12,  0 );
                    g(&mut v, &m, sigma, 1,  5,  9, 13,  2 );
                    g(&mut v, &m, sigma, 2,  6, 10, 14,  4 );
                    g(&mut v, &m, sigma, 3,  7, 11, 15,  6 );
                    // diagonal step
                    g(&mut v, &m, sigma, 0,  5, 10, 15,  8 );
                    g(&mut v, &m, sigma, 1,  6, 11, 12, 10 );
                    g(&mut v, &m, sigma, 2,  7,  8, 13, 12 );
                    g(&mut v, &m, sigma, 3,  4,  9, 14, 14 );
                }

                for (i, vx) in v.iter().enumerate() {
                    self.state.h[i % 8] ^= *vx;
                }

                for (i, hx) in self.state.h.iter_mut().enumerate() {
                    *hx ^= self.state.s[i % 4];
                }
            }
        }
    }
}

macro_rules! define_hasher {
    ($name:ident, $word:ident, $buf:expr, $Buffer:ident, $bits:expr, $Bytes:ident,
     $serializer:ident, $compressor:ident, $iv:expr) => {
        #[derive(Clone, Copy)]
        pub struct $name {
            compressor: $compressor,
            buffer: $Buffer
        }

        impl core::fmt::Debug for $name {
            fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
                f.debug_struct("Blake")
                    .field("compressor", &self.compressor)
                    .field("buffer.position()", &self.buffer.position())
                    .finish()
            }
        }

        impl Default for $name {
            fn default() -> Self {
                Self {
                    compressor: $compressor {
                        state: State::<$word> {
                            h: $iv,
                            s: [0; 4],
                            t: [0; 2],
                            nullt: false,
                        }
                    },
                    buffer: $Buffer::default()
                }
            }
        }

        impl digest::BlockInput for $name {
            type BlockSize = $Bytes;
        }

        impl digest::Input for $name {
            fn process(&mut self, data: &[u8]) {
                let compressor = &mut self.compressor;
                self.buffer.input(data, |block| {
                    compressor.increase_count((mem::size_of::<$word>() * 16) as $word);
                    compressor.put_block(block);
                });
            }
        }

        impl digest::FixedOutput for $name {
            type OutputSize = $Bytes;

            fn fixed_result(self) -> GenericArray<u8, $Bytes> {
                let mut compressor = self.compressor;
                let mut buffer = self.buffer;

                compressor.increase_count(buffer.position() as $word);

                let mut msglen = [0u8; $buf/8];
                $serializer(&mut msglen[..$buf/16], compressor.state.t[1]);
                $serializer(&mut msglen[$buf/16..], compressor.state.t[0]);

                let footerlen = 1 + 2 * mem::size_of::<$word>();

                // low bit indicates full-length variant
                let isfull = ($bits == 8 * mem::size_of::<[$word; 8]>()) as u8;
                // high bit indicates fit with no padding
                let exactfit = if buffer.position() + footerlen != $buf { 0x00 } else { 0x80 };
                let magic = isfull | exactfit;

                // if header won't fit in last data block, pad to the end and start a new one
                let extra_block = buffer.position() + footerlen > $buf;
                if extra_block {
                    let pad = $buf - buffer.position();
                    buffer.input(&PADDING[..pad], |block| compressor.put_block(block));
                    debug_assert_eq!(buffer.position(), 0);
                }

                // pad last block up to footer start point
                compressor.state.nullt = buffer.position() == 0;
                // skip begin-padding byte if continuing padding
                let x = extra_block as usize;
                let (start, end) = (x, x + ($buf - footerlen - buffer.position()));
                buffer.input(&PADDING[start..end], |_| unreachable!());
                buffer.input(&[magic], |_| unreachable!());
                buffer.input(&msglen, |block| compressor.put_block(block));
                debug_assert_eq!(buffer.position(), 0);

                let mut out = GenericArray::default();
                for (h, out) in compressor.state.h.iter()
                    .zip(out.chunks_mut(mem::size_of::<$word>())) {
                    $serializer(out, *h);
                }
                out
            }
        }
    }
}

use block_buffer::{BlockBuffer1024, BlockBuffer512};
use byte_tools::{read_u32_be, read_u64_be, write_u32_be, write_u64_be};
use consts::{BLAKE224_IV, BLAKE256_IV, BLAKE256_U, BLAKE384_IV, BLAKE512_IV, BLAKE512_U, PADDING,
             SIGMA};
use digest::generic_array::typenum::{U28, U32, U48, U64};

#[cfg_attr(rustfmt, rustfmt_skip)]
define_compressor!(Compressor256, u32, 64, read_u32_be, BLAKE256_U, 14, 16, 12, 8, 7);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_hasher!(
    Blake224, u32, 64, BlockBuffer512, 224, U28, write_u32_be, Compressor256, BLAKE224_IV);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_hasher!(
    Blake256, u32, 64, BlockBuffer512, 256, U32, write_u32_be, Compressor256, BLAKE256_IV);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_compressor!(Compressor512, u64, 128, read_u64_be, BLAKE512_U, 16, 32, 25, 16, 11);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_hasher!(
    Blake384, u64, 128, BlockBuffer1024, 384, U48, write_u64_be, Compressor512, BLAKE384_IV);

#[cfg_attr(rustfmt, rustfmt_skip)]
define_hasher!(
    Blake512, u64, 128, BlockBuffer1024, 512, U64, write_u64_be, Compressor512, BLAKE512_IV);
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{Read, BufReader, Seek, SeekFrom};
use file::metadata::{RowGroupMetaData, FileMetaData};
use byteorder::{LittleEndian, ByteOrder};

pub trait ParquetFileInfo {
  /// Get the metadata about this file
  fn metadata(&mut self) -> FileMetaData;

  /// Get the `i`th row group. Note this doesn't do bound check.
  fn get_row_group(&self, i: usize) -> Box<ParquetRowGroupInfo>;
}

/// TODO: add page reader
pub trait ParquetRowGroupInfo {
  fn metadata(&self) -> RowGroupMetaData;
}

pub struct ParquetFileReader {
  buf: BufReader<File>
}

impl ParquetFileReader {
  pub fn new(b: BufReader<File>) -> Self {
    ParquetFileReader{buf: b}
  }
}

const FOOTER_SIZE: usize = 8;
const PARQUET_MAGIC: [u8; 4] = ['P' as u8, 'A' as u8, 'R' as u8, '1' as u8];

impl ParquetFileInfo for ParquetFileReader {
  fn metadata(&mut self) -> FileMetaData {
    let mut file_metadata = FileMetaData{};
    let file_size =
      if let Ok(file_info) = self.buf.get_ref().metadata() {
        file_info.len()
      } else {
        panic!("Fail to get metadata for file");
      };
    if file_size < FOOTER_SIZE as u64 {
      panic!("Corrputed file, smaller than file footer");
    }
    let mut footer_buffer: [u8; FOOTER_SIZE] = [0; FOOTER_SIZE];
    self.buf.seek(SeekFrom::End(-(FOOTER_SIZE as i64)));
    self.buf.read_exact(&mut footer_buffer);
    if footer_buffer[4..] != PARQUET_MAGIC {
      panic!("Invalid parquet file. Corrupt footer.");
    }
    let metadata_len = LittleEndian::read_i32(&footer_buffer[0..4]);
    println!("Metadata length: {}", &metadata_len);
    let mut metadata_buffer: Vec<u8> = Vec::new();
    self.buf.seek(SeekFrom::Start(0));
    file_metadata
  }

  fn get_row_group(&self, i: usize) -> Box<ParquetRowGroupInfo> {
    unimplemented!()
  }
}
<commit_msg>Read metadata from footer<commit_after>use std::fs::File;
use std::io::{Read, BufReader, Seek, SeekFrom};
use file::metadata::{RowGroupMetaData, FileMetaData};
use byteorder::{LittleEndian, ByteOrder};

pub trait ParquetFileInfo {
  /// Get the metadata about this file
  /// TODO: think about returning a Result type
  fn metadata(&mut self) -> FileMetaData;

  /// Get the `i`th row group. Note this doesn't do bound check.
  fn get_row_group(&self, i: usize) -> Box<ParquetRowGroupInfo>;
}

/// TODO: add page reader
pub trait ParquetRowGroupInfo {
  fn metadata(&self) -> RowGroupMetaData;
}

pub struct ParquetFileReader {
  buf: BufReader<File>
}

impl ParquetFileReader {
  pub fn new(b: BufReader<File>) -> Self {
    ParquetFileReader{buf: b}
  }
}

const FOOTER_SIZE: usize = 8;
const PARQUET_MAGIC: [u8; 4] = ['P' as u8, 'A' as u8, 'R' as u8, '1' as u8];

impl ParquetFileInfo for ParquetFileReader {
  fn metadata(&mut self) -> FileMetaData {
    let mut file_metadata = FileMetaData{};
    let file_size =
      if let Ok(file_info) = self.buf.get_ref().metadata() {
        file_info.len()
      } else {
        panic!("Fail to get metadata for file");
      };
    if file_size < FOOTER_SIZE as u64 {
      panic!("Corrputed file, smaller than file footer");
    }
    let mut footer_buffer: [u8; FOOTER_SIZE] = [0; FOOTER_SIZE];
    self.buf.seek(SeekFrom::End(-(FOOTER_SIZE as i64)));
    self.buf.read_exact(&mut footer_buffer);
    if footer_buffer[4..] != PARQUET_MAGIC {
      panic!("Invalid parquet file. Corrupt footer.");
    }
    let metadata_len = LittleEndian::read_i32(&footer_buffer[0..4]);
    let mut metadata_buffer = vec![0; metadata_len as usize];
    self.buf.seek(SeekFrom::Start(0));
    match self.buf.read_exact(metadata_buffer.as_mut_slice()) {
      Ok(_) => (),
      Err(e) => {
        panic!("Failed to read metadata {}", e);
      }
    }
    // TODO: read the metadata buffer and construct a meaningful metadata
    file_metadata
  }

  fn get_row_group(&self, i: usize) -> Box<ParquetRowGroupInfo> {
    unimplemented!()
  }
}
<|endoftext|>


<commit_before>use crate::genmsg;
use proc_macro::TokenStream;
use quote::quote;
use std::env;
use std::path::Path;

pub fn depend_on_messages(messages: &[&str], internal: bool) -> TokenStream {
    let cmake_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_share_folder)
        .collect::<Vec<String>>();
    let cmake_alt_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_src_folder)
        .collect::<Vec<String>>();
    let extra_paths = env::var("ROSRUST_MSG_PATH")
        .unwrap_or_default()
        .split(':')
        .map(String::from)
        .collect::<Vec<String>>();
    let paths = cmake_paths
        .iter()
        .chain(cmake_alt_paths.iter())
        .chain(extra_paths.iter())
        .map(String::as_str)
        .collect::<Vec<&str>>();
    let output = genmsg::depend_on_messages(paths.as_slice(), messages)
        .unwrap_or_else(|r| panic!("{}", r))
        .token_stream(&if internal {
            quote! { crate:: }
        } else {
            quote! { rosrust:: }
        });
    (quote! {#output}).into()
}

fn append_share_folder(path: &str) -> Option<String> {
    Path::new(path).join("share").to_str().map(String::from)
}

fn append_src_folder(path: &str) -> Option<String> {
    Path::new(path)
        .join("..")
        .join("src")
        .to_str()
        .map(String::from)
}
<commit_msg>Traverse subfolders when looking for dependencies<commit_after>use crate::genmsg;
use proc_macro::TokenStream;
use quote::quote;
use std::env;
use std::ffi::OsStr;
use std::fs::read_dir;
use std::path::Path;

pub fn depend_on_messages(messages: &[&str], internal: bool) -> TokenStream {
    let cmake_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_share_folder)
        .collect::<Vec<String>>();
    let cmake_alt_paths = env::var("CMAKE_PREFIX_PATH")
        .unwrap_or_default()
        .split(':')
        .filter_map(append_src_folder)
        .collect::<Vec<String>>();
    let extra_paths = env::var("ROSRUST_MSG_PATH")
        .unwrap_or_default()
        .split(':')
        .map(String::from)
        .collect::<Vec<String>>();
    let paths_owned = cmake_paths
        .iter()
        .chain(cmake_alt_paths.iter())
        .chain(extra_paths.iter())
        .flat_map(|v| find_all_package_groups(&Path::new(v)))
        .collect::<Vec<String>>();
    let paths = paths_owned
        .iter()
        .map(String::as_str)
        .collect::<Vec<&str>>();
    let output = genmsg::depend_on_messages(paths.as_slice(), messages)
        .unwrap_or_else(|r| panic!("{}", r))
        .token_stream(&if internal {
            quote! { crate:: }
        } else {
            quote! { rosrust:: }
        });
    (quote! {#output}).into()
}

fn find_all_package_groups(root: &Path) -> Vec<String> {
    categorize_tree_folders(root)
        .into_iter()
        .filter(|v| v.has_msg_or_srv_grandchild)
        .map(|v| v.name)
        .collect()
}

fn categorize_tree_folders(root: &Path) -> Vec<FolderInfo> {
    if !root.is_dir() {
        return vec![];
    }
    let mut folders = vec![];
    let is_msg_or_srv =
        root.file_name() == Some(OsStr::new("msg")) || root.file_name() == Some(OsStr::new("srv"));
    let mut has_msg_or_srv_child = false;
    let mut has_msg_or_srv_grandchild = false;
    if let Ok(children) = read_dir(root) {
        for child in children.filter_map(Result::ok) {
            for folder in categorize_tree_folders(&child.path()) {
                has_msg_or_srv_child = has_msg_or_srv_child || folder.is_msg_or_srv;
                has_msg_or_srv_grandchild =
                    has_msg_or_srv_grandchild || folder.has_msg_or_srv_child;
                folders.push(folder);
            }
        }
    }
    folders.push(FolderInfo {
        name: root.to_str().unwrap_or("").into(),
        is_msg_or_srv,
        has_msg_or_srv_child,
        has_msg_or_srv_grandchild,
    });
    folders
}

struct FolderInfo {
    name: String,
    is_msg_or_srv: bool,
    has_msg_or_srv_child: bool,
    has_msg_or_srv_grandchild: bool,
}

fn append_share_folder(path: &str) -> Option<String> {
    Path::new(path).join("share").to_str().map(String::from)
}

fn append_src_folder(path: &str) -> Option<String> {
    Path::new(path)
        .join("..")
        .join("src")
        .to_str()
        .map(String::from)
}
<|endoftext|>


<commit_before>
use num::traits::One;

use na::{Iso2, Rot2, Vec1, Vec2};
use ncollide::shape::{Cone, Cuboid, Cylinder};
use nphysics::object::{RigidBody};

use constants::*;
use tagtree;

enum Part {
    Vessel { width: f64, length: f64 },
    FuelTank { radius: f64, length: f64 },
    Engine { radius: f64, length: f64, group: i32 }
}

struct PointMass {
    center: Vec2<f64>,
    mass: f64
}

impl Part {

    fn mass (&self) -> f64 {
        match self {
            &Part::Vessel {width, length} => {
                VESSEL_DENSITY * width * length
            }
            &Part::FuelTank {radius, length} => {
                FUELTANK_DENSITY * radius * length
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                ENGINE_DENSITY * radius * length * 0.5
            }
        }
    }

    fn object (&self) -> RigidBody {
        match self {
            &Part::Vessel {width, length} => {
                let geom = Cuboid::new(Vec2::new(width, length));
                RigidBody::new_dynamic(geom, VESSEL_DENSITY, 1.0, 1.0)
            }
            &Part::FuelTank {radius, length} => {
                let geom = Cylinder::new(length, radius);
                RigidBody::new_dynamic(geom, FUELTANK_DENSITY, 1.0, 1.0)
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                let geom = Cone::new(length, radius);
                RigidBody::new_dynamic(geom, ENGINE_DENSITY, 1.0, 1.0)
            }
        }
    }

    fn point_mass (&self) -> PointMass {
        PointMass { center: Vec2::new(0.0,0.0), mass: self.mass() }
    }

}

#[test]
fn simple_parts () {

    let p1 = Part::Vessel { width: 2.0, length: 4.0 };
    let _p2 = Part::FuelTank { radius: 1.0, length: 5.0};
    let _p3 = Part::Engine { radius: 1.0, length: 2.0, group: 3};

    let _m1 = p1.mass();
    let _pm1 = p1.point_mass();

}

struct PartObjectCache {
    part: Part,
    object: RigidBody,
    mass: f64
}

struct Beam {
    length: f64
}

impl Beam {

    fn object (&self) -> RigidBody {
        let geom = Cuboid::new(Vec2::new(BEAM_WIDTH, self.length));
        RigidBody::new_dynamic(geom, BEAM_DENSITY, 1.0, 1.0)
    }

    fn mass (&self) -> f64 {
        self.length * BEAM_DENSITY
    }

    fn point_mass (&self) -> PointMass {
        let midpoint = self.length / 2.0;
        PointMass { center: Vec2::new(midpoint, 0.0), mass: self.mass() }
    }

}

struct Attach {
    location: f64,
    rotation: f64
}

type Structure = tagtree::TagTree<Part,Beam,Attach>;

struct WithDepth<T> {
    depth: usize,
    item: T
}

impl Structure {

    fn mass(&self) -> f64 {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                part.mass()
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                beam.mass()
            }
        }
    }

    fn total_mass(&self) -> f64 {
        let mut total_mass: f64 = 0.0;
        for item in self.iter() {
            total_mass += item.structure.mass();
        }
        total_mass
    }

    fn point_masses(&self) -> Vec<PointMass> {
        self.iter().fold(Vec::new(), |mut acc, item| {
            acc.push(PointMass{ center: item.context.translation, mass: item.structure.mass() });
            acc
        })
    }

}

// Opportunity to move into tagtree if Attach is a monoid
struct StructureContextItem<'a> {
    context: Iso2<f64>,
    structure: &'a Structure
}

struct StructureIter<'a> {
    contexts: Vec<Iso2<f64>>,
    work: Vec<WithDepth<&'a Structure>>
}

impl Structure {
    pub fn iter(&self) -> StructureIter {
        let work = vec!(WithDepth { depth: 0, item: self });
        StructureIter { contexts: vec!(Iso2::one()), work: work }
    }
}

impl<'a> Iterator for StructureIter<'a> {

    type Item = StructureContextItem<'a>;

    fn next(&mut self) -> Option<Self::Item> {

        match self.work.pop() {
            None => { None }
            Some(ref curr_work) => {
                let context = self.contexts[curr_work.depth];

                match curr_work.item {
                    &tagtree::TagTree::Leaf(_) => {}
                    &tagtree::TagTree::Node(_, ref attachments) => {
                        attachments.iter().fold((), |_, &(ref attach, ref attachment)| {
                            let trn = Vec2::new(attach.location, 0.0);
                            let rot = Rot2::new(Vec1::new(attach.rotation));
                            let iso = Iso2::new_with_rotmat(trn, rot);
                            let next_context = context * iso;
                            let next_depth = curr_work.depth + 1;
                            if self.contexts.len() < next_depth + 1 {
                                self.contexts.push(next_context);
                            } else {
                                self.contexts[next_depth] = next_context;
                            }
                            self.work.push(WithDepth{depth: next_depth, item: &**attachment});
                        })
                    }
                }

                Some(StructureContextItem { context: context, structure: curr_work.item })

            }
        }

    }

}

fn part(attrs: Part) -> Structure {
    tagtree::TagTree::Leaf(attrs)
}

fn beam(length: f64, parts: Vec<(Attach, Box<Structure>)>) -> Structure {
    tagtree::TagTree::Node(Beam {length: length}, parts)
}

#[test]
fn simple_structures () {
    let p1 = part(Part::Vessel { width: 2.0, length: 4.0 });
    let a1 = Attach{location: 2.0, rotation: 0.0};
    let p2 = part(Part::FuelTank { radius: 1.0, length: 5.0});
    let a2 = Attach{location: 8.0, rotation: 0.0};
    let p3 = part(Part::Engine { radius: 1.0, length: 2.0, group: 3});
    let a3 = Attach{location: 10.0, rotation: 0.0};
    let b1 = beam(5.0, vec![(a1, box p1),(a2, box p2),(a3, box p3)]);
    b1.mass();
}

#[test]
fn simple_ships () {
    beam(8.0, vec![
         (Attach {location: 2.0, rotation: 0.0},
          box part(Part::Vessel {width: 2.0, length: 4.0})),
          (Attach {location: 6.0, rotation: 0.0},
           box part(Part::FuelTank {radius: 1.0, length: 1.5})),
           (Attach {location: 8.0, rotation: 0.0},
            box part(Part::Engine {radius: 1.5, length: 0.5, group: 1}))
           ]);
}
<commit_msg>clean up structure context iteration and add moment of inertia<commit_after>
use std::ops::Neg;
use num::traits::{One, Zero};

use na::{Iso2, Norm, Rot2, Translation, Vec1, Vec2};
use ncollide::shape::{Cone, Cuboid, Cylinder};
use nphysics::object::{RigidBody};

use constants::*;
use tagtree;

enum Part {
    Vessel { width: f64, length: f64 },
    FuelTank { radius: f64, length: f64 },
    Engine { radius: f64, length: f64, group: i32 }
}

struct PointMass {
    center: Vec2<f64>,
    mass: f64
}

impl PointMass {

    fn mass_contrib (&self) -> Vec2<f64> {
        self.center * self.mass
    }

    fn moment_contrib (&self) -> f64 {
        self.mass * self.center.sqnorm()
    }

}

impl Part {

    fn mass (&self) -> f64 {
        match self {
            &Part::Vessel {width, length} => {
                VESSEL_DENSITY * width * length
            }
            &Part::FuelTank {radius, length} => {
                FUELTANK_DENSITY * radius * length
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                ENGINE_DENSITY * radius * length * 0.5
            }
        }
    }

    fn object (&self) -> RigidBody {
        match self {
            &Part::Vessel {width, length} => {
                let geom = Cuboid::new(Vec2::new(width, length));
                RigidBody::new_dynamic(geom, VESSEL_DENSITY, 1.0, 1.0)
            }
            &Part::FuelTank {radius, length} => {
                let geom = Cylinder::new(length, radius);
                RigidBody::new_dynamic(geom, FUELTANK_DENSITY, 1.0, 1.0)
            }
            &Part::Engine {radius, length, group} => {
                let _group = group;
                let geom = Cone::new(length, radius);
                RigidBody::new_dynamic(geom, ENGINE_DENSITY, 1.0, 1.0)
            }
        }
    }

    fn point_mass (&self) -> PointMass {
        PointMass { center: Vec2::new(0.0,0.0), mass: self.mass() }
    }

}

#[test]
fn simple_parts () {

    let p1 = Part::Vessel { width: 2.0, length: 4.0 };
    let _p2 = Part::FuelTank { radius: 1.0, length: 5.0};
    let _p3 = Part::Engine { radius: 1.0, length: 2.0, group: 3};

    let _m1 = p1.mass();
    let _pm1 = p1.point_mass();

}

struct PartObjectCache {
    part: Part,
    object: RigidBody,
    mass: f64
}

struct Beam {
    length: f64
}

impl Beam {

    fn object (&self) -> RigidBody {
        let geom = Cuboid::new(Vec2::new(BEAM_WIDTH, self.length));
        RigidBody::new_dynamic(geom, BEAM_DENSITY, 1.0, 1.0)
    }

    fn mass (&self) -> f64 {
        self.length * BEAM_DENSITY
    }

    fn point_mass (&self) -> PointMass {
        let midpoint = self.length / 2.0;
        PointMass { center: Vec2::new(midpoint, 0.0), mass: self.mass() }
    }

}

struct Attach {
    location: f64,
    rotation: f64
}

type Structure = tagtree::TagTree<Part,Beam,Attach>;

impl Structure {

    fn mass(&self) -> f64 {
        match self {
            &tagtree::TagTree::Leaf(ref part) => {
                part.mass()
            }
            &tagtree::TagTree::Node(ref beam, _) => {
                beam.mass()
            }
        }
    }

    fn total_mass(&self) -> f64 {
        let mut total_mass: f64 = 0.0;
        for item in self.iter() {
            total_mass += item.structure.mass();
        }
        total_mass
    }

    fn point_masses(&self) -> Vec<PointMass> {
        // This smells, could probably return an iterator?
        self.iter().fold(Vec::new(), |mut acc, item| {
            acc.push(PointMass{ center: item.context.translation, mass: item.structure.mass() });
            acc
        })
    }

    fn center_of_mass(&self) -> Vec2<f64> {
        self.point_masses().iter().fold(Vec2::zero(), |acc, pm| {
            acc + pm.mass_contrib()
        })
    }

    fn total_moment(&self) -> f64 {
        let mut point_masses = self.point_masses();
        let neg_center = self.center_of_mass().neg();
        for mut pm in point_masses.iter_mut() {
            pm.center.append_translation_mut(&neg_center);
        }
        point_masses.iter().fold(0.0, |acc, pm| {
            acc + pm.moment_contrib()
        })
    }
}

// Opportunity to move into tagtree if Attach is a monoid
struct StructureContextItem<'a> {
    context: Iso2<f64>,
    structure: &'a Structure,
}

struct StructureWorkItem<'a> {
    context: Iso2<f64>,
    structure: &'a Structure,
}

struct StructureIter<'a> {
    work: Vec<StructureWorkItem<'a>>,
}

impl Structure {
    pub fn iter(&self) -> StructureIter {
        let root_work_item = StructureWorkItem {
            context: Iso2::one(),
            structure: self,
        };
        StructureIter { work: vec!(root_work_item) }
    }
}

impl<'a> Iterator for StructureIter<'a> {

    type Item = StructureContextItem<'a>;

    fn next(&mut self) -> Option<Self::Item> {

        match self.work.pop() {
            None => { None }
            Some(ref curr_work) => {
                let context = curr_work.context;

                match curr_work.structure {
                    &tagtree::TagTree::Leaf(_) => {}
                    &tagtree::TagTree::Node(_, ref attachments) => {
                        // This smells, should probably rewrite as a normal for loop
                        attachments.iter().fold((), |_, &(ref attach, ref attachment)| {
                            let trn = Vec2::new(attach.location, 0.0);
                            let rot = Rot2::new(Vec1::new(attach.rotation));
                            let iso = Iso2::new_with_rotmat(trn, rot);
                            let next_context = context * iso;
                            let next_work = StructureWorkItem {
                                context: next_context,
                            structure: &**attachment
                            };

                            self.work.push(next_work);
                        })
                    }
                }

                Some(StructureContextItem { context: context, structure: curr_work.structure })

            }
        }

    }

}

fn part(attrs: Part) -> Structure {
    tagtree::TagTree::Leaf(attrs)
}

fn beam(length: f64, parts: Vec<(Attach, Box<Structure>)>) -> Structure {
    tagtree::TagTree::Node(Beam {length: length}, parts)
}

#[test]
fn simple_structures () {
    let p1 = part(Part::Vessel { width: 2.0, length: 4.0 });
    let a1 = Attach{location: 2.0, rotation: 0.0};
    let p2 = part(Part::FuelTank { radius: 1.0, length: 5.0});
    let a2 = Attach{location: 8.0, rotation: 0.0};
    let p3 = part(Part::Engine { radius: 1.0, length: 2.0, group: 3});
    let a3 = Attach{location: 10.0, rotation: 0.0};
    let b1 = beam(5.0, vec![(a1, box p1),(a2, box p2),(a3, box p3)]);
    b1.mass();
}

#[test]
fn simple_ships () {
    beam(8.0, vec![
         (Attach {location: 2.0, rotation: 0.0},
          box part(Part::Vessel {width: 2.0, length: 4.0})),
          (Attach {location: 6.0, rotation: 0.0},
           box part(Part::FuelTank {radius: 1.0, length: 1.5})),
           (Attach {location: 8.0, rotation: 0.0},
            box part(Part::Engine {radius: 1.5, length: 0.5, group: 1}))
           ]);
}
<|endoftext|>


<commit_before>use futures::Stream;
use futures::future::Future;
use futures::sync::oneshot;
use hyper;
use hyper::{Method, Request};
use hyper::header::UserAgent;
use hyper_rustls::HttpsConnector;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use serde_json;
use std::collections::HashMap;
use tokio_core::reactor::Remote;

pub struct HTTPClient {
    api_base: String,
    headers: HashMap<&'static str, String>,
    core_remote: Remote,
}

struct InternalResp {
    data: hyper::Chunk,
}

type InternalResponseResult = Result<InternalResp, String>;
type FutureInternalResponse = oneshot::Receiver<InternalResponseResult>;

impl HTTPClient {
    pub fn new(core_remote: Remote, api_base: &str) -> HTTPClient {
        HTTPClient {
            api_base: api_base.into(),
            headers: HashMap::new(),
            core_remote: core_remote,
        }
    }

    pub fn with_headers(self, headers: HashMap<&'static str, String>) -> HTTPClient {
        let mut c = self;
        c.headers = headers;
        c
    }

    pub fn get<T: DeserializeOwned>(&self, path: &str) -> Result<T, String> {
        self.request_de::<T, ()>(Method::Get, path, None)
    }

    pub fn post<T: DeserializeOwned, U: Serialize>(&self, path: &str, body: &U) -> Result<T, String> {
        self.request_de::<T, U>(Method::Post, path, Some(body))
    }

    pub fn post_void<U: Serialize>(&self, path: &str, body: &U) -> Result<(), String> {
        self.request_void::<U>(Method::Post, path, Some(body))
    }

    pub fn put<T: DeserializeOwned, U: Serialize>(&self, path: &str, body: &U) -> Result<T, String> {
        self.request_de::<T, U>(Method::Put, path, Some(body))
    }

    pub fn put_void<U: Serialize>(&self, path: &str, body: &U) -> Result<(), String> {
        self.request_void::<U>(Method::Put, path, Some(body))
    }

    pub fn delete_void(&self, path: &str) -> Result<(), String> {
        self.request_void::<()>(Method::Delete, path, None)
    }

    fn request_de<T: DeserializeOwned, U: Serialize>(
        &self,
        method: Method,
        path: &str,
        body: Option<&U>,
    ) -> Result<T, String> {
        let res = self.request_sync(method, path, body)?;

        let obj: T = match serde_json::from_slice(&res.data) {
            Ok(obj) => obj,
            Err(e) => {
                return Err(format!("Could not parse response: {}\n---\n{}\n---", e, String::from_utf8_lossy(&res.data)))
            }
        };

        Ok(obj)
    }

    fn request_void<U: Serialize>(&self, method: Method, path: &str, body: Option<&U>) -> Result<(), String> {
        self.request_sync(method, path, body)?;
        Ok(())
    }

    fn request_sync<U: Serialize>(&self, method: Method, path: &str, body: Option<&U>) -> Result<InternalResp, String> {
        match self.request_async(method, path, body).wait() {
            Ok(Ok(r)) => Ok(r),
            Ok(Err(e)) => Err(e),
            Err(e) => return Err(format!("{}", e)),
        }
    }

    fn request_async<U: Serialize>(&self, method: Method, path: &str, body: Option<&U>) -> FutureInternalResponse {
        let (tx, rx) = oneshot::channel::<InternalResponseResult>();

        let send_future = |it| if let Err(_) = tx.send(it) {
            error!("Error sending on future channel");
        };

        let url;
        if path.is_empty() {
            url = self.api_base.clone();
        } else if path.starts_with("http://") || path.starts_with("https://") {
            url = path.to_string();
        } else if path.starts_with("/") {
            url = self.api_base.clone() + path;
        } else {
            url = self.api_base.clone() + "/" + path;
        }
        let url: hyper::Uri = match url.parse() {
            Ok(u) => u,
            Err(e) => {
                let _ = send_future(Err(format!("Error: {}", e)));
                return rx;
            }
        };

        let headers = self.headers.clone();

        let mut req = Request::new(method, url);
        req.headers_mut().set(UserAgent::new("octobot"));

        for (k, v) in &headers {
            req.headers_mut().set_raw(k.clone(), v.clone());
        }

        if let Some(body) = body {
            let body_json = match serde_json::to_string(&body) {
                Ok(j) => j,
                Err(e) => {
                    send_future(Err(format!("Error json-encoding body: {}", e)));
                    return rx;
                }
            };
            req.set_body(body_json)
        }

        let path = path.to_string();

        self.core_remote.spawn(move |handle| {
            // TODO: I wonder if these objects are expensive to create and we should be sharing them across requests?
            let https = HttpsConnector::new(4, &handle);
            let client = hyper::Client::configure().connector(https).build(&handle);

            client
                .request(req)
                .map_err(|e| {
                    error!("Error in HTTP request: {}", e);
                })
                .and_then(|res| {
                    let status = res.status();
                    res.body()
                        .concat2()
                        .map_err(|e| {
                            error!("Error in HTTP request: {}", e);
                        })
                        .map(move |buffer| {
                            debug!("Response: HTTP {}\n---\n{}\n---", status, String::from_utf8_lossy(&buffer));
                            if !status.is_success() {
                                send_future(Err(format!(
                                    "Failed request to {}: HTTP {}\n---\n{}\n---",
                                    path,
                                    status,
                                    String::from_utf8_lossy(&buffer)
                                )));
                            } else {
                                send_future(Ok(InternalResp { data: buffer }));
                            }
                        })
                })
        });

        rx
    }
}
<commit_msg>Add public async HTTP methods (#148)<commit_after>use futures::Stream;
use futures::future::{self, Future};
use futures::sync::oneshot;
use hyper;
use hyper::{Method, Request};
use hyper::header::UserAgent;
use hyper_rustls::HttpsConnector;
use serde::de::DeserializeOwned;
use serde::ser::Serialize;
use serde_json;
use std::collections::HashMap;
use tokio_core::reactor::Remote;

pub struct HTTPClient {
    api_base: String,
    headers: HashMap<&'static str, String>,
    core_remote: Remote,
}

struct InternalResp {
    data: hyper::Chunk,
}

type InternalResponseResult = Result<InternalResp, String>;
type FutureInternalResponse = oneshot::Receiver<InternalResponseResult>;

pub type Response<T> = Result<T, String>;
pub type FutureResponse<T> = Box<Future<Item = Response<T>, Error = ()>>;

impl HTTPClient {
    pub fn new(core_remote: Remote, api_base: &str) -> HTTPClient {
        HTTPClient {
            api_base: api_base.into(),
            headers: HashMap::new(),
            core_remote: core_remote,
        }
    }

    pub fn with_headers(self, headers: HashMap<&'static str, String>) -> HTTPClient {
        let mut c = self;
        c.headers = headers;
        c
    }

    pub fn get<T: DeserializeOwned>(&self, path: &str) -> Response<T> {
        self.request_de::<T, ()>(Method::Get, path, None)
    }

    pub fn get_async<T: DeserializeOwned>(&self, path: &str) -> FutureResponse<T> {
        self.request_de_async::<T, ()>(Method::Get, path, None)
    }

    pub fn post<T: DeserializeOwned, U: Serialize>(&self, path: &str, body: &U) -> Response<T> {
        self.request_de::<T, U>(Method::Post, path, Some(body))
    }

    pub fn post_async<T: DeserializeOwned, U: Serialize>(&self, path: &str, body: &U) -> FutureResponse<T> {
        self.request_de_async::<T, U>(Method::Post, path, Some(body))
    }

    pub fn post_void<U: Serialize>(&self, path: &str, body: &U) -> Response<()> {
        self.request_void::<U>(Method::Post, path, Some(body))
    }

    pub fn post_void_async<U: Serialize>(&self, path: &str, body: &U) -> FutureResponse<()> {
        self.request_void_async::<U>(Method::Post, path, Some(body))
    }

    pub fn put<T: DeserializeOwned, U: Serialize>(&self, path: &str, body: &U) -> Response<T> {
        self.request_de::<T, U>(Method::Put, path, Some(body))
    }

    pub fn put_async<T: DeserializeOwned, U: Serialize>(&self, path: &str, body: &U) -> FutureResponse<T> {
        self.request_de_async::<T, U>(Method::Put, path, Some(body))
    }

    pub fn put_void<U: Serialize>(&self, path: &str, body: &U) -> Response<()> {
        self.request_void::<U>(Method::Put, path, Some(body))
    }

    pub fn put_void_async<U: Serialize>(&self, path: &str, body: &U) -> FutureResponse<()> {
        self.request_void_async::<U>(Method::Put, path, Some(body))
    }

    pub fn delete_void(&self, path: &str) -> Response<()> {
        self.request_void::<()>(Method::Delete, path, None)
    }

    pub fn delete_void_async(&self, path: &str) -> FutureResponse<()> {
        self.request_void_async::<()>(Method::Delete, path, None)
    }

    fn request_de<T: DeserializeOwned, U: Serialize>(
        &self,
        method: Method,
        path: &str,
        body: Option<&U>,
    ) -> Response<T> {
        match self.request_de_async(method, path, body).wait() {
            Ok(r) => r,
            Err(_) => Err(format!("Error waiting for HTTP response")),
        }
    }

    fn request_de_async<T: DeserializeOwned, U: Serialize>(
        &self,
        method: Method,
        path: &str,
        body: Option<&U>,
    ) -> FutureResponse<T> {
        Box::new(
            self.request_async(method, path, body)
                .or_else(|_| future::ok(Err(format!("HTTP Request was cancelled"))))
                .map(|res| match res {
                    Ok(res) => {
                        let obj: T = match serde_json::from_slice(&res.data) {
                            Ok(obj) => obj,
                            Err(e) => {
                                return Err(format!(
                                    "Could not parse response: {}\n---\n{}\n---",
                                    e,
                                    String::from_utf8_lossy(&res.data)
                                ))
                            }
                        };
                        Ok(obj)
                    }
                    Err(e) => Err(e),
                }),
        )
    }

    fn request_void<U: Serialize>(&self, method: Method, path: &str, body: Option<&U>) -> Response<()> {
        match self.request_void_async(method, path, body).wait() {
            Ok(r) => r,
            Err(_) => Err(format!("Error waiting for HTTP response")),
        }
    }

    fn request_void_async<U: Serialize>(&self, method: Method, path: &str, body: Option<&U>) -> FutureResponse<()> {
        Box::new(
            self.request_async(method, path, body)
                .or_else(|_| future::ok(Err(format!("HTTP Request was cancelled"))))
                .map(|res| match res {
                    Ok(_) => Ok(()),
                    Err(e) => Err(e),
                }),
        )
    }

    fn request_async<U: Serialize>(&self, method: Method, path: &str, body: Option<&U>) -> FutureInternalResponse {
        let (tx, rx) = oneshot::channel::<InternalResponseResult>();

        let send_future = |it| if let Err(_) = tx.send(it) {
            error!("Error sending on future channel");
        };

        let url;
        if path.is_empty() {
            url = self.api_base.clone();
        } else if path.starts_with("http://") || path.starts_with("https://") {
            url = path.to_string();
        } else if path.starts_with("/") {
            url = self.api_base.clone() + path;
        } else {
            url = self.api_base.clone() + "/" + path;
        }
        let url: hyper::Uri = match url.parse() {
            Ok(u) => u,
            Err(e) => {
                let _ = send_future(Err(format!("Error: {}", e)));
                return rx;
            }
        };

        let headers = self.headers.clone();

        let mut req = Request::new(method, url);
        req.headers_mut().set(UserAgent::new("octobot"));

        for (k, v) in &headers {
            req.headers_mut().set_raw(k.clone(), v.clone());
        }

        if let Some(body) = body {
            let body_json = match serde_json::to_string(&body) {
                Ok(j) => j,
                Err(e) => {
                    send_future(Err(format!("Error json-encoding body: {}", e)));
                    return rx;
                }
            };
            req.set_body(body_json)
        }

        let path = path.to_string();

        self.core_remote.spawn(move |handle| {
            // TODO: I wonder if these objects are expensive to create and we should be sharing them across requests?
            let https = HttpsConnector::new(4, &handle);
            let client = hyper::Client::configure().connector(https).build(&handle);

            client
                .request(req)
                .map_err(|e| {
                    error!("Error in HTTP request: {}", e);
                })
                .and_then(|res| {
                    let status = res.status();
                    res.body()
                        .concat2()
                        .map_err(|e| {
                            error!("Error in HTTP request: {}", e);
                        })
                        .map(move |buffer| {
                            debug!("Response: HTTP {}\n---\n{}\n---", status, String::from_utf8_lossy(&buffer));
                            if !status.is_success() {
                                send_future(Err(format!(
                                    "Failed request to {}: HTTP {}\n---\n{}\n---",
                                    path,
                                    status,
                                    String::from_utf8_lossy(&buffer)
                                )));
                            } else {
                                send_future(Ok(InternalResp { data: buffer }));
                            }
                        })
                })
        });

        rx
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use foxbox_taxonomy::manager::WatchGuard;
use foxbox_taxonomy::api::API;
use hyper::net::{ NetworkListener };
use iron::{ AfterMiddleware, Chain, Handler,
            HttpServerFactory, Iron, IronResult, Request,
            Response, ServerFactory };
use iron_cors::CORS;
use iron::error::{ IronError };
use iron::method::Method;
use iron::status::Status;
use mount::Mount;
use router::NoRoute;
use service_router;
use static_router;
use std::net::SocketAddr;
use std::thread;
use taxonomy_router;
use tls::SniServerFactory;
use traits::Controller;

const THREAD_COUNT: usize = 8;

struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        use std::io::Error as StdError;
        use std::io::ErrorKind;

        if let Some(_) = err.error.downcast::<NoRoute>() {
            // Router error
            return Ok(Response::with((Status::NotFound,
                                      format!("Unknown resource: {}", err))));
        } else if let Some(err) = err.error.downcast::<StdError>() {
            // StaticFile error
            if err.kind() == ErrorKind::NotFound {
                return Ok(Response::with((Status::NotFound,
                                          format!("Unknown resource: {}", err))));
            }
        }

        // Just let other errors go through, like 401.
        Err(err)
    }
}

struct Ping;

impl Handler for Ping {
    fn handle (&self, _: &mut Request) -> IronResult<Response> {
        Ok(Response::with(Status::Ok))
    }
}

pub struct HttpServer<T: Controller> {
    controller: T
}

impl<T: Controller> HttpServer<T> {
    pub fn new(controller: T) -> Self {
        HttpServer { controller: controller }
    }

    pub fn start<A>(&mut self, adapter_api: A)
        where A: API<WatchGuard=WatchGuard> + 'static {

        let router = service_router::create(self.controller.clone());
        let taxonomy_chain = taxonomy_router::create(self.controller.clone(),
                                                      adapter_api);

        let users_manager = self.controller.get_users_manager();
        let mut mount = Mount::new();
        mount.mount("/", static_router::create(users_manager.clone()))
             .mount("/ping", Ping)
             .mount("/services", router)
             .mount("/api/v1", taxonomy_chain)
             .mount("/users", users_manager.get_router_chain());

        let mut chain = Chain::new(mount);
        chain.link_after(Custom404);

        let cors = CORS::new(vec![
            (vec![Method::Get], "ping".to_owned()),
            (vec![Method::Get, Method::Post, Method::Put, Method::Delete],
             "services/:service/:command".to_owned()),
            (vec![Method::Get], "services/list".to_owned()),

            // Taxonomy router paths. Keep in sync with taxonomy_router.rs
            (vec![Method::Get, Method::Post], "api/v1/services".to_owned()),
            (vec![Method::Post, Method::Delete], "api/v1/services/tags".to_owned()),
            (vec![Method::Get, Method::Post], "api/v1/channels/getters".to_owned()),
            (vec![Method::Get, Method::Post], "api/v1/channels/setters".to_owned()),
            (vec![Method::Get], "api/v1/channels/get".to_owned()),
            (vec![Method::Put], "api/v1/channels/set".to_owned()),
            (vec![Method::Post, Method::Delete], "api/v1/channel/getters/tags".to_owned()),
            (vec![Method::Post, Method::Delete], "api/v1/channel/setters/tags".to_owned())
        ]);
        chain.link_after(cors);

        let addrs: Vec<_> = self.controller.http_as_addrs().unwrap().collect();

        if self.controller.get_tls_enabled() {
            let mut certificate_manager = self.controller.get_certificate_manager();
            let server_factory = SniServerFactory::new(&mut certificate_manager);
            start_server(addrs, chain, server_factory);
        } else {
            start_server(addrs, chain, HttpServerFactory {});
        }
    }
}

fn start_server<TListener, T>(addrs: Vec<SocketAddr>, chain: Chain, factory: T)
    where TListener: NetworkListener + Send + 'static,
          T: ServerFactory<TListener> + Send + 'static {

    thread::Builder::new().name("HttpServer".to_owned())
                          .spawn(move || {
        Iron::new(chain)
             .listen_with(addrs[0], THREAD_COUNT, &factory, None)
             .unwrap();
    }).unwrap();
}

#[cfg(test)]
describe! ping {
    before_each {
        use mount::Mount;
        use iron::Headers;
        use iron::status::Status;
        use iron_test::request;
        use super::Ping;

        let mut mount = Mount::new();
        mount.mount("/ping", Ping);
    }

    it "should response 200 Ok" {
        let response = request::get("http://localhost:3000/ping",
                                    Headers::new(),
                                    &mount).unwrap();
        assert_eq!(response.status.unwrap(), Status::Ok);
    }
}

#[cfg(test)]
describe! cors {
    before_each {
        extern crate hyper;

        use foxbox_taxonomy::manager::AdapterManager;
        use iron::headers;
        use iron::method::Method;
        use std::thread;
        use std::time::Duration;
        use stubs::controller::ControllerStub;

        let taxo_manager = AdapterManager::new();

        let mut http_server = HttpServer::new(ControllerStub::new());
        http_server.start(taxo_manager);
    }

    it "should get the appropriate CORS headers" {
        let endpoints = vec![
            (vec![Method::Get, Method::Post, Method::Put],
             "services/:service/:command".to_owned()),
            (vec![Method::Get], "services/list".to_owned())
        ];
        // HACK: Let some time for the http server to start.
        thread::sleep(Duration::new(3, 0));
        let client = hyper::Client::new();
        for endpoint in endpoints {
            let (_, path) = endpoint;
            let path = "http://localhost:3000/".to_owned() +
                       &(path.replace(":", "foo"));
            let res = client.get(&path).send();
            let headers = &res.unwrap().headers;
            assert!(headers.has::<headers::AccessControlAllowOrigin>());
            assert!(headers.has::<headers::AccessControlAllowHeaders>());
            assert!(headers.has::<headers::AccessControlAllowMethods>());
        };
    }
}

<commit_msg>Enable CORS support for binary response. r=fabrice<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use foxbox_taxonomy::manager::WatchGuard;
use foxbox_taxonomy::api::API;
use hyper::net::{ NetworkListener };
use iron::{ AfterMiddleware, Chain, Handler,
            HttpServerFactory, Iron, IronResult, Request,
            Response, ServerFactory };
use iron_cors::CORS;
use iron::error::{ IronError };
use iron::method::Method;
use iron::status::Status;
use mount::Mount;
use router::NoRoute;
use service_router;
use static_router;
use std::net::SocketAddr;
use std::thread;
use taxonomy_router;
use tls::SniServerFactory;
use traits::Controller;

const THREAD_COUNT: usize = 8;

struct Custom404;

impl AfterMiddleware for Custom404 {
    fn catch(&self, _: &mut Request, err: IronError) -> IronResult<Response> {
        use std::io::Error as StdError;
        use std::io::ErrorKind;

        if let Some(_) = err.error.downcast::<NoRoute>() {
            // Router error
            return Ok(Response::with((Status::NotFound,
                                      format!("Unknown resource: {}", err))));
        } else if let Some(err) = err.error.downcast::<StdError>() {
            // StaticFile error
            if err.kind() == ErrorKind::NotFound {
                return Ok(Response::with((Status::NotFound,
                                          format!("Unknown resource: {}", err))));
            }
        }

        // Just let other errors go through, like 401.
        Err(err)
    }
}

struct Ping;

impl Handler for Ping {
    fn handle (&self, _: &mut Request) -> IronResult<Response> {
        Ok(Response::with(Status::Ok))
    }
}

pub struct HttpServer<T: Controller> {
    controller: T
}

impl<T: Controller> HttpServer<T> {
    pub fn new(controller: T) -> Self {
        HttpServer { controller: controller }
    }

    pub fn start<A>(&mut self, adapter_api: A)
        where A: API<WatchGuard=WatchGuard> + 'static {

        let router = service_router::create(self.controller.clone());
        let taxonomy_chain = taxonomy_router::create(self.controller.clone(),
                                                      adapter_api);

        let users_manager = self.controller.get_users_manager();
        let mut mount = Mount::new();
        mount.mount("/", static_router::create(users_manager.clone()))
             .mount("/ping", Ping)
             .mount("/services", router)
             .mount("/api/v1", taxonomy_chain)
             .mount("/users", users_manager.get_router_chain());

        let mut chain = Chain::new(mount);
        chain.link_after(Custom404);

        let cors = CORS::new(vec![
            (vec![Method::Get], "ping".to_owned()),
            (vec![Method::Get, Method::Post, Method::Put, Method::Delete],
             "services/:service/:command".to_owned()),
            (vec![Method::Get], "services/list".to_owned()),

            // Taxonomy router paths. Keep in sync with taxonomy_router.rs
            (vec![Method::Get, Method::Post], "api/v1/services".to_owned()),
            (vec![Method::Post, Method::Delete], "api/v1/services/tags".to_owned()),
            (vec![Method::Get, Method::Post], "api/v1/channels/getters".to_owned()),
            (vec![Method::Get, Method::Post], "api/v1/channels/setters".to_owned()),
            (vec![Method::Put], "api/v1/channels/get".to_owned()),
            (vec![Method::Put], "api/v1/channels/set".to_owned()),
            (vec![Method::Post, Method::Delete], "api/v1/channel/getters/tags".to_owned()),
            (vec![Method::Post, Method::Delete], "api/v1/channel/setters/tags".to_owned())
        ]);
        chain.link_after(cors);

        let addrs: Vec<_> = self.controller.http_as_addrs().unwrap().collect();

        if self.controller.get_tls_enabled() {
            let mut certificate_manager = self.controller.get_certificate_manager();
            let server_factory = SniServerFactory::new(&mut certificate_manager);
            start_server(addrs, chain, server_factory);
        } else {
            start_server(addrs, chain, HttpServerFactory {});
        }
    }
}

fn start_server<TListener, T>(addrs: Vec<SocketAddr>, chain: Chain, factory: T)
    where TListener: NetworkListener + Send + 'static,
          T: ServerFactory<TListener> + Send + 'static {

    thread::Builder::new().name("HttpServer".to_owned())
                          .spawn(move || {
        Iron::new(chain)
             .listen_with(addrs[0], THREAD_COUNT, &factory, None)
             .unwrap();
    }).unwrap();
}

#[cfg(test)]
describe! ping {
    before_each {
        use mount::Mount;
        use iron::Headers;
        use iron::status::Status;
        use iron_test::request;
        use super::Ping;

        let mut mount = Mount::new();
        mount.mount("/ping", Ping);
    }

    it "should response 200 Ok" {
        let response = request::get("http://localhost:3000/ping",
                                    Headers::new(),
                                    &mount).unwrap();
        assert_eq!(response.status.unwrap(), Status::Ok);
    }
}

#[cfg(test)]
describe! cors {
    before_each {
        extern crate hyper;

        use foxbox_taxonomy::manager::AdapterManager;
        use iron::headers;
        use iron::method::Method;
        use std::thread;
        use std::time::Duration;
        use stubs::controller::ControllerStub;

        let taxo_manager = AdapterManager::new();

        let mut http_server = HttpServer::new(ControllerStub::new());
        http_server.start(taxo_manager);
    }

    it "should get the appropriate CORS headers" {
        let endpoints = vec![
            (vec![Method::Get, Method::Post, Method::Put],
             "services/:service/:command".to_owned()),
            (vec![Method::Get], "services/list".to_owned())
        ];
        // HACK: Let some time for the http server to start.
        thread::sleep(Duration::new(3, 0));
        let client = hyper::Client::new();
        for endpoint in endpoints {
            let (_, path) = endpoint;
            let path = "http://localhost:3000/".to_owned() +
                       &(path.replace(":", "foo"));
            let res = client.get(&path).send();
            let headers = &res.unwrap().headers;
            assert!(headers.has::<headers::AccessControlAllowOrigin>());
            assert!(headers.has::<headers::AccessControlAllowHeaders>());
            assert!(headers.has::<headers::AccessControlAllowMethods>());
        };
    }
}

<|endoftext|>


<commit_before>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

#[derive(Debug)]
pub enum RuntimeError {
    RuntimeError,
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Expr::Literal(ref l) => unimplemented!(),
            &Expr::Unary(ref u) => unimplemented!(),
            &Expr::Binary(ref b) => unimplemented!(),
            &Expr::Grouping(ref g) => unimplemented!(),
        }
    }
}
<commit_msg>Interpret for literals<commit_after>use ast::{Expr, Literal, UnaryOperator, UnaryExpr, BinaryOperator, BinaryExpr, Grouping};

#[derive(Debug)]
pub enum Value {
    Nil,
    Boolean(bool),
    Number(f64),
    String(String),
}

#[derive(Debug)]
pub enum RuntimeError {
    RuntimeError,
}

pub trait Interpret {
    fn interpret(&self) -> Result<Value, RuntimeError>;
}

impl Interpret for Expr {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Expr::Literal(ref l) => l.interpret(),
            &Expr::Unary(ref u) => unimplemented!(),
            &Expr::Binary(ref b) => unimplemented!(),
            &Expr::Grouping(ref g) => unimplemented!(),
        }
    }
}

impl Interpret for Literal {
    fn interpret(&self) -> Result<Value, RuntimeError> {
        match self {
            &Literal::NilLiteral => Ok(Value::Nil),
            &Literal::BoolLiteral(b) => Ok(Value::Boolean(b)),
            &Literal::StringLiteral(ref s) => Ok(Value::String(s.clone())),
            &Literal::NumberLiteral(n) => Ok(Value::Number(n)),
        }
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;

use hyper::Client;
use hyper::client::{Response};
use hyper::header::Headers;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use hyper::status::StatusCode;
use jira_request::*;
use std::io::Read;

pub fn send<R: JIRARequest, T: serde::de::Deserialize>(request: R) -> Result<T, String> {
    let tls = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(tls);
    let client = Client::with_connector(connector);

    let url = format!("{}{}", &request.base_url(), &request.path());

    let mut res: Response = client.request(request.method(), &url)
        .headers(request.headers().unwrap_or(Headers::new()))
        .body(&request.body().unwrap_or("".to_string()))
        .send()
        .map_err(|e| e.to_string())?;

    let mut body = String::new();
    res.read_to_string(&mut body).map_err(|e| e.to_string())?;

    match res.status {
        StatusCode::Ok => serde_json::from_str::<T>(&body).map_err(|e| e.to_string()),
        _ => Err(body),
    }
}<commit_msg>:hammer: Fix the type of body to Vec<commit_after>extern crate serde;
extern crate serde_json;

use hyper::Client;
use hyper::client::{Response};
use hyper::header::Headers;
use hyper::net::HttpsConnector;
use hyper_native_tls::NativeTlsClient;
use hyper::status::StatusCode;
use jira_request::*;
use std::io::Read;

pub fn send<R: JIRARequest, T: serde::de::Deserialize>(request: R) -> Result<T, String> {
    let tls = NativeTlsClient::new().unwrap();
    let connector = HttpsConnector::new(tls);
    let client = Client::with_connector(connector);

    let url = format!("{}{}", &request.base_url(), &request.path());

    let mut res: Response = client.request(request.method(), &url)
        .headers(request.headers().unwrap_or(Headers::new()))
        .body(&request.body().unwrap_or("".to_string()))
        .send()
        .map_err(|e| e.to_string())?;

    let mut body = vec![];
    res.read_to_end(&mut body).unwrap();

    match res.status {
        StatusCode::Ok => serde_json::from_str::<T>(&String::from_utf8_lossy(&body)).map_err(|e| e.to_string()),
        _ => Err(String::from_utf8_lossy(&body).to_string()),
    }
}<|endoftext|>


<commit_before>#[macro_use] extern crate diesel;

use diesel::*;
use diesel::pg::PgConnection;
use diesel::types::Text;

table! {
    users {
        id -> Integer,
        name -> VarChar,
    }
}

table! {
    posts {
        id -> Integer,
        title -> Text,
        user_id -> Integer,
    }
}

joinable!(posts -> users (user_id));
select_column_workaround!(posts -> users (id, title, user_id));
select_column_workaround!(users -> posts (id, name));
sql_function!(lower, lower_t, (x: Text) -> Text);

fn main() {
    let conn = PgConnection::establish("some url").unwrap();
    let join = users::table.left_outer_join(posts::table);

    // Valid
    let _ = join.select(posts::title.nullable());
    // FIXME: This doesn't compile but we want it to
    // Valid -- NULL to a function will return null
    let _ = join.select(lower(posts::title).nullable()); //~ ERROR E0271
    // Invalid, only Nullable<title> is selectable
    let _ = join.select(lower(posts::title)); //~ ERROR E0271
    // Invalid, Nullable<title> is selectable, but lower expects not-null
    let _ = join.select(lower(posts::title.nullable())); //~ ERROR E0271
}
<commit_msg>Fix failing tests<commit_after>#[macro_use] extern crate diesel;

use diesel::*;
use diesel::pg::PgConnection;
use diesel::types::Text;

table! {
    users {
        id -> Integer,
        name -> VarChar,
    }
}

table! {
    posts {
        id -> Integer,
        title -> Text,
        user_id -> Integer,
    }
}

joinable!(posts -> users (user_id));
sql_function!(lower, lower_t, (x: Text) -> Text);

fn main() {
    let conn = PgConnection::establish("some url").unwrap();
    let join = users::table.left_outer_join(posts::table);

    // Valid
    let _ = join.select(posts::title.nullable());
    // FIXME: This doesn't compile but we want it to
    // Valid -- NULL to a function will return null
    let _ = join.select(lower(posts::title).nullable()); //~ ERROR E0271
    // Invalid, only Nullable<title> is selectable
    let _ = join.select(lower(posts::title)); //~ ERROR E0271
    // Invalid, Nullable<title> is selectable, but lower expects not-null
    let _ = join.select(lower(posts::title.nullable())); //~ ERROR E0271
}
<|endoftext|>


<commit_before>#![cfg(feature = "ram")]

extern crate rusoto_core;
extern crate rusoto_ram;

use rusoto_core::Region;
use rusoto_ram::{ListResourcesRequest, Ram, RamClient};

#[test]
fn should_list_skills() {
    let client = RamClient::new(Region::UsEast1);
    let response = client
        .list_resources(ListResourcesRequest {
            resource_owner: "SELF".into(),
            ..ListResourcesRequest::default()
        })
        .sync();
    println!("response is {:#?}", response);
}
<commit_msg>copied test name<commit_after>#![cfg(feature = "ram")]

extern crate rusoto_core;
extern crate rusoto_ram;

use rusoto_core::Region;
use rusoto_ram::{ListResourcesRequest, Ram, RamClient};

#[test]
fn should_work() {
    let client = RamClient::new(Region::UsEast1);
    let response = client
        .list_resources(ListResourcesRequest {
            resource_owner: "SELF".into(),
            ..ListResourcesRequest::default()
        })
        .sync();
    println!("response is {:#?}", response);
}
<|endoftext|>