<commit_before>use rustc::{declare_lint, hir, lint, lint_array};
use crate::utils;

/// **What it does:** Checks for usage of the `offset` pointer method with a `usize` casted to an
/// `isize`.
///
/// **Why is this bad?** If we’re always increasing the pointer address, we can avoid the numeric
/// cast by using the `add` method instead.
///
/// **Known problems:** None
///
/// **Example:**
/// ```rust
/// let vec = vec![b'a', b'b', b'c'];
/// let ptr = vec.as_ptr();
/// let offset = 1_usize;
///
/// unsafe { ptr.offset(offset as isize); }
/// ```
///
/// Could be written:
///
/// ```rust
/// let vec = vec![b'a', b'b', b'c'];
/// let ptr = vec.as_ptr();
/// let offset = 1_usize;
///
/// unsafe { ptr.add(offset); }
/// ```
declare_clippy_lint! {
    pub PTR_OFFSET_WITH_CAST,
    complexity,
    "uneeded pointer offset cast"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl lint::LintPass for Pass {
    fn get_lints(&self) -> lint::LintArray {
        lint_array!(PTR_OFFSET_WITH_CAST)
    }
}

impl<'a, 'tcx> lint::LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &lint::LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
        // Check if the expressions is a ptr.offset method call
        let [receiver_expr, arg_expr] = match expr_as_ptr_offset_call(cx, expr) {
            Some(call_arg) => call_arg,
            None => return,
        };

        // Check if the argument to ptr.offset is a cast from usize
        let cast_lhs_expr = match expr_as_cast_from_usize(cx, arg_expr) {
            Some(cast_lhs_expr) => cast_lhs_expr,
            None => return,
        };

        utils::span_lint_and_sugg(
            cx,
            PTR_OFFSET_WITH_CAST,
            expr.span,
            "use of `offset` with a `usize` casted to an `isize`",
            "try",
            build_suggestion(cx, receiver_expr, cast_lhs_expr),
        );
    }
}

// If the given expression is a cast from a usize, return the lhs of the cast
fn expr_as_cast_from_usize<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    expr: &'tcx hir::Expr,
) -> Option<&'tcx hir::Expr> {
    if let hir::ExprKind::Cast(ref cast_lhs_expr, _) = expr.node {
        if is_expr_ty_usize(cx, &cast_lhs_expr) {
            return Some(cast_lhs_expr);
        }
    }
    None
}

// If the given expression is a ptr::offset method call, return the receiver and the arg of the
// method call.
fn expr_as_ptr_offset_call<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    expr: &'tcx hir::Expr,
) -> Option<[&'tcx hir::Expr; 2]> {
    if let hir::ExprKind::MethodCall(ref path_segment, _, ref args) = expr.node {
        if path_segment.ident.name == "offset" && is_expr_ty_raw_ptr(cx, &args[0]) {
            return Some([&args[0], &args[1]]);
        }
    }
    None
}

// Is the type of the expression a usize?
fn is_expr_ty_usize<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    expr: &hir::Expr,
) -> bool {
    cx.tables.expr_ty(expr) == cx.tcx.types.usize
}

// Is the type of the expression a raw pointer?
fn is_expr_ty_raw_ptr<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    expr: &hir::Expr,
) -> bool {
    cx.tables.expr_ty(expr).is_unsafe_ptr()
}

fn build_suggestion<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    receiver_expr: &hir::Expr,
    cast_lhs_expr: &hir::Expr,
) -> String {
    match (
        utils::snippet_opt(cx, receiver_expr.span),
        utils::snippet_opt(cx, cast_lhs_expr.span)
    ) {
        (Some(receiver), Some(cast_lhs)) => format!("{}.add({})", receiver, cast_lhs),
        _ => String::new(),
    }
}
<commit_msg>if no suggestion, dont add suggestion<commit_after>use rustc::{declare_lint, hir, lint, lint_array};
use crate::utils;

/// **What it does:** Checks for usage of the `offset` pointer method with a `usize` casted to an
/// `isize`.
///
/// **Why is this bad?** If we’re always increasing the pointer address, we can avoid the numeric
/// cast by using the `add` method instead.
///
/// **Known problems:** None
///
/// **Example:**
/// ```rust
/// let vec = vec![b'a', b'b', b'c'];
/// let ptr = vec.as_ptr();
/// let offset = 1_usize;
///
/// unsafe { ptr.offset(offset as isize); }
/// ```
///
/// Could be written:
///
/// ```rust
/// let vec = vec![b'a', b'b', b'c'];
/// let ptr = vec.as_ptr();
/// let offset = 1_usize;
///
/// unsafe { ptr.add(offset); }
/// ```
declare_clippy_lint! {
    pub PTR_OFFSET_WITH_CAST,
    complexity,
    "uneeded pointer offset cast"
}

#[derive(Copy, Clone, Debug)]
pub struct Pass;

impl lint::LintPass for Pass {
    fn get_lints(&self) -> lint::LintArray {
        lint_array!(PTR_OFFSET_WITH_CAST)
    }
}

impl<'a, 'tcx> lint::LateLintPass<'a, 'tcx> for Pass {
    fn check_expr(&mut self, cx: &lint::LateContext<'a, 'tcx>, expr: &'tcx hir::Expr) {
        // Check if the expressions is a ptr.offset method call
        let [receiver_expr, arg_expr] = match expr_as_ptr_offset_call(cx, expr) {
            Some(call_arg) => call_arg,
            None => return,
        };

        // Check if the argument to ptr.offset is a cast from usize
        let cast_lhs_expr = match expr_as_cast_from_usize(cx, arg_expr) {
            Some(cast_lhs_expr) => cast_lhs_expr,
            None => return,
        };

        let msg = "use of `offset` with a `usize` casted to an `isize`";
        if let Some(sugg) = build_suggestion(cx, receiver_expr, cast_lhs_expr) {
            utils::span_lint_and_sugg(cx, PTR_OFFSET_WITH_CAST, expr.span, msg, "try", sugg);
        } else {
            utils::span_lint(cx, PTR_OFFSET_WITH_CAST, expr.span, msg);
        }

    }
}

// If the given expression is a cast from a usize, return the lhs of the cast
fn expr_as_cast_from_usize<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    expr: &'tcx hir::Expr,
) -> Option<&'tcx hir::Expr> {
    if let hir::ExprKind::Cast(ref cast_lhs_expr, _) = expr.node {
        if is_expr_ty_usize(cx, &cast_lhs_expr) {
            return Some(cast_lhs_expr);
        }
    }
    None
}

// If the given expression is a ptr::offset method call, return the receiver and the arg of the
// method call.
fn expr_as_ptr_offset_call<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    expr: &'tcx hir::Expr,
) -> Option<[&'tcx hir::Expr; 2]> {
    if let hir::ExprKind::MethodCall(ref path_segment, _, ref args) = expr.node {
        if path_segment.ident.name == "offset" && is_expr_ty_raw_ptr(cx, &args[0]) {
            return Some([&args[0], &args[1]]);
        }
    }
    None
}

// Is the type of the expression a usize?
fn is_expr_ty_usize<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    expr: &hir::Expr,
) -> bool {
    cx.tables.expr_ty(expr) == cx.tcx.types.usize
}

// Is the type of the expression a raw pointer?
fn is_expr_ty_raw_ptr<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    expr: &hir::Expr,
) -> bool {
    cx.tables.expr_ty(expr).is_unsafe_ptr()
}

fn build_suggestion<'a, 'tcx>(
    cx: &lint::LateContext<'a, 'tcx>,
    receiver_expr: &hir::Expr,
    cast_lhs_expr: &hir::Expr,
) -> Option<String> {
    match (
        utils::snippet_opt(cx, receiver_expr.span),
        utils::snippet_opt(cx, cast_lhs_expr.span)
    ) {
        (Some(receiver), Some(cast_lhs)) => Some(format!("{}.add({})", receiver, cast_lhs)),
        _ => None,
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(clippy::float_cmp)]

use average::Histogram;
use rand::{Rng, SeedableRng};
use rand_distr::Normal;

average::define_histogram!(hist, 100);
use hist::Histogram as Histogram100;

mod sparkline;

#[test]
fn normal() {
    const N_SAMPLES: u64 = 1_000_000;
    const MEAN: f64 = 2.;
    const STD_DEV: f64 = 0.5;
    const MIN_X: f64 = -1.;
    const MAX_X: f64 = 5.;

    let dist = Normal::new(MEAN, STD_DEV).unwrap();
    let mut hist = Histogram100::with_const_width(MIN_X,MAX_X);
    let mut rng = rand::rngs::SmallRng::seed_from_u64(1);

    for _ in 0..N_SAMPLES {
        let _ = hist.add(rng.sample(dist));  // Ignore out-of-range values
    }

    println!("Sampled normal distribution:\n{}",
        sparkline::render_u64_as_string(hist.bins()));

    fn pdf(x: f64) -> f64 {
        (-0.5 * ((x - MEAN) / STD_DEV).powi(2)).exp() /
            (STD_DEV * (2. * core::f64::consts::PI).sqrt())
    }

    let mut bin_centers = hist.centers();
    let mut expected = [0.; 100];
    for e in &mut expected[..] {
        *e = pdf(bin_centers.next().unwrap());
    }

    println!("Expected normal distribution:\n{}",
        sparkline::render_u64_as_string(hist.bins()));

    let mut normalized_bins= hist.normalized_bins();
    let mut diff = [0.; 100];
    for i in 0..100 {
        let bin = (normalized_bins.next().unwrap() as f64) / (N_SAMPLES as f64) ;
        diff[i] = (bin - expected[i]).abs();
    }

    println!("Difference:\n{}",
        sparkline::render_f64_as_string(&diff[..]));
    println!("max diff: {:?}", diff.iter().fold(
        core::f64::NEG_INFINITY, |a, &b| a.max(b)));

    // Check that the differences are significantly smaller than the expected error.
    let mut expected_error = [0.; 100];
    // Calculate error from histogram
    for (err, var) in expected_error.iter_mut().zip(hist.variances()) {
        *err = var.sqrt() / (N_SAMPLES as f64);
    }
    // Normalize error by bin width
    for (err, width) in expected_error.iter_mut().zip(hist.widths()) {
        *err /= width;
    }
    // TODO: Calculate error from distribution cutoff / normalization

    println!("max expected_error: {:?}", expected_error.iter().fold(
        core::f64::NEG_INFINITY, |a, &b| a.max(b)));
    for (&d, &e) in diff.iter().zip(expected_error.iter()) {
        // Difference larger than 3 standard deviations or cutoff
        let tol = (3. * e).max(1e-4);
        if d > tol {
            panic!("Difference = {} * tol", d / tol);
        }
    }
}<commit_msg>Define constant for histogram size<commit_after>// Copyright 2021 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![allow(clippy::float_cmp)]

use average::Histogram;
use rand::{Rng, SeedableRng};
use rand_distr::Normal;

const HIST_LEN: usize = 100;
average::define_histogram!(hist, crate::HIST_LEN);
use hist::Histogram as Histogram100;

mod sparkline;

#[test]
fn normal() {
    const N_SAMPLES: u64 = 1_000_000;
    const MEAN: f64 = 2.;
    const STD_DEV: f64 = 0.5;
    const MIN_X: f64 = -1.;
    const MAX_X: f64 = 5.;

    let dist = Normal::new(MEAN, STD_DEV).unwrap();
    let mut hist = Histogram100::with_const_width(MIN_X,MAX_X);
    let mut rng = rand::rngs::SmallRng::seed_from_u64(1);

    for _ in 0..N_SAMPLES {
        let _ = hist.add(rng.sample(dist));  // Ignore out-of-range values
    }

    println!("Sampled normal distribution:\n{}",
        sparkline::render_u64_as_string(hist.bins()));

    fn pdf(x: f64) -> f64 {
        (-0.5 * ((x - MEAN) / STD_DEV).powi(2)).exp() /
            (STD_DEV * (2. * core::f64::consts::PI).sqrt())
    }

    let mut bin_centers = hist.centers();
    let mut expected = [0.; HIST_LEN];
    for e in &mut expected[..] {
        *e = pdf(bin_centers.next().unwrap());
    }

    println!("Expected normal distribution:\n{}",
        sparkline::render_u64_as_string(hist.bins()));

    let mut normalized_bins= hist.normalized_bins();
    let mut diff = [0.; HIST_LEN];
    for i in 0..HIST_LEN {
        let bin = (normalized_bins.next().unwrap() as f64) / (N_SAMPLES as f64) ;
        diff[i] = (bin - expected[i]).abs();
    }

    println!("Difference:\n{}",
        sparkline::render_f64_as_string(&diff[..]));
    println!("max diff: {:?}", diff.iter().fold(
        core::f64::NEG_INFINITY, |a, &b| a.max(b)));

    // Check that the differences are significantly smaller than the expected error.
    let mut expected_error = [0.; HIST_LEN];
    // Calculate error from histogram
    for (err, var) in expected_error.iter_mut().zip(hist.variances()) {
        *err = var.sqrt() / (N_SAMPLES as f64);
    }
    // Normalize error by bin width
    for (err, width) in expected_error.iter_mut().zip(hist.widths()) {
        *err /= width;
    }
    // TODO: Calculate error from distribution cutoff / normalization

    println!("max expected_error: {:?}", expected_error.iter().fold(
        core::f64::NEG_INFINITY, |a, &b| a.max(b)));
    for (&d, &e) in diff.iter().zip(expected_error.iter()) {
        // Difference larger than 3 standard deviations or cutoff
        let tol = (3. * e).max(1e-4);
        if d > tol {
            panic!("Difference = {} * tol", d / tol);
        }
    }
}<|endoftext|>


<commit_before>// Simple prometheus support. Still a work in progress.
// TODO
// We aren't collecting metrics properly we should be
// on the regular collecting metrics, and snapshoting them
// and sending them all up when prometheus comes to scrape.
use registry::{Registry, StdRegistry};
use std::thread;
use std::sync::Arc;
use reporter::base::Reporter;
use time;
use promo_proto::MetricFamily;
use router::Router;
use iron;
use iron::typemap::Key;
use iron::prelude::*;
use iron::status;

use promo_proto;
use persistent::Read;
use protobuf::Message;
use protobuf::repeated::RepeatedField;
use promo_proto::LabelPair;
use std::collections::HashMap;
use metrics::metric::MetricValue::{Counter, Gauge, Histogram, Meter};

#[derive(Copy, Clone)]
struct HandlerStorage;

#[allow(dead_code)] // until `prefix is used
pub struct PrometheusReporter {
    host_and_port: &'static str,
    // TODO to use as the application name?
    prefix: &'static str,
    registry: Arc<StdRegistry<'static>>,
    reporter_name: &'static str,
}

impl Key for HandlerStorage {
    type Value = Arc<StdRegistry<'static>>;
}

impl Reporter for PrometheusReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

#[allow(dead_code)] // until `prefix is used
fn prefix(metric_line: String, prefix_str: &'static str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

impl PrometheusReporter {
    pub fn new(registry: Arc<StdRegistry<'static>>,
               reporter_name: &'static str,
               host_and_port: &'static str,
               prefix: &'static str)
               -> PrometheusReporter {
        PrometheusReporter {
            host_and_port: host_and_port,
            prefix: prefix,
            registry: registry,
            reporter_name: reporter_name,
        }
    }

    pub fn start(self) -> thread::JoinHandle<iron::Listening> {
        thread::spawn(move || {
            let mut router = Router::new();
            router.get("/metrics", handler);
            let mut chain = Chain::new(router);
            // The double long ARC pointer FTW!
            chain.link_before(Read::<HandlerStorage>::one(self.registry));
            // TODO -> Result<iron::Listening, iron::error::Error>
            Iron::new(chain).http(self.host_and_port).unwrap()
        })
    }
}

// TODO get an i64 instead?
fn timestamp() -> f64 {
    let timespec = time::get_time();
    // 1459440009.113178
    timespec.sec as f64 + (timespec.nsec as f64 / 1000.0 / 1000.0 / 1000.0)
}

fn handler(req: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok,
                       families_to_u8(to_pba(req.get::<Read<HandlerStorage>>().unwrap())))))
}

fn families_to_u8(metric_families: Vec<promo_proto::MetricFamily>) -> Vec<u8> {
    let mut buf = Vec::new();
    for family in metric_families {
        family.write_length_delimited_to_writer(&mut buf).unwrap();
    }
    buf
}

fn to_repeated_fields_labels(labels: HashMap<String, String>) -> RepeatedField<LabelPair> {
    let mut repeated_fields = Vec::new();
    // name/value is what they call it in the protobufs *shrug*
    for (name, value) in labels {
        let mut label_pair = LabelPair::new();
        label_pair.set_name(name);
        label_pair.set_value(value);
        repeated_fields.push(label_pair);
    }
    RepeatedField::from_vec(repeated_fields)
}

// This is totally terrible, it'd be much better to use macros
// and serde once nightly is stable. I'd consider setting a feature flag but
// it still might increase complexity to deploy
// To an array of MetricFamily
fn to_pba(registry: Arc<Arc<StdRegistry<'static>>>) -> Vec<promo_proto::MetricFamily> {
    let mut metric_families = Vec::new();
    let metric_names = registry.get_metrics_names();
    for metric_by_name in metric_names {
        let mut metric_family = MetricFamily::new();
        let mut pb_metric = promo_proto::Metric::new();
        let metric = registry.get(metric_by_name);
        let formated_metric = format!("{}_{}_{}", "application_name", metric_by_name, "bytes");
        metric_family.set_name(String::from(formated_metric));
        let ts = timestamp() as i64;
        pb_metric.set_timestamp_ms(ts);
        pb_metric.set_label(to_repeated_fields_labels(registry.labels()));

        match metric.export_metric() {
            Counter(x) => {
                let mut counter = promo_proto::Counter::new();
                counter.set_value(x.value);
                pb_metric.set_counter(counter);
                metric_family.set_field_type(promo_proto::MetricType::COUNTER);
            }
            Gauge(x) => {
                let mut gauge = promo_proto::Gauge::new();
                gauge.set_value(x.value);
                pb_metric.set_gauge(gauge);
                metric_family.set_field_type(promo_proto::MetricType::GAUGE);

            }
            Meter(_) => {
                // TODO ask the prometheus guys what we want to do
                pb_metric.set_summary(promo_proto::Summary::new());
                metric_family.set_field_type(promo_proto::MetricType::SUMMARY);

            }
            Histogram(_) => {
                pb_metric.set_histogram(promo_proto::Histogram::new());
                metric_family.set_field_type(promo_proto::MetricType::HISTOGRAM);
            }
        }

        metric_family.set_metric(RepeatedField::from_vec(vec![pb_metric,]));
        metric_families.push(metric_family);
    }
    metric_families
}

#[cfg(test)]
mod test {
    use metrics::meter::{Meter, StdMeter};
    use metrics::counter::{Counter, StdCounter};
    use metrics::gauge::{Gauge, StdGauge};
    use registry::{Registry, StdRegistry};
    use reporter::prometheus::PrometheusReporter;
    use std::sync::Arc;
    use std::time::Duration;
    use std::thread;
    use histogram::*;
    use std::collections::HashMap;

    #[test]
    fn add_some_stats_and_slurp_them_with_http() {
        extern crate hyper;
        let m = StdMeter::new();
        m.mark(100);

        let mut c: StdCounter = StdCounter::new();
        c.inc();

        let mut g: StdGauge = StdGauge { value: 0.0 };
        g.set(1.2);

        let mut hc = HistogramConfig::new();
        hc.max_value(100).precision(1);
        let mut h = Histogram::configured(hc).unwrap();

        h.record(1, 1).unwrap();

        let mut r = StdRegistry::new_with_labels(HashMap::new());
        r.insert("meter1", m);
        r.insert("counter1", c);
        r.insert("gauge1", g);
        r.insert("histogram", h);

        let arc_registry = Arc::new(r);
        let reporter =
            PrometheusReporter::new(arc_registry.clone(), "test", "0.0.0.0:8080", "asd.asdf");
        reporter.start();

        let client = hyper::client::Client::new();
        // Seems as though iron isn't running maybe
        thread::sleep(Duration::from_millis(1024));
        let res = client.get("http://127.0.0.1:8080").send().unwrap();
        // TODO fix url and check to make sure we got a valid protobuf
    }
}
<commit_msg>Remove an unused variable assignment<commit_after>// Simple prometheus support. Still a work in progress.
// TODO
// We aren't collecting metrics properly we should be
// on the regular collecting metrics, and snapshoting them
// and sending them all up when prometheus comes to scrape.
use registry::{Registry, StdRegistry};
use std::thread;
use std::sync::Arc;
use reporter::base::Reporter;
use time;
use promo_proto::MetricFamily;
use router::Router;
use iron;
use iron::typemap::Key;
use iron::prelude::*;
use iron::status;

use promo_proto;
use persistent::Read;
use protobuf::Message;
use protobuf::repeated::RepeatedField;
use promo_proto::LabelPair;
use std::collections::HashMap;
use metrics::metric::MetricValue::{Counter, Gauge, Histogram, Meter};

#[derive(Copy, Clone)]
struct HandlerStorage;

#[allow(dead_code)] // until `prefix is used
pub struct PrometheusReporter {
    host_and_port: &'static str,
    // TODO to use as the application name?
    prefix: &'static str,
    registry: Arc<StdRegistry<'static>>,
    reporter_name: &'static str,
}

impl Key for HandlerStorage {
    type Value = Arc<StdRegistry<'static>>;
}

impl Reporter for PrometheusReporter {
    fn get_unique_reporter_name(&self) -> &'static str {
        self.reporter_name
    }
}

#[allow(dead_code)] // until `prefix is used
fn prefix(metric_line: String, prefix_str: &'static str) -> String {
    format!("{}.{}", prefix_str, metric_line)
}

impl PrometheusReporter {
    pub fn new(registry: Arc<StdRegistry<'static>>,
               reporter_name: &'static str,
               host_and_port: &'static str,
               prefix: &'static str)
               -> PrometheusReporter {
        PrometheusReporter {
            host_and_port: host_and_port,
            prefix: prefix,
            registry: registry,
            reporter_name: reporter_name,
        }
    }

    pub fn start(self) -> thread::JoinHandle<iron::Listening> {
        thread::spawn(move || {
            let mut router = Router::new();
            router.get("/metrics", handler);
            let mut chain = Chain::new(router);
            // The double long ARC pointer FTW!
            chain.link_before(Read::<HandlerStorage>::one(self.registry));
            // TODO -> Result<iron::Listening, iron::error::Error>
            Iron::new(chain).http(self.host_and_port).unwrap()
        })
    }
}

// TODO get an i64 instead?
fn timestamp() -> f64 {
    let timespec = time::get_time();
    // 1459440009.113178
    timespec.sec as f64 + (timespec.nsec as f64 / 1000.0 / 1000.0 / 1000.0)
}

fn handler(req: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok,
                       families_to_u8(to_pba(req.get::<Read<HandlerStorage>>().unwrap())))))
}

fn families_to_u8(metric_families: Vec<promo_proto::MetricFamily>) -> Vec<u8> {
    let mut buf = Vec::new();
    for family in metric_families {
        family.write_length_delimited_to_writer(&mut buf).unwrap();
    }
    buf
}

fn to_repeated_fields_labels(labels: HashMap<String, String>) -> RepeatedField<LabelPair> {
    let mut repeated_fields = Vec::new();
    // name/value is what they call it in the protobufs *shrug*
    for (name, value) in labels {
        let mut label_pair = LabelPair::new();
        label_pair.set_name(name);
        label_pair.set_value(value);
        repeated_fields.push(label_pair);
    }
    RepeatedField::from_vec(repeated_fields)
}

// This is totally terrible, it'd be much better to use macros
// and serde once nightly is stable. I'd consider setting a feature flag but
// it still might increase complexity to deploy
// To an array of MetricFamily
fn to_pba(registry: Arc<Arc<StdRegistry<'static>>>) -> Vec<promo_proto::MetricFamily> {
    let mut metric_families = Vec::new();
    let metric_names = registry.get_metrics_names();
    for metric_by_name in metric_names {
        let mut metric_family = MetricFamily::new();
        let mut pb_metric = promo_proto::Metric::new();
        let metric = registry.get(metric_by_name);
        let formated_metric = format!("{}_{}_{}", "application_name", metric_by_name, "bytes");
        metric_family.set_name(String::from(formated_metric));
        let ts = timestamp() as i64;
        pb_metric.set_timestamp_ms(ts);
        pb_metric.set_label(to_repeated_fields_labels(registry.labels()));

        match metric.export_metric() {
            Counter(x) => {
                let mut counter = promo_proto::Counter::new();
                counter.set_value(x.value);
                pb_metric.set_counter(counter);
                metric_family.set_field_type(promo_proto::MetricType::COUNTER);
            }
            Gauge(x) => {
                let mut gauge = promo_proto::Gauge::new();
                gauge.set_value(x.value);
                pb_metric.set_gauge(gauge);
                metric_family.set_field_type(promo_proto::MetricType::GAUGE);

            }
            Meter(_) => {
                // TODO ask the prometheus guys what we want to do
                pb_metric.set_summary(promo_proto::Summary::new());
                metric_family.set_field_type(promo_proto::MetricType::SUMMARY);

            }
            Histogram(_) => {
                pb_metric.set_histogram(promo_proto::Histogram::new());
                metric_family.set_field_type(promo_proto::MetricType::HISTOGRAM);
            }
        }

        metric_family.set_metric(RepeatedField::from_vec(vec![pb_metric,]));
        metric_families.push(metric_family);
    }
    metric_families
}

#[cfg(test)]
mod test {
    use metrics::meter::{Meter, StdMeter};
    use metrics::counter::{Counter, StdCounter};
    use metrics::gauge::{Gauge, StdGauge};
    use registry::{Registry, StdRegistry};
    use reporter::prometheus::PrometheusReporter;
    use std::sync::Arc;
    use std::time::Duration;
    use std::thread;
    use histogram::*;
    use std::collections::HashMap;

    #[test]
    fn add_some_stats_and_slurp_them_with_http() {
        extern crate hyper;
        let m = StdMeter::new();
        m.mark(100);

        let mut c: StdCounter = StdCounter::new();
        c.inc();

        let mut g: StdGauge = StdGauge { value: 0.0 };
        g.set(1.2);

        let mut hc = HistogramConfig::new();
        hc.max_value(100).precision(1);
        let mut h = Histogram::configured(hc).unwrap();

        h.record(1, 1).unwrap();

        let mut r = StdRegistry::new_with_labels(HashMap::new());
        r.insert("meter1", m);
        r.insert("counter1", c);
        r.insert("gauge1", g);
        r.insert("histogram", h);

        let arc_registry = Arc::new(r);
        let reporter =
            PrometheusReporter::new(arc_registry.clone(), "test", "0.0.0.0:8080", "asd.asdf");
        reporter.start();

        let client = hyper::client::Client::new();
        // Seems as though iron isn't running maybe
        thread::sleep(Duration::from_millis(1024));
        client.get("http://127.0.0.1:8080").send().unwrap();
        // TODO fix url and check to make sure we got a valid protobuf
    }
}
<|endoftext|>


<commit_before><commit_msg>Add basic terminal struct<commit_after>use std::fs::{File, OpenOptions};
use std::io::Result;

pub struct Terminal {
    file: File
}

impl Terminal {
    pub fn from(filename: &str) -> Result<Terminal> {
        let file = OpenOptions::new().write(true).read(true).open(filename)?;

        let terminal = Terminal {
            file: file
        };

        Ok(terminal)
    }
}
<|endoftext|>


<commit_before>use std::ptr::null;
use libc::{c_char, c_int, c_double};
use std::ffi::CString;
use std::cell::RefCell;
use utils::_string;
use vector::ogr;
use geo;

/// OGR Geometry
pub struct Geometry {
    c_geometry_ref: RefCell<Option<*const ()>>,
    owned: bool,
}

impl Geometry {
    pub unsafe fn lazy_feature_geometry() -> Geometry {
        // Geometry objects created with this method map to a Feature's
        // geometry whose memory is managed by the GDAL feature.
        // This object has a tricky lifecycle:
        //
        // * Initially it's created with a null c_geometry
        // * The first time `Feature::geometry` is called, it gets
        //   c_geometry from GDAL and calls `set_c_geometry` with it.
        // * When the Feature is destroyed, this object is also destroyed,
        //   which is good, because that's when c_geometry (which is managed
        //   by the GDAL feature) becomes invalid. Because `self.owned` is
        //   `true`, we don't call `OGR_G_DestroyGeometry`.
        return Geometry{c_geometry_ref: RefCell::new(None), owned: false};
    }

    pub fn has_gdal_ptr(&self) -> bool {
        return self.c_geometry_ref.borrow().is_some();
    }

    pub unsafe fn set_c_geometry(&self, c_geometry: *const ()) {
        assert!(! self.has_gdal_ptr());
        assert_eq!(self.owned, false);
        *(self.c_geometry_ref.borrow_mut()) = Some(c_geometry);
    }

    unsafe fn with_c_geometry(c_geom: *const(), owned: bool) -> Geometry {
        return Geometry{
            c_geometry_ref: RefCell::new(Some(c_geom)),
            owned: owned,
        };
    }

    pub fn empty(wkb_type: c_int) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_CreateGeometry(wkb_type) };
        assert!(c_geom != null());
        return unsafe { Geometry::with_c_geometry(c_geom, true) };
    }

    /// Create a geometry by parsing a
    /// [WKT](https://en.wikipedia.org/wiki/Well-known_text) string.
    pub fn from_wkt(wkt: &str) -> Geometry {
        let c_wkt = CString::new(wkt.as_bytes()).unwrap();
        let mut c_wkt_ptr: *const c_char = c_wkt.as_ptr();
        let mut c_geom: *const () = null();
        let rv = unsafe { ogr::OGR_G_CreateFromWkt(&mut c_wkt_ptr, null(), &mut c_geom) };
        assert_eq!(rv, ogr::OGRERR_NONE);
        return unsafe { Geometry::with_c_geometry(c_geom, true) };
    }

    /// Create a rectangular geometry from West, South, East and North values.
    pub fn bbox(w: f64, s: f64, e: f64, n: f64) -> Geometry {
        Geometry::from_wkt(&format!(
            "POLYGON (({} {}, {} {}, {} {}, {} {}, {} {}))",
            w, n,
            e, n,
            e, s,
            w, s,
            w, n,
        ))
    }

    /// Serialize the geometry as JSON.
    pub fn json(&self) -> String {
        let c_json = unsafe { ogr::OGR_G_ExportToJson(self.c_geometry()) };
        let rv = _string(c_json);
        unsafe { ogr::VSIFree(c_json as *mut ()) };
        return rv;
    }

    /// Serialize the geometry as WKT.
    pub fn wkt(&self) -> String {
        let mut c_wkt: *const c_char = null();
        let _err = unsafe { ogr::OGR_G_ExportToWkt(self.c_geometry(), &mut c_wkt) };
        assert_eq!(_err, ogr::OGRERR_NONE);
        let wkt = _string(c_wkt);
        unsafe { ogr::OGRFree(c_wkt as *mut ()) };
        return wkt;
    }

    pub unsafe fn c_geometry(&self) -> *const () {
        return self.c_geometry_ref.borrow().unwrap();
    }

    pub fn set_point_2d(&mut self, i: usize, p: (f64, f64)) {
        let (x, y) = p;
        unsafe { ogr::OGR_G_SetPoint_2D(
            self.c_geometry(),
            i as c_int,
            x as c_double,
            y as c_double,
        ) };
    }

    pub fn get_point(&self, i: i32) -> (f64, f64, f64) {
        let mut x: c_double = 0.;
        let mut y: c_double = 0.;
        let mut z: c_double = 0.;
        unsafe { ogr::OGR_G_GetPoint(self.c_geometry(), i, &mut x, &mut y, &mut z) };
        return (x as f64, y as f64, z as f64);
    }

    pub fn get_point_vec(&self) -> Vec<(f64, f64, f64)> {
        let length = unsafe{ ogr::OGR_G_GetPointCount(self.c_geometry()) };
        return (0..length).map(|i| self.get_point(i)).collect();
    }

    /// Compute the convex hull of this geometry.
    pub fn convex_hull(&self) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_ConvexHull(self.c_geometry()) };
        return unsafe { Geometry::with_c_geometry(c_geom, true) };
    }

    unsafe fn _get_geometry(&self, n: usize) -> Geometry {
        // get the n-th sub-geometry as a non-owned Geometry; don't keep this
        // object for long.
        let c_geom = ogr::OGR_G_GetGeometryRef(self.c_geometry(), n as c_int);
        return Geometry::with_c_geometry(c_geom, false);
    }

    pub fn add_geometry(&mut self, mut sub: Geometry) {
        assert!(sub.owned);
        sub.owned = false;
        let rv = unsafe { ogr::OGR_G_AddGeometryDirectly(
            self.c_geometry(),
            sub.c_geometry(),
        ) };
        assert_eq!(rv, ogr::OGRERR_NONE);
    }
}

impl geo::ToGeo for Geometry {
    fn to_geo(&self) -> geo::Geometry {
        let geometry_type = unsafe { ogr::OGR_G_GetGeometryType(self.c_geometry()) };

        let ring = |n: usize| {
            let ring = unsafe { self._get_geometry(n) };
            return match ring.to_geo() {
                geo::Geometry::LineString(r) => r,
                _ => panic!("Expected to get a LineString")
            };
        };

        match geometry_type {
            ogr::WKB_POINT => {
                let (x, y, _) = self.get_point(0);
                geo::Geometry::Point(geo::Point(geo::Coordinate{x: x, y: y}))
            },
            ogr::WKB_MULTIPOINT => {
                let point_count = unsafe { ogr::OGR_G_GetGeometryCount(self.c_geometry()) } as usize;
                let coords = (0..point_count)
                    .map(|n| {
                        match unsafe { self._get_geometry(n) }.to_geo() {
                            geo::Geometry::Point(p) => p,
                            _ => panic!("Expected to get a Point")
                        }
                    })
                    .collect();
                geo::Geometry::MultiPoint(geo::MultiPoint(coords))
            },
            ogr::WKB_LINESTRING => {
                let coords = self.get_point_vec().iter()
                    .map(|&(x, y, _)| geo::Point(geo::Coordinate{x: x, y: y}))
                    .collect();
                geo::Geometry::LineString(geo::LineString(coords))
            },
            ogr::WKB_POLYGON => {
                let ring_count = unsafe { ogr::OGR_G_GetGeometryCount(self.c_geometry()) } as usize;
                let outer = ring(0);
                let holes = (1..ring_count).map(|n| ring(n)).collect();
                geo::Geometry::Polygon(geo::Polygon(outer, holes))
            },
            _ => panic!("Unknown geometry type")
        }
    }
}

impl Drop for Geometry {
    fn drop(&mut self) {
        if self.owned {
            let c_geometry = self.c_geometry_ref.borrow();
            unsafe { ogr::OGR_G_DestroyGeometry(c_geometry.unwrap() as *mut ()) };
        }
    }
}

pub trait ToGdal {
    fn to_gdal(&self) -> Geometry;
}

impl ToGdal for geo::Point {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_POINT);
        let &geo::Point(coordinate) = self;
        geom.set_point_2d(0, (coordinate.x, coordinate.y));
        return geom;
    }
}

fn geometry_with_points(wkb_type: c_int, points: &geo::LineString) -> Geometry {
    let mut geom = Geometry::empty(wkb_type);
    let &geo::LineString(ref linestring) = points;
    for (i, &geo::Point(coordinate)) in linestring.iter().enumerate() {
        geom.set_point_2d(i, (coordinate.x, coordinate.y));
    }
    return geom;
}

impl ToGdal for geo::LineString {
    fn to_gdal(&self) -> Geometry {
        geometry_with_points(ogr::WKB_LINESTRING, self)
    }
}

impl ToGdal for geo::Polygon {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_POLYGON);
        let &geo::Polygon(ref outer, ref holes) = self;
        geom.add_geometry(geometry_with_points(ogr::WKB_LINEARRING, outer));
        for ring in holes.iter() {
            geom.add_geometry(geometry_with_points(ogr::WKB_LINEARRING, ring));
        }
        return geom;
    }
}

impl ToGdal for geo::Geometry {
    fn to_gdal(&self) -> Geometry {
        return match *self {
            geo::Geometry::Point(ref c) => c.to_gdal(),
            geo::Geometry::LineString(ref c) => c.to_gdal(),
            geo::Geometry::Polygon(ref c) => c.to_gdal(),
            _ => panic!("Unknown geometry type")
        }
    }
}

#[cfg(test)]
mod tests {
    use vector::{Geometry, ToGdal};
    use geo;
    use geo::ToGeo;

    #[test]
    fn test_import_export_point() {
        let wkt = "POINT (1 2)";
        let coord = geo::Coordinate{x: 1., y: 2.};
        let geo = geo::Geometry::Point(geo::Point(coord));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo.to_gdal().wkt(), wkt);
    }

    #[test]
    fn test_import_export_multipoint() {
        let wkt = "MULTIPOINT ((0 0),(0 1),(1 2))";
        let coord = vec!(
            geo::Point(geo::Coordinate{x: 0., y: 0.}),
            geo::Point(geo::Coordinate{x: 0., y: 1.}),
            geo::Point(geo::Coordinate{x: 1., y: 2.}),
        );
        let geo = geo::Geometry::MultiPoint(geo::MultiPoint(coord));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
    }

    #[test]
    fn test_import_export_linestring() {
        let wkt = "LINESTRING (0 0,0 1,1 2)";
        let coord = vec!(
            geo::Point(geo::Coordinate{x: 0., y: 0.}),
            geo::Point(geo::Coordinate{x: 0., y: 1.}),
            geo::Point(geo::Coordinate{x: 1., y: 2.}),
        );
        let geo = geo::Geometry::LineString(geo::LineString(coord));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo.to_gdal().wkt(), wkt);
    }

    fn square(x0: isize, y0: isize, x1: isize, y1: isize) -> geo::LineString {
        geo::LineString(vec!(
            geo::Point(geo::Coordinate{x: x0 as f64, y: y0 as f64}),
            geo::Point(geo::Coordinate{x: x0 as f64, y: y1 as f64}),
            geo::Point(geo::Coordinate{x: x1 as f64, y: y1 as f64}),
            geo::Point(geo::Coordinate{x: x1 as f64, y: y0 as f64}),
            geo::Point(geo::Coordinate{x: x0 as f64, y: y0 as f64}),
        ))
    }

    #[test]
    fn test_import_export_polygon() {
        let wkt = "POLYGON ((0 0,0 5,5 5,5 0,0 0),\
                            (1 1,1 2,2 2,2 1,1 1),\
                            (3 3,3 4,4 4,4 3,3 3))";
        let outer = square(0, 0, 5, 5);
        let holes = vec!(square(1, 1, 2, 2), square(3, 3, 4, 4));
        let geo = geo::Geometry::Polygon(geo::Polygon(outer, holes));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo.to_gdal().wkt(), wkt);
    }
}
<commit_msg>export multipoint to gdal<commit_after>use std::ptr::null;
use libc::{c_char, c_int, c_double};
use std::ffi::CString;
use std::cell::RefCell;
use utils::_string;
use vector::ogr;
use geo;

/// OGR Geometry
pub struct Geometry {
    c_geometry_ref: RefCell<Option<*const ()>>,
    owned: bool,
}

impl Geometry {
    pub unsafe fn lazy_feature_geometry() -> Geometry {
        // Geometry objects created with this method map to a Feature's
        // geometry whose memory is managed by the GDAL feature.
        // This object has a tricky lifecycle:
        //
        // * Initially it's created with a null c_geometry
        // * The first time `Feature::geometry` is called, it gets
        //   c_geometry from GDAL and calls `set_c_geometry` with it.
        // * When the Feature is destroyed, this object is also destroyed,
        //   which is good, because that's when c_geometry (which is managed
        //   by the GDAL feature) becomes invalid. Because `self.owned` is
        //   `true`, we don't call `OGR_G_DestroyGeometry`.
        return Geometry{c_geometry_ref: RefCell::new(None), owned: false};
    }

    pub fn has_gdal_ptr(&self) -> bool {
        return self.c_geometry_ref.borrow().is_some();
    }

    pub unsafe fn set_c_geometry(&self, c_geometry: *const ()) {
        assert!(! self.has_gdal_ptr());
        assert_eq!(self.owned, false);
        *(self.c_geometry_ref.borrow_mut()) = Some(c_geometry);
    }

    unsafe fn with_c_geometry(c_geom: *const(), owned: bool) -> Geometry {
        return Geometry{
            c_geometry_ref: RefCell::new(Some(c_geom)),
            owned: owned,
        };
    }

    pub fn empty(wkb_type: c_int) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_CreateGeometry(wkb_type) };
        assert!(c_geom != null());
        return unsafe { Geometry::with_c_geometry(c_geom, true) };
    }

    /// Create a geometry by parsing a
    /// [WKT](https://en.wikipedia.org/wiki/Well-known_text) string.
    pub fn from_wkt(wkt: &str) -> Geometry {
        let c_wkt = CString::new(wkt.as_bytes()).unwrap();
        let mut c_wkt_ptr: *const c_char = c_wkt.as_ptr();
        let mut c_geom: *const () = null();
        let rv = unsafe { ogr::OGR_G_CreateFromWkt(&mut c_wkt_ptr, null(), &mut c_geom) };
        assert_eq!(rv, ogr::OGRERR_NONE);
        return unsafe { Geometry::with_c_geometry(c_geom, true) };
    }

    /// Create a rectangular geometry from West, South, East and North values.
    pub fn bbox(w: f64, s: f64, e: f64, n: f64) -> Geometry {
        Geometry::from_wkt(&format!(
            "POLYGON (({} {}, {} {}, {} {}, {} {}, {} {}))",
            w, n,
            e, n,
            e, s,
            w, s,
            w, n,
        ))
    }

    /// Serialize the geometry as JSON.
    pub fn json(&self) -> String {
        let c_json = unsafe { ogr::OGR_G_ExportToJson(self.c_geometry()) };
        let rv = _string(c_json);
        unsafe { ogr::VSIFree(c_json as *mut ()) };
        return rv;
    }

    /// Serialize the geometry as WKT.
    pub fn wkt(&self) -> String {
        let mut c_wkt: *const c_char = null();
        let _err = unsafe { ogr::OGR_G_ExportToWkt(self.c_geometry(), &mut c_wkt) };
        assert_eq!(_err, ogr::OGRERR_NONE);
        let wkt = _string(c_wkt);
        unsafe { ogr::OGRFree(c_wkt as *mut ()) };
        return wkt;
    }

    pub unsafe fn c_geometry(&self) -> *const () {
        return self.c_geometry_ref.borrow().unwrap();
    }

    pub fn set_point_2d(&mut self, i: usize, p: (f64, f64)) {
        let (x, y) = p;
        unsafe { ogr::OGR_G_SetPoint_2D(
            self.c_geometry(),
            i as c_int,
            x as c_double,
            y as c_double,
        ) };
    }

    pub fn get_point(&self, i: i32) -> (f64, f64, f64) {
        let mut x: c_double = 0.;
        let mut y: c_double = 0.;
        let mut z: c_double = 0.;
        unsafe { ogr::OGR_G_GetPoint(self.c_geometry(), i, &mut x, &mut y, &mut z) };
        return (x as f64, y as f64, z as f64);
    }

    pub fn get_point_vec(&self) -> Vec<(f64, f64, f64)> {
        let length = unsafe{ ogr::OGR_G_GetPointCount(self.c_geometry()) };
        return (0..length).map(|i| self.get_point(i)).collect();
    }

    /// Compute the convex hull of this geometry.
    pub fn convex_hull(&self) -> Geometry {
        let c_geom = unsafe { ogr::OGR_G_ConvexHull(self.c_geometry()) };
        return unsafe { Geometry::with_c_geometry(c_geom, true) };
    }

    unsafe fn _get_geometry(&self, n: usize) -> Geometry {
        // get the n-th sub-geometry as a non-owned Geometry; don't keep this
        // object for long.
        let c_geom = ogr::OGR_G_GetGeometryRef(self.c_geometry(), n as c_int);
        return Geometry::with_c_geometry(c_geom, false);
    }

    pub fn add_geometry(&mut self, mut sub: Geometry) {
        assert!(sub.owned);
        sub.owned = false;
        let rv = unsafe { ogr::OGR_G_AddGeometryDirectly(
            self.c_geometry(),
            sub.c_geometry(),
        ) };
        assert_eq!(rv, ogr::OGRERR_NONE);
    }
}

impl geo::ToGeo for Geometry {
    fn to_geo(&self) -> geo::Geometry {
        let geometry_type = unsafe { ogr::OGR_G_GetGeometryType(self.c_geometry()) };

        let ring = |n: usize| {
            let ring = unsafe { self._get_geometry(n) };
            return match ring.to_geo() {
                geo::Geometry::LineString(r) => r,
                _ => panic!("Expected to get a LineString")
            };
        };

        match geometry_type {
            ogr::WKB_POINT => {
                let (x, y, _) = self.get_point(0);
                geo::Geometry::Point(geo::Point(geo::Coordinate{x: x, y: y}))
            },
            ogr::WKB_MULTIPOINT => {
                let point_count = unsafe { ogr::OGR_G_GetGeometryCount(self.c_geometry()) } as usize;
                let coords = (0..point_count)
                    .map(|n| {
                        match unsafe { self._get_geometry(n) }.to_geo() {
                            geo::Geometry::Point(p) => p,
                            _ => panic!("Expected to get a Point")
                        }
                    })
                    .collect();
                geo::Geometry::MultiPoint(geo::MultiPoint(coords))
            },
            ogr::WKB_LINESTRING => {
                let coords = self.get_point_vec().iter()
                    .map(|&(x, y, _)| geo::Point(geo::Coordinate{x: x, y: y}))
                    .collect();
                geo::Geometry::LineString(geo::LineString(coords))
            },
            ogr::WKB_POLYGON => {
                let ring_count = unsafe { ogr::OGR_G_GetGeometryCount(self.c_geometry()) } as usize;
                let outer = ring(0);
                let holes = (1..ring_count).map(|n| ring(n)).collect();
                geo::Geometry::Polygon(geo::Polygon(outer, holes))
            },
            _ => panic!("Unknown geometry type")
        }
    }
}

impl Drop for Geometry {
    fn drop(&mut self) {
        if self.owned {
            let c_geometry = self.c_geometry_ref.borrow();
            unsafe { ogr::OGR_G_DestroyGeometry(c_geometry.unwrap() as *mut ()) };
        }
    }
}

pub trait ToGdal {
    fn to_gdal(&self) -> Geometry;
}

impl ToGdal for geo::Point {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_POINT);
        let &geo::Point(coordinate) = self;
        geom.set_point_2d(0, (coordinate.x, coordinate.y));
        return geom;
    }
}

impl ToGdal for geo::MultiPoint {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_MULTIPOINT);
        let &geo::MultiPoint(ref point_list) = self;
        for point in point_list.iter() {
            geom.add_geometry(point.to_gdal());
        }
        return geom;
    }
}

fn geometry_with_points(wkb_type: c_int, points: &geo::LineString) -> Geometry {
    let mut geom = Geometry::empty(wkb_type);
    let &geo::LineString(ref linestring) = points;
    for (i, &geo::Point(coordinate)) in linestring.iter().enumerate() {
        geom.set_point_2d(i, (coordinate.x, coordinate.y));
    }
    return geom;
}

impl ToGdal for geo::LineString {
    fn to_gdal(&self) -> Geometry {
        geometry_with_points(ogr::WKB_LINESTRING, self)
    }
}

impl ToGdal for geo::Polygon {
    fn to_gdal(&self) -> Geometry {
        let mut geom = Geometry::empty(ogr::WKB_POLYGON);
        let &geo::Polygon(ref outer, ref holes) = self;
        geom.add_geometry(geometry_with_points(ogr::WKB_LINEARRING, outer));
        for ring in holes.iter() {
            geom.add_geometry(geometry_with_points(ogr::WKB_LINEARRING, ring));
        }
        return geom;
    }
}

impl ToGdal for geo::Geometry {
    fn to_gdal(&self) -> Geometry {
        return match *self {
            geo::Geometry::Point(ref c) => c.to_gdal(),
            geo::Geometry::MultiPoint(ref c) => c.to_gdal(),
            geo::Geometry::LineString(ref c) => c.to_gdal(),
            geo::Geometry::Polygon(ref c) => c.to_gdal(),
            _ => panic!("Unknown geometry type")
        }
    }
}

#[cfg(test)]
mod tests {
    use vector::{Geometry, ToGdal};
    use geo;
    use geo::ToGeo;

    #[test]
    fn test_import_export_point() {
        let wkt = "POINT (1 2)";
        let coord = geo::Coordinate{x: 1., y: 2.};
        let geo = geo::Geometry::Point(geo::Point(coord));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo.to_gdal().wkt(), wkt);
    }

    #[test]
    fn test_import_export_multipoint() {
        let wkt = "MULTIPOINT (0 0,0 1,1 2)";
        let coord = vec!(
            geo::Point(geo::Coordinate{x: 0., y: 0.}),
            geo::Point(geo::Coordinate{x: 0., y: 1.}),
            geo::Point(geo::Coordinate{x: 1., y: 2.}),
        );
        let geo = geo::Geometry::MultiPoint(geo::MultiPoint(coord));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo.to_gdal().wkt(), wkt);
    }

    #[test]
    fn test_import_export_linestring() {
        let wkt = "LINESTRING (0 0,0 1,1 2)";
        let coord = vec!(
            geo::Point(geo::Coordinate{x: 0., y: 0.}),
            geo::Point(geo::Coordinate{x: 0., y: 1.}),
            geo::Point(geo::Coordinate{x: 1., y: 2.}),
        );
        let geo = geo::Geometry::LineString(geo::LineString(coord));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo.to_gdal().wkt(), wkt);
    }

    fn square(x0: isize, y0: isize, x1: isize, y1: isize) -> geo::LineString {
        geo::LineString(vec!(
            geo::Point(geo::Coordinate{x: x0 as f64, y: y0 as f64}),
            geo::Point(geo::Coordinate{x: x0 as f64, y: y1 as f64}),
            geo::Point(geo::Coordinate{x: x1 as f64, y: y1 as f64}),
            geo::Point(geo::Coordinate{x: x1 as f64, y: y0 as f64}),
            geo::Point(geo::Coordinate{x: x0 as f64, y: y0 as f64}),
        ))
    }

    #[test]
    fn test_import_export_polygon() {
        let wkt = "POLYGON ((0 0,0 5,5 5,5 0,0 0),\
                            (1 1,1 2,2 2,2 1,1 1),\
                            (3 3,3 4,4 4,4 3,3 3))";
        let outer = square(0, 0, 5, 5);
        let holes = vec!(square(1, 1, 2, 2), square(3, 3, 4, 4));
        let geo = geo::Geometry::Polygon(geo::Polygon(outer, holes));

        assert_eq!(Geometry::from_wkt(wkt).to_geo(), geo);
        assert_eq!(geo.to_gdal().wkt(), wkt);
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]
use core::prelude::*;
use core::{mem, ptr, raw};
use core::str::raw::c_str_to_static_slice;
use collections::str::StrAllocating;
use collections::string::String;
use libc::{c_char, c_void, size_t};

use lua::lib::raw::*;
use lua::aux::raw::*;
use lua::raw::*;
use luajit::*;
use luajit_constants::*;

use glcommon::GLResult;
use log::{logi, loge};

use lua_callbacks::LuaCallback;

static mut GLDRAW_LUA_CREATE_SANDBOX: *mut c_void = 0 as *mut c_void;
static mut GLDRAW_LUA_STOPFNS: *mut c_void = 0 as *mut c_void;
static mut gldraw_lua_key: i32 = 0;
static LUA_FFI_SCRIPT: &'static str = include_str!("../includes/lua/ffi_loader.lua");
static LUA_RUNNER: &'static str = include_str!("../includes/lua/lua_runner.lua");
static DEFAULT_SCRIPT: &'static str = include_str!("../includes/lua/default_interpolator.lua");

static mut STATIC_LUA: Option<*mut lua_State> = None;

macro_rules! assert_stacksize {
    ($L:expr, $body:expr) => (
        {
            let stacksize = lua_gettop($L);
            let result = $body;
            assert_eq!(stacksize, lua_gettop($L));
            result
        }
    )
}

type ReaderState<'a> = (&'a str, bool);

enum SandboxMode {
    Sandboxed(LuaValue),
    Unsandboxed,
}

enum LuaValue {
    RegistryValue(*mut c_void),
    IndexValue(i32),
}

impl LuaValue {
    unsafe fn push_self(&self, L: *mut lua_State) {
        match self {
            &RegistryValue(key) => {
                lua_pushlightuserdata(L, key);
                lua_gettable(L, LUA_REGISTRYINDEX);
            },
            &IndexValue(idx) => {
                lua_pushvalue(L, idx);
            },
        }
    }
}

#[allow(unused)]
extern "C" fn stringreader(L: *mut lua_State, data: *mut c_void, size: *mut size_t) -> *const c_char {
    unsafe {
        let state: &mut ReaderState = mem::transmute(data);
        let (ref chars, ref mut done) = *state;
        if *done {
            ptr::null()
        } else {
            *done = true;
            *size = chars.len() as u32;
            chars.as_ptr() as *const i8
        }
    }
}

unsafe fn err_to_str(L: *mut lua_State) -> String {
    let mut size: size_t = 0;
    let strptr = lua_tolstring(L, -1, &mut size);
    let luastr: &str = mem::transmute(raw::Slice { data: strptr, len: size as uint });
    let result = luastr.into_string();
    lua_pop(L, -1);
    result
}

unsafe fn runstring(L: *mut lua_State, s: &str, filename: *const i8, env: SandboxMode) -> bool {
    let mut state: ReaderState = (s, false);
    let stateref: *mut c_void = mem::transmute(&mut state);
    if 0 != lua_load(L, stringreader, stateref, filename) {
        false
        //Err(format!("script failed to load: {}", err_to_str(L)))
    } else {
        if let Sandboxed(key) = env {
            key.push_self(L);
            lua_setfenv(L, -2);
        }
        let result = lua_pcall(L, 0, MULTRET, 0);
        if 0 != result {
            false
            //Err(format!("script failed to run: {}", err_to_str(L)));
        } else {
            true
            //Ok(())
        }
    }
}

static mut LUA_ORIGINAL_PANICFN: *mut c_void = 0 as *mut c_void;

#[no_mangle]
unsafe extern "C" fn panic_wrapper(L: *mut lua_State) -> i32 {
    loge!("inside lua panic handler!");
    let errorcstr = lua_tostring(L, -1);
    let errorstr = if errorcstr.is_null() { "" } else { c_str_to_static_slice(errorcstr) };
    loge!("error is {}", errorstr);
    let panicfn: lua_CFunction = mem::transmute(LUA_ORIGINAL_PANICFN);
    panicfn(L); // should never return
    -1
}

unsafe fn init_lua() -> GLResult<*mut lua_State> {
    GLDRAW_LUA_STOPFNS = &mut GLDRAW_LUA_STOPFNS as *mut *mut c_void as *mut c_void;

    let L = luaL_newstate();
    let stacksize = lua_gettop(L);
    luaL_openlibs(L);

    luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE as i32|LUAJIT_MODE_ON as i32);

    if runstring(L, LUA_FFI_SCRIPT, cstr!("built-in ffi init script"), Unsandboxed) {
        logi!("ffi init script loaded");
        lua_pushlightuserdata(L, GLDRAW_LUA_CREATE_SANDBOX);
        lua_getglobal(L, cstr!("create_sandbox"));
        lua_settable(L, LUA_REGISTRYINDEX);

        lua_pushlightuserdata(L, GLDRAW_LUA_STOPFNS);
        lua_newtable(L);
        lua_settable(L, LUA_REGISTRYINDEX);

        LUA_ORIGINAL_PANICFN = lua_atpanic(L, panic_wrapper) as *mut c_void;
        assert_eq!(stacksize, lua_gettop(L));
        Ok(L)
    } else {
        let err = format!("ffi init script failed to load: {}\nThis should never happen!", err_to_str(L));
        lua_close(L);
        log_err(err)
    }
}

unsafe fn get_lua() -> GLResult<*mut lua_State> {
    match STATIC_LUA {
        Some(x) => Ok(x),
        None => {
            STATIC_LUA = Some(try!(init_lua()));
            get_lua()
        }
    }
}

#[no_mangle]
pub unsafe fn rust_raise_lua_err(L: Option<*mut lua_State>, msg: *const i8) -> ! {
    let L = L.unwrap_or(get_existing_lua().unwrap());
    ::lua::aux::raw::luaL_error(L, msg);
    panic!("luaL_error() returned, this should never happen!");
}

#[inline(always)]
pub unsafe fn get_existing_lua() -> Option<*mut lua_State> {
    STATIC_LUA
}

pub unsafe fn get_existing_lua_or_err() -> GLResult<*mut lua_State> {
    match get_existing_lua() {
        Some(lua) => Ok(lua),
        None => Err("couldn't get lua state!".into_string()),
    }
}

unsafe fn create_sandbox(L: *mut lua_State) {
    lua_pushlightuserdata(L, GLDRAW_LUA_CREATE_SANDBOX);
    lua_gettable(L, LUA_REGISTRYINDEX);
    lua_pcall(L, 0, 1, 0);
}

unsafe fn save_ondone(L: *mut lua_State, key: i32, sandbox: LuaValue) -> GLResult<()> {
    logi!("saving ondone() method");
    let stacksize = lua_gettop(L);
    sandbox.push_self(L); {
        lua_pushlightuserdata(L, GLDRAW_LUA_STOPFNS); {
            lua_gettable(L, LUA_REGISTRYINDEX);
            logi!("type of gldraw_lua_stopfns is {}", c_str_to_static_slice(lua_typename(L, lua_type(L, -1))));
            // stack holds sandbox -- stopfns
            lua_pushlightuserdata(L, key as *mut c_void); {
                // stack holds sandbox -- stopfns -- stopidx
                lua_getfield(L, -3, cstr!("ondone")); {
                    // stack holds sandbox -- stopfns -- stopidx -- ondone
                    if !lua_isfunction(L, -1) {
                        lua_pop(L, 4);
                        assert_eq!(stacksize, lua_gettop(L));
                        return log_err("ondone not defined.\nThis should never happen!".into_string());
                    }
                    logi!("saving ondone method to 0x{:x} in gldraw_lua_stopfns", key);
                    lua_settable(L, -3);
                }
            }
            // stack holds sandbox -- stopfns
            lua_pop(L, 2);
            assert_eq!(stacksize, lua_gettop(L));
            Ok(())
        }
    }
}

pub unsafe fn load_lua_script(script: Option<&str>) -> GLResult<i32> {
    let L = try!(get_lua());
    logi!("got lua");
    let stacksize = lua_gettop(L);

    let key = (&gldraw_lua_key) as *const i32 as i32 + gldraw_lua_key;
    let script = script.unwrap_or(DEFAULT_SCRIPT);

    create_sandbox(L); {
        let sandbox_idx = IndexValue(lua_gettop(L));

        lua_pushlightuserdata(L, key as *mut c_void); {

            if !runstring(L, script, cstr!("interpolator script"), Sandboxed(sandbox_idx)) {
                let err = format!("script failed to load: {}", err_to_str(L));
                assert_eq!(stacksize, lua_gettop(L));
                return log_err(err);
            }

            sandbox_idx.push_self(L); {
                lua_getfield(L, -1, cstr!("main")); {
                    if !lua_isfunction(L, -1) {
                        lua_pop(L, 3);
                        return log_err("no main function defined :(".into_string());
                    }
                    luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE as i32|LUAJIT_MODE_ON as i32);
                    lua_pop(L, 1);
                }

                // make values defined in script available to lua_runner
                lua_setglobal(L, cstr!("callbacks"));
            }

            // FIXME compile runner once
            if !runstring(L, LUA_RUNNER, cstr!("built-in lua_runner script"), Unsandboxed) {
                let err = format!("lua runner failed to load: {}\n This should never happen!", err_to_str(L));
                lua_pop(L, 1);
                assert_eq!(stacksize, lua_gettop(L));
                return log_err(err);
            }

            lua_getglobal(L, cstr!("runmain")); {
                if !lua_isfunction(L, -1) {
                    lua_pop(L, 2);
                    assert_eq!(stacksize, lua_gettop(L));
                    return log_err("runmain not defined.\nThis should never happen!".into_string());
                }
                luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE as i32|LUAJIT_MODE_ON as i32);

                if let Err(msg) = save_ondone(L, key, sandbox_idx) {
                    lua_pop(L, 2);
                    assert_eq!(stacksize, lua_gettop(L));
                    return Err(msg);
                }

                lua_settable(L, LUA_REGISTRYINDEX);
            }
        }

        lua_pop(L, 1);
    }

    gldraw_lua_key += 1;
    logi!("created script for {}", script);
    assert_eq!(stacksize, lua_gettop(L));
    Ok(key)
}

pub unsafe fn finish_lua_script<T: LuaCallback>(output: &mut T, script: &::luascript::LuaScript) -> GLResult<()> {
    let L = get_lua().unwrap();
    let stacksize = lua_gettop(L);
    lua_pushlightuserdata(L, GLDRAW_LUA_STOPFNS);
    lua_gettable(L, LUA_REGISTRYINDEX);
    logi!("type of gldraw_lua_stopfns is {}", c_str_to_static_slice(lua_typename(L, lua_type(L, -1))));

    // stack is stopfns
    script.push_self();
    lua_gettable(L, -2);
    logi!("type of stopfn for {} is {}", script, c_str_to_static_slice(lua_typename(L, lua_type(L, -1))));
    // stack is stopfns -- stopfn
    lua_pushlightuserdata(L, output as *mut T as *mut c_void);
    logi!("calling lua ondone()");
    let result = match lua_pcall(L, 1, 0, 0) {
        0 => {
            lua_pop(L, 1); // remove stopfns
            Ok(())
        },
        _ => log_err(format!("ondone() script failed to run: {}", err_to_str(L))),
    };
    assert_eq!(stacksize, lua_gettop(L));
    result
}

pub unsafe fn destroy_lua_script(key: i32) {
    let L = get_lua().unwrap();
    let stacksize = lua_gettop(L);
    lua_pushlightuserdata(L, key as *mut c_void);
    lua_pushnil(L);
    lua_settable(L, LUA_REGISTRYINDEX);
    assert_eq!(stacksize, lua_gettop(L));
}

fn log_err<T>(message: String) -> GLResult<T> {
    loge(message.as_slice());
    Err(message)
}

#[inline]
pub unsafe fn push_lua_script(key: i32) {
    let L = get_lua().unwrap();
    lua_pushlightuserdata(L, key as *mut c_void);
}

pub unsafe fn do_interpolate_lua<T: LuaCallback>(script: &::luascript::LuaScript, dimensions: (i32, i32), output: &mut T) -> GLResult<()> {
    let L = try!(get_existing_lua_or_err());
    let stacksize = lua_gettop(L);
    script.push_self();
    lua_gettable(L, LUA_REGISTRYINDEX);

    let (x, y) = dimensions;
    lua_pushnumber(L, x as f64);
    lua_pushnumber(L, y as f64);
    lua_pushlightuserdata(L, output as *mut T as *mut c_void);

    let result = match lua_pcall(L, 3, 0, 0) {
        0 => Ok(()),
        _ => log_err(format!("script failed to run: {}", err_to_str(L))),
    };
    assert_eq!(stacksize, lua_gettop(L));
    result
}
<commit_msg>change it from MULTRET and it works.  What the f.<commit_after>#![allow(non_snake_case)]
use core::prelude::*;
use core::{mem, ptr, raw};
use core::str::raw::c_str_to_static_slice;
use collections::str::StrAllocating;
use collections::string::String;
use libc::{c_char, c_void, size_t};

use lua::lib::raw::*;
use lua::aux::raw::*;
use lua::raw::*;
use luajit::*;
use luajit_constants::*;

use glcommon::GLResult;
use log::{logi, loge};

use lua_callbacks::LuaCallback;

static mut GLDRAW_LUA_CREATE_SANDBOX: *mut c_void = 0 as *mut c_void;
static mut GLDRAW_LUA_STOPFNS: *mut c_void = 0 as *mut c_void;
static mut gldraw_lua_key: i32 = 0;
static LUA_FFI_SCRIPT: &'static str = include_str!("../includes/lua/ffi_loader.lua");
static LUA_RUNNER: &'static str = include_str!("../includes/lua/lua_runner.lua");
static DEFAULT_SCRIPT: &'static str = include_str!("../includes/lua/default_interpolator.lua");

static mut STATIC_LUA: Option<*mut lua_State> = None;

macro_rules! assert_stacksize {
    ($L:expr, $body:expr) => (
        {
            let stacksize = lua_gettop($L);
            let result = $body;
            assert_eq!(stacksize, lua_gettop($L));
            result
        }
    )
}

type ReaderState<'a> = (&'a str, bool);

enum SandboxMode {
    Sandboxed(LuaValue),
    Unsandboxed,
}

enum LuaValue {
    RegistryValue(*mut c_void),
    IndexValue(i32),
}

impl LuaValue {
    unsafe fn push_self(&self, L: *mut lua_State) {
        match self {
            &RegistryValue(key) => {
                lua_pushlightuserdata(L, key);
                lua_gettable(L, LUA_REGISTRYINDEX);
            },
            &IndexValue(idx) => {
                lua_pushvalue(L, idx);
            },
        }
    }
}

#[allow(unused)]
extern "C" fn stringreader(L: *mut lua_State, data: *mut c_void, size: *mut size_t) -> *const c_char {
    unsafe {
        let state: &mut ReaderState = mem::transmute(data);
        let (ref chars, ref mut done) = *state;
        if *done {
            ptr::null()
        } else {
            *done = true;
            *size = chars.len() as u32;
            chars.as_ptr() as *const i8
        }
    }
}

unsafe fn err_to_str(L: *mut lua_State) -> String {
    let mut size: size_t = 0;
    let strptr = lua_tolstring(L, -1, &mut size);
    let luastr: &str = mem::transmute(raw::Slice { data: strptr, len: size as uint });
    let result = luastr.into_string();
    lua_pop(L, -1);
    result
}

unsafe fn runstring(L: *mut lua_State, s: &str, filename: *const i8, env: SandboxMode) -> bool {
    let mut state: ReaderState = (s, false);
    let stateref: *mut c_void = mem::transmute(&mut state);
    if 0 != lua_load(L, stringreader, stateref, filename) {
        false
        //Err(format!("script failed to load: {}", err_to_str(L)))
    } else {
        if let Sandboxed(key) = env {
            key.push_self(L);
            lua_setfenv(L, -2);
        }
        let result = lua_pcall(L, 0, 0, 0);
        if 0 != result {
            false
            //Err(format!("script failed to run: {}", err_to_str(L)));
        } else {
            true
            //Ok(())
        }
    }
}

static mut LUA_ORIGINAL_PANICFN: *mut c_void = 0 as *mut c_void;

#[no_mangle]
unsafe extern "C" fn panic_wrapper(L: *mut lua_State) -> i32 {
    loge!("inside lua panic handler!");
    let errorcstr = lua_tostring(L, -1);
    let errorstr = if errorcstr.is_null() { "" } else { c_str_to_static_slice(errorcstr) };
    loge!("error is {}", errorstr);
    let panicfn: lua_CFunction = mem::transmute(LUA_ORIGINAL_PANICFN);
    panicfn(L); // should never return
    -1
}

unsafe fn init_lua() -> GLResult<*mut lua_State> {
    GLDRAW_LUA_STOPFNS = &mut GLDRAW_LUA_STOPFNS as *mut *mut c_void as *mut c_void;

    let L = luaL_newstate();
    let stacksize = lua_gettop(L);
    luaL_openlibs(L);

    luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE as i32|LUAJIT_MODE_ON as i32);

    if runstring(L, LUA_FFI_SCRIPT, cstr!("built-in ffi init script"), Unsandboxed) {
        logi!("ffi init script loaded");
        lua_pushlightuserdata(L, GLDRAW_LUA_CREATE_SANDBOX);
        lua_getglobal(L, cstr!("create_sandbox"));
        lua_settable(L, LUA_REGISTRYINDEX);

        lua_pushlightuserdata(L, GLDRAW_LUA_STOPFNS);
        lua_newtable(L);
        lua_settable(L, LUA_REGISTRYINDEX);

        LUA_ORIGINAL_PANICFN = lua_atpanic(L, panic_wrapper) as *mut c_void;
        assert_eq!(stacksize, lua_gettop(L));
        Ok(L)
    } else {
        let err = format!("ffi init script failed to load: {}\nThis should never happen!", err_to_str(L));
        lua_close(L);
        log_err(err)
    }
}

unsafe fn get_lua() -> GLResult<*mut lua_State> {
    match STATIC_LUA {
        Some(x) => Ok(x),
        None => {
            STATIC_LUA = Some(try!(init_lua()));
            get_lua()
        }
    }
}

#[no_mangle]
pub unsafe fn rust_raise_lua_err(L: Option<*mut lua_State>, msg: *const i8) -> ! {
    let L = L.unwrap_or(get_existing_lua().unwrap());
    ::lua::aux::raw::luaL_error(L, msg);
    panic!("luaL_error() returned, this should never happen!");
}

#[inline(always)]
pub unsafe fn get_existing_lua() -> Option<*mut lua_State> {
    STATIC_LUA
}

pub unsafe fn get_existing_lua_or_err() -> GLResult<*mut lua_State> {
    match get_existing_lua() {
        Some(lua) => Ok(lua),
        None => Err("couldn't get lua state!".into_string()),
    }
}

unsafe fn create_sandbox(L: *mut lua_State) {
    lua_pushlightuserdata(L, GLDRAW_LUA_CREATE_SANDBOX);
    lua_gettable(L, LUA_REGISTRYINDEX);
    lua_pcall(L, 0, 1, 0);
}

unsafe fn save_ondone(L: *mut lua_State, key: i32, sandbox: LuaValue) -> GLResult<()> {
    logi!("saving ondone() method");
    let stacksize = lua_gettop(L);
    sandbox.push_self(L); {
        lua_pushlightuserdata(L, GLDRAW_LUA_STOPFNS); {
            lua_gettable(L, LUA_REGISTRYINDEX);
            logi!("type of gldraw_lua_stopfns is {}", c_str_to_static_slice(lua_typename(L, lua_type(L, -1))));
            // stack holds sandbox -- stopfns
            lua_pushlightuserdata(L, key as *mut c_void); {
                // stack holds sandbox -- stopfns -- stopidx
                lua_getfield(L, -3, cstr!("ondone")); {
                    // stack holds sandbox -- stopfns -- stopidx -- ondone
                    if !lua_isfunction(L, -1) {
                        lua_pop(L, 4);
                        assert_eq!(stacksize, lua_gettop(L));
                        return log_err("ondone not defined.\nThis should never happen!".into_string());
                    }
                    logi!("saving ondone method to 0x{:x} in gldraw_lua_stopfns", key);
                    lua_settable(L, -3);
                }
            }
            // stack holds sandbox -- stopfns
            lua_pop(L, 2);
            assert_eq!(stacksize, lua_gettop(L));
            Ok(())
        }
    }
}

pub unsafe fn load_lua_script(script: Option<&str>) -> GLResult<i32> {
    let L = try!(get_lua());
    logi!("got lua");
    let stacksize = lua_gettop(L);

    let key = (&gldraw_lua_key) as *const i32 as i32 + gldraw_lua_key;
    let script = script.unwrap_or(DEFAULT_SCRIPT);

    create_sandbox(L); {
        let sandbox_idx = IndexValue(lua_gettop(L));

        lua_pushlightuserdata(L, key as *mut c_void); {

            if !runstring(L, script, cstr!("interpolator script"), Sandboxed(sandbox_idx)) {
                let err = format!("script failed to load: {}", err_to_str(L));
                assert_eq!(stacksize, lua_gettop(L));
                return log_err(err);
            }

            sandbox_idx.push_self(L); {
                lua_getfield(L, -1, cstr!("main")); {
                    if !lua_isfunction(L, -1) {
                        lua_pop(L, 3);
                        return log_err("no main function defined :(".into_string());
                    }
                    luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE as i32|LUAJIT_MODE_ON as i32);
                    lua_pop(L, 1);
                }

                // make values defined in script available to lua_runner
                lua_setglobal(L, cstr!("callbacks"));
            }

            // FIXME compile runner once
            if !runstring(L, LUA_RUNNER, cstr!("built-in lua_runner script"), Unsandboxed) {
                let err = format!("lua runner failed to load: {}\n This should never happen!", err_to_str(L));
                lua_pop(L, 1);
                assert_eq!(stacksize, lua_gettop(L));
                return log_err(err);
            }

            lua_getglobal(L, cstr!("runmain")); {
                if !lua_isfunction(L, -1) {
                    lua_pop(L, 2);
                    assert_eq!(stacksize, lua_gettop(L));
                    return log_err("runmain not defined.\nThis should never happen!".into_string());
                }
                luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE as i32|LUAJIT_MODE_ON as i32);

                if let Err(msg) = save_ondone(L, key, sandbox_idx) {
                    lua_pop(L, 2);
                    assert_eq!(stacksize, lua_gettop(L));
                    return Err(msg);
                }

                lua_settable(L, LUA_REGISTRYINDEX);
            }
        }

        lua_pop(L, 1);
    }

    gldraw_lua_key += 1;
    logi!("created script for {}", script);
    assert_eq!(stacksize, lua_gettop(L));
    Ok(key)
}

pub unsafe fn finish_lua_script<T: LuaCallback>(output: &mut T, script: &::luascript::LuaScript) -> GLResult<()> {
    let L = get_lua().unwrap();
    let stacksize = lua_gettop(L);
    lua_pushlightuserdata(L, GLDRAW_LUA_STOPFNS);
    lua_gettable(L, LUA_REGISTRYINDEX);
    logi!("type of gldraw_lua_stopfns is {}", c_str_to_static_slice(lua_typename(L, lua_type(L, -1))));

    // stack is stopfns
    script.push_self();
    lua_gettable(L, -2);
    logi!("type of stopfn for {} is {}", script, c_str_to_static_slice(lua_typename(L, lua_type(L, -1))));
    // stack is stopfns -- stopfn
    lua_pushlightuserdata(L, output as *mut T as *mut c_void);
    logi!("calling lua ondone()");
    let result = match lua_pcall(L, 1, 0, 0) {
        0 => {
            lua_pop(L, 1); // remove stopfns
            Ok(())
        },
        _ => log_err(format!("ondone() script failed to run: {}", err_to_str(L))),
    };
    assert_eq!(stacksize, lua_gettop(L));
    result
}

pub unsafe fn destroy_lua_script(key: i32) {
    let L = get_lua().unwrap();
    let stacksize = lua_gettop(L);
    lua_pushlightuserdata(L, key as *mut c_void);
    lua_pushnil(L);
    lua_settable(L, LUA_REGISTRYINDEX);
    assert_eq!(stacksize, lua_gettop(L));
}

fn log_err<T>(message: String) -> GLResult<T> {
    loge(message.as_slice());
    Err(message)
}

#[inline]
pub unsafe fn push_lua_script(key: i32) {
    let L = get_lua().unwrap();
    lua_pushlightuserdata(L, key as *mut c_void);
}

pub unsafe fn do_interpolate_lua<T: LuaCallback>(script: &::luascript::LuaScript, dimensions: (i32, i32), output: &mut T) -> GLResult<()> {
    let L = try!(get_existing_lua_or_err());
    let stacksize = lua_gettop(L);
    script.push_self();
    lua_gettable(L, LUA_REGISTRYINDEX);

    let (x, y) = dimensions;
    lua_pushnumber(L, x as f64);
    lua_pushnumber(L, y as f64);
    lua_pushlightuserdata(L, output as *mut T as *mut c_void);

    let result = match lua_pcall(L, 3, 0, 0) {
        0 => Ok(()),
        _ => log_err(format!("script failed to run: {}", err_to_str(L))),
    };
    assert_eq!(stacksize, lua_gettop(L));
    result
}
<|endoftext|>


<commit_before>/// Asserts that the type does **not** implement all of the given traits.
///
/// This can be used to ensure types implement auto traits such as [`Send`] and
/// [`Sync`], as well as traits with [blanket `impl`s][blanket].
///
/// Note that the combination of all provided traits is required to not be
/// implemented. If you want to check that none of multiple traits are
/// implemented you should invoke [`assert_not_impl_any`] instead.
///
/// # Examples
///
/// On stable Rust, using the macro requires a unique “label” when used in a
/// module scope:
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// # use static_assertions::_core::cell::Cell;
/// # fn main() {}
/// assert_not_impl_all!(ptr0; *const u16, Send, Sync);
/// assert_not_impl_all!(ptr1; *const u8, Send, Sync);
/// ```
///
/// The [labeling limitation](index.html#limitations) is not necessary if
/// compiling on nightly Rust with the `nightly` feature enabled:
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(underscore_const_names)]
/// # #[macro_use] extern crate static_assertions;
///
/// assert_not_impl_all!(&'static mut u8, Copy);
///
/// fn main() {
///     assert_not_impl_all!(u32, Into<usize>);
/// }
/// ```
///
/// The following example fails to compile since `u32` can be converted into
/// `u64`.
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {}
/// assert_not_impl_all!(u32, Into<u64>);
/// ```
///
/// `Cell<u32>` is not both `Sync` and `Send`.
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// # use static_assertions::_core::cell::Cell;
/// # fn main() {}
/// assert_not_impl_all!(cell; Cell<u32>, Sync, Send);
/// ```
/// But it is `Send`, so this fails to compile.
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # use static_assertions::_core::cell::Cell;
/// # fn main() {}
/// assert_not_impl_all!(cell; Cell<u32>, Send);
/// ```
///
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
/// [`assert_not_impl_any`]: macro.assert_not_impl_any.html
/// [blanket]: https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
#[macro_export(local_inner_macros)]
macro_rules! assert_not_impl_all {
    ($($xs:tt)+) => { _assert_not_impl_all!($($xs)+); };
}

/// Asserts that the type does **not** implement any of the given traits.
///
/// This can be used to ensure types implement auto traits such as [`Send`] and
/// [`Sync`], as well as traits with [blanket `impl`s][blanket].
///
/// The result of the macro fails to compile if any of the provided individual
/// traits are implemented for the type. If you want to check that a combination
/// of traits is not implemented you should invoke [`assert_not_impl_all`]
/// instead. For single traits both macros behave the same.
///
/// # Examples
///
/// On stable Rust, using the macro requires a unique “label” when used in a
/// module scope:
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {}
/// assert_not_impl_any!(ptr0; *const u16, Send);
/// assert_not_impl_any!(ptr1; *const u8, Send, Sync);
/// ```
///
/// The [labeling limitation](index.html#limitations) is not necessary if
/// compiling on nightly Rust with the `nightly` feature enabled:
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(underscore_const_names)]
/// # #[macro_use] extern crate static_assertions;
///
/// assert_not_impl_any!(&'static mut u8, Copy);
///
/// fn main() {
///     assert_not_impl_any!(u32, Into<usize>);
/// }
/// ```
///
/// The following example fails to compile since `u32` can be converted into
/// `u64` even though it can not be converted into a `u16`.
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {}
/// assert_not_impl_any!(u32, Into<u64>, Into<u16>);
/// ```
///
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
/// [`assert_not_impl_all`]: macro.assert_not_impl_all.html
/// [blanket]: https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
#[macro_export(local_inner_macros)]
macro_rules! assert_not_impl_any {
    ($($xs:tt)+) => { _assert_not_impl_any!($($xs)+); };
}

#[doc(hidden)]
#[cfg(feature = "nightly")]
#[macro_export(local_inner_macros)]
macro_rules! _assert_not_impl_all {
    ($x:ty, $($t:path),+ $(,)*) => {
        const _: fn() -> () = || {
            #[allow(dead_code)]
            struct Invalid;
            trait AmbiguousIfImpl<A> { fn some_item() {} }

            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
            impl<T: ?Sized $(+ $t)*> AmbiguousIfImpl<Invalid> for T {}

            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
        };
    };
}

#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
#[macro_export(local_inner_macros)]
macro_rules! _assert_not_impl_all {
    ($x:ty, $($t:path),+ $(,)*) => {
        {
            #[allow(dead_code)]
            struct Invalid;
            trait AmbiguousIfImpl<A> { fn some_item() {} }

            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
            impl<T: ?Sized $(+ $t)*> AmbiguousIfImpl<Invalid> for T {}

            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
        }
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_not_impl_all!($($xs)+); }
    };
}

#[doc(hidden)]
#[cfg(feature = "nightly")]
#[macro_export(local_inner_macros)]
macro_rules! _assert_not_impl_any {
    ($x:ty, $($t:path),+ $(,)*) => {
        const _: fn() -> () = || {
            trait AmbiguousIfImpl<A> { fn some_item() {} }

            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
            $({
                #[allow(dead_code)]
                struct Invalid;
                impl<T: ?Sized + $t> AmbiguousIfImpl<Invalid> for T {}
            })+

            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
        };
    };
}

#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
#[macro_export(local_inner_macros)]
macro_rules! _assert_not_impl_any {
    ($x:ty, $($t:path),+ $(,)*) => {
        {
            trait AmbiguousIfImpl<A> { fn some_item() {} }

            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
            $({
                #[allow(dead_code)]
                struct Invalid;
                impl<T: ?Sized + $t> AmbiguousIfImpl<Invalid> for T {}
            })+

            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
        }
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_not_impl_any!($($xs)+); }
    };
}
<commit_msg>Fix docs for assert_not_impl macros<commit_after>/// Asserts that the type does **not** implement _all_ of the given traits.
///
/// This can be used to ensure types do not implement auto traits such as
/// [`Send`] and [`Sync`], as well as traits with [blanket `impl`s][blanket].
///
/// Note that the combination of all provided traits is required to not be
/// implemented. If you want to check that none of multiple traits are
/// implemented you should invoke [`assert_not_impl_any!`] instead.
///
/// # Examples
///
/// On stable Rust, using the macro requires a unique “label” when used in a
/// module scope:
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// # use static_assertions::_core::cell::Cell;
/// # fn main() {}
/// assert_not_impl_all!(ptr0; *const u16, Send, Sync);
/// assert_not_impl_all!(ptr1; *const u8, Send, Sync);
/// ```
///
/// The [labeling limitation](index.html#limitations) is not necessary if
/// compiling on nightly Rust with the `nightly` feature enabled:
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(underscore_const_names)]
/// # #[macro_use] extern crate static_assertions;
///
/// assert_not_impl_all!(&'static mut u8, Copy);
///
/// fn main() {
///     assert_not_impl_all!(u32, Into<usize>);
/// }
/// ```
///
/// The following example fails to compile since `u32` can be converted into
/// `u64`.
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {}
/// assert_not_impl_all!(u32, Into<u64>);
/// ```
///
/// `Cell<u32>` is not both `Sync` and `Send`.
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// # use static_assertions::_core::cell::Cell;
/// # fn main() {}
/// assert_not_impl_all!(cell; Cell<u32>, Sync, Send);
/// ```
/// But it is `Send`, so this fails to compile.
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # use static_assertions::_core::cell::Cell;
/// # fn main() {}
/// assert_not_impl_all!(cell; Cell<u32>, Send);
/// ```
///
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
/// [`assert_not_impl_any!`]: macro.assert_not_impl_any.html
/// [blanket]: https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
#[macro_export(local_inner_macros)]
macro_rules! assert_not_impl_all {
    ($($xs:tt)+) => { _assert_not_impl_all!($($xs)+); };
}

/// Asserts that the type does **not** implement _any_ of the given traits.
///
/// This can be used to ensure types do not implement auto traits such as
/// [`Send`] and [`Sync`], as well as traits with [blanket `impl`s][blanket].
///
/// The result of the macro fails to compile if any of the provided individual
/// traits are implemented for the type. If you want to check that a combination
/// of traits is not implemented you should invoke [`assert_not_impl_all!`]
/// instead. For single traits both macros behave the same.
///
/// # Examples
///
/// On stable Rust, using the macro requires a unique “label” when used in a
/// module scope:
///
#[cfg_attr(feature = "nightly", doc = "```ignore")]
#[cfg_attr(not(feature = "nightly"), doc = "```")]
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {}
/// assert_not_impl_any!(ptr0; *const u16, Send);
/// assert_not_impl_any!(ptr1; *const u8, Send, Sync);
/// ```
///
/// The [labeling limitation](index.html#limitations) is not necessary if
/// compiling on nightly Rust with the `nightly` feature enabled:
///
#[cfg_attr(feature = "nightly", doc = "```")]
#[cfg_attr(not(feature = "nightly"), doc = "```ignore")]
/// #![feature(underscore_const_names)]
/// # #[macro_use] extern crate static_assertions;
///
/// assert_not_impl_any!(&'static mut u8, Copy);
///
/// fn main() {
///     assert_not_impl_any!(u32, Into<usize>);
/// }
/// ```
///
/// The following example fails to compile since `u32` can be converted into
/// `u64` even though it can not be converted into a `u16`.
///
/// ```compile_fail
/// # #[macro_use] extern crate static_assertions;
/// # fn main() {}
/// assert_not_impl_any!(u32, Into<u64>, Into<u16>);
/// ```
///
/// [`Send`]: https://doc.rust-lang.org/std/marker/trait.Send.html
/// [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html
/// [`assert_not_impl_all!`]: macro.assert_not_impl_all.html
/// [blanket]: https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html#using-trait-bounds-to-conditionally-implement-methods
#[macro_export(local_inner_macros)]
macro_rules! assert_not_impl_any {
    ($($xs:tt)+) => { _assert_not_impl_any!($($xs)+); };
}

#[doc(hidden)]
#[cfg(feature = "nightly")]
#[macro_export(local_inner_macros)]
macro_rules! _assert_not_impl_all {
    ($x:ty, $($t:path),+ $(,)*) => {
        const _: fn() -> () = || {
            #[allow(dead_code)]
            struct Invalid;
            trait AmbiguousIfImpl<A> { fn some_item() {} }

            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
            impl<T: ?Sized $(+ $t)*> AmbiguousIfImpl<Invalid> for T {}

            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
        };
    };
}

#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
#[macro_export(local_inner_macros)]
macro_rules! _assert_not_impl_all {
    ($x:ty, $($t:path),+ $(,)*) => {
        {
            #[allow(dead_code)]
            struct Invalid;
            trait AmbiguousIfImpl<A> { fn some_item() {} }

            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
            impl<T: ?Sized $(+ $t)*> AmbiguousIfImpl<Invalid> for T {}

            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
        }
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_not_impl_all!($($xs)+); }
    };
}

#[doc(hidden)]
#[cfg(feature = "nightly")]
#[macro_export(local_inner_macros)]
macro_rules! _assert_not_impl_any {
    ($x:ty, $($t:path),+ $(,)*) => {
        const _: fn() -> () = || {
            trait AmbiguousIfImpl<A> { fn some_item() {} }

            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
            $({
                #[allow(dead_code)]
                struct Invalid;
                impl<T: ?Sized + $t> AmbiguousIfImpl<Invalid> for T {}
            })+

            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
        };
    };
}

#[doc(hidden)]
#[cfg(not(feature = "nightly"))]
#[macro_export(local_inner_macros)]
macro_rules! _assert_not_impl_any {
    ($x:ty, $($t:path),+ $(,)*) => {
        {
            trait AmbiguousIfImpl<A> { fn some_item() {} }

            impl<T: ?Sized> AmbiguousIfImpl<()> for T {}
            $({
                #[allow(dead_code)]
                struct Invalid;
                impl<T: ?Sized + $t> AmbiguousIfImpl<Invalid> for T {}
            })+

            let _ = <$x as AmbiguousIfImpl<_>>::some_item;
        }
    };
    ($label:ident; $($xs:tt)+) => {
        #[allow(dead_code, non_snake_case)]
        fn $label() { assert_not_impl_any!($($xs)+); }
    };
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate o3;

use o3::iter::wrap::Wrap;
use o3::comb::all::All;

#[test]
fn all() {
    let first = (0..5).wrap();
    let second = (0..10).wrap();

    let mut trace = vec![];
    each!(first.all(second) => i in {
        trace.push(i);
    });

    assert_eq!(trace, [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9]);
}
<commit_msg>Test the return of `all`<commit_after>#[macro_use]
extern crate o3;

use o3::iter::wrap::Wrap;
use o3::comb::all::All;
use o3::map::ret::MapReturn;

#[test]
fn all() {
    let first = (0..5).wrap().map_return(|_| "first");
    let second = (0..10).wrap().map_return(|_| "second");

    let mut trace = vec![];
    let both = each!(first.all(second) => i in {
        trace.push(i);
    });

    assert_eq!(trace, [0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9]);
    assert_eq!(both, ("first", "second"));
}
<|endoftext|>


<commit_before>extern crate opentype;

use opentype::{Tag, Value};
use opentype::layout::Scripts;
use std::fs::File;

macro_rules! ok(($result:expr) => ($result.unwrap()));

macro_rules! tags(
    ($($name:expr),*) => (vec![$(Tag(*$name)),*]);
);

#[test]
fn glyph_positioning_features() {
    use opentype::GlyphPositioning;

    let GlyphPositioning { features, .. } = ok!(GlyphPositioning::read(&mut setup(60412)));
    let tags = features.headers.iter().map(|header| header.tag).collect::<Vec<_>>();
    assert_eq!(tags, tags![b"kern", b"kern", b"kern", b"kern", b"kern",
                           b"size", b"size", b"size", b"size", b"size"]);
    let lookups = features.records.iter().map(|record| record.lookup_count).collect::<Vec<_>>();
    assert_eq!(lookups, &[1, 1, 1, 1, 1, 0, 0, 0, 0, 0]);
}

#[test]
fn glyph_positioning_lookups() {
    use opentype::GlyphPositioning;
    use opentype::glyph_positioning::table::{PairAdjustment, Table};

    let GlyphPositioning { lookups, .. } = ok!(GlyphPositioning::read(&mut setup(60412)));
    assert_eq!(lookups.records.len(), 1);
    assert_eq!(lookups.records[0].kind, 2);
    assert!(lookups.records[0].mark_filtering_set.is_none());

    let tables = &lookups.records[0].tables;
    assert_eq!(tables.len(), 2);
    match &tables[0] {
        &Table::PairAdjustment(PairAdjustment::Format1(ref table)) => {
            assert_eq!(table.pair_set_count, 65);
        },
        _ => unreachable!(),
    }
    match &tables[1] {
        &Table::PairAdjustment(PairAdjustment::Format2(ref table)) => {
            assert_eq!(table.class1_count, 99);
            assert_eq!(table.class2_count, 95);
        },
        _ => unreachable!(),
    }
}

#[test]
fn glyph_positioning_scripts() {
    use opentype::GlyphPositioning;
    scripts(&ok!(GlyphPositioning::read(&mut setup(60412))).scripts);
}

#[test]
fn glyph_substitution_features() {
    use opentype::GlyphSubstitution;

    let GlyphSubstitution { features, .. } = ok!(GlyphSubstitution::read(&mut setup(57648)));
    let tags = features.headers.iter().map(|header| header.tag).collect::<Vec<_>>();
    assert_eq!(tags, tags![b"aalt", b"aalt", b"aalt", b"aalt", b"aalt",
                           b"case", b"case", b"case", b"case", b"case",
                           b"dnom", b"dnom", b"dnom", b"dnom", b"dnom",
                           b"frac", b"frac", b"frac", b"frac", b"frac",
                           b"liga", b"liga", b"liga", b"liga", b"liga",
                           b"lnum", b"lnum", b"lnum", b"lnum", b"lnum",
                           b"locl", b"locl", b"locl",
                           b"numr", b"numr", b"numr", b"numr", b"numr",
                           b"onum", b"onum", b"onum", b"onum", b"onum",
                           b"ordn", b"ordn", b"ordn", b"ordn", b"ordn",
                           b"pnum", b"pnum", b"pnum", b"pnum", b"pnum",
                           b"sinf", b"sinf", b"sinf", b"sinf", b"sinf",
                           b"subs", b"subs", b"subs", b"subs", b"subs",
                           b"sups", b"sups", b"sups", b"sups", b"sups",
                           b"tnum", b"tnum", b"tnum", b"tnum", b"tnum",
                           b"zero", b"zero", b"zero", b"zero", b"zero"]);
    let lookups = features.records.iter().map(|record| record.lookup_count).collect::<Vec<_>>();
    assert_eq!(lookups, vec![2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1, 1, 1,
                             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1,
                             1, 1, 1, 1, 1, 1, 1, 1, 1]);
}

#[test]
fn glyph_substitution_scripts() {
    use opentype::GlyphSubstitution;
    scripts(&ok!(GlyphSubstitution::read(&mut setup(57648))).scripts);
}

fn scripts(scripts: &Scripts) {
    let tags = scripts.headers.iter().map(|header| header.tag).collect::<Vec<_>>();
    assert_eq!(tags, tags![b"DFLT", b"latn"]);
    let tags = scripts.records.iter()
                              .map(|record| record.language_headers.iter()
                                                                   .map(|header| header.tag)
                                                                   .collect::<Vec<_>>())
                              .collect::<Vec<Vec<_>>>();
    assert_eq!(tags, &[vec![], tags![b"AZE ", b"CRT ", b"TRK "]]);
    assert!(scripts.records[0].default_language.is_some());
}

fn setup(seek: u64) -> File {
    use std::io::{Seek, SeekFrom};

    let mut file = ok!(File::open("tests/fixtures/SourceSerifPro-Regular.otf"));
    ok!(file.seek(SeekFrom::Start(seek)));
    file
}
<commit_msg>Add another test for the glyph-substitution table<commit_after>extern crate opentype;

use opentype::{Tag, Value};
use opentype::layout::Scripts;
use std::fs::File;

macro_rules! ok(($result:expr) => ($result.unwrap()));
macro_rules! tags(($($name:expr),*) => (vec![$(Tag(*$name)),*]));

#[test]
fn glyph_positioning_features() {
    use opentype::GlyphPositioning;

    let GlyphPositioning { features, .. } = ok!(GlyphPositioning::read(&mut setup(60412)));
    let tags = features.headers.iter().map(|header| header.tag).collect::<Vec<_>>();
    assert_eq!(tags, tags![b"kern", b"kern", b"kern", b"kern", b"kern",
                           b"size", b"size", b"size", b"size", b"size"]);
    let lookups = features.records.iter().map(|record| record.lookup_count).collect::<Vec<_>>();
    assert_eq!(lookups, &[1, 1, 1, 1, 1, 0, 0, 0, 0, 0]);
}

#[test]
fn glyph_positioning_lookups() {
    use opentype::GlyphPositioning;
    use opentype::glyph_positioning::table::{PairAdjustment, Table};

    let GlyphPositioning { lookups, .. } = ok!(GlyphPositioning::read(&mut setup(60412)));
    assert_eq!(lookups.records.len(), 1);
    let record = &lookups.records[0];
    assert!(record.mark_filtering_set.is_none());
    assert_eq!(record.tables.len(), 2);
    match &record.tables[0] {
        &Table::PairAdjustment(PairAdjustment::Format1(ref table)) => {
            assert_eq!(table.pair_set_count, 65);
        },
        _ => unreachable!(),
    }
    match &record.tables[1] {
        &Table::PairAdjustment(PairAdjustment::Format2(ref table)) => {
            assert_eq!(table.class1_count, 99);
            assert_eq!(table.class2_count, 95);
        },
        _ => unreachable!(),
    }
}

#[test]
fn glyph_positioning_scripts() {
    use opentype::GlyphPositioning;
    scripts(&ok!(GlyphPositioning::read(&mut setup(60412))).scripts);
}

#[test]
fn glyph_substitution_features() {
    use opentype::GlyphSubstitution;

    let GlyphSubstitution { features, .. } = ok!(GlyphSubstitution::read(&mut setup(57648)));
    let tags = features.headers.iter().map(|header| header.tag).collect::<Vec<_>>();
    assert_eq!(tags, tags![b"aalt", b"aalt", b"aalt", b"aalt", b"aalt",
                           b"case", b"case", b"case", b"case", b"case",
                           b"dnom", b"dnom", b"dnom", b"dnom", b"dnom",
                           b"frac", b"frac", b"frac", b"frac", b"frac",
                           b"liga", b"liga", b"liga", b"liga", b"liga",
                           b"lnum", b"lnum", b"lnum", b"lnum", b"lnum",
                           b"locl", b"locl", b"locl",
                           b"numr", b"numr", b"numr", b"numr", b"numr",
                           b"onum", b"onum", b"onum", b"onum", b"onum",
                           b"ordn", b"ordn", b"ordn", b"ordn", b"ordn",
                           b"pnum", b"pnum", b"pnum", b"pnum", b"pnum",
                           b"sinf", b"sinf", b"sinf", b"sinf", b"sinf",
                           b"subs", b"subs", b"subs", b"subs", b"subs",
                           b"sups", b"sups", b"sups", b"sups", b"sups",
                           b"tnum", b"tnum", b"tnum", b"tnum", b"tnum",
                           b"zero", b"zero", b"zero", b"zero", b"zero"]);
    let lookups = features.records.iter().map(|record| record.lookup_count).collect::<Vec<_>>();
    assert_eq!(lookups, vec![2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1, 1, 1,
                             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                             1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1,
                             1, 1, 1, 1, 1, 1, 1, 1, 1]);
}

#[test]
fn glyph_substitution_lookups() {
    use opentype::GlyphSubstitution;
    use opentype::glyph_substitution::table::Table;

    let GlyphSubstitution { lookups, .. } = ok!(GlyphSubstitution::read(&mut setup(57648)));
    let kinds = lookups.records.iter().map(|record| record.kind).collect::<Vec<_>>();
    assert_eq!(kinds, &[1, 3, 1, 1, 1, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1]);
    let record = &lookups.records[0];
    assert_eq!(record.tables.len(), 1);
    match &record.tables[0] {
        &Table::SingleSubstibution(..) => {},
        _ => unreachable!(),
    }
    let record = &lookups.records[17];
    assert_eq!(record.tables.len(), 1);
    match &record.tables[0] {
        &Table::LigatureSubstibution(..) => {},
        _ => unreachable!(),
    }
}

#[test]
fn glyph_substitution_scripts() {
    use opentype::GlyphSubstitution;
    scripts(&ok!(GlyphSubstitution::read(&mut setup(57648))).scripts);
}

fn scripts(scripts: &Scripts) {
    let tags = scripts.headers.iter().map(|header| header.tag).collect::<Vec<_>>();
    assert_eq!(tags, tags![b"DFLT", b"latn"]);
    let tags = scripts.records.iter()
                              .map(|record| record.language_headers.iter()
                                                                   .map(|header| header.tag)
                                                                   .collect::<Vec<_>>())
                              .collect::<Vec<Vec<_>>>();
    assert_eq!(tags, &[vec![], tags![b"AZE ", b"CRT ", b"TRK "]]);
    assert!(scripts.records[0].default_language.is_some());
}

fn setup(seek: u64) -> File {
    use std::io::{Seek, SeekFrom};

    let mut file = ok!(File::open("tests/fixtures/SourceSerifPro-Regular.otf"));
    ok!(file.seek(SeekFrom::Start(seek)));
    file
}
<|endoftext|>