<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    counters,
    errors::is_internal_error,
    methods::{Handler, JsonRpcService},
    response::{JsonRpcResponse, X_DIEM_CHAIN_ID, X_DIEM_TIMESTAMP_USEC_ID, X_DIEM_VERSION_ID},
    util::{sdk_info_from_user_agent, SdkInfo},
};
use anyhow::{ensure, Result};
use diem_config::config::{NodeConfig, RoleType};
use diem_json_rpc_types::Method;
use diem_logger::{debug, Schema};
use diem_mempool::MempoolClientSender;
use diem_types::{chain_id::ChainId, ledger_info::LedgerInfoWithSignatures};
use futures::future::{join_all, Either};
use rand::{rngs::OsRng, RngCore};
use serde_json::Value;
use std::{
    net::SocketAddr,
    ops::Sub,
    sync::Arc,
    time::{Duration, SystemTime, UNIX_EPOCH},
};
use storage_interface::DbReader;
use tokio::runtime::{Builder, Runtime};
use warp::{
    http::header,
    reject::{self, Reject},
    Filter, Reply,
};

// Counter labels for runtime metrics
const LABEL_FAIL: &str = "fail";
const LABEL_SUCCESS: &str = "success";
const LABEL_BATCH: &str = "batch";
const LABEL_SINGLE: &str = "single";

#[derive(Schema)]
struct HttpRequestLog<'a> {
    #[schema(display)]
    remote_addr: Option<std::net::SocketAddr>,
    method: String,
    path: String,
    status: u16,
    referer: Option<&'a str>,
    user_agent: Option<&'a str>,
    #[schema(debug)]
    elapsed: std::time::Duration,
    forwarded: Option<&'a str>,
}

#[derive(Schema)]
struct RpcRequestLog<'a> {
    trace_id: &'a str,
    request: &'a Value,
}

#[derive(Schema)]
struct RpcResponseLog<'a> {
    trace_id: &'a str,
    is_batch: bool,
    response_error: bool,
    response: &'a JsonRpcResponse,
}

// HealthCheckParams is optional params for different layer's health check.
// If no param is provided, server return 200 by default to indicate HTTP server is running health.
#[derive(serde::Deserialize)]
struct HealthCheckParams {
    // Health check returns 200 when this param is provided and meet the following condition:
    //   server latest ledger info timestamp >= server current time timestamp + duration_secs
    pub duration_secs: Option<u64>,
}

#[macro_export]
macro_rules! log_response {
    ($trace_id: expr, $resp: expr, $is_batch: expr) => {
        let log = RpcResponseLog {
            trace_id: $trace_id,
            is_batch: $is_batch,
            response_error: $resp.error.is_some(),
            response: $resp,
        };
        match &$resp.error {
            Some(error) if is_internal_error(&error.code) => {
                diem_logger::error!(log)
            }
            _ => diem_logger::trace!(log),
        }
    };
}

/// Creates HTTP server (warp-based) that serves JSON RPC requests
/// Returns handle to corresponding Tokio runtime
pub fn bootstrap(
    address: SocketAddr,
    batch_size_limit: u16,
    page_size_limit: u16,
    content_len_limit: usize,
    tls_cert_path: &Option<String>,
    tls_key_path: &Option<String>,
    diem_db: Arc<dyn DbReader>,
    mp_sender: MempoolClientSender,
    role: RoleType,
    chain_id: ChainId,
) -> Runtime {
    let runtime = Builder::new_multi_thread()
        .thread_name("json-rpc")
        .enable_all()
        .build()
        .expect("[json-rpc] failed to create runtime");

    let service = JsonRpcService::new(
        diem_db.clone(),
        mp_sender,
        role,
        chain_id,
        batch_size_limit,
        page_size_limit,
    );

    let base_route = warp::any()
        .and(warp::post())
        .and(warp::header::exact("content-type", "application/json"))
        .and(warp::body::content_length_limit(content_len_limit as u64))
        .and(warp::body::json())
        .and(warp::any().map(move || service.clone()))
        .and(warp::filters::header::optional::<String>("user-agent"))
        .and_then(rpc_endpoint)
        .with(warp::log::custom(|info| {
            debug!(HttpRequestLog {
                remote_addr: info.remote_addr(),
                method: info.method().to_string(),
                path: info.path().to_string(),
                status: info.status().as_u16(),
                referer: info.referer(),
                user_agent: info.user_agent(),
                elapsed: info.elapsed(),
                forwarded: info
                    .request_headers()
                    .get(header::FORWARDED)
                    .and_then(|v| v.to_str().ok())
            })
        }))
        // CORS is required for full node server to accept requests from different domain web pages.
        // It needs to be configured for the json-rpc request accepting method and headers.
        // Technically it's fine for any headers, but for simplicity we only set must have header
        // content-type.
        .with(
            warp::cors()
                .allow_any_origin()
                .allow_methods(vec!["POST"])
                .allow_headers(vec![header::CONTENT_TYPE]),
        );

    // For now we still allow user to use "/", but user should start to move to "/v1" soon
    let route_root = warp::path::end().and(base_route.clone());

    let route_v1 = warp::path::path("v1")
        .and(warp::path::end())
        .and(base_route);

    let health_route = warp::path!("-" / "healthy")
        .and(warp::path::end())
        .and(warp::query().map(move |params: HealthCheckParams| params))
        .and(warp::any().map(move || diem_db.clone()))
        .and(warp::any().map(SystemTime::now))
        .and_then(health_check);

    let full_route = health_route.or(route_v1.or(route_root));

    // Ensure that we actually bind to the socket first before spawning the
    // server tasks. This helps in tests to prevent races where a client attempts
    // to make a request before the server task is actually listening on the
    // socket.
    //
    // Note: we need to enter the runtime context first to actually bind, since
    //       tokio TcpListener can only be bound inside a tokio context.
    let _guard = runtime.enter();
    let server = match tls_cert_path {
        None => Either::Left(warp::serve(full_route).bind(address)),
        Some(cert_path) => Either::Right(
            warp::serve(full_route)
                .tls()
                .cert_path(cert_path)
                .key_path(tls_key_path.as_ref().unwrap())
                .bind(address),
        ),
    };
    runtime.handle().spawn(server);
    runtime
}

/// Creates JSON RPC endpoint by given node config
pub fn bootstrap_from_config(
    config: &NodeConfig,
    chain_id: ChainId,
    diem_db: Arc<dyn DbReader>,
    mp_sender: MempoolClientSender,
) -> Runtime {
    bootstrap(
        config.json_rpc.address,
        config.json_rpc.batch_size_limit,
        config.json_rpc.page_size_limit,
        config.json_rpc.content_length_limit,
        &config.json_rpc.tls_cert_path,
        &config.json_rpc.tls_key_path,
        diem_db,
        mp_sender,
        config.base.role,
        chain_id,
    )
}

async fn health_check(
    params: HealthCheckParams,
    db: Arc<dyn DbReader>,
    now: SystemTime,
) -> Result<Box<dyn warp::Reply>, warp::Rejection> {
    if let Some(duration) = params.duration_secs {
        let ledger_info = db
            .get_latest_ledger_info()
            .map_err(|_| reject::custom(HealthCheckError))?;
        let timestamp = ledger_info.ledger_info().timestamp_usecs();

        check_latest_ledger_info_timestamp(duration, timestamp, now)
            .map_err(|_| reject::custom(HealthCheckError))?;
    }
    Ok(Box::new("diem-node:ok"))
}

pub fn check_latest_ledger_info_timestamp(
    duration_sec: u64,
    timestamp_usecs: u64,
    now: SystemTime,
) -> Result<()> {
    let timestamp = Duration::from_micros(timestamp_usecs);
    let expectation = now
        .sub(Duration::from_secs(duration_sec))
        .duration_since(UNIX_EPOCH)?;
    ensure!(timestamp >= expectation);
    Ok(())
}

/// JSON RPC entry point
/// Handles all incoming rpc requests
pub(crate) async fn rpc_endpoint(
    data: Value,
    service: JsonRpcService,
    user_agent: Option<String>,
) -> Result<warp::reply::Response, warp::Rejection> {
    let label = match data {
        Value::Array(_) => LABEL_BATCH,
        _ => LABEL_SINGLE,
    };
    counters::RPC_REQUESTS.with_label_values(&[label]).inc();
    let timer = counters::RPC_REQUEST_LATENCY
        .with_label_values(&[label])
        .start_timer();
    let ret = rpc_endpoint_without_metrics(data, service, user_agent.as_deref()).await;
    timer.stop_and_record();
    ret
}

async fn rpc_endpoint_without_metrics(
    data: Value,
    service: JsonRpcService,
    user_agent: Option<&str>,
) -> Result<warp::reply::Response, warp::Rejection> {
    // take snapshot of latest version of DB to be used across all requests, especially for batched requests
    let ledger_info = service
        .get_latest_ledger_info()
        .map_err(|_| reject::custom(DatabaseError))?;

    let mut rng = OsRng;
    let trace_id = format!("{:x}", rng.next_u64());
    debug!(RpcRequestLog {
        trace_id: &trace_id,
        request: &data,
    });
    let chain_id = service.chain_id();
    let latest_ledger_version = ledger_info.ledger_info().version();
    let latest_ledger_timestamp_usecs = ledger_info.ledger_info().timestamp_usecs();
    let sdk_info = sdk_info_from_user_agent(user_agent);

    let resp = if let Value::Array(requests) = data {
        match service.validate_batch_size_limit(requests.len()) {
            Ok(_) => {
                // batch API call
                let futures = requests.into_iter().map(|req| {
                    rpc_request_handler(req, &service, &ledger_info, LABEL_BATCH, sdk_info)
                });
                let responses = join_all(futures).await;
                for resp in &responses {
                    log_response!(&trace_id, &resp, true);
                }
                warp::reply::json(&responses)
            }
            Err(err) => {
                let mut response = JsonRpcResponse::new(
                    chain_id,
                    latest_ledger_version,
                    latest_ledger_timestamp_usecs,
                );
                response.error = Some(err);
                bump_counters(&response, LABEL_BATCH, None, sdk_info);
                log_response!(&trace_id, &response, true);

                warp::reply::json(&response)
            }
        }
    } else {
        // single API call
        let resp = rpc_request_handler(data, &service, &ledger_info, LABEL_SINGLE, sdk_info).await;
        log_response!(&trace_id, &resp, false);

        warp::reply::json(&resp)
    };

    let mut http_response = resp.into_response();
    let headers = http_response.headers_mut();

    headers.insert(
        X_DIEM_CHAIN_ID,
        header::HeaderValue::from_str(&chain_id.id().to_string()).unwrap(),
    );
    headers.insert(
        X_DIEM_VERSION_ID,
        header::HeaderValue::from_str(&latest_ledger_version.to_string()).unwrap(),
    );
    headers.insert(
        X_DIEM_TIMESTAMP_USEC_ID,
        header::HeaderValue::from_str(&latest_ledger_timestamp_usecs.to_string()).unwrap(),
    );

    Ok(http_response)
}

async fn rpc_request_handler(
    request: Value,
    service: &JsonRpcService,
    ledger_info: &LedgerInfoWithSignatures,
    request_type_label: &str,
    sdk_info: SdkInfo,
) -> JsonRpcResponse {
    let handler = Handler::new(&service, &ledger_info);

    let mut response = JsonRpcResponse::new(
        service.chain_id(),
        ledger_info.ledger_info().version(),
        ledger_info.ledger_info().timestamp_usecs(),
    );
    let method: Option<Method>;

    match diem_json_rpc_types::request::JsonRpcRequest::from_value(request) {
        Ok(request) => {
            method = Some(request.method_request.method());
            let timer = counters::METHOD_LATENCY
                .with_label_values(&[request_type_label, request.method_request.method().as_str()])
                .start_timer();
            response.id = Some(serde_json::to_value(&request.id).unwrap());
            match handler.handle(request.method_request).await {
                Ok(ret) => response.result = Some(ret),
                Err(e) => response.error = Some(e),
            }
            timer.stop_and_record();
        }
        Err((e, m, id)) => {
            method = m;
            response.id = id.map(|id| serde_json::to_value(&id).unwrap());
            response.error = Some(e);
        }
    }

    bump_counters(&response, request_type_label, method, sdk_info);

    response
}

fn bump_counters(
    response: &JsonRpcResponse,
    request_type: &str,
    method: Option<Method>,
    sdk_info: SdkInfo,
) {
    let method_str = method.as_ref().map(|m| m.as_str()).unwrap_or("not_found");
    let result_label = if let Some(error) = &response.error {
        if is_internal_error(&error.code) {
            counters::INTERNAL_ERRORS
                .with_label_values(&[
                    request_type,
                    method_str,
                    &error.code.to_string(),
                    sdk_info.language.as_str(),
                    &sdk_info.version.to_string(),
                ])
                .inc();
        } else {
            let label = match error.code {
                -32600 => "invalid_request",
                -32601 => "method_not_found",
                -32602 => "invalid_params",
                -32604 => "invalid_format",
                _ => "unexpected_code",
            };
            counters::INVALID_REQUESTS
                .with_label_values(&[
                    request_type,
                    method_str,
                    label,
                    sdk_info.language.as_str(),
                    &sdk_info.version.to_string(),
                ])
                .inc();
        }
        LABEL_FAIL
    } else {
        LABEL_SUCCESS
    };

    if method.is_some() {
        counters::REQUESTS
            .with_label_values(&[
                request_type,
                method_str,
                result_label,
                sdk_info.language.as_str(),
                &sdk_info.version.to_string(),
            ])
            .inc();
    }
}

/// Warp rejection types
#[derive(Debug)]
struct DatabaseError;

impl Reject for DatabaseError {}

#[derive(Debug)]
struct HealthCheckError;
impl warp::reject::Reject for HealthCheckError {}
<commit_msg>json-rpc: fix comment explaining the behavior of the '/-/healthy' route behaves<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    counters,
    errors::is_internal_error,
    methods::{Handler, JsonRpcService},
    response::{JsonRpcResponse, X_DIEM_CHAIN_ID, X_DIEM_TIMESTAMP_USEC_ID, X_DIEM_VERSION_ID},
    util::{sdk_info_from_user_agent, SdkInfo},
};
use anyhow::{ensure, Result};
use diem_config::config::{NodeConfig, RoleType};
use diem_json_rpc_types::Method;
use diem_logger::{debug, Schema};
use diem_mempool::MempoolClientSender;
use diem_types::{chain_id::ChainId, ledger_info::LedgerInfoWithSignatures};
use futures::future::{join_all, Either};
use rand::{rngs::OsRng, RngCore};
use serde_json::Value;
use std::{
    net::SocketAddr,
    ops::Sub,
    sync::Arc,
    time::{Duration, SystemTime, UNIX_EPOCH},
};
use storage_interface::DbReader;
use tokio::runtime::{Builder, Runtime};
use warp::{
    http::header,
    reject::{self, Reject},
    Filter, Reply,
};

// Counter labels for runtime metrics
const LABEL_FAIL: &str = "fail";
const LABEL_SUCCESS: &str = "success";
const LABEL_BATCH: &str = "batch";
const LABEL_SINGLE: &str = "single";

#[derive(Schema)]
struct HttpRequestLog<'a> {
    #[schema(display)]
    remote_addr: Option<std::net::SocketAddr>,
    method: String,
    path: String,
    status: u16,
    referer: Option<&'a str>,
    user_agent: Option<&'a str>,
    #[schema(debug)]
    elapsed: std::time::Duration,
    forwarded: Option<&'a str>,
}

#[derive(Schema)]
struct RpcRequestLog<'a> {
    trace_id: &'a str,
    request: &'a Value,
}

#[derive(Schema)]
struct RpcResponseLog<'a> {
    trace_id: &'a str,
    is_batch: bool,
    response_error: bool,
    response: &'a JsonRpcResponse,
}

// HealthCheckParams is optional params for different layer's health check.
// If no param is provided, server return 200 by default to indicate HTTP server is running health.
#[derive(serde::Deserialize)]
struct HealthCheckParams {
    // Health check returns 200 when this param is provided and meet the following condition:
    //   server latest ledger info timestamp >= server current time timestamp - duration_secs
    pub duration_secs: Option<u64>,
}

#[macro_export]
macro_rules! log_response {
    ($trace_id: expr, $resp: expr, $is_batch: expr) => {
        let log = RpcResponseLog {
            trace_id: $trace_id,
            is_batch: $is_batch,
            response_error: $resp.error.is_some(),
            response: $resp,
        };
        match &$resp.error {
            Some(error) if is_internal_error(&error.code) => {
                diem_logger::error!(log)
            }
            _ => diem_logger::trace!(log),
        }
    };
}

/// Creates HTTP server (warp-based) that serves JSON RPC requests
/// Returns handle to corresponding Tokio runtime
pub fn bootstrap(
    address: SocketAddr,
    batch_size_limit: u16,
    page_size_limit: u16,
    content_len_limit: usize,
    tls_cert_path: &Option<String>,
    tls_key_path: &Option<String>,
    diem_db: Arc<dyn DbReader>,
    mp_sender: MempoolClientSender,
    role: RoleType,
    chain_id: ChainId,
) -> Runtime {
    let runtime = Builder::new_multi_thread()
        .thread_name("json-rpc")
        .enable_all()
        .build()
        .expect("[json-rpc] failed to create runtime");

    let service = JsonRpcService::new(
        diem_db.clone(),
        mp_sender,
        role,
        chain_id,
        batch_size_limit,
        page_size_limit,
    );

    let base_route = warp::any()
        .and(warp::post())
        .and(warp::header::exact("content-type", "application/json"))
        .and(warp::body::content_length_limit(content_len_limit as u64))
        .and(warp::body::json())
        .and(warp::any().map(move || service.clone()))
        .and(warp::filters::header::optional::<String>("user-agent"))
        .and_then(rpc_endpoint)
        .with(warp::log::custom(|info| {
            debug!(HttpRequestLog {
                remote_addr: info.remote_addr(),
                method: info.method().to_string(),
                path: info.path().to_string(),
                status: info.status().as_u16(),
                referer: info.referer(),
                user_agent: info.user_agent(),
                elapsed: info.elapsed(),
                forwarded: info
                    .request_headers()
                    .get(header::FORWARDED)
                    .and_then(|v| v.to_str().ok())
            })
        }))
        // CORS is required for full node server to accept requests from different domain web pages.
        // It needs to be configured for the json-rpc request accepting method and headers.
        // Technically it's fine for any headers, but for simplicity we only set must have header
        // content-type.
        .with(
            warp::cors()
                .allow_any_origin()
                .allow_methods(vec!["POST"])
                .allow_headers(vec![header::CONTENT_TYPE]),
        );

    // For now we still allow user to use "/", but user should start to move to "/v1" soon
    let route_root = warp::path::end().and(base_route.clone());

    let route_v1 = warp::path::path("v1")
        .and(warp::path::end())
        .and(base_route);

    let health_route = warp::path!("-" / "healthy")
        .and(warp::path::end())
        .and(warp::query().map(move |params: HealthCheckParams| params))
        .and(warp::any().map(move || diem_db.clone()))
        .and(warp::any().map(SystemTime::now))
        .and_then(health_check);

    let full_route = health_route.or(route_v1.or(route_root));

    // Ensure that we actually bind to the socket first before spawning the
    // server tasks. This helps in tests to prevent races where a client attempts
    // to make a request before the server task is actually listening on the
    // socket.
    //
    // Note: we need to enter the runtime context first to actually bind, since
    //       tokio TcpListener can only be bound inside a tokio context.
    let _guard = runtime.enter();
    let server = match tls_cert_path {
        None => Either::Left(warp::serve(full_route).bind(address)),
        Some(cert_path) => Either::Right(
            warp::serve(full_route)
                .tls()
                .cert_path(cert_path)
                .key_path(tls_key_path.as_ref().unwrap())
                .bind(address),
        ),
    };
    runtime.handle().spawn(server);
    runtime
}

/// Creates JSON RPC endpoint by given node config
pub fn bootstrap_from_config(
    config: &NodeConfig,
    chain_id: ChainId,
    diem_db: Arc<dyn DbReader>,
    mp_sender: MempoolClientSender,
) -> Runtime {
    bootstrap(
        config.json_rpc.address,
        config.json_rpc.batch_size_limit,
        config.json_rpc.page_size_limit,
        config.json_rpc.content_length_limit,
        &config.json_rpc.tls_cert_path,
        &config.json_rpc.tls_key_path,
        diem_db,
        mp_sender,
        config.base.role,
        chain_id,
    )
}

async fn health_check(
    params: HealthCheckParams,
    db: Arc<dyn DbReader>,
    now: SystemTime,
) -> Result<Box<dyn warp::Reply>, warp::Rejection> {
    if let Some(duration) = params.duration_secs {
        let ledger_info = db
            .get_latest_ledger_info()
            .map_err(|_| reject::custom(HealthCheckError))?;
        let timestamp = ledger_info.ledger_info().timestamp_usecs();

        check_latest_ledger_info_timestamp(duration, timestamp, now)
            .map_err(|_| reject::custom(HealthCheckError))?;
    }
    Ok(Box::new("diem-node:ok"))
}

pub fn check_latest_ledger_info_timestamp(
    duration_sec: u64,
    timestamp_usecs: u64,
    now: SystemTime,
) -> Result<()> {
    let timestamp = Duration::from_micros(timestamp_usecs);
    let expectation = now
        .sub(Duration::from_secs(duration_sec))
        .duration_since(UNIX_EPOCH)?;
    ensure!(timestamp >= expectation);
    Ok(())
}

/// JSON RPC entry point
/// Handles all incoming rpc requests
pub(crate) async fn rpc_endpoint(
    data: Value,
    service: JsonRpcService,
    user_agent: Option<String>,
) -> Result<warp::reply::Response, warp::Rejection> {
    let label = match data {
        Value::Array(_) => LABEL_BATCH,
        _ => LABEL_SINGLE,
    };
    counters::RPC_REQUESTS.with_label_values(&[label]).inc();
    let timer = counters::RPC_REQUEST_LATENCY
        .with_label_values(&[label])
        .start_timer();
    let ret = rpc_endpoint_without_metrics(data, service, user_agent.as_deref()).await;
    timer.stop_and_record();
    ret
}

async fn rpc_endpoint_without_metrics(
    data: Value,
    service: JsonRpcService,
    user_agent: Option<&str>,
) -> Result<warp::reply::Response, warp::Rejection> {
    // take snapshot of latest version of DB to be used across all requests, especially for batched requests
    let ledger_info = service
        .get_latest_ledger_info()
        .map_err(|_| reject::custom(DatabaseError))?;

    let mut rng = OsRng;
    let trace_id = format!("{:x}", rng.next_u64());
    debug!(RpcRequestLog {
        trace_id: &trace_id,
        request: &data,
    });
    let chain_id = service.chain_id();
    let latest_ledger_version = ledger_info.ledger_info().version();
    let latest_ledger_timestamp_usecs = ledger_info.ledger_info().timestamp_usecs();
    let sdk_info = sdk_info_from_user_agent(user_agent);

    let resp = if let Value::Array(requests) = data {
        match service.validate_batch_size_limit(requests.len()) {
            Ok(_) => {
                // batch API call
                let futures = requests.into_iter().map(|req| {
                    rpc_request_handler(req, &service, &ledger_info, LABEL_BATCH, sdk_info)
                });
                let responses = join_all(futures).await;
                for resp in &responses {
                    log_response!(&trace_id, &resp, true);
                }
                warp::reply::json(&responses)
            }
            Err(err) => {
                let mut response = JsonRpcResponse::new(
                    chain_id,
                    latest_ledger_version,
                    latest_ledger_timestamp_usecs,
                );
                response.error = Some(err);
                bump_counters(&response, LABEL_BATCH, None, sdk_info);
                log_response!(&trace_id, &response, true);

                warp::reply::json(&response)
            }
        }
    } else {
        // single API call
        let resp = rpc_request_handler(data, &service, &ledger_info, LABEL_SINGLE, sdk_info).await;
        log_response!(&trace_id, &resp, false);

        warp::reply::json(&resp)
    };

    let mut http_response = resp.into_response();
    let headers = http_response.headers_mut();

    headers.insert(
        X_DIEM_CHAIN_ID,
        header::HeaderValue::from_str(&chain_id.id().to_string()).unwrap(),
    );
    headers.insert(
        X_DIEM_VERSION_ID,
        header::HeaderValue::from_str(&latest_ledger_version.to_string()).unwrap(),
    );
    headers.insert(
        X_DIEM_TIMESTAMP_USEC_ID,
        header::HeaderValue::from_str(&latest_ledger_timestamp_usecs.to_string()).unwrap(),
    );

    Ok(http_response)
}

async fn rpc_request_handler(
    request: Value,
    service: &JsonRpcService,
    ledger_info: &LedgerInfoWithSignatures,
    request_type_label: &str,
    sdk_info: SdkInfo,
) -> JsonRpcResponse {
    let handler = Handler::new(&service, &ledger_info);

    let mut response = JsonRpcResponse::new(
        service.chain_id(),
        ledger_info.ledger_info().version(),
        ledger_info.ledger_info().timestamp_usecs(),
    );
    let method: Option<Method>;

    match diem_json_rpc_types::request::JsonRpcRequest::from_value(request) {
        Ok(request) => {
            method = Some(request.method_request.method());
            let timer = counters::METHOD_LATENCY
                .with_label_values(&[request_type_label, request.method_request.method().as_str()])
                .start_timer();
            response.id = Some(serde_json::to_value(&request.id).unwrap());
            match handler.handle(request.method_request).await {
                Ok(ret) => response.result = Some(ret),
                Err(e) => response.error = Some(e),
            }
            timer.stop_and_record();
        }
        Err((e, m, id)) => {
            method = m;
            response.id = id.map(|id| serde_json::to_value(&id).unwrap());
            response.error = Some(e);
        }
    }

    bump_counters(&response, request_type_label, method, sdk_info);

    response
}

fn bump_counters(
    response: &JsonRpcResponse,
    request_type: &str,
    method: Option<Method>,
    sdk_info: SdkInfo,
) {
    let method_str = method.as_ref().map(|m| m.as_str()).unwrap_or("not_found");
    let result_label = if let Some(error) = &response.error {
        if is_internal_error(&error.code) {
            counters::INTERNAL_ERRORS
                .with_label_values(&[
                    request_type,
                    method_str,
                    &error.code.to_string(),
                    sdk_info.language.as_str(),
                    &sdk_info.version.to_string(),
                ])
                .inc();
        } else {
            let label = match error.code {
                -32600 => "invalid_request",
                -32601 => "method_not_found",
                -32602 => "invalid_params",
                -32604 => "invalid_format",
                _ => "unexpected_code",
            };
            counters::INVALID_REQUESTS
                .with_label_values(&[
                    request_type,
                    method_str,
                    label,
                    sdk_info.language.as_str(),
                    &sdk_info.version.to_string(),
                ])
                .inc();
        }
        LABEL_FAIL
    } else {
        LABEL_SUCCESS
    };

    if method.is_some() {
        counters::REQUESTS
            .with_label_values(&[
                request_type,
                method_str,
                result_label,
                sdk_info.language.as_str(),
                &sdk_info.version.to_string(),
            ])
            .inc();
    }
}

/// Warp rejection types
#[derive(Debug)]
struct DatabaseError;

impl Reject for DatabaseError {}

#[derive(Debug)]
struct HealthCheckError;
impl warp::reject::Reject for HealthCheckError {}
<|endoftext|>


<commit_before>use std::io::{self, Write, BufWriter};

use super::{MatchWithPositions, match_and_score_with_positions};
use ansi::{clear, color, cursor, style};
use terminal::{self, Terminal, Key, Event};

use rayon::prelude::*;

#[derive(Debug)]
pub enum Error {
    Exit,
    Write(io::Error),
    Reset(terminal::Error)
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Write(err)
    }
}

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Interface<'a> {
    lines: &'a [String],
    matches: Vec<MatchWithPositions<'a>>,
    search: String,
    selected: usize,
    choices_width: usize,
    width: usize,
    terminal: Terminal,
}

impl<'a> Interface<'a> {
    pub fn new(lines: &'a [String]) -> Interface<'a> {
        let mut terminal = Terminal::from("/dev/tty").unwrap();
        let choices_width = format!("{}", lines.len()).len();

        terminal.set_raw_mode().unwrap();

        Interface {
            lines: lines,
            matches: vec![],
            search: String::new(),
            selected: 0,
            choices_width: choices_width,
            width: terminal.max_width,
            terminal: terminal,
        }
    }

    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_matches();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') | Key::Ctrl('d') | Key::Escape => {
                        self.reset()?;
                        return Err(Error::Exit);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.saturating_sub(1);
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_existing();
                        self.render()?;
                    },

                    Key::Backspace | Key::Ctrl('h') => {
                        self.search.pop();
                        self.filter_matches();
                        self.render()?;
                    }

                    Key::Ctrl('u') => {
                        self.search.clear();
                        self.filter_matches();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.reset()?;
        Ok(self.result())
    }

    fn filter_matches(&mut self) {
        let ref search = self.search;

        self.matches = self.lines.
            par_iter().
            filter_map(|line| match_and_score_with_positions(search, line)).
            collect();

        self.matches.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
    }

    fn filter_existing(&mut self) {
        let ref search = self.search;

        self.matches = self.matches.
            par_iter().
            filter_map(|&(line, _, _)| match_and_score_with_positions(search, line)).
            collect();

        self.matches.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
    }

    fn render(&mut self) -> io::Result<()> {
        self.clamp_selected();

        let prompt = self.prompt();
        let matches = self.matches.iter().take(10);
        let n = matches.len() as u16;

        let mut term = BufWriter::new(&mut self.terminal);

        write!(term, "{}{}{}", cursor::Column(1), clear::Screen, prompt)?;

        for (i, choice) in matches.enumerate() {
            let selected = i == self.selected;
            let chars = choice.0.chars().take(self.width);

            write!(term, "\r\n")?;

            if selected {
                write!(term, "{}", style::Invert)?;
            }

            let ref positions = choice.2;

            for (i, ch) in chars.enumerate() {
                if positions.contains(&i) {
                    let color = color::Fg(color::Colors::Magenta);
                    let reset = color::Fg(color::Reset);
                    write!(term, "{}{}{}", color, ch, reset)?;
                } else {
                    write!(term, "{}", ch)?;
                }
            }

            if selected {
                write!(term, "{}", style::NoInvert)?;
            }
        }

        if n > 0 {
            let col = (prompt.len() + 1) as u16;
            write!(term, "{}{}", cursor::Up(n), cursor::Column(col))?;
        }

        Ok(())
    }

    // Generates the input prompt
    fn prompt(&self) -> String {
        let count = self.matches.len();
        format!("{:width$} > {}", count, self.search, width = self.choices_width)
    }

    fn clamp_selected(&mut self) {
        let mut max = self.matches.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = if max > 0 { max - 1 } else { 0 };
        }
    }

    fn reset(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matches.iter().
            map(|choice| choice.0).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<commit_msg>Simplify fetching result<commit_after>use std::io::{self, Write, BufWriter};

use super::{MatchWithPositions, match_and_score_with_positions};
use ansi::{clear, color, cursor, style};
use terminal::{self, Terminal, Key, Event};

use rayon::prelude::*;

#[derive(Debug)]
pub enum Error {
    Exit,
    Write(io::Error),
    Reset(terminal::Error)
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Write(err)
    }
}

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Interface<'a> {
    lines: &'a [String],
    matches: Vec<MatchWithPositions<'a>>,
    search: String,
    selected: usize,
    choices_width: usize,
    width: usize,
    terminal: Terminal,
}

impl<'a> Interface<'a> {
    pub fn new(lines: &'a [String]) -> Interface<'a> {
        let mut terminal = Terminal::from("/dev/tty").unwrap();
        let choices_width = format!("{}", lines.len()).len();

        terminal.set_raw_mode().unwrap();

        Interface {
            lines: lines,
            matches: vec![],
            search: String::new(),
            selected: 0,
            choices_width: choices_width,
            width: terminal.max_width,
            terminal: terminal,
        }
    }

    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_matches();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') | Key::Ctrl('d') | Key::Escape => {
                        self.reset()?;
                        return Err(Error::Exit);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.saturating_sub(1);
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_existing();
                        self.render()?;
                    },

                    Key::Backspace | Key::Ctrl('h') => {
                        self.search.pop();
                        self.filter_matches();
                        self.render()?;
                    }

                    Key::Ctrl('u') => {
                        self.search.clear();
                        self.filter_matches();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.reset()?;
        Ok(self.result())
    }

    fn filter_matches(&mut self) {
        let ref search = self.search;

        self.matches = self.lines.
            par_iter().
            filter_map(|line| match_and_score_with_positions(search, line)).
            collect();

        self.matches.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
    }

    fn filter_existing(&mut self) {
        let ref search = self.search;

        self.matches = self.matches.
            par_iter().
            filter_map(|&(line, _, _)| match_and_score_with_positions(search, line)).
            collect();

        self.matches.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());
    }

    fn render(&mut self) -> io::Result<()> {
        self.clamp_selected();

        let prompt = self.prompt();
        let matches = self.matches.iter().take(10);
        let n = matches.len() as u16;

        let mut term = BufWriter::new(&mut self.terminal);

        write!(term, "{}{}{}", cursor::Column(1), clear::Screen, prompt)?;

        for (i, choice) in matches.enumerate() {
            let selected = i == self.selected;
            let chars = choice.0.chars().take(self.width);

            write!(term, "\r\n")?;

            if selected {
                write!(term, "{}", style::Invert)?;
            }

            let ref positions = choice.2;

            for (i, ch) in chars.enumerate() {
                if positions.contains(&i) {
                    let color = color::Fg(color::Colors::Magenta);
                    let reset = color::Fg(color::Reset);
                    write!(term, "{}{}{}", color, ch, reset)?;
                } else {
                    write!(term, "{}", ch)?;
                }
            }

            if selected {
                write!(term, "{}", style::NoInvert)?;
            }
        }

        if n > 0 {
            let col = (prompt.len() + 1) as u16;
            write!(term, "{}{}", cursor::Up(n), cursor::Column(col))?;
        }

        Ok(())
    }

    // Generates the input prompt
    fn prompt(&self) -> String {
        let count = self.matches.len();
        format!("{:width$} > {}", count, self.search, width = self.choices_width)
    }

    fn clamp_selected(&mut self) {
        let mut max = self.matches.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = if max > 0 { max - 1 } else { 0 };
        }
    }

    fn reset(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matches.iter().
            nth(self.selected).
            map(|choice| choice.0).
            unwrap_or(&self.search)
    }
}
<|endoftext|>


<commit_before>
extern crate gcc;

fn main() {
	let config = gcc::Config {
		include_directories: vec![Path::new("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers")],
		definitions: Vec::new(),
		objects: Vec::new(),
	};

	gcc::compile_library("libinterface.a", &config, &["src/interface.c"]);
}
<commit_msg>Updated dependencies, fixed compilation issues<commit_after>
extern crate gcc;

fn main() {
	let config = gcc::Config {
		include_directories: vec![Path::new("/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/System/Library/Frameworks/JavaVM.framework/Versions/A/Headers")],
		definitions: Vec::new(),
		objects: Vec::new(),
		flags: Vec::new(),
	};

	gcc::compile_library("libinterface.a", &config, &["src/interface.c"]);
}
<|endoftext|>


<commit_before>
// https://serde.rs/codegen-hybrid.html

#[cfg(feature = "serde_codegen")]
fn main() {
    extern crate serde_codegen;

    use std::env;
    use std::path::Path;

    let out_dir = env::var_os("OUT_DIR").unwrap();

    let src = Path::new("src/serde_types.in.rs");
    let dst = Path::new(&out_dir).join("serde_types.rs");

    serde_codegen::expand(&src, &dst).unwrap();
}

#[cfg(not(feature = "serde_codegen"))]
fn main() {
    // do nothing
}
<commit_msg>Build merge_requests' serde_types<commit_after>
// https://serde.rs/codegen-hybrid.html

#[cfg(feature = "serde_codegen")]
fn main() {
    extern crate serde_codegen;

    use std::env;
    use std::path::Path;

    let out_dir = env::var_os("OUT_DIR").unwrap();

    let src = Path::new("src/serde_types.in.rs");
    let dst = Path::new(&out_dir).join("serde_types.rs");
    serde_codegen::expand(&src, &dst).unwrap();

    let src = Path::new("src/merge_requests/serde_types.in.rs");
    let dst = Path::new(&out_dir).join("merge_requests");
    std::fs::create_dir_all(&dst).expect(&format!("Cannot create directory {:?}!", dst));
    let dst = dst.join("serde_types.rs");
    serde_codegen::expand(&src, &dst).unwrap();
}

#[cfg(not(feature = "serde_codegen"))]
fn main() {
    // do nothing
}
<|endoftext|>


<commit_before>use std::env;

fn main() {
    let cfgs = env::var("OVERRIDE_GDK_CFG")
        .or_else(|_| env::var("DEP_GDK_CFG"))
        .unwrap_or_else(|e| panic!("Failed to read `DEP_GDK_CFG`: {}", e));
    for cfg in cfgs.split(' ') {
        println!("cargo:rustc-cfg={}", cfg);
    }
}
<commit_msg>build.rs: avoid returning empty cfg directives<commit_after>use std::env;

fn main() {
    let cfgs = env::var("OVERRIDE_GDK_CFG")
        .or_else(|_| env::var("DEP_GDK_CFG"))
        .unwrap_or_else(|e| panic!("Failed to read `DEP_GDK_CFG`: {}", e));
    for cfg in cfgs.split(' ').filter(|s| !s.is_empty()) {
        println!("cargo:rustc-cfg={}", cfg);
    }
}
<|endoftext|>


<commit_before>use serde::Deserialize;
use std::{
    fs::{self, File},
    io::{self, Read, Write},
};

const INPUT_DIRECTORY: &str = "src/format/languages";
const OUTPUT_FILE: &str = "src/format/language.rs";

#[derive(Deserialize)]
struct Language {
    name: String,
    iso_code: String,
    months: [String; 12],
    abbr_months: [String; 12],
    weekdays: [String; 7],
    abbr_weekdays: [String; 7],
}

fn languages() -> io::Result<Vec<Language>> {
    let mut languages: Vec<Language> = vec![];

    for file in fs::read_dir(INPUT_DIRECTORY)? {
        let mut file = File::open(file?.path())?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        languages.push(toml::from_str(&contents)?);
    }

    languages.sort_unstable_by(|a, b| a.iso_code.cmp(&b.iso_code));

    Ok(languages)
}

fn main() -> io::Result<()> {
    let languages = languages()?;

    let mut out_file = File::create(OUTPUT_FILE)?;

    out_file.write(b"\
//! The `Language` struct and its various methods.

// Localizations are sourced from glibc.
// https://sourceware.org/git/?p=glibc.git;a=tree;f=localedata/locales;hb=HEAD

/// Languages used in formatting. Follows [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
///
/// Additional languages may be added at any time. Contributions will be
/// accepted by native and highly fluent speakers of any living language.
///
/// All languages must have the following:
/// - Month names
/// - Short month names
/// - Weekday names
/// - Short weekday names
#[non_exhaustive]
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Language {\n\
    ")?;

    // Generate `Language` struct
    for language in &languages {
        writeln!(out_file, "    /// {}", language.name)?;
        writeln!(out_file, "    {},", language.iso_code)?;
    }

    out_file.write(
        b"}

impl Language {
    /// Get the month names for the given language.
    #[inline]
    pub fn month_names(self) -> [&'static str; 12] {
        match self {\n\
    ",
    )?;

    // Month names
    for language in &languages {
        writeln!(out_file, "            Self::{} => [", language.iso_code)?;
        for month in &language.months {
            writeln!(out_file, "                \"{}\",", month.escape_default())?;
        }
        writeln!(out_file, "            ],")?;
    }

    out_file.write(
        b"        }
    }

    /// Get the abbreviated month names for the given language.
    #[inline]
    pub fn short_month_names(self) -> [&'static str; 12] {
        match self {\n\
    ",
    )?;

    // Abbreviated month names
    for language in &languages {
        writeln!(out_file, "            Self::{} => [", language.iso_code)?;
        for month in &language.abbr_months {
            writeln!(out_file, "                \"{}\",", month.escape_default())?;
        }
        writeln!(out_file, "            ],")?;
    }

    out_file.write(
        b"        }
    }

    /// Get the names of days of the week for the given language. Starts with
    /// Monday.
    #[inline]
    pub fn week_days(self) -> [&'static str; 7] {
        match self {\n\
    ",
    )?;

    // Weekdays
    for language in &languages {
        writeln!(out_file, "            Self::{} => [", language.iso_code)?;
        for weekday in &language.weekdays {
            writeln!(
                out_file,
                "                \"{}\",",
                weekday.escape_default()
            )?;
        }
        writeln!(out_file, "            ],")?;
    }

    out_file.write(
        b"        }
    }

    /// Get the abbreviated names of days of the week for the given language.
    /// Starts with Monday.
    #[inline]
    pub fn short_week_days(self) -> [&'static str; 7] {
        match self {\n\
    ",
    )?;

    // Abbreviated weekdays
    for language in &languages {
        writeln!(out_file, "            Self::{} => [", language.iso_code)?;
        for weekday in &language.abbr_weekdays {
            writeln!(
                out_file,
                "                \"{}\",",
                weekday.escape_default()
            )?;
        }
        writeln!(out_file, "            ],")?;
    }

    out_file.write(b"        }\n    }\n}\n")?;

    Ok(())
}
<commit_msg>Silence clippy warnings on generated file<commit_after>use serde::Deserialize;
use std::{
    fs::{self, File},
    io::{self, Read, Write},
};

const INPUT_DIRECTORY: &str = "src/format/languages";
const OUTPUT_FILE: &str = "src/format/language.rs";

#[derive(Deserialize)]
struct Language {
    name: String,
    iso_code: String,
    months: [String; 12],
    abbr_months: [String; 12],
    weekdays: [String; 7],
    abbr_weekdays: [String; 7],
}

fn languages() -> io::Result<Vec<Language>> {
    let mut languages: Vec<Language> = vec![];

    for file in fs::read_dir(INPUT_DIRECTORY)? {
        let mut file = File::open(file?.path())?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        languages.push(toml::from_str(&contents)?);
    }

    languages.sort_unstable_by(|a, b| a.iso_code.cmp(&b.iso_code));

    Ok(languages)
}

fn main() -> io::Result<()> {
    let languages = languages()?;

    let mut out_file = File::create(OUTPUT_FILE)?;

    out_file.write(b"\
#![allow(clippy::too_many_lines, clippy::match_same_arms)]

//! The `Language` struct and its various methods.

// Localizations are sourced from glibc.
// https://sourceware.org/git/?p=glibc.git;a=tree;f=localedata/locales;hb=HEAD

/// Languages used in formatting. Follows [ISO 639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes).
///
/// Additional languages may be added at any time. Contributions will be
/// accepted by native and highly fluent speakers of any living language.
///
/// All languages must have the following:
/// - Month names
/// - Short month names
/// - Weekday names
/// - Short weekday names
#[non_exhaustive]
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Language {\n\
    ")?;

    // Generate `Language` struct
    for language in &languages {
        writeln!(out_file, "    /// {}", language.name)?;
        writeln!(out_file, "    {},", language.iso_code)?;
    }

    out_file.write(
        b"}

impl Language {
    /// Get the month names for the given language.
    #[inline]
    pub fn month_names(self) -> [&'static str; 12] {
        match self {\n\
    ",
    )?;

    // Month names
    for language in &languages {
        writeln!(out_file, "            Self::{} => [", language.iso_code)?;
        for month in &language.months {
            writeln!(out_file, "                \"{}\",", month.escape_default())?;
        }
        writeln!(out_file, "            ],")?;
    }

    out_file.write(
        b"        }
    }

    /// Get the abbreviated month names for the given language.
    #[inline]
    pub fn short_month_names(self) -> [&'static str; 12] {
        match self {\n\
    ",
    )?;

    // Abbreviated month names
    for language in &languages {
        writeln!(out_file, "            Self::{} => [", language.iso_code)?;
        for month in &language.abbr_months {
            writeln!(out_file, "                \"{}\",", month.escape_default())?;
        }
        writeln!(out_file, "            ],")?;
    }

    out_file.write(
        b"        }
    }

    /// Get the names of days of the week for the given language. Starts with
    /// Monday.
    #[inline]
    pub fn week_days(self) -> [&'static str; 7] {
        match self {\n\
    ",
    )?;

    // Weekdays
    for language in &languages {
        writeln!(out_file, "            Self::{} => [", language.iso_code)?;
        for weekday in &language.weekdays {
            writeln!(
                out_file,
                "                \"{}\",",
                weekday.escape_default()
            )?;
        }
        writeln!(out_file, "            ],")?;
    }

    out_file.write(
        b"        }
    }

    /// Get the abbreviated names of days of the week for the given language.
    /// Starts with Monday.
    #[inline]
    pub fn short_week_days(self) -> [&'static str; 7] {
        match self {\n\
    ",
    )?;

    // Abbreviated weekdays
    for language in &languages {
        writeln!(out_file, "            Self::{} => [", language.iso_code)?;
        for weekday in &language.abbr_weekdays {
            writeln!(
                out_file,
                "                \"{}\",",
                weekday.escape_default()
            )?;
        }
        writeln!(out_file, "            ],")?;
    }

    out_file.write(b"        }\n    }\n}\n")?;

    Ok(())
}
<|endoftext|>


<commit_before>// build.rs

extern crate pkg_config;
extern crate bindgen;
extern crate cmake;
extern crate cc;

use std::env;
use std::path::Path;

use std::fs::File;
use std::io::Write;

fn format_write(builder: bindgen::Builder, output: &str) {
    let s = builder
        .generate()
        .unwrap()
        .to_string()
        .replace("/**", "/*")
        .replace("/*!", "/*");

    let mut file = File::create(output).unwrap();

    let _ = file.write(s.as_bytes());
}

fn main() {
    let cargo_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let build_path = Path::new(&cargo_dir).join("aom_build/aom");

    let cfg = cmake::Config::new(build_path)
        .define("CONFIG_AV1_ENCODER", "0")
        .define("CONFIG_DEBUG", "1")
        .define("CONFIG_EXPERIMENTAL", "1")
        .define("CONFIG_UNIT_TESTS", "0")
        .define("CONFIG_AOM_QM", "0")
        .define("CONFIG_EXT_INTRA", "0")
        .define("CONFIG_EXT_PARTITION", "0")
        .define("CONFIG_EXT_PARTITION_TYPES", "0")
        .define("CONFIG_LOOPFILTER_LEVEL", "0")
        .define("CONFIG_INTRA_EDGE", "0")
        .define("CONFIG_CFL", "0")
        .define("CONFIG_KF_CTX", "0")
        .define("CONFIG_STRIPED_LOOP_RESTORATION", "0")
        .define("CONFIG_MAX_TILE", "0")
        .define("CONFIG_EXT_INTRA_MOD", "0")
        .define("CONFIG_FRAME_SIZE", "0")
        .define("CONFIG_SIMPLIFY_TX_MODE", "0")
        .define("CONFIG_OBU", "0")
        .define("CONFIG_FILTER_INTRA", "0")
        .define("CONFIG_LV_MAP", "0")
        .define("CONFIG_LV_MAP_MULTI", "0")
        .define("CONFIG_ANALYZER", "0")
        .build();

    env::set_var("PKG_CONFIG_PATH", cfg.join("lib/pkgconfig"));

    let libs = pkg_config::Config::new().statik(true).probe("aom").unwrap();
    let headers = libs.include_paths.clone();

    let mut builder = bindgen::builder()
        .raw_line("#![allow(dead_code)]")
        .raw_line("#![allow(non_camel_case_types)]")
        .raw_line("#![allow(non_snake_case)]")
        .raw_line("#![allow(non_upper_case_globals)]")
        .blacklist_type("max_align_t")
        .header("data/aom.h");

    for header in headers {
        builder = builder.clang_arg("-I").clang_arg(header.to_str().unwrap());
    }

    // Manually fix the comment so rustdoc won't try to pick them
    format_write(builder, "tests/aom.rs");

    cc::Build::new()
        .file("aom_build/aom/aom_dsp/fwd_txfm.c")
        .file("aom_build/aom/av1/encoder/dct.c")
        .include("aom_build")
        .include("aom_build/aom")
        .flag("-std=c99")
        .compile("libntr.a");
}
<commit_msg>Fix reconstruction on fresh builds.<commit_after>// build.rs

extern crate pkg_config;
extern crate bindgen;
extern crate cmake;
extern crate cc;

use std::env;
use std::path::Path;

use std::fs::File;
use std::io::Write;

fn format_write(builder: bindgen::Builder, output: &str) {
    let s = builder
        .generate()
        .unwrap()
        .to_string()
        .replace("/**", "/*")
        .replace("/*!", "/*");

    let mut file = File::create(output).unwrap();

    let _ = file.write(s.as_bytes());
}

fn main() {
    let cargo_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
    let build_path = Path::new(&cargo_dir).join("aom_build/aom");

    let cfg = cmake::Config::new(build_path)
        .define("CONFIG_AV1_ENCODER", "0")
        .define("CONFIG_DEBUG", "1")
        .define("CONFIG_EXPERIMENTAL", "1")
        .define("CONFIG_UNIT_TESTS", "0")
        .define("CONFIG_AOM_QM", "0")
        .define("CONFIG_EXT_INTRA", "0")
        .define("CONFIG_EXT_PARTITION", "0")
        .define("CONFIG_EXT_PARTITION_TYPES", "0")
        .define("CONFIG_LOOPFILTER_LEVEL", "0")
        .define("CONFIG_INTRA_EDGE", "0")
        .define("CONFIG_CFL", "0")
        .define("CONFIG_KF_CTX", "0")
        .define("CONFIG_STRIPED_LOOP_RESTORATION", "0")
        .define("CONFIG_MAX_TILE", "0")
        .define("CONFIG_EXT_INTRA_MOD", "0")
        .define("CONFIG_FRAME_SIZE", "0")
        .define("CONFIG_SIMPLIFY_TX_MODE", "0")
        .define("CONFIG_OBU", "0")
        .define("CONFIG_FILTER_INTRA", "0")
        .define("CONFIG_EXT_SKIP", "0")
        .define("CONFIG_LV_MAP", "0")
        .define("CONFIG_LV_MAP_MULTI", "0")
        .define("CONFIG_ANALYZER", "0")
        .build();

    env::set_var("PKG_CONFIG_PATH", cfg.join("lib/pkgconfig"));

    let libs = pkg_config::Config::new().statik(true).probe("aom").unwrap();
    let headers = libs.include_paths.clone();

    let mut builder = bindgen::builder()
        .raw_line("#![allow(dead_code)]")
        .raw_line("#![allow(non_camel_case_types)]")
        .raw_line("#![allow(non_snake_case)]")
        .raw_line("#![allow(non_upper_case_globals)]")
        .blacklist_type("max_align_t")
        .header("data/aom.h");

    for header in headers {
        builder = builder.clang_arg("-I").clang_arg(header.to_str().unwrap());
    }

    // Manually fix the comment so rustdoc won't try to pick them
    format_write(builder, "tests/aom.rs");

    cc::Build::new()
        .file("aom_build/aom/aom_dsp/fwd_txfm.c")
        .file("aom_build/aom/av1/encoder/dct.c")
        .include("aom_build")
        .include("aom_build/aom")
        .flag("-std=c99")
        .compile("libntr.a");
}
<|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 std::fs;
use std::path::Path;
use std::process::Command;

fn main() {
    build_mmtabbarview();
    build_nibs();
}

fn build_mmtabbarview() {
    Command::new("xcodebuild")
        .args(&["-project", "./macos/MMTabBarView/MMTabBarView/MMTabBarView.xcodeproj"])
        .args(&["-configuration", "Release"])
        .args(&["CONFIGURATION_BUILD_DIR=../../../target/MMTabBarView/"])
        .status()
        .ok()
        .expect("xcodebuild failed");
    println!("cargo:rustc-link-search=framework=target/MMTabBarView");
}

fn build_nibs() {
    fn ibtool(src: &str, out_dir: &Path) {
        let out = out_dir.to_str().unwrap();
        let filename = Path::new(src).file_name().unwrap();
        let out_file = filename.to_str().unwrap().replace("xib", "nib");
        Command::new("ibtool")
            .arg(src)
            .arg("--compile")
            .arg(&format!("{}/{}", out, out_file))
            .status()
            .ok()
            .expect("ibtool failed");
    }
    let nibs_dir = Path::new("nibs");
    fs::create_dir_all(&nibs_dir).unwrap();
    ibtool("macos/xib/App.xib", nibs_dir);
    ibtool("macos/xib/Window.xib", nibs_dir);
}
<commit_msg>build in target<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 std::fs;
use std::path::Path;
use std::process::Command;

fn main() {
    build_mmtabbarview();
    build_nibs();
}

fn build_mmtabbarview() {
    Command::new("xcodebuild")
        .args(&["-project", "./macos/MMTabBarView/MMTabBarView/MMTabBarView.xcodeproj"])
        .args(&["-configuration", "Release"])
        .args(&["SYMROOT=../../../target/MMTabBarView/"])
        .status()
        .expect("xcodebuild failed");
    println!("cargo:rustc-link-search=framework=target/MMTabBarView");
}

fn build_nibs() {
    fn ibtool(src: &str, out_dir: &Path) {
        let out = out_dir.to_str().unwrap();
        let filename = Path::new(src).file_name().unwrap();
        let out_file = filename.to_str().unwrap().replace("xib", "nib");
        Command::new("ibtool")
            .arg(src)
            .arg("--compile")
            .arg(&format!("{}/{}", out, out_file))
            .status()
            .ok()
            .expect("ibtool failed");
    }
    let nibs_dir = Path::new("nibs");
    fs::create_dir_all(&nibs_dir).unwrap();
    ibtool("macos/xib/App.xib", nibs_dir);
    ibtool("macos/xib/Window.xib", nibs_dir);
}
<|endoftext|>


<commit_before>#[cfg(feature = "rust-stable")]
mod inner {
    extern crate syntex;
    extern crate serde_codegen;

    use std::env;
    use std::path::Path;

    pub fn main() {
        let out_dir = env::var_os("OUT_DIR").unwrap();

        let src = Path::new("src/lib.rs.in");
        let dst = Path::new(&out_dir).join("lib.rs");
        let mut registry = syntex::Registry::new();
        serde_codegen::register(&mut registry);
        registry.expand("", &src, &dst).unwrap();
    }
}

#[cfg(feature = "rust-nightly")]
mod inner {
    pub fn main() {}
}

pub fn main() {
    inner::main()
}
<commit_msg>Improve build.rs script to make error more clear about the version skew issues when they arise<commit_after>#[cfg(feature = "rust-stable")]
extern crate syntex;
#[cfg(feature = "rust-stable")]
extern crate serde_codegen;

#[cfg(feature = "rust-stable")]
mod inner {

    use std::env;
    use std::path::Path;

    pub fn main() {
        let out_dir = env::var_os("OUT_DIR").unwrap();

        let src = Path::new("src/lib.rs.in");
        let dst = Path::new(&out_dir).join("lib.rs");

        let mut registry = ::syntex::Registry::new();

        ::serde_codegen::register(&mut registry);
        registry.expand("", &src, &dst).unwrap();
    }
}

#[cfg(feature = "rust-nightly")]
mod inner {
    pub fn main() {}
}

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


<commit_before>extern crate cheddar;

fn main() {
    // Generate mp4parse.h.
    cheddar::Cheddar::new().expect("could not read manifest")
        .module("capi").expect("invalid module path")
        .insert_code("// This Source Code Form is subject to the terms of the Mozilla Public\n")
        .insert_code("// License, v. 2.0. If a copy of the MPL was not distributed with this\n")
        .insert_code("// file, You can obtain one at https://mozilla.org/MPL/2.0/.")
        .run_build("include/mp4parse.h");
}
<commit_msg>Add warning about hand-editing mp4parse.h.<commit_after>extern crate cheddar;

fn main() {
    // Generate mp4parse.h.
    cheddar::Cheddar::new().expect("could not read manifest")
        .module("capi").expect("invalid module path")
        .insert_code("// THIS FILE IS AUTOGENERATED BY mp4parse-rust/build.rs - DO NOT EDIT\n\n")
        .insert_code("// This Source Code Form is subject to the terms of the Mozilla Public\n")
        .insert_code("// License, v. 2.0. If a copy of the MPL was not distributed with this\n")
        .insert_code("// file, You can obtain one at https://mozilla.org/MPL/2.0/.")
        .run_build("include/mp4parse.h");
}
<|endoftext|>


<commit_before>extern crate crossbeam;
extern crate clap;
#[macro_use] extern crate version;
#[macro_use] extern crate log;
extern crate walkdir;

extern crate libimagrt;
extern crate libimagerror;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;
use clap::{Arg, AppSettings, SubCommand};

use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error;

/// Returns the helptext, putting the Strings in cmds as possible
/// subcommands into it
fn help_text(cmds: Vec<String>) -> String {
    let text = format!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:

    {imagbins}

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#, imagbins = cmds.into_iter()
        .map(|cmd| format!("\t{}\n", cmd))
        .fold(String::new(), |s, c| {
            let s = s + c.as_str();
            s
        }));
    text
}

/// Returns the list of imag-* executables found in $PATH
fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .and_then(|s| s.splitn(2, "-").nth(1).map(String::from))
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn main() {
    // Initialize the Runtime and build the CLI
    let appname  = "imag";
    let version  = &version!();
    let about    = "imag - the PIM suite for the commandline";
    let commands = get_commands();
    let helptext = help_text(commands.clone());
    let app      = Runtime::get_default_cli_builder(appname, version, about)
        .settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp])
        .arg(Arg::with_name("version")
             .long("version")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the version of imag"))
        .arg(Arg::with_name("versions")
             .long("versions")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the versions of the imag commands"))
        .subcommand(SubCommand::with_name("help").help("Show help"))
        .help(helptext.as_str());
    let rt = Runtime::new(app)
        .unwrap_or_else(|e| {
            println!("Runtime couldn't be setup. Exiting");
            trace_error(&e);
            exit(1);
        });
    let matches = rt.cli();

    debug!("matches: {:?}", matches);

    // Begin checking for arguments

    if matches.is_present("version") {
        debug!("Showing version");
        println!("imag {}", &version!()[..]);
        exit(0);
    }

    if matches.is_present("versions") {
        debug!("Showing versions");
        let mut result = vec![];
        for command in get_commands().iter() {
            result.push(crossbeam::scope(|scope| {
                scope.spawn(|| {
                    let v = Command::new(command).arg("--version").output();
                    match v {
                        Ok(v) => match String::from_utf8(v.stdout) {
                            Ok(s) => format!("{} -> {}", command, s),
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        },
                        Err(e) => format!("Failed calling {} -> {:?}", command, e),
                    }
                })
            }))
        }

        for versionstring in result.into_iter().map(|handle| handle.join()) {
            println!("{}", versionstring);
        }
    }

    // Matches any subcommand given
    match matches.subcommand() {
        (subcommand, Some(scmd)) => {
            // Get all given arguments and further subcommands to pass to
            // the imag-<> binary
            // Providing no arguments is OK, and is therefore ignored here
            let subcommand_args : Vec<&str> = match scmd.values_of("") {
                Some(values) => values.collect(),
                None => Vec::new()
            };

            // Typos happen, so check if the given subcommand is one found in $PATH
            if !commands.clone().contains(&String::from(subcommand)) {
                println!("No such command: 'imag-{}'", subcommand);
                println!("See 'imag --help' for available subcommands");
                exit(2);
            }

            debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args);

            // Create a Command, and pass it the gathered arguments
            match Command::new(format!("imag-{}", subcommand))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status);
                        println!("{} exited with non-zero exit code", subcommand);
                        exit(exit_status.code().unwrap_or(1));
                    }
                    debug!("Successful exit!");
                },

                Err(e) => {
                    debug!("Error calling the subcommand");
                    match e.kind() {
                        ErrorKind::NotFound => {
                            // With the check above, this absolutely should not happen.
                            // Keeping it to be safe
                            println!("No such command: 'imag-{}'", subcommand);
                            println!("See 'imag --help' for available subcommands");
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", subcommand);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1);
                        }
                    }
                }
            }
        },
        // Calling for example 'imag --versions' will lead here, as this option does not exit.
        // There's nothing to do in such a case
        _ => {},
    }
}
<commit_msg>Fix --versions<commit_after>extern crate crossbeam;
extern crate clap;
#[macro_use] extern crate version;
#[macro_use] extern crate log;
extern crate walkdir;

extern crate libimagrt;
extern crate libimagerror;

use std::env;
use std::process::exit;
use std::process::Command;
use std::process::Stdio;
use std::io::ErrorKind;

use walkdir::WalkDir;
use crossbeam::*;
use clap::{Arg, AppSettings, SubCommand};

use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error;

/// Returns the helptext, putting the Strings in cmds as possible
/// subcommands into it
fn help_text(cmds: Vec<String>) -> String {
    let text = format!(r#"

     _
    (_)_ __ ___   __ _  __ _
    | | '_ \` _ \/ _\`|/ _\`|
    | | | | | | | (_| | (_| |
    |_|_| |_| |_|\__,_|\__, |
                       |___/
    -------------------------

    Usage: imag [--version | --versions | -h | --help] <command> <args...>

    imag - the personal information management suite for the commandline

    imag is a PIM suite for the commandline. It consists of several commands,
    called "modules". Each module implements one PIM aspect and all of these
    modules can be used independently.

    Available commands:

    {imagbins}

    Call a command with 'imag <command> <args>'
    Each command can be called with "--help" to get the respective helptext.

    Please visit https://github.com/matthiasbeyer/imag to view the source code,
    follow the development of imag or maybe even contribute to imag.

    imag is free software. It is released under the terms of LGPLv2.1

    (c) 2016 Matthias Beyer and contributors"#, imagbins = cmds.into_iter()
        .map(|cmd| format!("\t{}\n", cmd))
        .fold(String::new(), |s, c| {
            let s = s + c.as_str();
            s
        }));
    text
}

/// Returns the list of imag-* executables found in $PATH
fn get_commands() -> Vec<String> {
    let path = env::var("PATH");
    if path.is_err() {
        println!("PATH error: {:?}", path);
        exit(1);
    }
    let pathelements = path.unwrap();
    let pathelements = pathelements.split(":");

    let joinhandles : Vec<ScopedJoinHandle<Vec<String>>> = pathelements
        .map(|elem| {
            crossbeam::scope(|scope| {
                scope.spawn(|| {
                    WalkDir::new(elem)
                        .max_depth(1)
                        .into_iter()
                        .filter(|path| {
                            match path {
                                &Ok(ref p) => p.file_name()
                                    .to_str()
                                    .map_or(false, |filename| filename.starts_with("imag-")),
                                &Err(_)   => false,
                            }
                        })
                        .filter_map(|x| x.ok())
                        .filter_map(|path| {
                           path.file_name()
                               .to_str()
                               .and_then(|s| s.splitn(2, "-").nth(1).map(String::from))
                        })
                        .collect()
                })
            })
        })
        .collect();

    let mut execs = vec![];
    for joinhandle in joinhandles.into_iter() {
        let mut v = joinhandle.join();
        execs.append(&mut v);
    }

    execs
}

fn main() {
    // Initialize the Runtime and build the CLI
    let appname  = "imag";
    let version  = &version!();
    let about    = "imag - the PIM suite for the commandline";
    let commands = get_commands();
    let helptext = help_text(commands.clone());
    let app      = Runtime::get_default_cli_builder(appname, version, about)
        .settings(&[AppSettings::AllowExternalSubcommands, AppSettings::ArgRequiredElseHelp])
        .arg(Arg::with_name("version")
             .long("version")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the version of imag"))
        .arg(Arg::with_name("versions")
             .long("versions")
             .takes_value(false)
             .required(false)
             .multiple(false)
             .help("Get the versions of the imag commands"))
        .subcommand(SubCommand::with_name("help").help("Show help"))
        .help(helptext.as_str());
    let rt = Runtime::new(app)
        .unwrap_or_else(|e| {
            println!("Runtime couldn't be setup. Exiting");
            trace_error(&e);
            exit(1);
        });
    let matches = rt.cli();

    debug!("matches: {:?}", matches);

    // Begin checking for arguments

    if matches.is_present("version") {
        debug!("Showing version");
        println!("imag {}", &version!()[..]);
        exit(0);
    }

    if matches.is_present("versions") {
        debug!("Showing versions");
        let mut result = vec![];
        for command in get_commands().iter() {
            result.push(crossbeam::scope(|scope| {
                scope.spawn(|| {
                    let v = Command::new(format!("imag-{}",command)).arg("--version").output();
                    match v {
                        Ok(v) => match String::from_utf8(v.stdout) {
                            Ok(s) => format!("{} -> {}", command, s),
                            Err(e) => format!("Failed calling {} -> {:?}", command, e),
                        },
                        Err(e) => format!("Failed calling {} -> {:?}", command, e),
                    }
                })
            }))
        }

        for versionstring in result.into_iter().map(|handle| handle.join()) {
            println!("{}", versionstring);
        }
    }

    // Matches any subcommand given
    match matches.subcommand() {
        (subcommand, Some(scmd)) => {
            // Get all given arguments and further subcommands to pass to
            // the imag-<> binary
            // Providing no arguments is OK, and is therefore ignored here
            let subcommand_args : Vec<&str> = match scmd.values_of("") {
                Some(values) => values.collect(),
                None => Vec::new()
            };

            // Typos happen, so check if the given subcommand is one found in $PATH
            if !commands.clone().contains(&String::from(subcommand)) {
                println!("No such command: 'imag-{}'", subcommand);
                println!("See 'imag --help' for available subcommands");
                exit(2);
            }

            debug!("Calling 'imag-{}' with args: {:?}", subcommand, subcommand_args);

            // Create a Command, and pass it the gathered arguments
            match Command::new(format!("imag-{}", subcommand))
                .stdin(Stdio::inherit())
                .stdout(Stdio::inherit())
                .stderr(Stdio::inherit())
                .args(&subcommand_args[..])
                .spawn()
                .and_then(|mut handle| handle.wait())
            {
                Ok(exit_status) => {
                    if !exit_status.success() {
                        debug!("{} exited with non-zero exit code: {:?}", subcommand, exit_status);
                        println!("{} exited with non-zero exit code", subcommand);
                        exit(exit_status.code().unwrap_or(1));
                    }
                    debug!("Successful exit!");
                },

                Err(e) => {
                    debug!("Error calling the subcommand");
                    match e.kind() {
                        ErrorKind::NotFound => {
                            // With the check above, this absolutely should not happen.
                            // Keeping it to be safe
                            println!("No such command: 'imag-{}'", subcommand);
                            println!("See 'imag --help' for available subcommands");
                            exit(2);
                        },
                        ErrorKind::PermissionDenied => {
                            println!("No permission to execute: 'imag-{}'", subcommand);
                            exit(1);
                        },
                        _ => {
                            println!("Error spawning: {:?}", e);
                            exit(1);
                        }
                    }
                }
            }
        },
        // Calling for example 'imag --versions' will lead here, as this option does not exit.
        // There's nothing to do in such a case
        _ => {},
    }
}
<|endoftext|>


<commit_before>use na::{DefaultAllocator, Dim, VectorN, U1, U2, U3};
use na::allocator::Allocator;
use domain::NPoint;

/// A kd tree
pub struct KdTree<N : Dim>(Box<kd_tree::KdTreeImpl<N>>) where DefaultAllocator: Allocator<f64, N>;

impl<N : Dim> KdTree<N> where DefaultAllocator: Allocator<f64, N> {
    /// Get all the points from the kd-tree
    fn get_points(self) -> Vec<Box<NPoint<N>>>  {
        let mut pts = Vec::new();
        let KdTree(tree) = self;
        kd_tree::add_points_to_vector(tree, &mut pts);
        pts
    }

    fn build<TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>) -> Self where DefaultAllocator: Allocator<f64, N> {
        KdTree(Box::new(kd_tree::build(pts, 0)))
    }
}

mod kd_tree {
    use na::{DefaultAllocator, Dim, Vector3, VectorN, U1, U2, U3};
    use na::allocator::Allocator;
    use std::cmp::Ordering;
    use domain::NPoint;
    use super::{KdTree};

    /// kd-Tree implementation structure
    pub(super) enum KdTreeImpl<N : Dim> where DefaultAllocator: Allocator<f64, N> {
        Node(usize, Box<KdTreeImpl<N>>, Box<NPoint<N>>, Box<KdTreeImpl<N>>),
        Empty()
    }

    /// mutably enunerate points from a kd tree into a vector
    pub(super) fn add_points_to_vector<N : Dim>(tree : Box<KdTreeImpl<N>>, pts : &mut Vec<Box<NPoint<N>>>) where DefaultAllocator: Allocator<f64, N> {
        let unboxed_tree = *tree;
        match unboxed_tree {
            KdTreeImpl::Node(_, l, pt, r) => {
                add_points_to_vector(l, pts);
                pts.push(pt);
                add_points_to_vector(r, pts);
            },
            KdTreeImpl::Empty() => {}
        }
    }

    fn split_vec<N : Dim, TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>, dim_count :usize) -> (Option<Vec<TItem>>, Option<TItem>, Option<Vec<TItem>>) where DefaultAllocator: Allocator<f64, N> {
        unsafe {
            let mut pts = pts.to_vec();
            pts.sort_by( |a,b| a.from_origin().get_unchecked(0, dim_count).partial_cmp(b.from_origin().get_unchecked(0, dim_count)).unwrap() );
            if pts.len() >= 3 {
                let length = pts.len();
                let mut middle = pts.split_off(length / 2);
                let right = middle.split_off(1);
                (Some(pts), Some(middle[0]), Some(right))
            } else if pts.len() == 2 {
                let length = pts.len();
                let mut middle = pts.split_off(length / 2);
                (Some(pts), Some(middle[0]), None)
            } else if pts.len() == 1 {
                (None, Some(pts[0]), None)
            } else{
                (None, None, None)
            }
        }
    }

    pub(super) fn build<N : Dim, TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>, dimIdx :usize) -> KdTreeImpl<N> where DefaultAllocator: Allocator<f64, N> {
        match pts.first() {
            Some(firstPt) => {
                let nextDimIdx = if dimIdx + 1 >= firstPt.from_origin().ncols() {0} else {dimIdx + 1};
                match split_vec(pts, dimIdx) {
                    (Some(vec1), Some(pt), Some(vec2))  => KdTreeImpl::Node(nextDimIdx,     Box::new(build(&vec1, nextDimIdx)),   Box::new(pt),     Box::new(build(&vec2, nextDimIdx))),
                    (Some(vec1), Some(pt), None)        => KdTreeImpl::Node(nextDimIdx,     Box::new(build(&vec1, nextDimIdx)),   Box::new(pt),     Box::new(KdTreeImpl::Empty())),
                    (None,       Some(pt), None)        => KdTreeImpl::Node(nextDimIdx,     Box::new(KdTreeImpl::Empty()),        Box::new(pt),     Box::new(KdTreeImpl::Empty())),
                    _                                   => panic!("Should be impossible to have a first point but still split into (None, None, None)"),
                }
            }
            None => {
                KdTreeImpl::Empty()
            }
        }
    }
}
<commit_msg>made splitting location more explicit for length = 2<commit_after>use na::{DefaultAllocator, Dim, VectorN, U1, U2, U3};
use na::allocator::Allocator;
use domain::NPoint;

/// A kd tree
pub struct KdTree<N : Dim>(Box<kd_tree::KdTreeImpl<N>>) where DefaultAllocator: Allocator<f64, N>;

impl<N : Dim> KdTree<N> where DefaultAllocator: Allocator<f64, N> {
    /// Get all the points from the kd-tree
    fn get_points(self) -> Vec<Box<NPoint<N>>>  {
        let mut pts = Vec::new();
        let KdTree(tree) = self;
        kd_tree::add_points_to_vector(tree, &mut pts);
        pts
    }

    fn build<TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>) -> Self where DefaultAllocator: Allocator<f64, N> {
        KdTree(Box::new(kd_tree::build(pts, 0)))
    }
}

mod kd_tree {
    use na::{DefaultAllocator, Dim, Vector3, VectorN, U1, U2, U3};
    use na::allocator::Allocator;
    use std::cmp::Ordering;
    use domain::NPoint;
    use super::{KdTree};

    /// kd-Tree implementation structure
    pub(super) enum KdTreeImpl<N : Dim> where DefaultAllocator: Allocator<f64, N> {
        Node(usize, Box<KdTreeImpl<N>>, Box<NPoint<N>>, Box<KdTreeImpl<N>>),
        Empty()
    }

    /// mutably enunerate points from a kd tree into a vector
    pub(super) fn add_points_to_vector<N : Dim>(tree : Box<KdTreeImpl<N>>, pts : &mut Vec<Box<NPoint<N>>>) where DefaultAllocator: Allocator<f64, N> {
        let unboxed_tree = *tree;
        match unboxed_tree {
            KdTreeImpl::Node(_, l, pt, r) => {
                add_points_to_vector(l, pts);
                pts.push(pt);
                add_points_to_vector(r, pts);
            },
            KdTreeImpl::Empty() => {}
        }
    }

    fn split_vec<N : Dim, TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>, dim_count :usize) -> (Option<Vec<TItem>>, Option<TItem>, Option<Vec<TItem>>) where DefaultAllocator: Allocator<f64, N> {
        unsafe {
            let mut pts = pts.to_vec();
            pts.sort_by( |a,b| a.from_origin().get_unchecked(0, dim_count).partial_cmp(b.from_origin().get_unchecked(0, dim_count)).unwrap() );
            if pts.len() >= 3 {
                let length = pts.len();
                let mut middle = pts.split_off(length / 2);
                let right = middle.split_off(1);
                (Some(pts), Some(middle[0]), Some(right))
            } else if pts.len() == 2 {
                let length = pts.len();
                let mut middle = pts.split_off(1);
                (Some(pts), Some(middle[0]), None)
            } else if pts.len() == 1 {
                (None, Some(pts[0]), None)
            } else{
                (None, None, None)
            }
        }
    }

    pub(super) fn build<N : Dim, TItem : NPoint<N> + Copy + 'static>(pts : &Vec<TItem>, dimIdx :usize) -> KdTreeImpl<N> where DefaultAllocator: Allocator<f64, N> {
        match pts.first() {
            Some(firstPt) => {
                let nextDimIdx = if dimIdx + 1 >= firstPt.from_origin().ncols() {0} else {dimIdx + 1};
                match split_vec(pts, dimIdx) {
                    (Some(vec1), Some(pt), Some(vec2))  => KdTreeImpl::Node(nextDimIdx,     Box::new(build(&vec1, nextDimIdx)),   Box::new(pt),     Box::new(build(&vec2, nextDimIdx))),
                    (Some(vec1), Some(pt), None)        => KdTreeImpl::Node(nextDimIdx,     Box::new(build(&vec1, nextDimIdx)),   Box::new(pt),     Box::new(KdTreeImpl::Empty())),
                    (None,       Some(pt), None)        => KdTreeImpl::Node(nextDimIdx,     Box::new(KdTreeImpl::Empty()),        Box::new(pt),     Box::new(KdTreeImpl::Empty())),
                    _                                   => panic!("Should be impossible to have a first point but still split into (None, None, None)"),
                }
            }
            None => {
                KdTreeImpl::Empty()
            }
        }
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Initial 32-bit bootloader for x86_64
#![crate_name = "boot"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(lang_items)]
#![no_std]

const TABLE_LENGTH: usize = 512;

type Table = [u64; TABLE_LENGTH];

use core::fmt::Arguments;

#[lang = "panic_fmt"]
extern fn panic_fmt(fmt: Arguments, file: &'static str, line: u32) -> ! {
	loop {}
}

extern {
	static mut pml4_table: Table;
	static mut pdp_table: Table;
	static mut pd_table: Table;
	static mut page_table: Table;
    //
	// static low_end: u8;
	// static kernel_size: u8; // &kernel_size == kernel size in pages
}

#[no_mangle]
pub unsafe extern fn create_page_tables() {
    // recursive map last PML4 entry
    pml4_table[511] = (&pml4_table as *const Table as u64) | 3;
    // map first PML4 entry to PDP table
    pml4_table[0] = (&pdp_table as *const Table as u64) | 3;
    // map first PDPT entry to PD table
    pdp_table[0] = (&pd_table as *const Table as u64) | 3;

    // map the PD table
    // TODO: implement this in Rust
    asm!("
        // map each PD table entry to its own 2mB page
        mov         ecx, 0
    .pd_table_map: // maps the PD table ----------------------------------------
        mov     eax, 0x200000   // 2 mB
        mul     ecx             // times the start address of the page
        or      eax, 0b10000011 // check if present + writable + huge
        mov     [pd_table + ecx * 8], eax // map nth entry from pd -> own page
        // increment counter and check if done
        inc     ecx
        cmp     ecx, 512
        jne     .pd_table_map
        " :::: "volatile", "intel");
}
<commit_msg>[boot] implement page-table mapping in pure Rust<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2016-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Initial 32-bit bootloader for x86_64
#![crate_name = "boot"]
#![crate_type = "staticlib"]
#![feature(asm)]
#![feature(lang_items)]
#![feature(naked_functions)]
#![no_std]

const TABLE_LENGTH: usize = 512;

type Table = [u64; TABLE_LENGTH];

use core::fmt::Arguments;

#[lang = "panic_fmt"]
extern fn panic_fmt(fmt: Arguments, file: &'static str, line: u32) -> ! {
	loop {}
}

extern {
    static mut pml4_table: Table;
    static mut pdp_table: Table;
    static mut pd_table: Table;
    static mut page_table: Table;
    //
    // static low_end: u8;
    // static kernel_size: u8; // &kernel_size == kernel size in pages
}

#[no_mangle]
#[naked]
pub unsafe extern fn create_page_tables() {
    const HUGE_PAGE_SIZE: u64 = 2 * 1024 * 1024; // 2 MiB

    //-- map the PML4 and PDP tables -----------------------------------------
    // recursive map last PML4 entry
    pml4_table[511] = (&pml4_table as *const Table as u64) | 3;
    // map first PML4 entry to PDP table
    pml4_table[0] = (&pdp_table as *const Table as u64) | 3;
    // map first PDPT entry to PD table
    pdp_table[0] = (&pd_table as *const Table as u64) | 3;

    //-- map the PD table ----------------------------------------------------
    for (number, entry) in pd_table.iter_mut().enumerate() {
        // set each PD entry equal to the start address of the page (the page
        // number times the page's size)
        let addr = number as u64 * HUGE_PAGE_SIZE;
        // with the appropriate flags (present + writable + huge)
        // TODO: do we want to do this using bitflags, or is that too
        //       heavyweight for the boot module?
        //          - eliza, 1/23/2017
        *entry = addr | 0b10000011;
    }
}
<|endoftext|>