<commit_before>extern crate hyper;

use emailaddress::EmailAddress;
use iron::Url;
use openssl::bn::BigNum;
use openssl::crypto::hash;
use openssl::crypto::pkey::PKey;
use openssl::crypto::rsa::RSA;
use serde_json::de::{from_reader, from_slice};
use serde_json::value::Value;
use redis::Commands;
use rustc_serialize::base64::FromBase64;
use self::hyper::client::Client as HttpClient;
use self::hyper::header::ContentType as HyContentType;
use self::hyper::header::Headers;
use super::{AppConfig, create_jwt, session_id};
use std::collections::HashMap;
use std::iter::Iterator;
use time::now_utc;
use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};
use urlencoded::QueryMap;

/// Helper method to issue an OAuth authorization request.
///
/// When an authentication request comes in and matches one of the "famous"
/// identity providers configured in the `AppConfig`, we redirect the client
/// to an Authentication Request URL, which we discover by reading the
/// provider's configured Discovery URL. We pass in the client ID we received
/// when pre-registering for the provider, as well as a callback URL which the
/// user will be redirected back to after confirming (or denying) the
/// Authentication Request. Included in the request is a nonce which we can
/// later use to definitively match the callback to this request.
pub fn request(app: &AppConfig, params: &QueryMap) -> Url {

    let email_addr = EmailAddress::new(&params.get("login_hint").unwrap()[0]).unwrap();
    let client_id = &params.get("client_id").unwrap()[0];
    let session = session_id(&email_addr, client_id);

    // Store the nonce and the RP's `redirect_uri` in Redis for use in the
    // callback handler.
    let key = format!("session:{}", session);
    let _: String = app.store.hset_multiple(key.clone(), &[
        ("email", email_addr.to_string()),
        ("client_id", client_id.clone()),
        ("redirect", params.get("redirect_uri").unwrap()[0].clone()),
    ]).unwrap();
    let _: bool = app.store.expire(key.clone(), app.expire_keys).unwrap();

    // Retrieve the provider's Discovery document and extract the
    // `authorization_endpoint` from it.
    // TODO: cache other data for use in the callback handler, so that we
    // don't have to request the Discovery document twice. We could even store
    // per-provider data in Redis so we can amortize the cost of discovery.
    let provider = &app.providers[&email_addr.domain];
    let client = HttpClient::new();
    let rsp = client.get(&provider.discovery).send().unwrap();
    let val: Value = from_reader(rsp).unwrap();
    let config = val.as_object().unwrap();
    let authz_base = config["authorization_endpoint"].as_string().unwrap();

    // Create the URL to redirect to, properly escaping all parameters.
    Url::parse(&vec![
        authz_base,
        "?",
        "client_id=",
        &utf8_percent_encode(&provider.client_id, QUERY_ENCODE_SET).to_string(),
        "&response_type=code",
        "&scope=",
        &utf8_percent_encode("openid email", QUERY_ENCODE_SET).to_string(),
        "&redirect_uri=",
        &utf8_percent_encode(&format!("{}/callback", &app.base_url),
                             QUERY_ENCODE_SET).to_string(),
        "&state=",
        &utf8_percent_encode(&session, QUERY_ENCODE_SET).to_string(),
        "&login_hint=",
        &utf8_percent_encode(&email_addr.to_string(), QUERY_ENCODE_SET).to_string(),
    ].join("")).unwrap()

}

/// Helper method to verify OAuth authentication result.
///
/// Match the returned email address and nonce against our Redis data, then
/// extract the identity token returned by the provider and verify it. Return
/// an identity token for the RP if successful, or an error message otherwise.
pub fn verify(app: &AppConfig, session_id: &str, code: &str)
              -> Result<(String, String), &'static str> {

    // Validate that the callback matches an auth request in Redis.
    let key = format!("session:{}", session_id);
    let stored: HashMap<String, String> = app.store.hgetall(key.clone()).unwrap();
    if stored.is_empty() {
        return Err("session not found");
    }

    let email_addr = EmailAddress::new(stored.get("email").unwrap()).unwrap();
    let origin = stored.get("client_id").unwrap();

    // Request the provider's Discovery document to get the
    // `token_endpoint` and `jwks_uri` values from it. TODO: save these
    // when requesting the Discovery document in the `oauth_request()`
    // function, and/or cache them by provider host.
    let client = HttpClient::new();
    let provider = &app.providers[&email_addr.domain];
    let rsp = client.get(&provider.discovery).send().unwrap();
    let val: Value = from_reader(rsp).unwrap();
    let config = val.as_object().unwrap();
    let token_url = config["token_endpoint"].as_string().unwrap();

    // Create form data for the Token Request, where we exchange the code
    // received in this callback request for an identity token (while
    // proving our identity by passing the client secret value).
    let body: String = vec![
        "code=",
        &utf8_percent_encode(code, QUERY_ENCODE_SET).to_string(),
        "&client_id=",
        &utf8_percent_encode(&provider.client_id, QUERY_ENCODE_SET).to_string(),
        "&client_secret=",
        &utf8_percent_encode(&provider.secret, QUERY_ENCODE_SET).to_string(),
        "&redirect_uri=",
        &utf8_percent_encode(&format!("{}/callback", &app.base_url),
                             QUERY_ENCODE_SET).to_string(),
        "&grant_type=authorization_code",
    ].join("");

    // Send the Token Request and extract the `id_token` from the response.
    let mut headers = Headers::new();
    headers.set(HyContentType::form_url_encoded());
    let token_rsp = client.post(token_url).headers(headers).body(&body).send().unwrap();
    let token_obj: Value = from_reader(token_rsp).unwrap();
    let id_token = token_obj.find("id_token").unwrap().as_string().unwrap();

    // Extract the header from the JWT structure. First order of business
    // is to determine what key was used to sign the token, so we can then
    // verify the signature.
    let parts: Vec<&str> = id_token.split('.').collect();
    let jwt_header: Value = from_slice(&parts[0].from_base64().unwrap()).unwrap();
    let kid = jwt_header.find("kid").unwrap().as_string().unwrap();

    // Grab the keys from the provider and find keys that match the key ID
    // used to sign the identity token.
    let keys_url = config["jwks_uri"].as_string().unwrap();
    let keys_rsp = client.get(keys_url).send().unwrap();
    let keys_doc: Value = from_reader(keys_rsp).unwrap();
    let keys = keys_doc.find("keys").unwrap().as_array().unwrap().iter()
        .filter(|key_obj| {
            key_obj.find("kid").unwrap().as_string().unwrap() == kid &&
            key_obj.find("use").unwrap().as_string().unwrap() == "sig"
        })
        .collect::<Vec<&Value>>();

    // Verify that we found exactly one key matching the key ID.
    // Then, use the data to build a public key object for verification.
    assert!(keys.len() == 1);
    let n_b64 = keys[0].find("n").unwrap().as_string().unwrap();
    let e_b64 = keys[0].find("e").unwrap().as_string().unwrap();
    let n = BigNum::new_from_slice(&n_b64.from_base64().unwrap()).unwrap();
    let e = BigNum::new_from_slice(&e_b64.from_base64().unwrap()).unwrap();
    let mut pub_key = PKey::new();
    pub_key.set_rsa(&RSA::from_public_components(n, e).unwrap());

    // Verify the identity token's signature.
    let message = format!("{}.{}", parts[0], parts[1]);
    let sha256 = hash::hash(hash::Type::SHA256, message.as_bytes());
    let sig = parts[2].from_base64().unwrap();
    let verified = pub_key.verify(&sha256, &sig);
    assert!(verified);

    // Verify that the issuer matches the configured value.
    let jwt_payload: Value = from_slice(&parts[1].from_base64().unwrap()).unwrap();
    let iss = jwt_payload.find("iss").unwrap().as_string().unwrap();
    let issuer_origin = vec!["https://", &provider.issuer].join("");
    assert!(iss == provider.issuer || iss == issuer_origin);

    // Verify the audience, subject, and expiry.
    let aud = jwt_payload.find("aud").unwrap().as_string().unwrap();
    assert!(aud == provider.client_id);
    let token_addr = jwt_payload.find("email").unwrap().as_string().unwrap();
    assert!(token_addr == email_addr.to_string());
    let now = now_utc().to_timespec().sec;
    let exp = jwt_payload.find("exp").unwrap().as_i64().unwrap();
    assert!(now < exp);

    // If everything is okay, build a new identity token and send it
    // to the relying party.
    let id_token = create_jwt(&app, &email_addr.to_string(), origin);
    let redirect = stored.get("redirect").unwrap();
    Ok((id_token, redirect.to_string()))

}
<commit_msg>Fix one more needless borrow<commit_after>extern crate hyper;

use emailaddress::EmailAddress;
use iron::Url;
use openssl::bn::BigNum;
use openssl::crypto::hash;
use openssl::crypto::pkey::PKey;
use openssl::crypto::rsa::RSA;
use serde_json::de::{from_reader, from_slice};
use serde_json::value::Value;
use redis::Commands;
use rustc_serialize::base64::FromBase64;
use self::hyper::client::Client as HttpClient;
use self::hyper::header::ContentType as HyContentType;
use self::hyper::header::Headers;
use super::{AppConfig, create_jwt, session_id};
use std::collections::HashMap;
use std::iter::Iterator;
use time::now_utc;
use url::percent_encoding::{utf8_percent_encode, QUERY_ENCODE_SET};
use urlencoded::QueryMap;

/// Helper method to issue an OAuth authorization request.
///
/// When an authentication request comes in and matches one of the "famous"
/// identity providers configured in the `AppConfig`, we redirect the client
/// to an Authentication Request URL, which we discover by reading the
/// provider's configured Discovery URL. We pass in the client ID we received
/// when pre-registering for the provider, as well as a callback URL which the
/// user will be redirected back to after confirming (or denying) the
/// Authentication Request. Included in the request is a nonce which we can
/// later use to definitively match the callback to this request.
pub fn request(app: &AppConfig, params: &QueryMap) -> Url {

    let email_addr = EmailAddress::new(&params.get("login_hint").unwrap()[0]).unwrap();
    let client_id = &params.get("client_id").unwrap()[0];
    let session = session_id(&email_addr, client_id);

    // Store the nonce and the RP's `redirect_uri` in Redis for use in the
    // callback handler.
    let key = format!("session:{}", session);
    let _: String = app.store.hset_multiple(key.clone(), &[
        ("email", email_addr.to_string()),
        ("client_id", client_id.clone()),
        ("redirect", params.get("redirect_uri").unwrap()[0].clone()),
    ]).unwrap();
    let _: bool = app.store.expire(key.clone(), app.expire_keys).unwrap();

    // Retrieve the provider's Discovery document and extract the
    // `authorization_endpoint` from it.
    // TODO: cache other data for use in the callback handler, so that we
    // don't have to request the Discovery document twice. We could even store
    // per-provider data in Redis so we can amortize the cost of discovery.
    let provider = &app.providers[&email_addr.domain];
    let client = HttpClient::new();
    let rsp = client.get(&provider.discovery).send().unwrap();
    let val: Value = from_reader(rsp).unwrap();
    let config = val.as_object().unwrap();
    let authz_base = config["authorization_endpoint"].as_string().unwrap();

    // Create the URL to redirect to, properly escaping all parameters.
    Url::parse(&vec![
        authz_base,
        "?",
        "client_id=",
        &utf8_percent_encode(&provider.client_id, QUERY_ENCODE_SET).to_string(),
        "&response_type=code",
        "&scope=",
        &utf8_percent_encode("openid email", QUERY_ENCODE_SET).to_string(),
        "&redirect_uri=",
        &utf8_percent_encode(&format!("{}/callback", &app.base_url),
                             QUERY_ENCODE_SET).to_string(),
        "&state=",
        &utf8_percent_encode(&session, QUERY_ENCODE_SET).to_string(),
        "&login_hint=",
        &utf8_percent_encode(&email_addr.to_string(), QUERY_ENCODE_SET).to_string(),
    ].join("")).unwrap()

}

/// Helper method to verify OAuth authentication result.
///
/// Match the returned email address and nonce against our Redis data, then
/// extract the identity token returned by the provider and verify it. Return
/// an identity token for the RP if successful, or an error message otherwise.
pub fn verify(app: &AppConfig, session_id: &str, code: &str)
              -> Result<(String, String), &'static str> {

    // Validate that the callback matches an auth request in Redis.
    let key = format!("session:{}", session_id);
    let stored: HashMap<String, String> = app.store.hgetall(key.clone()).unwrap();
    if stored.is_empty() {
        return Err("session not found");
    }

    let email_addr = EmailAddress::new(stored.get("email").unwrap()).unwrap();
    let origin = stored.get("client_id").unwrap();

    // Request the provider's Discovery document to get the
    // `token_endpoint` and `jwks_uri` values from it. TODO: save these
    // when requesting the Discovery document in the `oauth_request()`
    // function, and/or cache them by provider host.
    let client = HttpClient::new();
    let provider = &app.providers[&email_addr.domain];
    let rsp = client.get(&provider.discovery).send().unwrap();
    let val: Value = from_reader(rsp).unwrap();
    let config = val.as_object().unwrap();
    let token_url = config["token_endpoint"].as_string().unwrap();

    // Create form data for the Token Request, where we exchange the code
    // received in this callback request for an identity token (while
    // proving our identity by passing the client secret value).
    let body: String = vec![
        "code=",
        &utf8_percent_encode(code, QUERY_ENCODE_SET).to_string(),
        "&client_id=",
        &utf8_percent_encode(&provider.client_id, QUERY_ENCODE_SET).to_string(),
        "&client_secret=",
        &utf8_percent_encode(&provider.secret, QUERY_ENCODE_SET).to_string(),
        "&redirect_uri=",
        &utf8_percent_encode(&format!("{}/callback", &app.base_url),
                             QUERY_ENCODE_SET).to_string(),
        "&grant_type=authorization_code",
    ].join("");

    // Send the Token Request and extract the `id_token` from the response.
    let mut headers = Headers::new();
    headers.set(HyContentType::form_url_encoded());
    let token_rsp = client.post(token_url).headers(headers).body(&body).send().unwrap();
    let token_obj: Value = from_reader(token_rsp).unwrap();
    let id_token = token_obj.find("id_token").unwrap().as_string().unwrap();

    // Extract the header from the JWT structure. First order of business
    // is to determine what key was used to sign the token, so we can then
    // verify the signature.
    let parts: Vec<&str> = id_token.split('.').collect();
    let jwt_header: Value = from_slice(&parts[0].from_base64().unwrap()).unwrap();
    let kid = jwt_header.find("kid").unwrap().as_string().unwrap();

    // Grab the keys from the provider and find keys that match the key ID
    // used to sign the identity token.
    let keys_url = config["jwks_uri"].as_string().unwrap();
    let keys_rsp = client.get(keys_url).send().unwrap();
    let keys_doc: Value = from_reader(keys_rsp).unwrap();
    let keys = keys_doc.find("keys").unwrap().as_array().unwrap().iter()
        .filter(|key_obj| {
            key_obj.find("kid").unwrap().as_string().unwrap() == kid &&
            key_obj.find("use").unwrap().as_string().unwrap() == "sig"
        })
        .collect::<Vec<&Value>>();

    // Verify that we found exactly one key matching the key ID.
    // Then, use the data to build a public key object for verification.
    assert!(keys.len() == 1);
    let n_b64 = keys[0].find("n").unwrap().as_string().unwrap();
    let e_b64 = keys[0].find("e").unwrap().as_string().unwrap();
    let n = BigNum::new_from_slice(&n_b64.from_base64().unwrap()).unwrap();
    let e = BigNum::new_from_slice(&e_b64.from_base64().unwrap()).unwrap();
    let mut pub_key = PKey::new();
    pub_key.set_rsa(&RSA::from_public_components(n, e).unwrap());

    // Verify the identity token's signature.
    let message = format!("{}.{}", parts[0], parts[1]);
    let sha256 = hash::hash(hash::Type::SHA256, message.as_bytes());
    let sig = parts[2].from_base64().unwrap();
    let verified = pub_key.verify(&sha256, &sig);
    assert!(verified);

    // Verify that the issuer matches the configured value.
    let jwt_payload: Value = from_slice(&parts[1].from_base64().unwrap()).unwrap();
    let iss = jwt_payload.find("iss").unwrap().as_string().unwrap();
    let issuer_origin = vec!["https://", &provider.issuer].join("");
    assert!(iss == provider.issuer || iss == issuer_origin);

    // Verify the audience, subject, and expiry.
    let aud = jwt_payload.find("aud").unwrap().as_string().unwrap();
    assert!(aud == provider.client_id);
    let token_addr = jwt_payload.find("email").unwrap().as_string().unwrap();
    assert!(token_addr == email_addr.to_string());
    let now = now_utc().to_timespec().sec;
    let exp = jwt_payload.find("exp").unwrap().as_i64().unwrap();
    assert!(now < exp);

    // If everything is okay, build a new identity token and send it
    // to the relying party.
    let id_token = create_jwt(app, &email_addr.to_string(), origin);
    let redirect = stored.get("redirect").unwrap();
    Ok((id_token, redirect.to_string()))

}
<|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/.

// Communication with the PowerDNS server happens through the http
// server.
// See https://doc.powerdns.com/md/authoritative/backend-remote/ for
// details about the various requests and responses.

use config::Config;
use errors::*;
use iron::headers::ContentType;
use iron::prelude::*;
use iron::status::{self, Status};
use serde_json;
use std::io::Read;

#[derive(Deserialize)]
struct PdnsRequestParameters {
    // intialize method
    path: Option<String>,
    timeout: Option<String>,

    // lookup method
    qtype: Option<String>,
    qname: Option<String>,
    #[serde(rename="zone-id")]
    zone_id: Option<i32>,
    remote: Option<String>,
    local: Option<String>,
    real_remote: Option<String>,
}

#[derive(Deserialize)]
struct PdnsRequest {
    method: String,
    parameters: PdnsRequestParameters,
}

#[derive(Serialize)]
struct PdnsLookupResponse {
    qtype: String,
    qname: String,
    content: String,
    ttl: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    domain_id: Option<String>,
    #[serde(rename="scopeMask")]
    #[serde(skip_serializing_if = "Option::is_none")]
    scope_mask: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    auth: Option<String>,
}

#[derive(Serialize)]
#[serde(untagged)]
enum PdnsResponseParams {
    Lookup(PdnsLookupResponse),
}

#[derive(Serialize)]
struct PdnsResponse {
    result: Vec<PdnsResponseParams>,
}

fn pdns_failure(reason: &str) -> IronResult<Response> {
    debug!("pdns_failure: {}", reason);
    let mut response = Response::with("{\"result\":false}");
    response.status = Some(Status::Ok);
    response.headers.set(ContentType::json());
    Ok(response)
}

pub fn pdns_endpoint(req: &mut Request, config: &Config) -> IronResult<Response> {
    // TODO: check where the request is coming from and only allow from pdns.

    info!("GET /pdns");

    // Read the request from the json body.
    let mut s = String::new();
    itry!(req.body.read_to_string(&mut s));

    debug!("Body is: {}", s);

    let input: PdnsRequest = match serde_json::from_str(&s) {
        Ok(value) => value,
        Err(err) => {
            error!("Bad request: {}", err);
            return EndpointError::with(status::BadRequest, 400);
        }
    };

    debug!("pdns request is {}", input.method);

    if input.method == "lookup" {
        let mut qname = input.parameters.qname.unwrap().to_lowercase();
        let qtype = input.parameters.qtype.unwrap();
        debug!("lookup for qtype={} qname={}", qtype, qname);

        // Example payload:
        //
        // {"method": "lookup",
        //  "parameters": {"local": "0.0.0.0",
        //                 "qname": "fabrice.box.knilxof.org.",
        //                 "qtype": "SOA",
        //                 "real-remote": "63.245.221.198/32",
        //                 "remote": "63.245.221.198",
        //                 "zone-id": -1}}

        // If the qname starts with `_acme-challenge.` this is a DNS-01 challenge verification,
        // so remove that part of the domain to retrieve our record.
        // See https://tools.ietf.org/html/draft-ietf-acme-acme-06#section-8.4
        if qname.starts_with("_acme-challenge.") {
            qname = qname[16..].to_owned();
        }
        debug!("final qname={}", qname);

        // Look for a record with for the qname.
        match config
                  .domain_db
                  .get_record_by_name(&qname)
                  .recv()
                  .unwrap() {
            Ok(record) => {
                if record.local_ip.is_none() && qtype == "A" {
                    // No info on this domain, bail out.
                    return pdns_failure("No local_ip");
                }

                // Choose either the local or public ip based on the parameters.remote one.
                let a_record = if record.public_ip.is_some() &&
                                  input.parameters.remote.unwrap() == record.public_ip.unwrap() {
                    // We are inside of the home network, return the local ip for the A record.
                    record.local_ip.unwrap()
                } else {
                    // We are outside of the home network, return the ip of the tunnel
                    // for the A record.
                    config.tunnel_ip.to_owned()
                };

                let mut pdns_response = PdnsResponse { result: Vec::new() };

                if qtype == "SOA" {
                    // Add a "SOA" record.
                    // TODO: don't hardcode the content of this record!
                    let ns_record = PdnsLookupResponse {
                        qtype: "SOA".to_owned(),
                        qname: qname.to_owned(),
                        content: "a.dns.gandi.net hostmaster.gandi.net 1476196782 10800 3600 604800 10800"
                            .to_owned(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if qtype == "ANY" || qtype == "A" {
                    // Add an "A" record.
                    let ns_record = PdnsLookupResponse {
                        qtype: "A".to_owned(),
                        qname: qname.to_owned(),
                        content: a_record,
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if (qtype == "ANY" || qtype == "TXT") && record.dns_challenge.is_some() {
                    // Add a "TXT" record with the dns challenge content.
                    let ns_record = PdnsLookupResponse {
                        qtype: "A".to_owned(),
                        qname: qname.to_owned(),
                        content: record.dns_challenge.unwrap(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                match serde_json::to_string(&pdns_response) {
                    Ok(serialized) => {
                        debug!("Response is: {}", serialized);
                        let mut response = Response::with(serialized);
                        response.status = Some(Status::Ok);
                        response.headers.set(ContentType::json());

                        return Ok(response);
                    }
                    Err(err) => {
                        error!("{}", err);
                        return EndpointError::with(status::InternalServerError, 501);
                    }
                }
            }
            Err(_) => {
                // No such domain, return a `false` result to PowerDNS.
                return pdns_failure("No record for this name.");
            }
        }
    }

    pdns_failure(&format!("Unsupported method: {}", input.method))
}
<commit_msg>Actually return TXT records...<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/.

// Communication with the PowerDNS server happens through the http
// server.
// See https://doc.powerdns.com/md/authoritative/backend-remote/ for
// details about the various requests and responses.

use config::Config;
use errors::*;
use iron::headers::ContentType;
use iron::prelude::*;
use iron::status::{self, Status};
use serde_json;
use std::io::Read;

#[derive(Deserialize)]
struct PdnsRequestParameters {
    // intialize method
    path: Option<String>,
    timeout: Option<String>,

    // lookup method
    qtype: Option<String>,
    qname: Option<String>,
    #[serde(rename="zone-id")]
    zone_id: Option<i32>,
    remote: Option<String>,
    local: Option<String>,
    real_remote: Option<String>,
}

#[derive(Deserialize)]
struct PdnsRequest {
    method: String,
    parameters: PdnsRequestParameters,
}

#[derive(Serialize)]
struct PdnsLookupResponse {
    qtype: String,
    qname: String,
    content: String,
    ttl: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    domain_id: Option<String>,
    #[serde(rename="scopeMask")]
    #[serde(skip_serializing_if = "Option::is_none")]
    scope_mask: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    auth: Option<String>,
}

#[derive(Serialize)]
#[serde(untagged)]
enum PdnsResponseParams {
    Lookup(PdnsLookupResponse),
}

#[derive(Serialize)]
struct PdnsResponse {
    result: Vec<PdnsResponseParams>,
}

fn pdns_failure(reason: &str) -> IronResult<Response> {
    debug!("pdns_failure: {}", reason);
    let mut response = Response::with("{\"result\":false}");
    response.status = Some(Status::Ok);
    response.headers.set(ContentType::json());
    Ok(response)
}

pub fn pdns_endpoint(req: &mut Request, config: &Config) -> IronResult<Response> {
    // TODO: check where the request is coming from and only allow from pdns.

    info!("GET /pdns");

    // Read the request from the json body.
    let mut s = String::new();
    itry!(req.body.read_to_string(&mut s));

    debug!("Body is: {}", s);

    let input: PdnsRequest = match serde_json::from_str(&s) {
        Ok(value) => value,
        Err(err) => {
            error!("Bad request: {}", err);
            return EndpointError::with(status::BadRequest, 400);
        }
    };

    debug!("pdns request is {}", input.method);

    if input.method == "lookup" {
        let mut qname = input.parameters.qname.unwrap().to_lowercase();
        let qtype = input.parameters.qtype.unwrap();
        debug!("lookup for qtype={} qname={}", qtype, qname);

        // Example payload:
        //
        // {"method": "lookup",
        //  "parameters": {"local": "0.0.0.0",
        //                 "qname": "fabrice.box.knilxof.org.",
        //                 "qtype": "SOA",
        //                 "real-remote": "63.245.221.198/32",
        //                 "remote": "63.245.221.198",
        //                 "zone-id": -1}}

        // If the qname starts with `_acme-challenge.` this is a DNS-01 challenge verification,
        // so remove that part of the domain to retrieve our record.
        // See https://tools.ietf.org/html/draft-ietf-acme-acme-06#section-8.4
        if qname.starts_with("_acme-challenge.") {
            qname = qname[16..].to_owned();
        }
        debug!("final qname={}", qname);

        // Look for a record with for the qname.
        match config
                  .domain_db
                  .get_record_by_name(&qname)
                  .recv()
                  .unwrap() {
            Ok(record) => {
                if record.local_ip.is_none() && qtype == "A" {
                    // No info on this domain, bail out.
                    return pdns_failure("No local_ip");
                }

                // Choose either the local or public ip based on the parameters.remote one.
                let a_record = if record.public_ip.is_some() &&
                                  input.parameters.remote.unwrap() == record.public_ip.unwrap() {
                    // We are inside of the home network, return the local ip for the A record.
                    record.local_ip.unwrap()
                } else {
                    // We are outside of the home network, return the ip of the tunnel
                    // for the A record.
                    config.tunnel_ip.to_owned()
                };

                let mut pdns_response = PdnsResponse { result: Vec::new() };

                if qtype == "SOA" {
                    // Add a "SOA" record.
                    // TODO: don't hardcode the content of this record!
                    let ns_record = PdnsLookupResponse {
                        qtype: "SOA".to_owned(),
                        qname: qname.to_owned(),
                        content: "a.dns.gandi.net hostmaster.gandi.net 1476196782 10800 3600 604800 10800"
                            .to_owned(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if qtype == "ANY" || qtype == "A" {
                    // Add an "A" record.
                    let ns_record = PdnsLookupResponse {
                        qtype: "A".to_owned(),
                        qname: qname.to_owned(),
                        content: a_record,
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                if (qtype == "ANY" || qtype == "TXT") && record.dns_challenge.is_some() {
                    // Add a "TXT" record with the dns challenge content.
                    let ns_record = PdnsLookupResponse {
                        qtype: "TXT".to_owned(),
                        qname: format!("_acme-challenge.{}", qname),
                        content: record.dns_challenge.unwrap(),
                        ttl: config.dns_ttl,
                        domain_id: None,
                        scope_mask: None,
                        auth: None,
                    };
                    pdns_response
                        .result
                        .push(PdnsResponseParams::Lookup(ns_record));
                }

                match serde_json::to_string(&pdns_response) {
                    Ok(serialized) => {
                        debug!("Response is: {}", serialized);
                        let mut response = Response::with(serialized);
                        response.status = Some(Status::Ok);
                        response.headers.set(ContentType::json());

                        return Ok(response);
                    }
                    Err(err) => {
                        error!("{}", err);
                        return EndpointError::with(status::InternalServerError, 501);
                    }
                }
            }
            Err(_) => {
                // No such domain, return a `false` result to PowerDNS.
                return pdns_failure("No record for this name.");
            }
        }
    }

    pdns_failure(&format!("Unsupported method: {}", input.method))
}
<|endoftext|>


<commit_before>use mysql::error::Error;
use mysql::conn::Conn;
use mysql::Opts;
use std::result::Result;
use r2d2;

#[derive(Debug)]
pub struct MysqlConnectionManager {
    params: Opts,
}

impl MysqlConnectionManager {
    /// Creates a new `MysqlConnectionManager`.
    ///
    /// See `postgres::Connection::connect` for a description of the parameter
    /// types.
    pub fn new<T: Into<Opts>>(params: T) -> Result<MysqlConnectionManager, Error> {
        self.param = try!(Opts::from(T));
    }

    fn do_connect(&self) -> Result<Conn,Error> {
        Conn::new(self.param);
    }
}

impl r2d2::ManageConnection for MysqlConnectionManager {
    type Connection = Conn;
    type Error = Error;

    fn connect(&self) -> Result<Conn,Error> {
    	self.do_connect()
    }

    fn is_valid(&self, conn: &mut Conn) -> Result<(), Error> {
        conn.query("select 1").map(|_| () )
    }

    fn has_broken(&self, conn: &mut Conn) -> bool {
        self.is_valid(conn).is_err()
    }
}
<commit_msg>Made the new method more generic as suggestion for https://github.com/outersky/r2d2-mysql/issues/5<commit_after>use mysql::error::Error;
use mysql::conn::Conn;
use mysql::Opts;
use mysql::OptsBuilder;
use std::result::Result;
use r2d2;

#[derive(Debug)]
pub struct MysqlConnectionManager {
    params: Opts,
}

pub trait CreateManager<T> {
 type Manager;
 fn new(params: T) -> Result<Self::Manager, Error>;
}

impl CreateManager<OptsBuilder> for MysqlConnectionManager {
    type Manager = MysqlConnectionManager;
     fn new(params: OptsBuilder) -> Result<Self::Manager, Error> {
         Ok(
             MysqlConnectionManager {
                 params: Opts::from(params)
             }
         )
    }
}

impl <'a> CreateManager<&'a str> for MysqlConnectionManager {
     type Manager = MysqlConnectionManager;
     fn new(params: &'a str) -> Result<Self::Manager, Error> {
         Ok(
             MysqlConnectionManager {
                 params: Opts::from(params)
             }
         )
    }
}

impl r2d2::ManageConnection for MysqlConnectionManager {
    type Connection = Conn;
    type Error = Error;

    fn connect(&self) -> Result<Conn,Error> {
    	    Conn::new(self.params.clone())
    }

    fn is_valid(&self, conn: &mut Conn) -> Result<(), Error> {
        conn.query("SELECT version()").map(|_| () )
    }

    fn has_broken(&self, conn: &mut Conn) -> bool {
        self.is_valid(conn).is_err()
    }
}
<|endoftext|>


<commit_before>import mre::mre;
import mre::router::router;
import mre::response::response;
import zmq::context;

type data = {
    mut session: option<mre::session::session>,
    mut user: option<mre::user::user>,
};

type app = @{
    zmq: zmq::context,
    m2: mongrel2::connection,
    mre: mre::mre<data>,
    es: elasticsearch::client,
    mu: mustache::context,
    password_hasher: mre::auth::hasher
};

fn app() -> app {
    let zmq =
        alt zmq::init(1) {
          ok(ctx) { ctx }
          err(e) { fail e.to_str() }
        };

    let m2 = mongrel2::connect(zmq,
        "F0D32575-2ABB-4957-BC8B-12DAC8AFF13A",
        "tcp://127.0.0.1:9998",
        "tcp://127.0.0.1:9999");

    let es = elasticsearch::connect_with_zmq(zmq, "tcp://localhost:9700");

    let middleware = mre::middleware::middleware([
        mre::middleware::logger(io::stdout()),
        mre::middleware::session(es,
            "blog",
            "blog",
            "session"
        ) { |req: @request<data>, session, user|
            req.data.session = some(session);
            req.data.user = some(user);
        }
    ]);

    let mre = mre::mre(m2, middleware) { ||
        { mut session: none, mut user: none }
    };

    let mu = mustache::context("views", ".mustache");

    @{
        zmq: zmq,
        m2: m2,
        mre: mre,
        es: es,
        mu: mu,
        password_hasher: mre::auth::default_pbkdf2_sha1()
    }
}

impl app for app {
    fn get(regex: str, f: mre::router::handler<data>) {
        self.mre.router.add(mre::request::GET, regex, f)
    }

    fn post(regex: str, f: mre::router::handler<data>) {
        self.mre.router.add(mre::request::POST, regex, f)
    }

    fn run() {
        self.mre.run();
    }

    fn term() {
        self.m2.term();
        self.zmq.term();
    }
}
<commit_msg>mongrel2 now listen and reply to multiple socket urls.<commit_after>import mre::mre;
import mre::router::router;
import mre::response::response;
import zmq::context;

type data = {
    mut session: option<mre::session::session>,
    mut user: option<mre::user::user>,
};

type app = @{
    zmq: zmq::context,
    m2: mongrel2::connection,
    mre: mre::mre<data>,
    es: elasticsearch::client,
    mu: mustache::context,
    password_hasher: mre::auth::hasher
};

fn app() -> app {
    let zmq =
        alt zmq::init(1) {
          ok(ctx) { ctx }
          err(e) { fail e.to_str() }
        };

    let m2 = mongrel2::connect(zmq,
        "F0D32575-2ABB-4957-BC8B-12DAC8AFF13A",
        ["tcp://127.0.0.1:9998"],
        ["tcp://127.0.0.1:9999"]);

    let es = elasticsearch::connect_with_zmq(zmq, "tcp://localhost:9700");

    let middleware = mre::middleware::middleware([
        mre::middleware::logger(io::stdout()),
        mre::middleware::session(es,
            "blog",
            "blog",
            "session"
        ) { |req: @request<data>, session, user|
            req.data.session = some(session);
            req.data.user = some(user);
        }
    ]);

    let mre = mre::mre(m2, middleware) { ||
        { mut session: none, mut user: none }
    };

    let mu = mustache::context("views", ".mustache");

    @{
        zmq: zmq,
        m2: m2,
        mre: mre,
        es: es,
        mu: mu,
        password_hasher: mre::auth::default_pbkdf2_sha1()
    }
}

impl app for app {
    fn get(regex: str, f: mre::router::handler<data>) {
        self.mre.router.add(mre::request::GET, regex, f)
    }

    fn post(regex: str, f: mre::router::handler<data>) {
        self.mre.router.add(mre::request::POST, regex, f)
    }

    fn run() {
        self.mre.run();
    }

    fn term() {
        self.m2.term();
        self.zmq.term();
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Cesar Eduardo Barros
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

pub use simdty::{u32x4, u64x4};
#[cfg(feature = "simd")] use simdint;

use std::ops::{Add, BitXor, Shl, Shr};

macro_rules! impl_ops {
    ($vec:ident) => {
        impl Add for $vec {
            type Output = Self;

            #[cfg(feature = "simd")]
            #[inline(always)]
            fn add(self, rhs: Self) -> Self::Output {
                unsafe { simdint::simd_add(self, rhs) }
            }

            #[cfg(not(feature = "simd"))]
            #[inline(always)]
            fn add(self, rhs: Self) -> Self::Output {
                $vec::new(self.0.wrapping_add(rhs.0),
                          self.1.wrapping_add(rhs.1),
                          self.2.wrapping_add(rhs.2),
                          self.3.wrapping_add(rhs.3))
            }
        }

        impl BitXor for $vec {
            type Output = Self;

            #[cfg(feature = "simd")]
            #[inline(always)]
            fn bitxor(self, rhs: Self) -> Self::Output {
                unsafe { simdint::simd_xor(self, rhs) }
            }

            #[cfg(not(feature = "simd"))]
            #[inline(always)]
            fn bitxor(self, rhs: Self) -> Self::Output {
                $vec::new(self.0 ^ rhs.0,
                          self.1 ^ rhs.1,
                          self.2 ^ rhs.2,
                          self.3 ^ rhs.3)
            }
        }

        impl Shl<$vec> for $vec {
            type Output = Self;

            #[cfg(feature = "simd")]
            #[inline(always)]
            fn shl(self, rhs: Self) -> Self::Output {
                unsafe { simdint::simd_shl(self, rhs) }
            }

            #[cfg(not(feature = "simd"))]
            #[inline(always)]
            fn shl(self, rhs: Self) -> Self::Output {
                $vec::new(self.0 << rhs.0,
                          self.1 << rhs.1,
                          self.2 << rhs.2,
                          self.3 << rhs.3)
            }
        }

        impl Shr<$vec> for $vec {
            type Output = Self;

            #[cfg(feature = "simd")]
            #[inline(always)]
            fn shr(self, rhs: Self) -> Self::Output {
                unsafe { simdint::simd_shr(self, rhs) }
            }

            #[cfg(not(feature = "simd"))]
            #[inline(always)]
            fn shr(self, rhs: Self) -> Self::Output {
                $vec::new(self.0 >> rhs.0,
                          self.1 >> rhs.1,
                          self.2 >> rhs.2,
                          self.3 >> rhs.3)
            }
        }
    }
}

impl_ops!(u32x4);
impl_ops!(u64x4);

pub trait Vector4<T>: Copy {
    fn gather(src: &[T], i0: usize, i1: usize, i2: usize, i3: usize) -> Self;

    fn from_le(self) -> Self;
    fn to_le(self) -> Self;

    fn wrapping_add(self, rhs: Self) -> Self;

    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self { self.rotate_right_any(n) }
    fn rotate_right_any(self, n: u32) -> Self;

    fn shuffle_left_1(self) -> Self;
    fn shuffle_left_2(self) -> Self;
    fn shuffle_left_3(self) -> Self;

    #[inline(always)] fn shuffle_right_1(self) -> Self { self.shuffle_left_3() }
    #[inline(always)] fn shuffle_right_2(self) -> Self { self.shuffle_left_2() }
    #[inline(always)] fn shuffle_right_3(self) -> Self { self.shuffle_left_1() }
}

macro_rules! impl_vector4_common {
    ($vec:ident, $word:ident, $bits:expr) => {
        #[inline(always)]
        fn gather(src: &[$word], i0: usize, i1: usize,
                                 i2: usize, i3: usize) -> Self {
            $vec::new(src[i0], src[i1], src[i2], src[i3])
        }

        #[cfg(target_endian = "little")]
        #[inline(always)]
        fn from_le(self) -> Self { self }

        #[cfg(not(target_endian = "little"))]
        #[inline(always)]
        fn from_le(self) -> Self {
            $vec::new($word::from_le(self.0),
                      $word::from_le(self.1),
                      $word::from_le(self.2),
                      $word::from_le(self.3))
        }

        #[cfg(target_endian = "little")]
        #[inline(always)]
        fn to_le(self) -> Self { self }

        #[cfg(not(target_endian = "little"))]
        #[inline(always)]
        fn to_le(self) -> Self {
            $vec::new(self.0.to_le(),
                      self.1.to_le(),
                      self.2.to_le(),
                      self.3.to_le())
        }

        #[inline(always)]
        fn wrapping_add(self, rhs: Self) -> Self { self + rhs }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn rotate_right_any(self, n: u32) -> Self {
            let r = n as $word;
            let l = $bits - r;

            (self >> $vec::new(r, r, r, r)) ^ (self << $vec::new(l, l, l, l))
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn rotate_right_any(self, n: u32) -> Self {
            $vec::new(self.0.rotate_right(n),
                      self.1.rotate_right(n),
                      self.2.rotate_right(n),
                      self.3.rotate_right(n))
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn shuffle_left_1(self) -> Self {
            unsafe { simdint::simd_shuffle4(self, self, [1, 2, 3, 0]) }
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn shuffle_left_1(self) -> Self {
            $vec::new(self.1, self.2, self.3, self.0)
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn shuffle_left_2(self) -> Self {
            unsafe { simdint::simd_shuffle4(self, self, [2, 3, 0, 1]) }
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn shuffle_left_2(self) -> Self {
            $vec::new(self.2, self.3, self.0, self.1)
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn shuffle_left_3(self) -> Self {
            unsafe { simdint::simd_shuffle4(self, self, [3, 0, 1, 2])  }
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn shuffle_left_3(self) -> Self {
            $vec::new(self.3, self.0, self.1, self.2)
        }
    }
}

#[cfg(feature = "simd_opt")]
#[cfg(any(target_arch = "arm", target_arch = "aarch64",
          target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u32x4_rotate_right_16(vec: u32x4) -> u32x4 {
    use simdty::u16x8;
    use std::mem::transmute;

    unsafe {
        let tmp: u16x8 = transmute(vec);
        let tmp: u16x8 = simdint::simd_shuffle8(tmp, tmp,
                                                [1, 0,
                                                 3, 2,
                                                 5, 4,
                                                 7, 6]);
        transmute(tmp)
    }
}

impl Vector4<u32> for u32x4 {
    impl_vector4_common!(u32x4, u32, 32);

    #[cfg(feature = "simd_opt")]
    #[cfg(any(target_arch = "arm", target_arch = "aarch64",
              target_arch = "x86", target_arch = "x86_64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            16 => u32x4_rotate_right_16(self),
            _ => self.rotate_right_any(n),
        }
    }
}

#[cfg(feature = "simd_opt")]
#[cfg(any(target_arch = "arm", target_arch = "aarch64",
          target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u64x4_rotate_right_32(vec: u64x4) -> u64x4 {
    use simdty::u32x8;
    use std::mem::transmute;

    unsafe {
        let tmp: u32x8 = transmute(vec);
        let tmp: u32x8 = simdint::simd_shuffle8(tmp, tmp,
                                                [1, 0,
                                                 3, 2,
                                                 5, 4,
                                                 7, 6]);
        transmute(tmp)
    }
}

#[cfg(feature = "simd_opt")]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u64x4_rotate_right_16(vec: u64x4) -> u64x4 {
    use simdty::u16x16;
    use std::mem::transmute;

    unsafe {
        let tmp: u16x16 = transmute(vec);
        let tmp: u16x16 = simdint::simd_shuffle16(tmp, tmp,
                                                  [ 1,  2,  3,  0,
                                                    5,  6,  7,  4,
                                                    9, 10, 11,  8,
                                                   13, 14, 15, 12]);
        transmute(tmp)
    }
}

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
use simdty::u64x2;

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
#[inline(always)]
fn vext_u64_u8(a: u64x2, b: u8) -> u64x2 {
    unsafe {
        let result: u64x2;
        asm!("vext.8 ${0:e}, ${1:e}, ${1:e}, $2\nvext.8 ${0:f}, ${1:f}, ${1:f}, $2"
           : "=w" (result)
           : "w" (a), "n" (b));
        result
    }
}

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
#[inline(always)]
fn u64x4_rotate_right_u8(vec: u64x4, n: u8) -> u64x4 {
    unsafe {
        let tmp0 = vext_u64_u8(simdint::simd_shuffle2(vec, vec, 0, 1), n);
        let tmp1 = vext_u64_u8(simdint::simd_shuffle2(vec, vec, 2, 3), n);
        simdint::simd_shuffle4(tmp0, tmp1, 0, 1, 2, 3)
    }
}

impl Vector4<u64> for u64x4 {
    impl_vector4_common!(u64x4, u64, 64);

    #[cfg(feature = "simd_opt")]
    #[cfg(any(all(target_arch = "arm", not(feature = "simd_asm")),
              target_arch = "aarch64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            _ => self.rotate_right_any(n),
        }
    }

    #[cfg(feature = "simd_asm")]
    #[cfg(target_arch = "arm")]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            24 => u64x4_rotate_right_u8(self, 3),
            16 => u64x4_rotate_right_u8(self, 2),
            _ => self.rotate_right_any(n),
        }
    }

    #[cfg(feature = "simd_opt")]
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            16 => u64x4_rotate_right_16(self),
            _ => self.rotate_right_any(n),
        }
    }
}
<commit_msg>Missed a few shuffles<commit_after>// Copyright (c) 2015 Cesar Eduardo Barros
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

pub use simdty::{u32x4, u64x4};
#[cfg(feature = "simd")] use simdint;

use std::ops::{Add, BitXor, Shl, Shr};

macro_rules! impl_ops {
    ($vec:ident) => {
        impl Add for $vec {
            type Output = Self;

            #[cfg(feature = "simd")]
            #[inline(always)]
            fn add(self, rhs: Self) -> Self::Output {
                unsafe { simdint::simd_add(self, rhs) }
            }

            #[cfg(not(feature = "simd"))]
            #[inline(always)]
            fn add(self, rhs: Self) -> Self::Output {
                $vec::new(self.0.wrapping_add(rhs.0),
                          self.1.wrapping_add(rhs.1),
                          self.2.wrapping_add(rhs.2),
                          self.3.wrapping_add(rhs.3))
            }
        }

        impl BitXor for $vec {
            type Output = Self;

            #[cfg(feature = "simd")]
            #[inline(always)]
            fn bitxor(self, rhs: Self) -> Self::Output {
                unsafe { simdint::simd_xor(self, rhs) }
            }

            #[cfg(not(feature = "simd"))]
            #[inline(always)]
            fn bitxor(self, rhs: Self) -> Self::Output {
                $vec::new(self.0 ^ rhs.0,
                          self.1 ^ rhs.1,
                          self.2 ^ rhs.2,
                          self.3 ^ rhs.3)
            }
        }

        impl Shl<$vec> for $vec {
            type Output = Self;

            #[cfg(feature = "simd")]
            #[inline(always)]
            fn shl(self, rhs: Self) -> Self::Output {
                unsafe { simdint::simd_shl(self, rhs) }
            }

            #[cfg(not(feature = "simd"))]
            #[inline(always)]
            fn shl(self, rhs: Self) -> Self::Output {
                $vec::new(self.0 << rhs.0,
                          self.1 << rhs.1,
                          self.2 << rhs.2,
                          self.3 << rhs.3)
            }
        }

        impl Shr<$vec> for $vec {
            type Output = Self;

            #[cfg(feature = "simd")]
            #[inline(always)]
            fn shr(self, rhs: Self) -> Self::Output {
                unsafe { simdint::simd_shr(self, rhs) }
            }

            #[cfg(not(feature = "simd"))]
            #[inline(always)]
            fn shr(self, rhs: Self) -> Self::Output {
                $vec::new(self.0 >> rhs.0,
                          self.1 >> rhs.1,
                          self.2 >> rhs.2,
                          self.3 >> rhs.3)
            }
        }
    }
}

impl_ops!(u32x4);
impl_ops!(u64x4);

pub trait Vector4<T>: Copy {
    fn gather(src: &[T], i0: usize, i1: usize, i2: usize, i3: usize) -> Self;

    fn from_le(self) -> Self;
    fn to_le(self) -> Self;

    fn wrapping_add(self, rhs: Self) -> Self;

    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self { self.rotate_right_any(n) }
    fn rotate_right_any(self, n: u32) -> Self;

    fn shuffle_left_1(self) -> Self;
    fn shuffle_left_2(self) -> Self;
    fn shuffle_left_3(self) -> Self;

    #[inline(always)] fn shuffle_right_1(self) -> Self { self.shuffle_left_3() }
    #[inline(always)] fn shuffle_right_2(self) -> Self { self.shuffle_left_2() }
    #[inline(always)] fn shuffle_right_3(self) -> Self { self.shuffle_left_1() }
}

macro_rules! impl_vector4_common {
    ($vec:ident, $word:ident, $bits:expr) => {
        #[inline(always)]
        fn gather(src: &[$word], i0: usize, i1: usize,
                                 i2: usize, i3: usize) -> Self {
            $vec::new(src[i0], src[i1], src[i2], src[i3])
        }

        #[cfg(target_endian = "little")]
        #[inline(always)]
        fn from_le(self) -> Self { self }

        #[cfg(not(target_endian = "little"))]
        #[inline(always)]
        fn from_le(self) -> Self {
            $vec::new($word::from_le(self.0),
                      $word::from_le(self.1),
                      $word::from_le(self.2),
                      $word::from_le(self.3))
        }

        #[cfg(target_endian = "little")]
        #[inline(always)]
        fn to_le(self) -> Self { self }

        #[cfg(not(target_endian = "little"))]
        #[inline(always)]
        fn to_le(self) -> Self {
            $vec::new(self.0.to_le(),
                      self.1.to_le(),
                      self.2.to_le(),
                      self.3.to_le())
        }

        #[inline(always)]
        fn wrapping_add(self, rhs: Self) -> Self { self + rhs }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn rotate_right_any(self, n: u32) -> Self {
            let r = n as $word;
            let l = $bits - r;

            (self >> $vec::new(r, r, r, r)) ^ (self << $vec::new(l, l, l, l))
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn rotate_right_any(self, n: u32) -> Self {
            $vec::new(self.0.rotate_right(n),
                      self.1.rotate_right(n),
                      self.2.rotate_right(n),
                      self.3.rotate_right(n))
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn shuffle_left_1(self) -> Self {
            unsafe { simdint::simd_shuffle4(self, self, [1, 2, 3, 0]) }
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn shuffle_left_1(self) -> Self {
            $vec::new(self.1, self.2, self.3, self.0)
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn shuffle_left_2(self) -> Self {
            unsafe { simdint::simd_shuffle4(self, self, [2, 3, 0, 1]) }
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn shuffle_left_2(self) -> Self {
            $vec::new(self.2, self.3, self.0, self.1)
        }

        #[cfg(feature = "simd")]
        #[inline(always)]
        fn shuffle_left_3(self) -> Self {
            unsafe { simdint::simd_shuffle4(self, self, [3, 0, 1, 2])  }
        }

        #[cfg(not(feature = "simd"))]
        #[inline(always)]
        fn shuffle_left_3(self) -> Self {
            $vec::new(self.3, self.0, self.1, self.2)
        }
    }
}

#[cfg(feature = "simd_opt")]
#[cfg(any(target_arch = "arm", target_arch = "aarch64",
          target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u32x4_rotate_right_16(vec: u32x4) -> u32x4 {
    use simdty::u16x8;
    use std::mem::transmute;

    unsafe {
        let tmp: u16x8 = transmute(vec);
        let tmp: u16x8 = simdint::simd_shuffle8(tmp, tmp,
                                                [1, 0,
                                                 3, 2,
                                                 5, 4,
                                                 7, 6]);
        transmute(tmp)
    }
}

impl Vector4<u32> for u32x4 {
    impl_vector4_common!(u32x4, u32, 32);

    #[cfg(feature = "simd_opt")]
    #[cfg(any(target_arch = "arm", target_arch = "aarch64",
              target_arch = "x86", target_arch = "x86_64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            16 => u32x4_rotate_right_16(self),
            _ => self.rotate_right_any(n),
        }
    }
}

#[cfg(feature = "simd_opt")]
#[cfg(any(target_arch = "arm", target_arch = "aarch64",
          target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u64x4_rotate_right_32(vec: u64x4) -> u64x4 {
    use simdty::u32x8;
    use std::mem::transmute;

    unsafe {
        let tmp: u32x8 = transmute(vec);
        let tmp: u32x8 = simdint::simd_shuffle8(tmp, tmp,
                                                [1, 0,
                                                 3, 2,
                                                 5, 4,
                                                 7, 6]);
        transmute(tmp)
    }
}

#[cfg(feature = "simd_opt")]
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
#[inline(always)]
fn u64x4_rotate_right_16(vec: u64x4) -> u64x4 {
    use simdty::u16x16;
    use std::mem::transmute;

    unsafe {
        let tmp: u16x16 = transmute(vec);
        let tmp: u16x16 = simdint::simd_shuffle16(tmp, tmp,
                                                  [ 1,  2,  3,  0,
                                                    5,  6,  7,  4,
                                                    9, 10, 11,  8,
                                                   13, 14, 15, 12]);
        transmute(tmp)
    }
}

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
use simdty::u64x2;

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
#[inline(always)]
fn vext_u64_u8(a: u64x2, b: u8) -> u64x2 {
    unsafe {
        let result: u64x2;
        asm!("vext.8 ${0:e}, ${1:e}, ${1:e}, $2\nvext.8 ${0:f}, ${1:f}, ${1:f}, $2"
           : "=w" (result)
           : "w" (a), "n" (b));
        result
    }
}

#[cfg(feature = "simd_asm")]
#[cfg(target_arch = "arm")]
#[inline(always)]
fn u64x4_rotate_right_u8(vec: u64x4, n: u8) -> u64x4 {
    unsafe {
        let tmp0 = vext_u64_u8(simdint::simd_shuffle2(vec, vec, [0, 1]), n);
        let tmp1 = vext_u64_u8(simdint::simd_shuffle2(vec, vec, [2, 3]), n);
        simdint::simd_shuffle4(tmp0, tmp1, [0, 1, 2, 3])
    }
}

impl Vector4<u64> for u64x4 {
    impl_vector4_common!(u64x4, u64, 64);

    #[cfg(feature = "simd_opt")]
    #[cfg(any(all(target_arch = "arm", not(feature = "simd_asm")),
              target_arch = "aarch64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            _ => self.rotate_right_any(n),
        }
    }

    #[cfg(feature = "simd_asm")]
    #[cfg(target_arch = "arm")]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            24 => u64x4_rotate_right_u8(self, 3),
            16 => u64x4_rotate_right_u8(self, 2),
            _ => self.rotate_right_any(n),
        }
    }

    #[cfg(feature = "simd_opt")]
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    #[inline(always)]
    fn rotate_right(self, n: u32) -> Self
    {
        match n {
            32 => u64x4_rotate_right_32(self),
            16 => u64x4_rotate_right_16(self),
            _ => self.rotate_right_any(n),
        }
    }
}
<|endoftext|>


<commit_before>use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span, respan};
use syntax::ptr::P;

use invoke::{Invoke, Identity};

use expr::ExprBuilder;
use ident::ToIdent;
use item::ItemBuilder;
use pat::PatBuilder;
use ty::TyBuilder;

//////////////////////////////////////////////////////////////////////////////

pub struct StmtBuilder<F=Identity> {
    callback: F,
    span: Span,
}

impl StmtBuilder {
    pub fn new() -> StmtBuilder {
        StmtBuilder::new_with_callback(Identity)
    }
}

impl<F> StmtBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    pub fn new_with_callback(callback: F) -> Self {
        StmtBuilder {
            callback: callback,
            span: DUMMY_SP,
        }
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn build_stmt(self, stmt_: ast::Stmt_) -> F::Result {
        self.callback.invoke(P(respan(self.span, stmt_)))
    }

    pub fn build_let(self,
                 pat: P<ast::Pat>,
                 ty: Option<P<ast::Ty>>,
                 init: Option<P<ast::Expr>>) -> F::Result {
        let local = ast::Local {
            pat: pat,
            ty: ty,
            init: init,
            id: ast::DUMMY_NODE_ID,
            span: self.span,
            source: ast::LocalSource::LocalLet,
        };

        let decl = respan(self.span, ast::Decl_::DeclLocal(P(local)));

        self.build_stmt(ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))
    }

    pub fn let_(self) -> PatBuilder<Self> {
        PatBuilder::new_with_callback(self)
    }

    pub fn let_id<I>(self, id: I) -> ExprBuilder<StmtLetIdBuilder<F>>
        where I: ToIdent,
    {
        let id = id.to_ident();
        ExprBuilder::new_with_callback(StmtLetIdBuilder(self, id))
    }

    pub fn build_expr(self, expr: P<ast::Expr>) -> F::Result {
        self.build_stmt(ast::Stmt_::StmtExpr(expr, ast::DUMMY_NODE_ID))
    }

    pub fn expr(self) -> ExprBuilder<StmtExprBuilder<F>> {
        ExprBuilder::new_with_callback(StmtExprBuilder(self))
    }

    pub fn semi(self) -> ExprBuilder<StmtSemiBuilder<F>> {
        ExprBuilder::new_with_callback(StmtSemiBuilder(self))
    }

    pub fn build_item(self, item: P<ast::Item>) -> F::Result {
        let decl = respan(self.span, ast::Decl_::DeclItem(item));
        self.build_stmt(ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))
    }

    pub fn item(self) -> ItemBuilder<StmtItemBuilder<F>> {
        ItemBuilder::new_with_callback(StmtItemBuilder(self))
    }
}

impl<F> Invoke<P<ast::Pat>> for StmtBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = StmtLetBuilder<F>;

    fn invoke(self, pat: P<ast::Pat>) -> StmtLetBuilder<F> {
        StmtLetBuilder {
            builder: self,
            pat: pat,
        }
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetIdBuilder<F>(StmtBuilder<F>, ast::Ident);

impl<F> Invoke<P<ast::Expr>> for StmtLetIdBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.let_().id(self.1).build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtExprBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtExprBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtSemiBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtSemiBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_stmt(ast::Stmt_::StmtSemi(expr, ast::DUMMY_NODE_ID))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetBuilder<F> {
    builder: StmtBuilder<F>,
    pat: P<ast::Pat>,
}

impl<F> StmtLetBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    fn build_ty(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        StmtLetTyBuilder {
            builder: self.builder,
            pat: self.pat,
            ty: ty,
        }
    }

    pub fn ty(self) -> TyBuilder<Self> {
        TyBuilder::new_with_callback(self)
    }

    pub fn build_expr(self, expr: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, None, Some(expr))
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::new_with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, None, None)
    }
}

impl<F> Invoke<P<ast::Ty>> for StmtLetBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = StmtLetTyBuilder<F>;

    fn invoke(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        self.build_ty(ty)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetTyBuilder<F> {
    builder: StmtBuilder<F>,
    pat: P<ast::Pat>,
    ty: P<ast::Ty>,
}

impl<F> StmtLetTyBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::new_with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, Some(self.ty), None)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetTyBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, Some(self.ty), Some(expr))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtItemBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Item>> for StmtItemBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, item: P<ast::Item>) -> F::Result {
        self.0.build_item(item)
    }
}

<commit_msg>Pass some spans to sub-builders<commit_after>use syntax::ast;
use syntax::codemap::{DUMMY_SP, Span, respan};
use syntax::ptr::P;

use invoke::{Invoke, Identity};

use expr::ExprBuilder;
use ident::ToIdent;
use item::ItemBuilder;
use pat::PatBuilder;
use ty::TyBuilder;

//////////////////////////////////////////////////////////////////////////////

pub struct StmtBuilder<F=Identity> {
    callback: F,
    span: Span,
}

impl StmtBuilder {
    pub fn new() -> StmtBuilder {
        StmtBuilder::new_with_callback(Identity)
    }
}

impl<F> StmtBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    pub fn new_with_callback(callback: F) -> Self {
        StmtBuilder {
            callback: callback,
            span: DUMMY_SP,
        }
    }

    pub fn span(mut self, span: Span) -> Self {
        self.span = span;
        self
    }

    pub fn build_stmt(self, stmt_: ast::Stmt_) -> F::Result {
        self.callback.invoke(P(respan(self.span, stmt_)))
    }

    pub fn build_let(self,
                 pat: P<ast::Pat>,
                 ty: Option<P<ast::Ty>>,
                 init: Option<P<ast::Expr>>) -> F::Result {
        let local = ast::Local {
            pat: pat,
            ty: ty,
            init: init,
            id: ast::DUMMY_NODE_ID,
            span: self.span,
            source: ast::LocalSource::LocalLet,
        };

        let decl = respan(self.span, ast::Decl_::DeclLocal(P(local)));

        self.build_stmt(ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))
    }

    pub fn let_(self) -> PatBuilder<Self> {
        PatBuilder::new_with_callback(self)
    }

    pub fn let_id<I>(self, id: I) -> ExprBuilder<StmtLetIdBuilder<F>>
        where I: ToIdent,
    {
        let span = self.span;
        ExprBuilder::new_with_callback(StmtLetIdBuilder(self, id.to_ident())).span(span)
    }

    pub fn build_expr(self, expr: P<ast::Expr>) -> F::Result {
        self.build_stmt(ast::Stmt_::StmtExpr(expr, ast::DUMMY_NODE_ID))
    }

    pub fn expr(self) -> ExprBuilder<StmtExprBuilder<F>> {
        let span = self.span;
        ExprBuilder::new_with_callback(StmtExprBuilder(self)).span(span)
    }

    pub fn semi(self) -> ExprBuilder<StmtSemiBuilder<F>> {
        let span = self.span;
        ExprBuilder::new_with_callback(StmtSemiBuilder(self)).span(span)
    }

    pub fn build_item(self, item: P<ast::Item>) -> F::Result {
        let decl = respan(self.span, ast::Decl_::DeclItem(item));
        self.build_stmt(ast::StmtDecl(P(decl), ast::DUMMY_NODE_ID))
    }

    pub fn item(self) -> ItemBuilder<StmtItemBuilder<F>> {
        let span = self.span;
        ItemBuilder::new_with_callback(StmtItemBuilder(self)).span(span)
    }
}

impl<F> Invoke<P<ast::Pat>> for StmtBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = StmtLetBuilder<F>;

    fn invoke(self, pat: P<ast::Pat>) -> StmtLetBuilder<F> {
        StmtLetBuilder {
            builder: self,
            pat: pat,
        }
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetIdBuilder<F>(StmtBuilder<F>, ast::Ident);

impl<F> Invoke<P<ast::Expr>> for StmtLetIdBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.let_().id(self.1).build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtExprBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtExprBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtSemiBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Expr>> for StmtSemiBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.0.build_stmt(ast::Stmt_::StmtSemi(expr, ast::DUMMY_NODE_ID))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetBuilder<F> {
    builder: StmtBuilder<F>,
    pat: P<ast::Pat>,
}

impl<F> StmtLetBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    fn build_ty(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        StmtLetTyBuilder {
            builder: self.builder,
            pat: self.pat,
            ty: ty,
        }
    }

    pub fn ty(self) -> TyBuilder<Self> {
        TyBuilder::new_with_callback(self)
    }

    pub fn build_expr(self, expr: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, None, Some(expr))
    }

    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::new_with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, None, None)
    }
}

impl<F> Invoke<P<ast::Ty>> for StmtLetBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = StmtLetTyBuilder<F>;

    fn invoke(self, ty: P<ast::Ty>) -> StmtLetTyBuilder<F> {
        self.build_ty(ty)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.build_expr(expr)
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtLetTyBuilder<F> {
    builder: StmtBuilder<F>,
    pat: P<ast::Pat>,
    ty: P<ast::Ty>,
}

impl<F> StmtLetTyBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    pub fn expr(self) -> ExprBuilder<Self> {
        ExprBuilder::new_with_callback(self)
    }

    pub fn build(self) -> F::Result {
        self.builder.build_let(self.pat, Some(self.ty), None)
    }
}

impl<F> Invoke<P<ast::Expr>> for StmtLetTyBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, expr: P<ast::Expr>) -> F::Result {
        self.builder.build_let(self.pat, Some(self.ty), Some(expr))
    }
}

//////////////////////////////////////////////////////////////////////////////

pub struct StmtItemBuilder<F>(StmtBuilder<F>);

impl<F> Invoke<P<ast::Item>> for StmtItemBuilder<F>
    where F: Invoke<P<ast::Stmt>>,
{
    type Result = F::Result;

    fn invoke(self, item: P<ast::Item>) -> F::Result {
        self.0.build_item(item)
    }
}

<|endoftext|>


<commit_before>use Display;

use context;
use version::Api;
use gl;

/// Provides a way to wait for a server-side operation to be finished.
///
/// Creating a `SyncFence` injects an element in the commands queue of the backend.
/// When this element is reached, the fence becomes signaled.
///
/// ## Example
///
/// ```no_run
/// # let display: glium::Display = unsafe { std::mem::uninitialized() };
/// # fn do_something<T>(_: &T) {}
/// let fence = glium::SyncFence::new_if_supported(&display).unwrap();
/// do_something(&display);
/// fence.wait();   // blocks until the previous operations have finished
/// ```
pub struct SyncFence {
    display: Display,
    id: Option<gl::types::GLsync>,
}

impl SyncFence {
    /// Builds a new `SyncFence` that is injected in the server.
    ///
    /// ## Features
    ///
    /// Only available if the `gl_sync` feature is enabled.
    #[cfg(feature = "gl_sync")]
    pub fn new(display: &Display) -> SyncFence {
        SyncFence::new_if_supported(display).unwrap()
    }

    /// Builds a new `SyncFence` that is injected in the server.
    ///
    /// Returns `None` is this is not supported by the backend.
    pub fn new_if_supported(display: &Display) -> Option<SyncFence> {
        let mut ctxt = display.context.context.make_current();

        unsafe { new_linear_sync_fence_if_supported(&mut ctxt) }
            .map(|f| f.into_sync_fence(display))
    }

    /// Blocks until the operation has finished on the server.
    pub fn wait(mut self) {
        let sync = self.id.take().unwrap();

        let ctxt = self.display.context.context.make_current();

        let result = unsafe {
            // waiting with a deadline of one year
            // the reason why the deadline is so long is because if you attach a GL debugger,
            // the wait can be blocked during a breaking point of the debugger
            let result = ctxt.gl.ClientWaitSync(sync, gl::SYNC_FLUSH_COMMANDS_BIT,
                                                365 * 24 * 3600 * 1000 * 1000 * 1000);
            ctxt.gl.DeleteSync(sync);
            result
        };

        match result {
            gl::ALREADY_SIGNALED | gl::CONDITION_SATISFIED => (),
            _ => panic!("Could not wait for the fence")
        };
    }
}

impl Drop for SyncFence {
    fn drop(&mut self) {
        let sync = match self.id {
            None => return,     // fence has already been deleted
            Some(s) => s
        };

        let ctxt = self.display.context.context.make_current();
        unsafe { ctxt.gl.DeleteSync(sync); }
    }
}

/// Prototype for a `SyncFence`.
///
/// The fence must be consumed with either `into_sync_fence`, otherwise
/// the destructor will panic.
#[must_use]
pub struct LinearSyncFence {
    id: Option<gl::types::GLsync>,
}

unsafe impl Send for LinearSyncFence {}

impl LinearSyncFence {
    /// Turns the prototype into a real fence.
    pub fn into_sync_fence(mut self, display: &Display) -> SyncFence {
        SyncFence {
            display: display.clone(),
            id: self.id.take()
        }
    }
}

impl Drop for LinearSyncFence {
    fn drop(&mut self) {
        assert!(self.id.is_none());
    }
}

#[cfg(feature = "gl_sync")]
pub unsafe fn new_linear_sync_fence(ctxt: &mut context::CommandContext) -> LinearSyncFence {
    LinearSyncFence {
        id: Some(ctxt.gl.FenceSync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0)),
    }
}

pub unsafe fn new_linear_sync_fence_if_supported(ctxt: &mut context::CommandContext) -> Option<LinearSyncFence> {
    if ctxt.version < &context::GlVersion(Api::Gl, 3, 2) && !ctxt.extensions.gl_arb_sync {
        return None;
    }

    Some(LinearSyncFence {
        id: Some(ctxt.gl.FenceSync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0)),
    })
}

/// Waits for this fence and destroys it, from within the commands context.
pub unsafe fn wait_linear_sync_fence_and_drop(mut fence: LinearSyncFence, ctxt: &mut context::CommandContext) {
    let fence = fence.id.take().unwrap();

    // we try waiting without flushing first
    let success = match ctxt.gl.ClientWaitSync(fence, 0, 0) {
        gl::ALREADY_SIGNALED => true,
        gl::TIMEOUT_EXPIRED => false,
        gl::WAIT_FAILED => false,
        gl::CONDITION_SATISFIED => true,
        _ => unreachable!()
    };

    // waiting *with* flushing this time
    if !success {
        ctxt.gl.ClientWaitSync(fence, gl::SYNC_FLUSH_COMMANDS_BIT,
                               365 * 24 * 3600 * 1000 * 1000 * 1000);
    }

    ctxt.gl.DeleteSync(fence);
}
<commit_msg>Cleanup sync, and OpenGL ES compatibility<commit_after>use Display;

use context;
use version::Api;
use gl;

/// Provides a way to wait for a server-side operation to be finished.
///
/// Creating a `SyncFence` injects an element in the commands queue of the backend.
/// When this element is reached, the fence becomes signaled.
///
/// ## Example
///
/// ```no_run
/// # let display: glium::Display = unsafe { std::mem::uninitialized() };
/// # fn do_something<T>(_: &T) {}
/// let fence = glium::SyncFence::new_if_supported(&display).unwrap();
/// do_something(&display);
/// fence.wait();   // blocks until the previous operations have finished
/// ```
pub struct SyncFence {
    display: Display,
    id: Option<gl::types::GLsync>,
}

impl SyncFence {
    /// Builds a new `SyncFence` that is injected in the server.
    ///
    /// ## Features
    ///
    /// Only available if the `gl_sync` feature is enabled.
    #[cfg(feature = "gl_sync")]
    pub fn new(display: &Display) -> SyncFence {
        SyncFence::new_if_supported(display).unwrap()
    }

    /// Builds a new `SyncFence` that is injected in the server.
    ///
    /// Returns `None` is this is not supported by the backend.
    pub fn new_if_supported(display: &Display) -> Option<SyncFence> {
        let mut ctxt = display.context.context.make_current();

        unsafe { new_linear_sync_fence_if_supported(&mut ctxt) }
            .map(|f| f.into_sync_fence(display))
    }

    /// Blocks until the operation has finished on the server.
    pub fn wait(mut self) {
        let sync = self.id.take().unwrap();

        let ctxt = self.display.context.context.make_current();

        let result = unsafe {
            // waiting with a deadline of one year
            // the reason why the deadline is so long is because if you attach a GL debugger,
            // the wait can be blocked during a breaking point of the debugger
            let result = ctxt.gl.ClientWaitSync(sync, gl::SYNC_FLUSH_COMMANDS_BIT,
                                                365 * 24 * 3600 * 1000 * 1000 * 1000);
            ctxt.gl.DeleteSync(sync);
            result
        };

        match result {
            gl::ALREADY_SIGNALED | gl::CONDITION_SATISFIED => (),
            _ => panic!("Could not wait for the fence")
        };
    }
}

impl Drop for SyncFence {
    fn drop(&mut self) {
        let sync = match self.id {
            None => return,     // fence has already been deleted
            Some(s) => s
        };

        let ctxt = self.display.context.context.make_current();
        unsafe { ctxt.gl.DeleteSync(sync); }
    }
}

/// Prototype for a `SyncFence`.
///
/// The fence must be consumed with either `into_sync_fence`, otherwise
/// the destructor will panic.
#[must_use]
pub struct LinearSyncFence {
    id: Option<gl::types::GLsync>,
}

unsafe impl Send for LinearSyncFence {}

impl LinearSyncFence {
    /// Turns the prototype into a real fence.
    pub fn into_sync_fence(mut self, display: &Display) -> SyncFence {
        SyncFence {
            display: display.clone(),
            id: self.id.take()
        }
    }
}

impl Drop for LinearSyncFence {
    fn drop(&mut self) {
        assert!(self.id.is_none());
    }
}

#[cfg(feature = "gl_sync")]
pub unsafe fn new_linear_sync_fence(ctxt: &mut context::CommandContext) -> LinearSyncFence {
    LinearSyncFence {
        id: Some(ctxt.gl.FenceSync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0)),
    }
}

pub unsafe fn new_linear_sync_fence_if_supported(ctxt: &mut context::CommandContext) -> Option<LinearSyncFence> {
    if !(ctxt.version >= &context::GlVersion(Api::Gl, 3, 2)) && !ctxt.extensions.gl_arb_sync
        && !(ctxt.version >= &context::GlVersion(Api::GlEs, 3, 0))
    {
        return None;
    }

    Some(LinearSyncFence {
        id: Some(ctxt.gl.FenceSync(gl::SYNC_GPU_COMMANDS_COMPLETE, 0)),
    })
}

/// Waits for this fence and destroys it, from within the commands context.
pub unsafe fn wait_linear_sync_fence_and_drop(mut fence: LinearSyncFence,
                                              ctxt: &mut context::CommandContext)
{
    let fence = fence.id.take().unwrap();

    // we try waiting without flushing first
    match ctxt.gl.ClientWaitSync(fence, 0, 0) {
        gl::ALREADY_SIGNALED | gl::CONDITION_SATISFIED => {
            ctxt.gl.DeleteSync(fence);
            return;
        },
        gl::TIMEOUT_EXPIRED => (),
        gl::WAIT_FAILED => (),
        _ => unreachable!()
    };

    // waiting *with* flushing this time
    ctxt.gl.ClientWaitSync(fence, gl::SYNC_FLUSH_COMMANDS_BIT,
                           365 * 24 * 3600 * 1000 * 1000 * 1000);
    ctxt.gl.DeleteSync(fence);
}
<|endoftext|>


<commit_before>extern crate sync;
extern crate geom;

use std::os::args;
use std::path::Path;
use std::io::{File, TempDir, stdio};
use geom::point::Point2D;
use gdal::proj::{Proj, DEG_TO_RAD};
use gdal::dataset::{Dataset, open};
use gdal::driver::get_driver;

static webmerc_limit: f64 = 20037508.342789244;

fn as_point((x, y): (f64, f64)) -> Point2D<f64> {
    return Point2D(x, y);
}

fn mul<T:Clone + Mul<T,T>>(value: &Point2D<T>, factor: T) -> Point2D<T> {
    return Point2D(value.x * factor, value.y * factor);
}

pub fn tile(source: Dataset, (x, y, z): (int, int, int)) -> ~[u8] {
    let memory_driver = get_driver("MEM").unwrap();
    let png_driver = get_driver("PNG").unwrap();

    let wgs84 = Proj::new("+proj=longlat +datum=WGS84 +no_defs").unwrap();
    let webmerc = Proj::new(
        "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 " +
        "+y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs").unwrap();

    let tile = Point2D(x, y);
    let tile_size = (webmerc_limit * 4.) / ((2 << z) as f64);
    let tile_min = Point2D(
        tile_size * (tile.x as f64) - webmerc_limit,
        webmerc_limit - tile_size * (tile.y as f64));
    let tile_max = tile_min + Point2D(tile_size, -tile_size);
    let nw = mul(&as_point(webmerc.project(&wgs84, tile_min.x, tile_min.y)), 1./DEG_TO_RAD);
    let se = mul(&as_point(webmerc.project(&wgs84, tile_max.x, tile_max.y)), 1./DEG_TO_RAD);

    let (width, height) = source.get_raster_size();
    let source_bounds = Point2D(width as f64, height as f64);

    fn xy(lng_lat: &Point2D<f64>, source_bounds: &Point2D<f64>) -> Point2D<f64> {
        let x = (lng_lat.x + 180.) / 360. * source_bounds.x;
        let y = (90. - lng_lat.y) / 180. * source_bounds.y;
        return Point2D(x, y);
    }

    let tile = memory_driver.create("", 256, 256, 3).unwrap();
    for band in range(1, 4) {
        let xy_min = xy(&nw, &source_bounds);
        let xy_max = xy(&se, &source_bounds);
        let xy_bounds = xy_max - xy_min;

        let raster = source.read_raster(
            band,
            xy_min.x as int,
            xy_min.y as int,
            xy_bounds.x as uint,
            xy_bounds.y as uint,
            256,
            256
        );
        tile.write_raster(band, 0, 0, 256, 256, raster);
    }

    let tmp = TempDir::new("rustile").unwrap();
    let tile_path = tmp.path().join("tile.png");
    tile.create_copy(png_driver, tile_path.as_str().unwrap());
    return File::open(&tile_path).read_to_end().unwrap();
}

fn main() {
    let source = open(&Path::new(args()[1])).unwrap();
    let tile_data = tile(source, (8, 5, 4));
    assert!(stdio::stdout_raw().write(tile_data).is_ok());
}
<commit_msg>remove main code from tile.rs<commit_after>extern crate sync;
extern crate geom;

use std::io::{File, TempDir};
use geom::point::Point2D;
use gdal::proj::{Proj, DEG_TO_RAD};
use gdal::dataset::{Dataset, open};
use gdal::driver::get_driver;

static webmerc_limit: f64 = 20037508.342789244;

fn as_point((x, y): (f64, f64)) -> Point2D<f64> {
    return Point2D(x, y);
}

fn mul<T:Clone + Mul<T,T>>(value: &Point2D<T>, factor: T) -> Point2D<T> {
    return Point2D(value.x * factor, value.y * factor);
}

pub fn tile(source: Dataset, (x, y, z): (int, int, int)) -> ~[u8] {
    let memory_driver = get_driver("MEM").unwrap();
    let png_driver = get_driver("PNG").unwrap();

    let wgs84 = Proj::new("+proj=longlat +datum=WGS84 +no_defs").unwrap();
    let webmerc = Proj::new(
        "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 " +
        "+y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext  +no_defs").unwrap();

    let tile = Point2D(x, y);
    let tile_size = (webmerc_limit * 4.) / ((2 << z) as f64);
    let tile_min = Point2D(
        tile_size * (tile.x as f64) - webmerc_limit,
        webmerc_limit - tile_size * (tile.y as f64));
    let tile_max = tile_min + Point2D(tile_size, -tile_size);
    let nw = mul(&as_point(webmerc.project(&wgs84, tile_min.x, tile_min.y)), 1./DEG_TO_RAD);
    let se = mul(&as_point(webmerc.project(&wgs84, tile_max.x, tile_max.y)), 1./DEG_TO_RAD);

    let (width, height) = source.get_raster_size();
    let source_bounds = Point2D(width as f64, height as f64);

    fn xy(lng_lat: &Point2D<f64>, source_bounds: &Point2D<f64>) -> Point2D<f64> {
        let x = (lng_lat.x + 180.) / 360. * source_bounds.x;
        let y = (90. - lng_lat.y) / 180. * source_bounds.y;
        return Point2D(x, y);
    }

    let tile = memory_driver.create("", 256, 256, 3).unwrap();
    for band in range(1, 4) {
        let xy_min = xy(&nw, &source_bounds);
        let xy_max = xy(&se, &source_bounds);
        let xy_bounds = xy_max - xy_min;

        let raster = source.read_raster(
            band,
            xy_min.x as int,
            xy_min.y as int,
            xy_bounds.x as uint,
            xy_bounds.y as uint,
            256,
            256
        );
        tile.write_raster(band, 0, 0, 256, 256, raster);
    }

    let tmp = TempDir::new("rustile").unwrap();
    let tile_path = tmp.path().join("tile.png");
    tile.create_copy(png_driver, tile_path.as_str().unwrap());
    return File::open(&tile_path).read_to_end().unwrap();
}
<|endoftext|>


<commit_before>extern crate glib;

extern crate gtk;
use gtk::{Inhibit, WidgetExt};

extern crate cairo;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use ::media::{Context, WaveformBuffer};

pub struct AudioController {
    container: gtk::Container,
    drawingarea: gtk::DrawingArea,

    position: u64,
    waveform_buffer_mtx: Arc<Mutex<Option<WaveformBuffer>>>,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),

            position: 0,
            waveform_buffer_mtx: Arc::new(Mutex::new(None)),
        }));

        {
            let this_ref = this.borrow();
            let this_rc = this.clone();
            this_ref.drawingarea.connect_draw(move |drawing_area, cairo_ctx| {
                this_rc.borrow()
                    .draw(drawing_area, cairo_ctx).into()
            });
        }

        this
    }

    pub fn cleanup(&mut self) {
        // force redraw to purge the double buffer
        self.drawingarea.queue_draw();
    }

    pub fn new_media(&mut self, context: &Context) {
        let has_audio = context.info.lock()
                .expect("Failed to lock media info while initializing audio controller")
                .audio_best
                .is_some();

        if has_audio {
            self.position = 0;
            self.waveform_buffer_mtx = context.waveform_buffer_mtx.clone();

            self.container.show();
        }
        else {
            self.container.hide();
        }
    }

    pub fn tic(&mut self, position: u64) {
        self.position = position;
        self.drawingarea.queue_draw();
    }

    fn draw(&self, drawing_area: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        if self.position == 0 {
            return Inhibit(false);
        }

        let allocation = drawing_area.get_allocation();
        let width = allocation.width;
        if width.is_negative() {
            return Inhibit(false);
        }

        let requested_duration = 2_000_000_000u64; // 2s TODO: adapt according to zoom

        // TODO: make width and height adapt to zoom
        let width = width as u64;
        cr.scale((width / 2) as f64, (allocation.height / 2) as f64);

        cr.set_line_width(0.0015f64);
        cr.set_source_rgb(0.8f64, 0.8f64, 0.8f64);

        // resolution
        let requested_step_duration =
            if requested_duration > width {
                requested_duration / width
            } else {
                1
            };

        let first_visible_pts = {
            let mut waveform_buffer_opt = self.waveform_buffer_mtx.lock()
                .expect("Couldn't lock waveform buffer in audio controller draw");
            let waveform_buffer =
                match waveform_buffer_opt.as_mut() {
                    Some(waveform_buffer) => waveform_buffer,
                    None => return Inhibit(false),
                };

            waveform_buffer.update_conditions(
                self.position,
                requested_duration,
                requested_step_duration
            );

            if waveform_buffer.samples.is_empty() {
                return Inhibit(false);
            }

            let mut relative_pts = 0f64;
            let step_duration = waveform_buffer.step_duration / 1_000_000_000f64;

            let mut sample_iter = waveform_buffer.iter();
            cr.move_to(relative_pts, *sample_iter.next().unwrap());

            for sample in sample_iter {
                relative_pts += step_duration;
                cr.line_to(relative_pts, *sample);
            }

            waveform_buffer.first_visible_pts
        };

        cr.stroke();

        // draw current pos
        let x = (self.position as f64 - first_visible_pts) / 1_000_000_000f64;
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_line_width(0.004f64);
        cr.move_to(x, 0f64);
        cr.line_to(x, 2f64);
        cr.stroke();

        Inhibit(false)
    }
}
<commit_msg>AudioController: stroke each segment individually (#25) Previous strategy was to stroke all the waveform at once, but it turns out to be slower.<commit_after>extern crate glib;

extern crate gtk;
use gtk::{Inhibit, WidgetExt};

extern crate cairo;

use std::rc::Rc;
use std::cell::RefCell;

use std::sync::{Arc, Mutex};

use ::media::{Context, WaveformBuffer};

pub struct AudioController {
    container: gtk::Container,
    drawingarea: gtk::DrawingArea,

    position: u64,
    waveform_buffer_mtx: Arc<Mutex<Option<WaveformBuffer>>>,
}

impl AudioController {
    pub fn new(builder: &gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(AudioController {
            container: builder.get_object("audio-container").unwrap(),
            drawingarea: builder.get_object("audio-drawingarea").unwrap(),

            position: 0,
            waveform_buffer_mtx: Arc::new(Mutex::new(None)),
        }));

        {
            let this_ref = this.borrow();
            let this_rc = this.clone();
            this_ref.drawingarea.connect_draw(move |drawing_area, cairo_ctx| {
                this_rc.borrow()
                    .draw(drawing_area, cairo_ctx).into()
            });
        }

        this
    }

    pub fn cleanup(&mut self) {
        // force redraw to purge the double buffer
        self.drawingarea.queue_draw();
    }

    pub fn new_media(&mut self, context: &Context) {
        let has_audio = context.info.lock()
                .expect("Failed to lock media info while initializing audio controller")
                .audio_best
                .is_some();

        if has_audio {
            self.position = 0;
            self.waveform_buffer_mtx = context.waveform_buffer_mtx.clone();

            self.container.show();
        }
        else {
            self.container.hide();
        }
    }

    pub fn tic(&mut self, position: u64) {
        self.position = position;
        self.drawingarea.queue_draw();
    }

    fn draw(&self, drawing_area: &gtk::DrawingArea, cr: &cairo::Context) -> Inhibit {
        if self.position == 0 {
            return Inhibit(false);
        }

        let allocation = drawing_area.get_allocation();
        let width = allocation.width;
        if width.is_negative() {
            return Inhibit(false);
        }

        let requested_duration = 2_000_000_000u64; // 2s TODO: adapt according to zoom

        // TODO: make width and height adapt to zoom
        let width = width as u64;
        cr.scale((width / 2) as f64, (allocation.height / 2) as f64);

        cr.set_line_width(0.0015f64);
        cr.set_source_rgb(0.8f64, 0.8f64, 0.8f64);

        // resolution
        let requested_step_duration =
            if requested_duration > width {
                requested_duration / width
            } else {
                1
            };

        let first_visible_pts = {
            let mut waveform_buffer_opt = self.waveform_buffer_mtx.lock()
                .expect("Couldn't lock waveform buffer in audio controller draw");
            let waveform_buffer =
                match waveform_buffer_opt.as_mut() {
                    Some(waveform_buffer) => waveform_buffer,
                    None => return Inhibit(false),
                };

            waveform_buffer.update_conditions(
                self.position,
                requested_duration,
                requested_step_duration
            );

            if waveform_buffer.samples.is_empty() {
                return Inhibit(false);
            }

            let mut relative_pts = 0f64;
            let step_duration = waveform_buffer.step_duration / 1_000_000_000f64;

            let mut sample_iter = waveform_buffer.iter();
            let mut sample_value = *sample_iter.next().unwrap();

            for sample in sample_iter {
                cr.move_to(relative_pts, sample_value);
                relative_pts += step_duration;
                sample_value = *sample;
                cr.line_to(relative_pts, sample_value);
                cr.stroke();
            }

            waveform_buffer.first_visible_pts
        };

        // draw current pos
        let x = (self.position as f64 - first_visible_pts) / 1_000_000_000f64;
        cr.set_source_rgb(1f64, 1f64, 0f64);
        cr.set_line_width(0.004f64);
        cr.move_to(x, 0f64);
        cr.line_to(x, 2f64);
        cr.stroke();

        Inhibit(false)
    }
}
<|endoftext|>


<commit_before>use pa::{PaResult, PaError, UnknownError};
use ll;
use std::time::duration::Duration;

pub fn to_pa_result(code: i32) -> PaResult
{
    if code == ll::paNoError
    {
        return Ok(());
    }
    let error: Option<PaError> = FromPrimitive::from_i32(code);
    match error
    {
        Some(value) => Err(value),
        None => Err(UnknownError),
    }
}

pub fn pa_time_to_duration(seconds: f64) -> Duration
{
    Duration::milliseconds((seconds / 1000.0) as i64)
}
<commit_msg>Fixed conversion from seconds to milliseconds<commit_after>use pa::{PaResult, PaError, UnknownError};
use ll;
use std::time::duration::Duration;

pub fn to_pa_result(code: i32) -> PaResult
{
    if code == ll::paNoError
    {
        return Ok(());
    }
    let error: Option<PaError> = FromPrimitive::from_i32(code);
    match error
    {
        Some(value) => Err(value),
        None => Err(UnknownError),
    }
}

pub fn pa_time_to_duration(seconds: f64) -> Duration
{
    Duration::milliseconds((seconds * 1000.0) as i64)
}
<|endoftext|>