<commit_before>#![feature(custom_attribute)]
#![allow(dead_code, unused_attributes)]

#[miri_run(expected = "Int(1)")]
fn ret() -> i32 {
    1
}

#[miri_run(expected = "Int(-1)")]
fn neg() -> i32 {
    -1
}

#[miri_run(expected = "Int(3)")]
fn add() -> i32 {
    1 + 2
}

#[miri_run(expected = "Int(3)")]
fn indirect_add() -> i32 {
    let x = 1;
    let y = 2;
    x + y
}

#[miri_run(expected = "Int(25)")]
fn arith() -> i32 {
    3*3 + 4*4
}

#[miri_run(expected = "Int(0)")]
fn if_false() -> i32 {
    if false { 1 } else { 0 }
}

#[miri_run(expected = "Int(1)")]
fn if_true() -> i32 {
    if true { 1 } else { 0 }
}

#[miri_run(expected = "Int(2)")]
fn call() -> i32 {
    fn increment(x: i32) -> i32 {
        x + 1
    }

    increment(1)
}

#[miri_run(expected = "Int(3628800)")]
fn factorial_loop() -> i32 {
    let mut product = 1;
    let mut i = 1;

    while i <= 10 {
        product *= i;
        i += 1;
    }

    product
}

#[miri_run(expected = "Int(3628800)")]
fn factorial_recursive() -> i32 {
    fn fact(n: i32) -> i32 {
        if n == 0 {
            1
        } else {
            n * fact(n - 1)
        }
    }

    fact(10)
}

#[miri_run(expected = "Int(1)")]
fn match_bool() -> i32 {
    let b = true;
    match b {
        true => 1,
        false => 0,
    }
}

#[miri_run(expected = "Int(20)")]
fn match_int() -> i32 {
    let n = 2;
    match n {
        0 => 0,
        1 => 10,
        2 => 20,
        3 => 30,
        _ => 100,
    }
}

// #[miri_run(expected = "Int(4)")]
// fn match_int_range() -> i32 {
//     let n = 42;
//     match n {
//         0...9 => 0,
//         10...19 => 1,
//         20...29 => 2,
//         30...39 => 3,
//         40...49 => 4,
//         _ => 5,
//     }
// }

enum MyOption<T> {
    Some { data: T },
    None,
}

#[miri_run(expected = "Int(13)")]
fn match_my_opt_some() -> i32 {
    let x = MyOption::Some { data: 13 };
    match x {
        MyOption::Some { data } => data,
        MyOption::None => 42,
    }
}

// #[miri_run(expected = "Int(13)")]
// fn match_opt_some() -> i32 {
//     let x = Some(13);
//     match x {
//         Some(data)  => data,
//         None => 42,
//     }
// }

// #[miri_run(expected = "Int(42)")]
// fn match_opt_none() -> i32 {
//     let x = MyOption::None;
//     match x {
//         MyOption::Some { data } => data,
//         MyOption::None => 42,
//     }
// }

/// Test calling a very simple function from the standard library.
#[miri_run(expected = "Int(1)")]
fn cross_crate_fn_call() -> i32 {
    if 1i32.is_positive() { 1 } else { 0 }
}

fn main() {}
<commit_msg>Uncomment other MyOption test.<commit_after>#![feature(custom_attribute)]
#![allow(dead_code, unused_attributes)]

#[miri_run(expected = "Int(1)")]
fn ret() -> i32 {
    1
}

#[miri_run(expected = "Int(-1)")]
fn neg() -> i32 {
    -1
}

#[miri_run(expected = "Int(3)")]
fn add() -> i32 {
    1 + 2
}

#[miri_run(expected = "Int(3)")]
fn indirect_add() -> i32 {
    let x = 1;
    let y = 2;
    x + y
}

#[miri_run(expected = "Int(25)")]
fn arith() -> i32 {
    3*3 + 4*4
}

#[miri_run(expected = "Int(0)")]
fn if_false() -> i32 {
    if false { 1 } else { 0 }
}

#[miri_run(expected = "Int(1)")]
fn if_true() -> i32 {
    if true { 1 } else { 0 }
}

#[miri_run(expected = "Int(2)")]
fn call() -> i32 {
    fn increment(x: i32) -> i32 {
        x + 1
    }

    increment(1)
}

#[miri_run(expected = "Int(3628800)")]
fn factorial_loop() -> i32 {
    let mut product = 1;
    let mut i = 1;

    while i <= 10 {
        product *= i;
        i += 1;
    }

    product
}

#[miri_run(expected = "Int(3628800)")]
fn factorial_recursive() -> i32 {
    fn fact(n: i32) -> i32 {
        if n == 0 {
            1
        } else {
            n * fact(n - 1)
        }
    }

    fact(10)
}

#[miri_run(expected = "Int(1)")]
fn match_bool() -> i32 {
    let b = true;
    match b {
        true => 1,
        false => 0,
    }
}

#[miri_run(expected = "Int(20)")]
fn match_int() -> i32 {
    let n = 2;
    match n {
        0 => 0,
        1 => 10,
        2 => 20,
        3 => 30,
        _ => 100,
    }
}

// #[miri_run(expected = "Int(4)")]
// fn match_int_range() -> i32 {
//     let n = 42;
//     match n {
//         0...9 => 0,
//         10...19 => 1,
//         20...29 => 2,
//         30...39 => 3,
//         40...49 => 4,
//         _ => 5,
//     }
// }

enum MyOption<T> {
    Some { data: T },
    None,
}

#[miri_run(expected = "Int(13)")]
fn match_my_opt_some() -> i32 {
    let x = MyOption::Some { data: 13 };
    match x {
        MyOption::Some { data } => data,
        MyOption::None => 42,
    }
}

#[miri_run(expected = "Int(42)")]
fn match_my_opt_none() -> i32 {
    let x = MyOption::None;
    match x {
        MyOption::Some { data } => data,
        MyOption::None => 42,
    }
}

// #[miri_run(expected = "Int(13)")]
// fn match_opt_some() -> i32 {
//     let x = Some(13);
//     match x {
//         Some(data)  => data,
//         None => 42,
//     }
// }

/// Test calling a very simple function from the standard library.
#[miri_run(expected = "Int(1)")]
fn cross_crate_fn_call() -> i32 {
    if 1i32.is_positive() { 1 } else { 0 }
}

fn main() {}
<|endoftext|>


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

use app_units::{Au, MAX_AU};
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
use std::i32;

// Units for use with euclid::length and euclid::scale_factor.

/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
/// should approximate a device-independent reference length.  This unit corresponds to Android's
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
///
/// The relationship between DevicePixel and ScreenPx is defined by the OS.  On most low-dpi
/// screens, one ScreenPx is equal to one DevicePixel.  But on high-density screens it can be
/// some larger number.  For example, by default on Apple "retina" displays, one ScreenPx equals
/// two DevicePixels.  On Android "MDPI" displays, one ScreenPx equals 1.5 device pixels.
///
/// The ratio between ScreenPx and DevicePixel for a given display be found by calling
/// `servo::windowing::WindowMethods::hidpi_factor`.
#[derive(Clone, Copy, Debug)]
pub enum ScreenPx {}

known_heap_size!(0, ScreenPx);

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.

#[inline(always)]
pub fn max_rect() -> Rect<Au> {
    Rect::new(Point2D::new(Au(i32::MIN / 2), Au(i32::MIN / 2)), Size2D::new(MAX_AU, MAX_AU))
}

/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
    Rect::new(Point2D::new(Au::from_f32_px(rect.origin.x), Au::from_f32_px(rect.origin.y)),
              Size2D::new(Au::from_f32_px(rect.size.width), Au::from_f32_px(rect.size.height)))
}

/// A helper function to convert a rect of `Au` pixels to a rect of f32 units.
pub fn au_rect_to_f32_rect(rect: Rect<Au>) -> Rect<f32> {
    Rect::new(Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()),
              Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()))
}

pub trait ExpandToPixelBoundaries {
    fn expand_to_px_boundaries(&self) -> Self;
}

impl ExpandToPixelBoundaries for Rect<Au> {
    fn expand_to_px_boundaries(&self) -> Rect<Au> {
        let bottom_right = self.bottom_right();
        let bottom_right = Point2D::new(Au::from_px(bottom_right.x.ceil_to_px()),
                                       Au::from_px(bottom_right.y.ceil_to_px()));
        let new_origin = Point2D::new(Au::from_px(self.origin.x.to_px()),
                                      Au::from_px(self.origin.y.to_px()));
        Rect::new(new_origin,
                  Size2D::new(bottom_right.x - new_origin.x,
                              bottom_right.y - new_origin.y))
    }
}
<commit_msg>Remove unused `ExpandToPixelBoundaries` trait from `util`.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use app_units::{Au, MAX_AU};
use euclid::point::Point2D;
use euclid::rect::Rect;
use euclid::size::Size2D;
use std::i32;

// Units for use with euclid::length and euclid::scale_factor.

/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it
/// should approximate a device-independent reference length.  This unit corresponds to Android's
/// "density-independent pixel" (dip), Mac OS X's "point", and Windows "device-independent pixel."
///
/// The relationship between DevicePixel and ScreenPx is defined by the OS.  On most low-dpi
/// screens, one ScreenPx is equal to one DevicePixel.  But on high-density screens it can be
/// some larger number.  For example, by default on Apple "retina" displays, one ScreenPx equals
/// two DevicePixels.  On Android "MDPI" displays, one ScreenPx equals 1.5 device pixels.
///
/// The ratio between ScreenPx and DevicePixel for a given display be found by calling
/// `servo::windowing::WindowMethods::hidpi_factor`.
#[derive(Clone, Copy, Debug)]
pub enum ScreenPx {}

known_heap_size!(0, ScreenPx);

// An Au is an "App Unit" and represents 1/60th of a CSS pixel.  It was
// originally proposed in 2002 as a standard unit of measure in Gecko.
// See https://bugzilla.mozilla.org/show_bug.cgi?id=177805 for more info.

#[inline(always)]
pub fn max_rect() -> Rect<Au> {
    Rect::new(Point2D::new(Au(i32::MIN / 2), Au(i32::MIN / 2)), Size2D::new(MAX_AU, MAX_AU))
}

/// A helper function to convert a rect of `f32` pixels to a rect of app units.
pub fn f32_rect_to_au_rect(rect: Rect<f32>) -> Rect<Au> {
    Rect::new(Point2D::new(Au::from_f32_px(rect.origin.x), Au::from_f32_px(rect.origin.y)),
              Size2D::new(Au::from_f32_px(rect.size.width), Au::from_f32_px(rect.size.height)))
}

/// A helper function to convert a rect of `Au` pixels to a rect of f32 units.
pub fn au_rect_to_f32_rect(rect: Rect<Au>) -> Rect<f32> {
    Rect::new(Point2D::new(rect.origin.x.to_f32_px(), rect.origin.y.to_f32_px()),
              Size2D::new(rect.size.width.to_f32_px(), rect.size.height.to_f32_px()))
}
<|endoftext|>


<commit_before>// Copyright 2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate rand;
extern crate ndarray;

use std::ptr;

use rand::Rng;
use rand::distributions::Sample;
use rand::distributions::IndependentSample;

use ndarray::{
    ArrayBase,
    Dimension,
    Data,
    DataOwned,
};

/// Constructors for n-dimensional arrays with random elements.
///
/// This trait extends ndarray’s `ArrayBase` and can not be implemented
/// for other types.
///
/// The default Rng is a fast automatically seeded rng (currently `rand::weak_rng`).
pub trait RandomExt<S, D>
    where S: DataOwned,
          D: Dimension,
{
    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`  using the default rng.
    ///
    /// ```
    /// extern crate rand;
    /// extern crate ndarray;
    /// extern crate ndarray_rand;
    ///
    /// use rand::distributions::Range;
    /// use ndarray::OwnedArray;
    /// use ndarray_rand::RandomExt;
    ///
    /// # fn main() {
    /// let a = OwnedArray::random((2, 5), Range::new(0., 10.));
    /// println!("{:8.4}", a);
    /// // Output:
    /// // [[  8.6900,   6.9824,   3.8922,   6.5861,   2.4890],
    /// //  [  0.0914,   5.5186,   5.8135,   5.2361,   3.1879]]
    /// # }
    fn random<IdS>(dim: D, distribution: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>;

    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`, using a specific Rng `rng`.
    fn random_using<IdS, R>(dim: D, distribution: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng;
}

impl<S, D> RandomExt<S, D> for ArrayBase<S, D>
    where S: DataOwned,
          D: Dimension,
{
    fn random<IdS>(dim: D, dist: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>
    {
        Self::random_using(dim, dist, &mut rand::weak_rng())
    }

    fn random_using<IdS, R>(dim: D, dist: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng
    {
        unsafe {
            let elements = to_vec((0..dim.size()).map(move |_| dist.ind_sample(rng)));
            Self::from_vec_dim(dim, elements).unwrap()
        }
    }
}

/// Like Iterator::collect, but only for trusted length iterators
unsafe fn to_vec<I>(iter: I) -> Vec<I::Item>
    where I: ExactSizeIterator
{
    // Use an `unsafe` block to do this efficiently.
    // We know that iter will produce exactly .size() elements,
    // and the loop can vectorize if it's clean (without branch to grow the vector).
    let (size, _) = iter.size_hint();
    let mut result = Vec::with_capacity(size);
    let mut out_ptr = result.as_mut_ptr();
    let mut len = 0;
    for elt in iter {
        ptr::write(out_ptr, elt);
        len += 1;
        result.set_len(len);
        out_ptr = out_ptr.offset(1);
    }
    debug_assert_eq!(size, result.len());
    result
}
<commit_msg>Add F32 newtype to ndarray-rand (a f32 helper)<commit_after>// Copyright 2016 bluss and ndarray developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate rand;
extern crate ndarray;

use std::ptr;

use rand::Rng;
use rand::distributions::Sample;
use rand::distributions::IndependentSample;

use ndarray::{
    ArrayBase,
    Dimension,
    DataOwned,
};

/// Constructors for n-dimensional arrays with random elements.
///
/// This trait extends ndarray’s `ArrayBase` and can not be implemented
/// for other types.
///
/// The default Rng is a fast automatically seeded rng (currently `rand::weak_rng`).
pub trait RandomExt<S, D>
    where S: DataOwned,
          D: Dimension,
{
    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`  using the default rng.
    ///
    /// ```
    /// extern crate rand;
    /// extern crate ndarray;
    /// extern crate ndarray_rand;
    ///
    /// use rand::distributions::Range;
    /// use ndarray::OwnedArray;
    /// use ndarray_rand::RandomExt;
    ///
    /// # fn main() {
    /// let a = OwnedArray::random((2, 5), Range::new(0., 10.));
    /// println!("{:8.4}", a);
    /// // Output:
    /// // [[  8.6900,   6.9824,   3.8922,   6.5861,   2.4890],
    /// //  [  0.0914,   5.5186,   5.8135,   5.2361,   3.1879]]
    /// # }
    fn random<IdS>(dim: D, distribution: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>;

    /// Create an array with shape `dim` with elements drawn from
    /// `distribution`, using a specific Rng `rng`.
    fn random_using<IdS, R>(dim: D, distribution: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng;
}

impl<S, D> RandomExt<S, D> for ArrayBase<S, D>
    where S: DataOwned,
          D: Dimension,
{
    fn random<IdS>(dim: D, dist: IdS) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>
    {
        Self::random_using(dim, dist, &mut rand::weak_rng())
    }

    fn random_using<IdS, R>(dim: D, dist: IdS, rng: &mut R) -> ArrayBase<S, D>
        where IdS: IndependentSample<S::Elem>,
              R: Rng
    {
        unsafe {
            let elements = to_vec((0..dim.size()).map(move |_| dist.ind_sample(rng)));
            Self::from_vec_dim(dim, elements).unwrap()
        }
    }
}

/// Like Iterator::collect, but only for trusted length iterators
unsafe fn to_vec<I>(iter: I) -> Vec<I::Item>
    where I: ExactSizeIterator
{
    // Use an `unsafe` block to do this efficiently.
    // We know that iter will produce exactly .size() elements,
    // and the loop can vectorize if it's clean (without branch to grow the vector).
    let (size, _) = iter.size_hint();
    let mut result = Vec::with_capacity(size);
    let mut out_ptr = result.as_mut_ptr();
    let mut len = 0;
    for elt in iter {
        ptr::write(out_ptr, elt);
        len += 1;
        result.set_len(len);
        out_ptr = out_ptr.offset(1);
    }
    debug_assert_eq!(size, result.len());
    result
}

/// A wrapper type that allows casting f64 distributions to f32
#[derive(Copy, Clone, Debug)]
pub struct F32<S>(pub S);

impl<S> Sample<f32> for F32<S>
    where S: Sample<f64>
{
    fn sample<R>(&mut self, rng: &mut R) -> f32 where R: Rng {
        self.0.sample(rng) as f32
    }
}

impl<S> IndependentSample<f32> for F32<S>
    where S: IndependentSample<f64>
{
    fn ind_sample<R>(&self, rng: &mut R) -> f32 where R: Rng {
        self.0.ind_sample(rng) as f32
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(plugin_registrar)]
#![feature(rustc_private)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::registry::Registry;
use std::ptr;
use syntax::ast::{
    DUMMY_NODE_ID, Block, CompilerGenerated, LitInt, Plus, TtToken, TokenTree, UnsafeBlock,
    UnsuffixedIntLit,
};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacExpr, MacResult, NormalTT};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{self, Comma, Semi};
use syntax::ptr::P;

#[macro_export]
/// Creates an owned matrix from its arguments
///
/// - Each argument is an element of the matrix
/// - Semicolons `;` are used to separate rows
/// - Trailing semicolons are allowed
/// - Commas `,` are used to separate columns
/// - Trailing commas are *not* allowed
/// - If the matrix contains a single row, the macro will return `RowVec`
/// - If the matrix contains a single column, the macro will return `ColVec`
/// - Otherwise, the macro will return `Mat`
///
/// # Expansion
///
/// There are three possible expansions:
///
/// - Row vector
///
/// ``` ignore
/// mat![0, 1, 2]
/// ```
///
/// expands into:
///
/// ``` ignore
/// RowVec::new(Box::new([0, 1, 2]))
/// ```
///
/// - Column vector
///
/// ``` ignore
/// // NB Newlines are *not* required
/// mat![
///     0;
///     1;
///     2;  // This semicolon can be removed if desired
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// ColVec::new(Box::new([0, 1, 2]))
/// ```
///
/// - Matrix
///
/// ``` ignore
/// mat![
///     0, 1, 2;
///     3, 4, 5;
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// unsafe { Mat::from_parts(Box::new([0, 3, 1, 4, 3, 5]), (2, 3)) }
/// ```
///
/// Note that the order of the arguments have changed because matrices are stored in column-major
/// order
macro_rules! mat {
    ($($($elem:expr),+);+;) => { /* syntax extension */ }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(r: &mut Registry) {
    r.register_syntax_extension(token::intern("mat"), NormalTT(Box::new(expand_mat), None));
}

fn expand_mat<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    tts: &[TokenTree],
) -> Box<MacResult + 'cx> {
    fn at_semicolons(tt: &TokenTree) -> bool {
        if let TtToken(_, Semi) = *tt {
            true
        } else {
            false
        }
    }

    fn at_commas(tt: &TokenTree) -> bool {
        if let TtToken(_, Comma) = *tt {
            true
        } else {
            false
        }
    }

    let rows = {
        let mut rows = tts.split(at_semicolons).collect::<Vec<_>>();
        // look for trailing semicolon
        if rows.last().map(|tts| tts.is_empty()) == Some(true) {
            rows.pop();
        }
        rows
    };

    let nrows = rows.len();

    let matrix = {
        let mut matrix = Vec::with_capacity(nrows);
        for (r, row) in rows.into_iter().enumerate() {
            let elems = row.split(at_commas).collect::<Vec<_>>();
            // look for trailing commas
            if elems.last().map(|tts| tts.is_empty()) == Some(true) {
                let err_msg = format!("row {}: trailing comma not allowed", r);
                cx.span_err(sp, &*err_msg);
                return DummyResult::expr(sp);
            }
            matrix.push(elems);
        }
        matrix
    };

    let ncols = {
        let mut cols_per_row = matrix.iter().map(|row| row.len());

        let ncols = match cols_per_row.next() {
            Some(ncols) => ncols,
            None => {
                cx.span_err(sp, "Empty matrix");
                return DummyResult::expr(sp);
            },
        };

        for (i, cols_per_row) in cols_per_row.enumerate() {
            if cols_per_row != ncols {
                let err_msg = format!(
                    "row {}: expected {} columns, but found {}",
                    i + 1,
                    ncols,
                    cols_per_row);
                cx.span_err(sp, &*err_msg);
                return DummyResult::expr(sp);
            }
        }

        ncols
    };

    for (r, row) in matrix.iter().enumerate() {
        for (c, elem) in row.iter().enumerate() {
            if elem.is_empty() {
                cx.span_err(sp, &*format!("no element found at ({}, {})", r, c));
                return DummyResult::expr(sp);
            }
        }
    }

    let nelems = nrows * ncols;
    let mut elems = Vec::with_capacity(nelems);
    unsafe { elems.set_len(nelems) }

    for (r, row) in matrix.into_iter().enumerate() {
        for (c, elem) in row.into_iter().enumerate() {
            let dst = &mut elems[c * nrows + r];

            unsafe { ptr::write(dst, cx.new_parser_from_tts(elem).parse_expr()) }
        }
    }

    let vec = {
        let stmts = vec![];

        let expr = {
            let box_new_path = {
                let strs = vec![
                    cx.ident_of("Box"),
                    cx.ident_of("new"),
                ];

                cx.path(sp, strs)
            };

            let array = cx.expr_vec(sp, elems);

            Some(cx.expr_call(sp, cx.expr_path(box_new_path), vec![array]))
        };

        cx.expr_block(cx.block_all(sp, stmts, expr))
    };

    if nrows == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("RowVec"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else if ncols == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("ColVec"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacExpr::new(cx.expr_call(sp, fn_name, args))
    } else {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Mat"),
                cx.ident_of("from_parts"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let size = cx.expr_tuple(sp, vec![
            cx.expr_lit(sp, LitInt(nrows as u64, UnsuffixedIntLit(Plus))),
            cx.expr_lit(sp, LitInt(ncols as u64, UnsuffixedIntLit(Plus))),
        ]);
        let args = vec![vec, size];

        let unsafe_block = cx.expr_block(P(Block {
            stmts: vec![],
            expr: Some(cx.expr_call(sp, fn_name, args)),
            id: DUMMY_NODE_ID,
            rules: UnsafeBlock(CompilerGenerated),
            span: sp,
        }));

        MacExpr::new(unsafe_block)
    }
}
<commit_msg>fix(macros): `MacExpr` -> `MacEager`<commit_after>#![deny(warnings)]
#![feature(plugin_registrar)]
#![feature(rustc_private)]

extern crate rustc;
extern crate syntax;

use rustc::plugin::registry::Registry;
use std::ptr;
use syntax::ast::{
    DUMMY_NODE_ID, Block, CompilerGenerated, LitInt, Plus, TtToken, TokenTree, UnsafeBlock,
    UnsuffixedIntLit,
};
use syntax::codemap::Span;
use syntax::ext::base::{DummyResult, ExtCtxt, MacEager, MacResult, NormalTT};
use syntax::ext::build::AstBuilder;
use syntax::parse::token::{self, Comma, Semi};
use syntax::ptr::P;

#[macro_export]
/// Creates an owned matrix from its arguments
///
/// - Each argument is an element of the matrix
/// - Semicolons `;` are used to separate rows
/// - Trailing semicolons are allowed
/// - Commas `,` are used to separate columns
/// - Trailing commas are *not* allowed
/// - If the matrix contains a single row, the macro will return `RowVec`
/// - If the matrix contains a single column, the macro will return `ColVec`
/// - Otherwise, the macro will return `Mat`
///
/// # Expansion
///
/// There are three possible expansions:
///
/// - Row vector
///
/// ``` ignore
/// mat![0, 1, 2]
/// ```
///
/// expands into:
///
/// ``` ignore
/// RowVec::new(Box::new([0, 1, 2]))
/// ```
///
/// - Column vector
///
/// ``` ignore
/// // NB Newlines are *not* required
/// mat![
///     0;
///     1;
///     2;  // This semicolon can be removed if desired
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// ColVec::new(Box::new([0, 1, 2]))
/// ```
///
/// - Matrix
///
/// ``` ignore
/// mat![
///     0, 1, 2;
///     3, 4, 5;
/// ]
/// ```
///
/// expands into:
///
/// ``` ignore
/// unsafe { Mat::from_parts(Box::new([0, 3, 1, 4, 3, 5]), (2, 3)) }
/// ```
///
/// Note that the order of the arguments have changed because matrices are stored in column-major
/// order
macro_rules! mat {
    ($($($elem:expr),+);+;) => { /* syntax extension */ }
}

#[plugin_registrar]
#[doc(hidden)]
pub fn plugin_registrar(r: &mut Registry) {
    r.register_syntax_extension(token::intern("mat"), NormalTT(Box::new(expand_mat), None));
}

fn expand_mat<'cx>(
    cx: &'cx mut ExtCtxt,
    sp: Span,
    tts: &[TokenTree],
) -> Box<MacResult + 'cx> {
    fn at_semicolons(tt: &TokenTree) -> bool {
        if let TtToken(_, Semi) = *tt {
            true
        } else {
            false
        }
    }

    fn at_commas(tt: &TokenTree) -> bool {
        if let TtToken(_, Comma) = *tt {
            true
        } else {
            false
        }
    }

    let rows = {
        let mut rows = tts.split(at_semicolons).collect::<Vec<_>>();
        // look for trailing semicolon
        if rows.last().map(|tts| tts.is_empty()) == Some(true) {
            rows.pop();
        }
        rows
    };

    let nrows = rows.len();

    let matrix = {
        let mut matrix = Vec::with_capacity(nrows);
        for (r, row) in rows.into_iter().enumerate() {
            let elems = row.split(at_commas).collect::<Vec<_>>();
            // look for trailing commas
            if elems.last().map(|tts| tts.is_empty()) == Some(true) {
                let err_msg = format!("row {}: trailing comma not allowed", r);
                cx.span_err(sp, &*err_msg);
                return DummyResult::expr(sp);
            }
            matrix.push(elems);
        }
        matrix
    };

    let ncols = {
        let mut cols_per_row = matrix.iter().map(|row| row.len());

        let ncols = match cols_per_row.next() {
            Some(ncols) => ncols,
            None => {
                cx.span_err(sp, "Empty matrix");
                return DummyResult::expr(sp);
            },
        };

        for (i, cols_per_row) in cols_per_row.enumerate() {
            if cols_per_row != ncols {
                let err_msg = format!(
                    "row {}: expected {} columns, but found {}",
                    i + 1,
                    ncols,
                    cols_per_row);
                cx.span_err(sp, &*err_msg);
                return DummyResult::expr(sp);
            }
        }

        ncols
    };

    for (r, row) in matrix.iter().enumerate() {
        for (c, elem) in row.iter().enumerate() {
            if elem.is_empty() {
                cx.span_err(sp, &*format!("no element found at ({}, {})", r, c));
                return DummyResult::expr(sp);
            }
        }
    }

    let nelems = nrows * ncols;
    let mut elems = Vec::with_capacity(nelems);
    unsafe { elems.set_len(nelems) }

    for (r, row) in matrix.into_iter().enumerate() {
        for (c, elem) in row.into_iter().enumerate() {
            let dst = &mut elems[c * nrows + r];

            unsafe { ptr::write(dst, cx.new_parser_from_tts(elem).parse_expr()) }
        }
    }

    let vec = {
        let stmts = vec![];

        let expr = {
            let box_new_path = {
                let strs = vec![
                    cx.ident_of("Box"),
                    cx.ident_of("new"),
                ];

                cx.path(sp, strs)
            };

            let array = cx.expr_vec(sp, elems);

            Some(cx.expr_call(sp, cx.expr_path(box_new_path), vec![array]))
        };

        cx.expr_block(cx.block_all(sp, stmts, expr))
    };

    if nrows == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("RowVec"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacEager::expr(cx.expr_call(sp, fn_name, args))
    } else if ncols == 1 {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("ColVec"),
                cx.ident_of("new"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let args = vec![vec];

        MacEager::expr(cx.expr_call(sp, fn_name, args))
    } else {
        let fn_name = {
            let segments = vec![
                cx.ident_of("linalg"),
                cx.ident_of("Mat"),
                cx.ident_of("from_parts"),
            ];

            cx.expr_path(cx.path_global(sp, segments))
        };
        let size = cx.expr_tuple(sp, vec![
            cx.expr_lit(sp, LitInt(nrows as u64, UnsuffixedIntLit(Plus))),
            cx.expr_lit(sp, LitInt(ncols as u64, UnsuffixedIntLit(Plus))),
        ]);
        let args = vec![vec, size];

        let unsafe_block = cx.expr_block(P(Block {
            stmts: vec![],
            expr: Some(cx.expr_call(sp, fn_name, args)),
            id: DUMMY_NODE_ID,
            rules: UnsafeBlock(CompilerGenerated),
            span: sp,
        }));

        MacEager::expr(unsafe_block)
    }
}
<|endoftext|>


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

extern crate lambda_calculus as lambda;

use lambda::*;
use lambda::data::list::*;
use lambda::data::boolean::fls;
use lambda::data::numerals::church::{add, is_zero};

#[test]
fn list_last() {
    let list1 = || { vec![1].into_church() };
    let list2 = || { vec![0, 1, 2, 3, 4].into_church() };

    assert_eq!(beta(app(last(), nil()), HAP, 0), nil());
    assert_eq!(beta(app(last(), list1()), HAP, 0), 1.into_church());
    assert_eq!(beta(app(last(), list2()), HAP, 0), 4.into_church());
}

#[test]
fn list_init() {
    let list1 = || { vec![0, 1, 2, 3, 4].into_church() };
    let list2 = || { vec![0, 1, 2, 3].into_church() };
    let list3 = || { vec![2, 3].into_church() };
    let list4 = || { vec![2].into_church() };

    assert_eq!(beta(app(init(), list1()), HAP, 0), list2());
    assert_eq!(beta(app(init(), list3()), HAP, 0), list4());
    assert_eq!(beta(app(init(), list4()), HAP, 0), nil());
    assert_eq!(beta(app(init(), nil()), HAP, 0), nil());
}

#[test]
fn list_zip() {
    let l1 = || { vec![0].into_church() };
    let l2 = || { vec![0, 1, 2].into_church() };
    let l3 = || { vec![2, 1].into_church() };
    let p1 = || { vec![(0, 0)].into_church() };
    let p2 = || { vec![(0, 0), (1, 1), (2, 2)].into_church() };
    let p3 = || { vec![(0, 2), (1, 1)].into_church() };

    assert_eq!(beta(app!(zip(), nil(), nil()), HAP, 0), nil());
    assert_eq!(beta(app!(zip(), nil(), l1()), HAP, 0), nil());
    assert_eq!(beta(app!(zip(), l1(), nil()), HAP, 0), nil());
    assert_eq!(beta(app!(zip(), l1(), l1()), HAP, 0), p1());
    assert_eq!(beta(app!(zip(), l1(), l2()), HAP, 0), p1());
    assert_eq!(beta(app!(zip(), l2(), l1()), HAP, 0), p1());
    assert_eq!(beta(app!(zip(), l2(), l2()), HAP, 0), p2());
    assert_eq!(beta(app!(zip(), l2(), l3()), HAP, 0), p3());
}

#[test]
fn list_zip_with() {
    let l1 = || { vec![1].into_church() };
    let l2 = || { vec![2].into_church() };
    let l3 = || { vec![1, 2, 3].into_church() };
    let l4 = || { vec![2, 4, 6].into_church() };
    let l5 = || { vec![3].into_church() };

    assert_eq!(beta(app!(zip_with(), add(), nil(), nil()), HAP, 0), nil());
    assert_eq!(beta(app!(zip_with(), add(), l1(), nil()), HAP, 0), nil());
    assert_eq!(beta(app!(zip_with(), add(), nil(), l1()), HAP, 0), nil());
    assert_eq!(beta(app!(zip_with(), abs!(2, Var(1)), l1(), l1()), HAP, 0), l1());
    assert_eq!(beta(app!(zip_with(), add(), l1(), l1()), HAP, 0), l2());
    assert_eq!(beta(app!(zip_with(), add(), l3(), l3()), HAP, 0), l4());
    assert_eq!(beta(app!(zip_with(), add(), l4(), l1()), HAP, 0), l5());
    assert_eq!(beta(app!(zip_with(), add(), l1(), l4()), HAP, 0), l5());
    assert_eq!(beta(app!(zip_with(), fls(), l1(), l4()), HAP, 0), l2());
    assert_eq!(beta(app!(zip_with(), fls(), l4(), l1()), HAP, 0), l1());
}

#[test]
fn list_take() {
    let l1 = || { vec![0].into_church() };
    let l2 = || { vec![0, 1].into_church() };
    let l3 = || { vec![0, 1, 2].into_church() };
    let l4 = || { vec![0, 1, 2, 3].into_church() };

    assert_eq!(beta(app!(take(), 5.into_church(), l4()), HAP, 0), l4());
    assert_eq!(beta(app!(take(), 4.into_church(), l4()), HAP, 0), l4());
    assert_eq!(beta(app!(take(), 3.into_church(), l4()), HAP, 0), l3());
    assert_eq!(beta(app!(take(), 2.into_church(), l4()), HAP, 0), l2());
    assert_eq!(beta(app!(take(), 1.into_church(), l4()), HAP, 0), l1());
    assert_eq!(beta(app!(take(), 0.into_church(), l4()), HAP, 0), nil());
    assert_eq!(beta(app!(take(), 1.into_church(), l1()), HAP, 0), l1());
    assert_eq!(beta(app!(take(), 0.into_church(), l1()), HAP, 0), nil());
    assert_eq!(beta(app!(take(), 1.into_church(), nil()), HAP, 0), nil());
}

#[test]
fn list_take_while() {
    let l1 = || { vec![0, 0, 2, 3].into_church() };
    let l2 = || { vec![0, 0].into_church() };
    let l3 = || { vec![1, 4, 2, 3].into_church() };
    let l4 = || { vec![0, 4, 0, 0].into_church() };
    let l5 = || { vec![0].into_church() };

    assert_eq!(beta(app!(take_while(), is_zero(), nil()), HAP, 0), nil());
    assert_eq!(beta(app!(take_while(), is_zero(), l1()), HAP, 0), l2());
    assert_eq!(beta(app!(take_while(), is_zero(), l2()), HAP, 0), l2());
    assert_eq!(beta(app!(take_while(), is_zero(), l3()), HAP, 0), nil());
    assert_eq!(beta(app!(take_while(), is_zero(), l4()), HAP, 0), l5());
}
<commit_msg>make list integration tests test all encodings at once (WIP)<commit_after>#![cfg(feature = "encoding")]

extern crate lambda_calculus as lambda;

use lambda::*;
use lambda::data::list::*;
//use lambda::data::numerals::church::{add, is_zero};

macro_rules! test_list {
    ($name:ident, $function:ident, $($($n:expr),+ => $result:expr),+) => (
        #[test]
        fn $name() {
            $(assert_eq!(beta(app!($function(), $($n.into_church()),*), HAP, 0), $result.into_church());)*
            $(assert_eq!(beta(app!($function(), $($n.into_scott()),*), HAP, 0), $result.into_scott());)*
            $(assert_eq!(beta(app!($function(), $($n.into_parigot()),*), HAP, 0), $result.into_parigot());)*
            $(assert_eq!(beta(app!($function(), $($n.into_stumpfu()),*), HAP, 0), $result.into_stumpfu());)*
        }
    );
}

test_list!(list_last, last,
    // TODO: test empty list?
    vec![1] => 1,
    vec![1, 2, 3] => 3
);

test_list!(list_init, init,
    // TODO: test singleton list?
    vec![1, 2] => vec![1],
    vec![1, 2, 3] => vec![1, 2]
);

test_list!(list_zip, zip,
    // TODO: test empty list
    vec![1], vec![1] => vec![(1, 1)],
    vec![1, 2], vec![1] => vec![(1, 1)],
    vec![1], vec![1, 2] => vec![(1, 1)],
    vec![1, 2], vec![3, 4] => vec![(1, 3), (2, 4)]
);
/* TODO: figure out passing multiple functions (inconsistent lockstep iteration)
test_list!(list_zip, zip_with, add,
    // TODO: test empty list
    vec![1], vec![1] => vec![2],
    vec![1, 2], vec![1] => vec![2],
    vec![1], vec![1, 2] => vec![2],
    vec![1, 2], vec![3, 4] => vec![4, 6]
);
#[test]
fn list_take_while() {
    let l1 = || { vec![0, 0, 2, 3].into_scott() };
    let l2 = || { vec![0, 0].into_scott() };
    let l3 = || { vec![1, 4, 2, 3].into_scott() };
    let l4 = || { vec![0, 4, 0, 0].into_scott() };
    let l5 = || { vec![0].into_scott() };

    assert_eq!(beta(app!(take_while(), is_zero(), nil()), HAP, 0), nil());
    assert_eq!(beta(app!(take_while(), is_zero(), l1()), HAP, 0), l2());
    assert_eq!(beta(app!(take_while(), is_zero(), l2()), HAP, 0), l2());
    assert_eq!(beta(app!(take_while(), is_zero(), l3()), HAP, 0), nil());
    assert_eq!(beta(app!(take_while(), is_zero(), l4()), HAP, 0), l5());
}
*/
<|endoftext|>


<commit_before>
extern crate nccl;

use nccl::{Pair, Value};

#[test]
fn pair_new() {
    assert_eq!(Pair::new("hello"), Pair {
        key: "hello".into(),
        value: vec![]
    });
}

#[test]
fn pair_add() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p, Pair {
        key: "top_level".into(),
        value: vec![Pair {
            key: "key".into(),
            value: vec![]
        }]
    });
}

#[test]
fn pair_get() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p.get("key"), &mut Pair {
        key: "key".into(),
        value: vec![]
    });
}

#[test]
fn pair_index() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p["key"], Pair {
        key: "key".into(),
        value: vec![]
    });
}

#[test]
fn pair_keys() {
    let mut p = Pair::new("top");
    p.add("numbers");
    p["numbers"].add("1");
    p["numbers"].add("2");
    p["numbers"].add("3");
    p["numbers"].add("4");
    p["numbers"].add("5");
    assert_eq!(p["numbers"].keys(), vec!["1", "2", "3", "4", "5"]);
}

#[test]
fn readme() {
    let mut config = Pair::new("top_level");

    // server
    //     domain
    //         example.com
    //         www.example.com
    //     port
    //         80
    //         443
    //     root
    //         /var/www/html

    config.add("server");
    config["server"].add("domain");
    config["server"].add("port");
    config["server"].add("root");
    config["server"]["domain"].add("example.com");
    config["server"]["domain"].add("www.example.com");
    config["server"]["port"].add("80");
    config["server"]["port"].add("443");
    config["server"]["root"].add("/var/www/html");

    let ports = config["server"]["port"].keys_as::<i32>();
    assert_eq!(ports, vec![80, 443]);
}

<commit_msg>add parsing test<commit_after>
extern crate nccl;

use nccl::{Pair, Value};

#[test]
fn pair_new() {
    assert_eq!(Pair::new("hello"), Pair {
        key: "hello".into(),
        value: vec![]
    });
}

#[test]
fn pair_add() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p, Pair {
        key: "top_level".into(),
        value: vec![Pair {
            key: "key".into(),
            value: vec![]
        }]
    });
}

#[test]
fn pair_get() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p.get("key"), &mut Pair {
        key: "key".into(),
        value: vec![]
    });
}

#[test]
fn pair_index() {
    let mut p = Pair::new("top_level");
    p.add("key");
    assert_eq!(p["key"], Pair {
        key: "key".into(),
        value: vec![]
    });
}

#[test]
fn pair_keys() {
    let mut p = Pair::new("top");
    p.add("numbers");
    p["numbers"].add("1");
    p["numbers"].add("2");
    p["numbers"].add("3");
    p["numbers"].add("4");
    p["numbers"].add("5");
    assert_eq!(p["numbers"].keys(), vec!["1", "2", "3", "4", "5"]);
}

#[test]
fn pair_value_parse() {
    let mut p = Pair::new("top");
    p.add("bools");
    p["bools"].add("true");
    p["bools"].add("false");
    assert!(p["bools"].keys_as::<bool>()[0]);
    assert!(!p["bools"].keys_as::<bool>()[1]);
}

#[test]
fn readme() {
    let mut config = Pair::new("top_level");

    // server
    //     domain
    //         example.com
    //         www.example.com
    //     port
    //         80
    //         443
    //     root
    //         /var/www/html

    config.add("server");
    config["server"].add("domain");
    config["server"].add("port");
    config["server"].add("root");
    config["server"]["domain"].add("example.com");
    config["server"]["domain"].add("www.example.com");
    config["server"]["port"].add("80");
    config["server"]["port"].add("443");
    config["server"]["root"].add("/var/www/html");

    let ports = config["server"]["port"].keys_as::<i32>();
    assert_eq!(ports, vec![80, 443]);
}

<|endoftext|>


<commit_before>// Copyright 2020 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::{bail, Context, Error};
use fehler::throws;
use libtest_mimic::{run_tests, Arguments, Outcome, Test};
use std::fs::{read_dir, read_to_string};
use std::path::Path;
use wasmbin::{
    io::DecodeError,
    visit::{Visit, VisitError},
    Module,
};
use wast::parser::{parse, ParseBuffer};
use wast::Wast;

const IGNORED_ERRORS: &[&str] = &[
    // We don't perform cross-section analysis.
    "function and code section have inconsistent lengths",
    "data count section required",
    "data count and data section have inconsistent lengths",
    // We allow non-zero table and memory IDs already.
    "zero flag expected",
    // We don't perform full function analysis either.
    "too many locals",
];

// See https://github.com/WebAssembly/bulk-memory-operations/issues/153.
const IGNORED_MODULES: &[&[u8]] = &[
    &[
        0x05, 0x03, 0x01, 0x00, 0x00, 0x0B, 0x07, 0x01, 0x80, 0x00, 0x41, 0x00, 0x0B, 0x00,
    ],
    &[
        0x04, 0x04, 0x01, 0x70, 0x00, 0x00, 0x09, 0x07, 0x01, 0x80, 0x00, 0x41, 0x00, 0x0B, 0x00,
    ],
];

struct WasmTest {
    module: Vec<u8>,
    expect_result: Result<(), String>,
}

#[throws]
fn read_tests_from_file(path: &Path, dest: &mut Vec<Test<WasmTest>>, ignore_malformed: bool) {
    let src = read_to_string(path)?;
    let set_err_path_text = |mut err: wast::Error| {
        err.set_path(path);
        err.set_text(&src);
        err
    };
    let buf = ParseBuffer::new(&src).map_err(set_err_path_text)?;
    let wast = parse::<Wast>(&buf).map_err(set_err_path_text)?;
    for directive in wast.directives {
        let (span, mut module, expect_result) = match directive {
            // Expect errors for assert_malformed on binary or AST modules.
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            }
            // Unlike other AssertInvalid, this is actually something we
            // check at the parsing time, because it's part of our
            // typesystem and doesn't require cross-function or
            // cross-section checks.
            //
            // See https://github.com/WebAssembly/simd/issues/256 for accepted
            // but pending suggestion to change proposal to match this as well.
            | wast::WastDirective::AssertInvalid {
                span,
                module,
                message: message @ "invalid lane index",
            } => (span, module, Err(message.to_owned())),
            // Expect successful parsing for regular AST modules.
            wast::WastDirective::Module(module) => (module.span, module, Ok(())),
            // Counter-intuitively, expect successful parsing for modules that are supposed
            // to error out at runtime or linking stage, too.
            wast::WastDirective::AssertInvalid { span, module, .. }
            | wast::WastDirective::AssertUnlinkable { span, module, .. } => (span, module, Ok(())),
            _ => {
                // Skipping interpreted
                continue;
            }
        };
        let (line, col) = span.linecol_in(&src);
        let module = module.encode()?;
        dest.push(Test {
            name: format!("{}:{}:{}", path.display(), line + 1, col + 1),
            kind: String::default(),
            is_ignored: match &expect_result {
                // see https://github.com/WebAssembly/bulk-memory-operations/issues/153
                Ok(()) => IGNORED_MODULES.contains(&&module[8..]),
                Err(err) => ignore_malformed || IGNORED_ERRORS.contains(&err.as_str()),
            },
            is_bench: false,
            data: WasmTest {
                module,
                expect_result,
            },
        });
    }
}

#[throws]
fn read_tests_from_dir(path: &Path, dest: &mut Vec<Test<WasmTest>>, ignore_malformed: bool) {
    for file in read_dir(path)? {
        let path = file?.path();
        if path.extension().map_or(false, |ext| ext == "wast") {
            read_tests_from_file(&path, dest, ignore_malformed)?;
        }
    }
}

#[throws]
fn read_all_tests(path: &Path) -> (Vec<Test<WasmTest>>, bool) {
    let mut tests = Vec::new();
    let proposals_dir = path.join("proposals");

    macro_rules! read_proposal_tests {
        ($name:literal) => {
            if cfg!(feature = $name) {
                read_tests_from_dir(&proposals_dir.join($name), &mut tests, false).context($name)?
            }
        };
    }

    read_proposal_tests!("bulk-memory-operations");
    read_proposal_tests!("reference-types");
    read_proposal_tests!("simd");
    read_proposal_tests!("tail-call");
    read_proposal_tests!("threads");

    let has_proposals = !tests.is_empty();

    read_tests_from_dir(path, &mut tests, has_proposals)?;

    if tests.is_empty() {
        bail!("Couldn't find any tests. Did you run `git submodule update --init`?");
    }

    (tests, has_proposals)
}

fn unlazify<T: Visit>(mut wasm: T) -> Result<T, DecodeError> {
    match wasm.visit_mut(|()| {}) {
        Ok(()) => Ok(wasm),
        Err(err) => match err {
            VisitError::LazyDecode(err) => Err(err),
            VisitError::Custom(err) => match err {},
        },
    }
}

#[throws]
fn run_test(test: &WasmTest) {
    let mut slice = test.module.as_slice();
    let module = match (Module::decode_from(&mut slice).and_then(unlazify), &test.expect_result) {
        (Ok(_), Err(err)) => bail!("Expected an invalid module definition with an error: {}", err),
        (Err(err), Ok(())) => bail!(
            "Expected a valid module definition, but got an error\nParsed part: {:02X?}\nUnparsed part: {:02X?}\nError: {:#}",
            &test.module[..test.module.len() - slice.len()],
            slice,
            err
        ),
        (Ok(module), Ok(())) => module,
        (Err(_), Err(_)) => return,
    };
    let out = module.encode_into(Vec::new())?;
    if out != test.module {
        // In the rare case that binary representation doesn't match, it
        // might be because the test uses longer LEB128 form than
        // required. Verify that at least decoding it back produces the
        // same module.
        let module2 = Module::decode_from(out.as_slice())?;
        if module != module2 {
            bail!(
                "Roundtrip mismatch. Old: {:#?}\nNew: {:#?}",
                module,
                module2
            );
        }
    }
}

#[throws]
fn main() {
    let (tests, has_proposals) = read_all_tests(&Path::new("tests").join("testsuite"))?;

    run_tests(&Arguments::from_args(), tests, |test| {
        match run_test(&test.data) {
            Ok(()) => Outcome::Passed,
            Err(err) => Outcome::Failed {
                msg: Some(err.to_string()),
            },
        }
    })
    .exit_if_failed();

    if has_proposals {
        eprintln!(
            "Proposals were enabled, so upstream `assert_malformed` tests were ignored.\n\
             Re-run without any proposals enabled for the full upstream test coverage."
        );
    }
}
<commit_msg>Improve IGNORED_MODULES support<commit_after>// Copyright 2020 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use anyhow::{bail, Context, Error};
use fehler::throws;
use libtest_mimic::{run_tests, Arguments, Outcome, Test};
use std::fs::{read_dir, read_to_string};
use std::path::Path;
use wasmbin::{
    io::DecodeError,
    visit::{Visit, VisitError},
    Module,
};
use wast::parser::{parse, ParseBuffer};
use wast::Wast;

const IGNORED_ERRORS: &[&str] = &[
    // We don't perform cross-section analysis.
    "function and code section have inconsistent lengths",
    "data count section required",
    "data count and data section have inconsistent lengths",
    // We allow non-zero table and memory IDs already.
    "zero flag expected",
    // We don't perform full function analysis either.
    "too many locals",
];

const IGNORED_MODULES: &[&[u8]] = &[
    // See https://github.com/WebAssembly/bulk-memory-operations/issues/153.
    &[
        0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x00, 0x0B, 0x07,
        0x01, 0x80, 0x00, 0x41, 0x00, 0x0B, 0x00,
    ],
    // See https://github.com/WebAssembly/bulk-memory-operations/issues/153.
    &[
        0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00, 0x04, 0x04, 0x01, 0x70, 0x00, 0x00, 0x09,
        0x07, 0x01, 0x80, 0x00, 0x41, 0x00, 0x0B, 0x00,
    ],
    // An `assert_malformed` test in bulk-memory proposal that becomes well-formed when threads are enabled.
    #[cfg(all(feature = "bulk-memory-operations", feature = "threads"))]
    &[
        0x00, b'a', b's', b'm', 0x01, 0x00, 0x00, 0x00, 0x05, 0x03, 0x01, 0x02, 0x00,
    ],
];

struct WasmTest {
    module: Vec<u8>,
    expect_result: Result<(), String>,
}

#[throws]
fn read_tests_from_file(path: &Path, dest: &mut Vec<Test<WasmTest>>, ignore_malformed: bool) {
    let src = read_to_string(path)?;
    let set_err_path_text = |mut err: wast::Error| {
        err.set_path(path);
        err.set_text(&src);
        err
    };
    let buf = ParseBuffer::new(&src).map_err(set_err_path_text)?;
    let wast = parse::<Wast>(&buf).map_err(set_err_path_text)?;
    for directive in wast.directives {
        let (span, mut module, expect_result) = match directive {
            // Expect errors for assert_malformed on binary or AST modules.
            wast::WastDirective::AssertMalformed {
                span,
                module: wast::QuoteModule::Module(module),
                message,
            }
            // Unlike other AssertInvalid, this is actually something we
            // check at the parsing time, because it's part of our
            // typesystem and doesn't require cross-function or
            // cross-section checks.
            //
            // See https://github.com/WebAssembly/simd/issues/256 for accepted
            // but pending suggestion to change proposal to match this as well.
            | wast::WastDirective::AssertInvalid {
                span,
                module,
                message: message @ "invalid lane index",
            } => (span, module, Err(message.to_owned())),
            // Expect successful parsing for regular AST modules.
            wast::WastDirective::Module(module) => (module.span, module, Ok(())),
            // Counter-intuitively, expect successful parsing for modules that are supposed
            // to error out at runtime or linking stage, too.
            wast::WastDirective::AssertInvalid { span, module, .. }
            | wast::WastDirective::AssertUnlinkable { span, module, .. } => (span, module, Ok(())),
            _ => {
                // Skipping interpreted
                continue;
            }
        };
        let (line, col) = span.linecol_in(&src);
        let module = module.encode()?;
        dest.push(Test {
            name: format!("{}:{}:{}", path.display(), line + 1, col + 1),
            kind: String::default(),
            is_ignored: IGNORED_MODULES.contains(&module.as_slice())
                || match &expect_result {
                    Ok(()) => false,
                    Err(err) => ignore_malformed || IGNORED_ERRORS.contains(&err.as_str()),
                },
            is_bench: false,
            data: WasmTest {
                module,
                expect_result,
            },
        });
    }
}

#[throws]
fn read_tests_from_dir(path: &Path, dest: &mut Vec<Test<WasmTest>>, ignore_malformed: bool) {
    for file in read_dir(path)? {
        let path = file?.path();
        if path.extension().map_or(false, |ext| ext == "wast") {
            read_tests_from_file(&path, dest, ignore_malformed)?;
        }
    }
}

#[throws]
fn read_all_tests(path: &Path) -> (Vec<Test<WasmTest>>, bool) {
    let mut tests = Vec::new();
    let proposals_dir = path.join("proposals");

    macro_rules! read_proposal_tests {
        ($name:literal) => {
            if cfg!(feature = $name) {
                read_tests_from_dir(&proposals_dir.join($name), &mut tests, false).context($name)?
            }
        };
    }

    read_proposal_tests!("bulk-memory-operations");
    read_proposal_tests!("reference-types");
    read_proposal_tests!("simd");
    read_proposal_tests!("tail-call");
    read_proposal_tests!("threads");

    let has_proposals = !tests.is_empty();

    read_tests_from_dir(path, &mut tests, has_proposals)?;

    if tests.is_empty() {
        bail!("Couldn't find any tests. Did you run `git submodule update --init`?");
    }

    (tests, has_proposals)
}

fn unlazify<T: Visit>(mut wasm: T) -> Result<T, DecodeError> {
    match wasm.visit_mut(|()| {}) {
        Ok(()) => Ok(wasm),
        Err(err) => match err {
            VisitError::LazyDecode(err) => Err(err),
            VisitError::Custom(err) => match err {},
        },
    }
}

#[throws]
fn run_test(test: &WasmTest) {
    let mut slice = test.module.as_slice();
    let module = match (Module::decode_from(&mut slice).and_then(unlazify), &test.expect_result) {
        (Ok(ref module), Err(err)) => bail!("Expected an invalid module definition with an error: {}\nParsed part: {:02X?}\nGot module: {:02X?}", err, test.module, module),
        (Err(err), Ok(())) => bail!(
            "Expected a valid module definition, but got an error\nParsed part: {:02X?}\nUnparsed part: {:02X?}\nError: {:#}",
            &test.module[..test.module.len() - slice.len()],
            slice,
            err
        ),
        (Ok(module), Ok(())) => module,
        (Err(_), Err(_)) => return,
    };
    let out = module.encode_into(Vec::new())?;
    if out != test.module {
        // In the rare case that binary representation doesn't match, it
        // might be because the test uses longer LEB128 form than
        // required. Verify that at least decoding it back produces the
        // same module.
        let module2 = Module::decode_from(out.as_slice())?;
        if module != module2 {
            bail!(
                "Roundtrip mismatch. Old: {:#?}\nNew: {:#?}",
                module,
                module2
            );
        }
    }
}

#[throws]
fn main() {
    let (tests, has_proposals) = read_all_tests(&Path::new("tests").join("testsuite"))?;

    run_tests(&Arguments::from_args(), tests, |test| {
        match run_test(&test.data) {
            Ok(()) => Outcome::Passed,
            Err(err) => Outcome::Failed {
                msg: Some(err.to_string()),
            },
        }
    })
    .exit_if_failed();

    if has_proposals {
        eprintln!(
            "Proposals were enabled, so upstream `assert_malformed` tests were ignored.\n\
             Re-run without any proposals enabled for the full upstream test coverage."
        );
    }
}
<|endoftext|>


<commit_before>// This is a test which attempts to blow out the system limit with how many
// arguments can be passed to a process. This'll successively call rustc with
// larger and larger argument lists in an attempt to find one that's way too
// big for the system at hand. This file itself is then used as a "linker" to
// detect when the process creation succeeds.
//
// Eventually we should see an argument that looks like `@` as we switch from
// passing literal arguments to passing everything in the file.

use std::collections::HashSet;
use std::env;
use std::fs::{self, File};
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};
use std::process::Command;

fn write_test_case(file: &Path, n: usize) -> HashSet<String> {
    let mut libs = HashSet::new();
    let mut f = BufWriter::new(File::create(&file).unwrap());
    let mut prefix = String::new();
    for _ in 0..n {
        prefix.push_str("foo");
    }
    for i in 0..n {
        writeln!(f, "#[link(name = \"S{}{}S\")]", prefix, i).unwrap();
        libs.insert(format!("{}{}", prefix, i));
    }
    writeln!(f, "extern {{}}\nfn main() {{}}").unwrap();
    f.into_inner().unwrap();

    libs
}

fn read_linker_args(path: &Path) -> String {
    let contents = fs::read(path).unwrap();
    if cfg!(target_env = "msvc") {
        let mut i = contents.chunks(2).map(|c| {
            c[0] as u16 | ((c[1] as u16) << 8)
        });
        assert_eq!(i.next(), Some(0xfeff), "Expected UTF-16 BOM");
        String::from_utf16(&i.collect::<Vec<u16>>()).unwrap()
    } else {
        String::from_utf8(contents).unwrap()
    }
}

fn main() {
    let tmpdir = PathBuf::from(env::var_os("TMPDIR").unwrap());
    let ok = tmpdir.join("ok");
    if env::var("YOU_ARE_A_LINKER").is_ok() {
        if let Some(file) = env::args_os().find(|a| a.to_string_lossy().contains("@")) {
            let file = file.to_str().expect("non-utf8 file argument");
            fs::copy(&file[1..], &ok).unwrap();
        }
        return
    }

    let rustc = env::var_os("RUSTC").unwrap_or("rustc".into());
    let me_as_linker = format!("linker={}", env::current_exe().unwrap().display());
    for i in (1..).map(|i| i * 100) {
        println!("attempt: {}", i);
        let file = tmpdir.join("bar.rs");
        let mut expected_libs = write_test_case(&file, i);

        drop(fs::remove_file(&ok));
        let output = Command::new(&rustc)
            .arg(&file)
            .arg("-C").arg(&me_as_linker)
            .arg("--out-dir").arg(&tmpdir)
            .env("YOU_ARE_A_LINKER", "1")
            .output()
            .unwrap();

        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            panic!("status: {}\nstdout:\n{}\nstderr:\n{}",
                   output.status,
                   String::from_utf8_lossy(&output.stdout),
                   stderr.lines().map(|l| {
                       if l.len() > 200 {
                           format!("{}...\n", &l[..200])
                       } else {
                           format!("{}\n", l)
                       }
                   }).collect::<String>());
        }

        if !ok.exists() {
            continue
        }

        let linker_args = read_linker_args(&ok);
        for mut arg in linker_args.split('S') {
            expected_libs.remove(arg);
        }

        assert!(
            expected_libs.is_empty(),
            "expected but missing libraries: {:#?}\nlinker arguments: \n{}",
            expected_libs,
            linker_args,
        );

        break
    }
}
<commit_msg>Rollup merge of #72741 - tmiasko:unused-mut, r=Mark-Simulacrum<commit_after>// This is a test which attempts to blow out the system limit with how many
// arguments can be passed to a process. This'll successively call rustc with
// larger and larger argument lists in an attempt to find one that's way too
// big for the system at hand. This file itself is then used as a "linker" to
// detect when the process creation succeeds.
//
// Eventually we should see an argument that looks like `@` as we switch from
// passing literal arguments to passing everything in the file.

use std::collections::HashSet;
use std::env;
use std::fs::{self, File};
use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};
use std::process::Command;

fn write_test_case(file: &Path, n: usize) -> HashSet<String> {
    let mut libs = HashSet::new();
    let mut f = BufWriter::new(File::create(&file).unwrap());
    let mut prefix = String::new();
    for _ in 0..n {
        prefix.push_str("foo");
    }
    for i in 0..n {
        writeln!(f, "#[link(name = \"S{}{}S\")]", prefix, i).unwrap();
        libs.insert(format!("{}{}", prefix, i));
    }
    writeln!(f, "extern {{}}\nfn main() {{}}").unwrap();
    f.into_inner().unwrap();

    libs
}

fn read_linker_args(path: &Path) -> String {
    let contents = fs::read(path).unwrap();
    if cfg!(target_env = "msvc") {
        let mut i = contents.chunks(2).map(|c| {
            c[0] as u16 | ((c[1] as u16) << 8)
        });
        assert_eq!(i.next(), Some(0xfeff), "Expected UTF-16 BOM");
        String::from_utf16(&i.collect::<Vec<u16>>()).unwrap()
    } else {
        String::from_utf8(contents).unwrap()
    }
}

fn main() {
    let tmpdir = PathBuf::from(env::var_os("TMPDIR").unwrap());
    let ok = tmpdir.join("ok");
    if env::var("YOU_ARE_A_LINKER").is_ok() {
        if let Some(file) = env::args_os().find(|a| a.to_string_lossy().contains("@")) {
            let file = file.to_str().expect("non-utf8 file argument");
            fs::copy(&file[1..], &ok).unwrap();
        }
        return
    }

    let rustc = env::var_os("RUSTC").unwrap_or("rustc".into());
    let me_as_linker = format!("linker={}", env::current_exe().unwrap().display());
    for i in (1..).map(|i| i * 100) {
        println!("attempt: {}", i);
        let file = tmpdir.join("bar.rs");
        let mut expected_libs = write_test_case(&file, i);

        drop(fs::remove_file(&ok));
        let output = Command::new(&rustc)
            .arg(&file)
            .arg("-C").arg(&me_as_linker)
            .arg("--out-dir").arg(&tmpdir)
            .env("YOU_ARE_A_LINKER", "1")
            .output()
            .unwrap();

        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            panic!("status: {}\nstdout:\n{}\nstderr:\n{}",
                   output.status,
                   String::from_utf8_lossy(&output.stdout),
                   stderr.lines().map(|l| {
                       if l.len() > 200 {
                           format!("{}...\n", &l[..200])
                       } else {
                           format!("{}\n", l)
                       }
                   }).collect::<String>());
        }

        if !ok.exists() {
            continue
        }

        let linker_args = read_linker_args(&ok);
        for arg in linker_args.split('S') {
            expected_libs.remove(arg);
        }

        assert!(
            expected_libs.is_empty(),
            "expected but missing libraries: {:#?}\nlinker arguments: \n{}",
            expected_libs,
            linker_args,
        );

        break
    }
}
<|endoftext|>


<commit_before>extern crate rusty_raft;
extern crate rand;
extern crate capnp;
mod relay_server;
mod mock_state_machine;

use mock_state_machine::*;
use relay_server::*;
use rusty_raft::server::{start_server_with_config, ServerHandle};
use rusty_raft::client::RaftConnection;
use rusty_raft::common::Config;

use rand::{thread_rng, Rng};
use rand::distributions::{IndependentSample, Range};

use std::collections::HashMap;
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::mpsc::{Receiver, channel};
use std::time::Duration;
use std::fs;

// Container around a MockStateMachine Receiver and a handle
// to the raft server that is running that instance of the state machine
struct StateMachineHandle {
    rx: Receiver<Vec<u8>>,
    _server_handle: ServerHandle,
    id: u64,
    state_filename: String,
    log_filename: String
}

impl Drop for StateMachineHandle {
    /// Deletes the state and log files
    fn drop (&mut self) {
        fs::remove_file(&self.state_filename).unwrap();
        fs::remove_file(&self.log_filename).unwrap();
    }
}

/// Starts a relay server that binds to num_servers os-assigned local ports
fn start_relay_server (num_servers: u64) -> (RelayServer, HashMap<u64, SocketAddr>) {
    let relay_server = RelayServer::new_with_random_addresses(num_servers);
    let addrs: HashMap<u64, SocketAddr> =
        relay_server.get_bound_addresses()
        .into_iter()
        .enumerate()
        .map(|(i, addr)| (i as u64, addr))
        .collect();

    (relay_server, addrs)
}

/// Starts up a raft server behind each port in the relay server and sets up the mapping
/// from the relay address to the raft server address.
/// Returns a StateMachineHandle that can be used to communicate with the raft server (through the
/// ServerHandle) or check on the state of the MockStateMachine
fn start_raft_servers(relay_server: &mut RelayServer, addrs: &HashMap<u64, SocketAddr>) -> Vec<StateMachineHandle> {
    const HEARTBEAT_TIMEOUT: u64 = 75;
    const STATE_FILENAME_LEN: usize = 20;
    println!("Starting {} raft servers", addrs.len());

    (0..addrs.len() as u64)
    .map(|i| {
        // create a config object
        let random_filename: String = thread_rng().gen_ascii_chars().take(STATE_FILENAME_LEN).collect();
        let state_filename = String::from("/tmp/state_") + &random_filename;
        let log_filename = String::from("/tmp/log_") + &random_filename;

        let (tx, rx) = channel();
        let state_machine = Box::new(MockStateMachine::new_with_sender(tx));
        let server_handle = {
            let config = Config::new (addrs.clone(), i, "127.0.0.1:0".to_socket_addrs().unwrap().next().unwrap(),
                    Duration::from_millis(HEARTBEAT_TIMEOUT), state_filename.clone(), &log_filename);
            start_server_with_config(config, move || state_machine).unwrap()
        };

        // map this server through the relay server
        relay_server.relay_address(*addrs.get(&i).unwrap(), server_handle.get_local_addr());
        StateMachineHandle {rx: rx, _server_handle: server_handle, id: i,
                            state_filename: state_filename, log_filename: log_filename}
    })
    .collect()
}

#[test]
/// This test is as much a sanity check on our testing code as on the raft code.
/// It just makes sure we can start up a static cluster of servers without crashing
fn it_starts_up_a_cluster() {
    const NUM_SERVERS: u64 = 3;

    let (mut relay_server, addrs) = start_relay_server(NUM_SERVERS);
    start_raft_servers(&mut relay_server, &addrs);
}

#[test]
fn it_replicates_an_entry() {
    const NUM_SERVERS: u64 = 3;
    const REPLICATE_TIMEOUT: u64 = 5000;
    const DATA_LENGTH: usize = 1;
    let replicate_timeout = Duration::from_millis(REPLICATE_TIMEOUT);

    let (mut relay_server, addrs) = start_relay_server(NUM_SERVERS);
    let state_machines = start_raft_servers(&mut relay_server, &addrs);

    let data: String = thread_rng().gen_ascii_chars().take(DATA_LENGTH).collect();
    let mut raft_db = RaftConnection::new_with_session(&addrs.clone()).unwrap();
    assert!(raft_db.command(data.as_bytes()).is_ok());

    // ensure that all state machines replicated the entry
    assert!(state_machines
                .iter()
                .map(|handle|handle.rx.recv_timeout(replicate_timeout).unwrap())
                .all(|vec| vec.iter()
                              .zip(data.clone().into_bytes())
                              .all(|(a, b)| *a == b)));
}

#[test]
fn it_handles_a_failure() {
    const NUM_SERVERS: u64 = 4;
    const REPLICATE_TIMEOUT: u64 = 100;
    const DATA_LENGTH: usize = 1;
    let replicate_timeout = Duration::from_millis(REPLICATE_TIMEOUT);

    let (mut relay_server, mut addrs) = start_relay_server(NUM_SERVERS);
    let mut state_machines = start_raft_servers(&mut relay_server, &addrs);

    // bring one server offline
    let index: u64 = Range::new(0, state_machines.len()).ind_sample(&mut thread_rng()) as u64;
    addrs.remove(&index);
    state_machines.remove(index as usize);

    // generate the client append RPC and send it
    let data: String = thread_rng().gen_ascii_chars().take(DATA_LENGTH).collect();
    let mut raft_db = RaftConnection::new_with_session(&addrs.clone()).unwrap();
    assert!(raft_db.command(data.as_bytes()).is_ok());

    // ensure that all online state machines replicated the entry
    assert!(state_machines
                .iter()
                .filter(|handle| handle.id != index)
                .map(|handle| {
                    let result = handle.rx.recv_timeout(replicate_timeout).unwrap();
                    result
                })
                .all(|vec| vec.iter()
                              .zip(data.clone().into_bytes())
                              .all(|(a, b)| *a == b)));
}
<commit_msg>integration test: revived server catches up properly<commit_after>extern crate rusty_raft;
extern crate rand;
extern crate capnp;
mod relay_server;
mod mock_state_machine;

use mock_state_machine::*;
use relay_server::*;
use rusty_raft::server::{start_server_with_config, ServerHandle};
use rusty_raft::client::RaftConnection;
use rusty_raft::common::Config;

use rand::{thread_rng, Rng};
use rand::distributions::{IndependentSample, Range};

use std::collections::HashMap;
use std::net::{SocketAddr, ToSocketAddrs};
use std::sync::mpsc::{Receiver, channel};
use std::time::Duration;
use std::fs;

// Container around a MockStateMachine Receiver and a handle
// to the raft server that is running that instance of the state machine
struct StateMachineHandle {
    rx: Receiver<Vec<u8>>,
    server_handle: ServerHandle,
    id: u64,
    state_filename: String,
    log_filename: String
}

impl Drop for StateMachineHandle {
    /// Deletes the state and log files
    fn drop (&mut self) {
        fs::remove_file(&self.state_filename).unwrap();
        fs::remove_file(&self.log_filename).unwrap();
    }
}

/// Starts a relay server that binds to num_servers os-assigned local ports
fn start_relay_server (num_servers: u64) -> (RelayServer, HashMap<u64, SocketAddr>) {
    let relay_server = RelayServer::new_with_random_addresses(num_servers);
    let addrs: HashMap<u64, SocketAddr> =
        relay_server.get_bound_addresses()
        .into_iter()
        .enumerate()
        .map(|(i, addr)| (i as u64, addr))
        .collect();

    (relay_server, addrs)
}

/// Starts up a raft server behind each port in the relay server and sets up the mapping
/// from the relay address to the raft server address.
/// Returns a StateMachineHandle that can be used to communicate with the raft server (through the
/// ServerHandle) or check on the state of the MockStateMachine
fn start_raft_servers(relay_server: &mut RelayServer, addrs: &HashMap<u64, SocketAddr>) -> Vec<StateMachineHandle> {
    println!("Starting {} raft servers", addrs.len());

    (0..addrs.len() as u64)
    .map(|i| start_raft_server(i, relay_server, addrs, None))
    .collect()
}

fn start_raft_server(i: u64, relay_server: &mut RelayServer, addrs: &HashMap<u64, SocketAddr>, local_addr: Option<SocketAddr>) -> StateMachineHandle {
    const HEARTBEAT_TIMEOUT: u64 = 75;
    const STATE_FILENAME_LEN: usize = 20;
    // create a config object
    let random_filename: String = thread_rng().gen_ascii_chars().take(STATE_FILENAME_LEN).collect();
    let state_filename = String::from("/tmp/state_") + &random_filename;
    let log_filename = String::from("/tmp/log_") + &random_filename;

    let (tx, rx) = channel();
    let state_machine = Box::new(MockStateMachine::new_with_sender(tx));
    let local_address = local_addr.unwrap_or("127.0.0.1:0".to_socket_addrs().unwrap().next().unwrap());
    let server_handle = {
        let config = Config::new (addrs.clone(), i, local_address,
                Duration::from_millis(HEARTBEAT_TIMEOUT), state_filename.clone(), &log_filename);
        start_server_with_config(config, move || state_machine).unwrap()
    };
    // map this server through the relay server;
    if local_addr.is_none() {
        relay_server.relay_address(*addrs.get(&i).unwrap(), server_handle.get_local_addr());
    }
    StateMachineHandle {rx: rx, server_handle: server_handle, id: i,
                        state_filename: state_filename, log_filename: log_filename}
}

#[test]
/// This test is as much a sanity check on our testing code as on the raft code.
/// It just makes sure we can start up a static cluster of servers without crashing
fn it_starts_up_a_cluster() {
    const NUM_SERVERS: u64 = 3;

    let (mut relay_server, addrs) = start_relay_server(NUM_SERVERS);
    start_raft_servers(&mut relay_server, &addrs);
}

#[test]
fn it_replicates_an_entry() {
    const NUM_SERVERS: u64 = 3;
    const REPLICATE_TIMEOUT: u64 = 5000;
    const DATA_LENGTH: usize = 1;
    let replicate_timeout = Duration::from_millis(REPLICATE_TIMEOUT);

    let (mut relay_server, addrs) = start_relay_server(NUM_SERVERS);
    let state_machines = start_raft_servers(&mut relay_server, &addrs);

    let data: String = thread_rng().gen_ascii_chars().take(DATA_LENGTH).collect();
    let mut raft_db = RaftConnection::new_with_session(&addrs.clone()).unwrap();
    assert!(raft_db.command(data.as_bytes()).is_ok());

    // ensure that all state machines replicated the entry
    assert!(state_machines
                .iter()
                .map(|handle|handle.rx.recv_timeout(replicate_timeout).unwrap())
                .all(|vec| vec.iter()
                              .zip(data.clone().into_bytes())
                              .all(|(a, b)| *a == b)));
}

#[test]
fn it_handles_a_failure() {
    const NUM_SERVERS: u64 = 4;
    const REPLICATE_TIMEOUT: u64 = 100;
    const DATA_LENGTH: usize = 1;
    let replicate_timeout = Duration::from_millis(REPLICATE_TIMEOUT);

    let (mut relay_server, mut addrs) = start_relay_server(NUM_SERVERS);
    let mut state_machines = start_raft_servers(&mut relay_server, &addrs);

    // bring one server offline
    let index: u64 = Range::new(0, state_machines.len()).ind_sample(&mut thread_rng()) as u64;
    addrs.remove(&index);
    state_machines.remove(index as usize);

    // generate the client append RPC and send it
    let data: String = thread_rng().gen_ascii_chars().take(DATA_LENGTH).collect();
    let mut raft_db = RaftConnection::new_with_session(&addrs.clone()).unwrap();
    assert!(raft_db.command(data.as_bytes()).is_ok());

    // ensure that all online state machines replicated the entry
    assert!(state_machines
                .iter()
                .filter(|handle| handle.id != index)
                .map(|handle| {
                    let result = handle.rx.recv_timeout(replicate_timeout).unwrap();
                    result
                })
                .all(|vec| vec.iter()
                              .zip(data.clone().into_bytes())
                              .all(|(a, b)| *a == b)));
}

fn issue_command_and_assert_ok(db: &mut RaftConnection) -> Vec<u8> {
    const DATA_LENGTH: usize = 1;
    let data: String = thread_rng().gen_ascii_chars().take(DATA_LENGTH).collect();
    assert!(db.command(data.as_bytes()).is_ok());
    data.as_bytes().to_vec()
}

fn assert_data_replicated<P>(state_machines: &Vec<StateMachineHandle>, data: &[u8],
                             predicate: P, timeout: Option<Duration>)
    where for <'r> P: FnMut(&'r &StateMachineHandle) -> bool {
    state_machines.iter()
                 .filter(predicate)
                 .map(|handle| {
                     let result = if timeout.is_some() {
                         handle.rx.recv_timeout(timeout.unwrap()).unwrap()
                     } else {
                         handle.rx.recv().unwrap()
                     };
                     result
                 })
                 .all(|vec| vec.iter()
                              .zip(data.clone())
                              .all(|(a, b)| *a == *b));
}

#[test]
fn it_catches_up_when_behind() {
    const NUM_SERVERS: u64 = 4;
    const REPLICATE_TIMEOUT: u64 = 100;

    let (mut relay_server, mut addrs) = start_relay_server(NUM_SERVERS);
    let mut state_machines = start_raft_servers(&mut relay_server, &addrs);

    // Bring a server down.
    let index: u64 = Range::new(0, state_machines.len()).ind_sample(&mut thread_rng()) as u64;
    let address = { // Shut down server.
        let sm = state_machines.remove(index as usize);
        sm.server_handle.get_local_addr()
    };

    // Connect client.
    let mut raft_db = RaftConnection::new_with_session(&addrs.clone()).unwrap();

    // Issue command.
    let data = issue_command_and_assert_ok(&mut raft_db);
    let replicate_timeout = Duration::from_millis(REPLICATE_TIMEOUT);
    // ensure that all online state machines replicated the entry
    assert_data_replicated(&state_machines, &data, |handle| handle.id != index,
                           Some(replicate_timeout));

    println!("[ Test ] Bringing server back online.");
    // Bring server back up.
    state_machines.insert(index as usize, start_raft_server(index, &mut relay_server, &addrs,
                                                            Some(address)));
    // Make sure the zombie server got the message.
    assert_data_replicated(&state_machines, &data, |handle| handle.id == index, None);
    { // Issue command again.
        let data = issue_command_and_assert_ok(&mut raft_db);
        // ensure that ALL state machines replicated the entry
        assert_data_replicated(&state_machines, &data, |_| true, None);
    }
}
<|endoftext|>


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

// Issue #2263.

// Should pass region checking.
fn ok(f: @fn(x: &uint)) {
    // Here, g is a function that can accept a uint pointer with
    // lifetime r, and f is a function that can accept a uint pointer
    // with any lifetime.  The assignment g = f should be OK (i.e.,
    // f's type should be a subtype of g's type), because f can be
    // used in any context that expects g's type.  But this currently
    // fails.
    let mut g: @fn<'r>(y: &'r uint) = |x| { };
    g = f;
}

// This version is the same as above, except that here, g's type is
// inferred.
fn ok_inferred(f: @fn(x: &uint)) {
    let mut g: @fn<'r>(x: &'r uint) = |_| {};
    g = f;
}

pub fn main() {
}
<commit_msg>test: xfail-pretty one of the run-pass tests. rs=burningtree<commit_after>// xfail-pretty

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

// Issue #2263.

// Should pass region checking.
fn ok(f: @fn(x: &uint)) {
    // Here, g is a function that can accept a uint pointer with
    // lifetime r, and f is a function that can accept a uint pointer
    // with any lifetime.  The assignment g = f should be OK (i.e.,
    // f's type should be a subtype of g's type), because f can be
    // used in any context that expects g's type.  But this currently
    // fails.
    let mut g: @fn<'r>(y: &'r uint) = |x| { };
    g = f;
}

// This version is the same as above, except that here, g's type is
// inferred.
fn ok_inferred(f: @fn(x: &uint)) {
    let mut g: @fn<'r>(x: &'r uint) = |_| {};
    g = f;
}

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


<commit_before>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Low-level glfw bindings. Includes public exports of core types and constants.

use std::libc::*;

// re-export constants
pub use consts::*;

// TODO: Will have to be changed once we can do external C callbacks nicely

pub type GLFWglproc             = *u8;  // typedef void (*GLFWglproc)(void);

pub type GLFWerrorfun           = *u8;  // typedef void (* GLFWerrorfun)(int,const char*);
pub type GLFWwindowposfun       = *u8;  // typedef void (* GLFWwindowposfun)(*GLFWwindow,int,int);
pub type GLFWwindowsizefun      = *u8;  // typedef void (* GLFWwindowsizefun)(*GLFWwindow,int,int);
pub type GLFWwindowclosefun     = *u8;  // typedef void (* GLFWwindowclosefun)(*GLFWwindow);
pub type GLFWwindowrefreshfun   = *u8;  // typedef void (* GLFWwindowrefreshfun)(*GLFWwindow);
pub type GLFWwindowfocusfun     = *u8;  // typedef void (* GLFWwindowfocusfun)(*GLFWwindow,int);
pub type GLFWwindowiconifyfun   = *u8;  // typedef void (* GLFWwindowiconifyfun)(*GLFWwindow,int);
pub type GLFWframebuffersizefun = *u8;  // typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int);
pub type GLFWmousebuttonfun     = *u8;  // typedef void (* GLFWmousebuttonfun)(*GLFWwindow,int,int,int);
pub type GLFWcursorposfun       = *u8;  // typedef void (* GLFWcursorposfun)(*GLFWwindow,double,double);
pub type GLFWcursorenterfun     = *u8;  // typedef void (* GLFWcursorenterfun)(*GLFWwindow,int);
pub type GLFWscrollfun          = *u8;  // typedef void (* GLFWscrollfun)(*GLFWwindow,double,double);
pub type GLFWkeyfun             = *u8;  // typedef void (* GLFWkeyfun)(*GLFWwindow,int,int,int);
pub type GLFWcharfun            = *u8;  // typedef void (* GLFWcharfun)(*GLFWwindow,unsigned int);
pub type GLFWmonitorfun         = *u8;  // typedef void (* GLFWmonitorfun)(*GLFWmonitor,int);

pub struct GLFWmonitor;

pub struct GLFWwindow;

pub struct GLFWgammaramp {
    red:    *c_ushort,
    green:  *c_ushort,
    blue:   *c_ushort,
    size:   c_uint,
}

pub struct GLFWvidmode {
    width:       c_int,
    height:      c_int,
    redBits:     c_int,
    greenBits:   c_int,
    blueBits:    c_int,
    refreshRate: c_int,
}

// Linking

#[nolink]
#[cfg(target_os = "macos")]
#[link_args="-lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework CoreFoundation"]
pub extern { }

#[nolink]
#[cfg(target_os = "linux")]
#[link_args="-lglfw -lX11 -lXrandr -lXi -lXxf86vm"]
pub extern { }

// C function bindings

pub extern "C" {
    pub fn glfwInit() -> c_int;
    pub fn glfwTerminate();
    pub fn glfwGetVersion(major: *c_int, minor: *c_int, rev: *c_int);
    pub fn glfwGetVersionString() -> *c_char;

    pub fn glfwSetErrorCallback(cbfun: GLFWerrorfun) -> GLFWerrorfun;

    pub fn glfwGetMonitors(count: *c_int) -> **GLFWmonitor;
    pub fn glfwGetPrimaryMonitor() -> *GLFWmonitor;
    pub fn glfwGetMonitorPos(monitor: *GLFWmonitor, xpos: *c_int, ypos: *c_int);
    pub fn glfwGetMonitorPhysicalSize(monitor: *GLFWmonitor, width: *c_int, height: *c_int);
    pub fn glfwGetMonitorName(monitor: *GLFWmonitor) -> *c_char;
    pub fn glfwSetMonitorCallback(cbfun: GLFWmonitorfun) -> GLFWmonitorfun;
    pub fn glfwGetVideoModes(monitor: *GLFWmonitor, count: *c_int) -> *GLFWvidmode;
    pub fn glfwGetVideoMode(monitor: *GLFWmonitor) -> *GLFWvidmode;
    pub fn glfwSetGamma(monitor: *GLFWmonitor, gamma: c_float);
    pub fn glfwGetGammaRamp(monitor: *GLFWmonitor) -> *GLFWgammaramp;
    pub fn glfwSetGammaRamp(monitor: *GLFWmonitor, ramp: *GLFWgammaramp);

    pub fn glfwDefaultWindowHints();
    pub fn glfwWindowHint(target: c_int, hint: c_int);
    pub fn glfwCreateWindow(width: c_int, height: c_int, title: *c_char, monitor: *GLFWmonitor, share: *GLFWwindow) -> *GLFWwindow;
    pub fn glfwDestroyWindow(window: *GLFWwindow);
    pub fn glfwWindowShouldClose(window: *GLFWwindow) -> c_int;
    pub fn glfwSetWindowShouldClose(window: *GLFWwindow, value: c_int);
    pub fn glfwSetWindowTitle(window: *GLFWwindow, title: *c_char);
    pub fn glfwGetWindowPos(window: *GLFWwindow, xpos: *c_int, ypos: *c_int);
    pub fn glfwSetWindowPos(window: *GLFWwindow, xpos: c_int, ypos: c_int);
    pub fn glfwGetWindowSize(window: *GLFWwindow, width: *c_int, height: *c_int);
    pub fn glfwSetWindowSize(window: *GLFWwindow, width: c_int, height: c_int);
    pub fn glfwGetFramebufferSize(window: *GLFWwindow, width: *c_int, height: *c_int);
    pub fn glfwIconifyWindow(window: *GLFWwindow);
    pub fn glfwRestoreWindow(window: *GLFWwindow);
    pub fn glfwShowWindow(window: *GLFWwindow);
    pub fn glfwHideWindow(window: *GLFWwindow);
    pub fn glfwGetWindowMonitor(window: *GLFWwindow) -> *GLFWmonitor;
    pub fn glfwGetWindowAttrib(window: *GLFWwindow, attrib: c_int) -> c_int;
    pub fn glfwSetWindowUserPointer(window: *GLFWwindow, pointer: *c_void);
    pub fn glfwGetWindowUserPointer(window: *GLFWwindow) -> *c_void;
    pub fn glfwSetWindowPosCallback(window: *GLFWwindow, cbfun: GLFWwindowposfun) -> GLFWwindowposfun;
    pub fn glfwSetWindowSizeCallback(window: *GLFWwindow, cbfun: GLFWwindowsizefun) -> GLFWwindowsizefun;
    pub fn glfwSetWindowCloseCallback(window: *GLFWwindow, cbfun: GLFWwindowclosefun) -> GLFWwindowclosefun;
    pub fn glfwSetWindowRefreshCallback(window: *GLFWwindow, cbfun: GLFWwindowrefreshfun) -> GLFWwindowrefreshfun;
    pub fn glfwSetWindowFocusCallback(window: *GLFWwindow, cbfun: GLFWwindowfocusfun) -> GLFWwindowfocusfun;
    pub fn glfwSetWindowIconifyCallback(window: *GLFWwindow, cbfun: GLFWwindowiconifyfun) -> GLFWwindowiconifyfun;
    pub fn glfwSetFramebufferSizeCallback(window: *GLFWwindow, cbfun: GLFWframebuffersizefun) -> GLFWframebuffersizefun;

    pub fn glfwPollEvents();
    pub fn glfwWaitEvents();

    pub fn glfwGetInputMode(window: *GLFWwindow, mode: c_int) -> c_int;
    pub fn glfwSetInputMode(window: *GLFWwindow, mode: c_int, value: c_int);
    pub fn glfwGetKey(window: *GLFWwindow, key: c_int) -> c_int;
    pub fn glfwGetMouseButton(window: *GLFWwindow, button: c_int) -> c_int;
    pub fn glfwGetCursorPos(window: *GLFWwindow, xpos: *c_double, ypos: *c_double);
    pub fn glfwSetCursorPos(window: *GLFWwindow, xpos: c_double, ypos: c_double);
    pub fn glfwSetKeyCallback(window: *GLFWwindow, cbfun: GLFWkeyfun) -> GLFWkeyfun;
    pub fn glfwSetCharCallback(window: *GLFWwindow, cbfun: GLFWcharfun) -> GLFWcharfun;
    pub fn glfwSetMouseButtonCallback(window: *GLFWwindow, cbfun: GLFWmousebuttonfun) -> GLFWmousebuttonfun;
    pub fn glfwSetCursorPosCallback(window: *GLFWwindow, cbfun: GLFWcursorposfun) -> GLFWcursorposfun;
    pub fn glfwSetCursorEnterCallback(window: *GLFWwindow, cbfun: GLFWcursorenterfun) -> GLFWcursorenterfun;
    pub fn glfwSetScrollCallback(window: *GLFWwindow, cbfun: GLFWscrollfun) -> GLFWscrollfun;

    pub fn glfwJoystickPresent(joy: c_int) -> c_int;
    pub fn glfwGetJoystickAxes(joy: c_int, count: *c_int) -> *c_float;
    pub fn glfwGetJoystickButtons(joy: c_int, count: *c_int) -> *c_uchar;
    pub fn glfwGetJoystickName(joy: c_int) -> *c_char;

    pub fn glfwSetClipboardString(window: *GLFWwindow, string: *c_char);
    pub fn glfwGetClipboardString(window: *GLFWwindow) -> *c_char;

    pub fn glfwGetTime() -> c_double;
    pub fn glfwSetTime(time: c_double);

    pub fn glfwMakeContextCurrent(window: *GLFWwindow);
    pub fn glfwGetCurrentContext() -> *GLFWwindow;
    pub fn glfwSwapBuffers(window: *GLFWwindow);
    pub fn glfwSwapInterval(interval: c_int);
    pub fn glfwExtensionSupported(extension: *c_char) -> c_int;
    pub fn glfwGetProcAddress(procname: *c_char) -> GLFWglproc;

    // native APIs
    #[cfg(target_os="linux")]
    pub fn glfwGetX11Display() -> *c_void;
}
<commit_msg>Add more native ll functions<commit_after>// Copyright 2013 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Low-level glfw bindings. Includes public exports of core types and constants.

use std::libc::*;

// re-export constants
pub use consts::*;

// TODO: Will have to be changed once we can do external C callbacks nicely

pub type GLFWglproc             = *u8;  // typedef void (*GLFWglproc)(void);

pub type GLFWerrorfun           = *u8;  // typedef void (* GLFWerrorfun)(int,const char*);
pub type GLFWwindowposfun       = *u8;  // typedef void (* GLFWwindowposfun)(*GLFWwindow,int,int);
pub type GLFWwindowsizefun      = *u8;  // typedef void (* GLFWwindowsizefun)(*GLFWwindow,int,int);
pub type GLFWwindowclosefun     = *u8;  // typedef void (* GLFWwindowclosefun)(*GLFWwindow);
pub type GLFWwindowrefreshfun   = *u8;  // typedef void (* GLFWwindowrefreshfun)(*GLFWwindow);
pub type GLFWwindowfocusfun     = *u8;  // typedef void (* GLFWwindowfocusfun)(*GLFWwindow,int);
pub type GLFWwindowiconifyfun   = *u8;  // typedef void (* GLFWwindowiconifyfun)(*GLFWwindow,int);
pub type GLFWframebuffersizefun = *u8;  // typedef void (* GLFWframebuffersizefun)(GLFWwindow*,int,int);
pub type GLFWmousebuttonfun     = *u8;  // typedef void (* GLFWmousebuttonfun)(*GLFWwindow,int,int,int);
pub type GLFWcursorposfun       = *u8;  // typedef void (* GLFWcursorposfun)(*GLFWwindow,double,double);
pub type GLFWcursorenterfun     = *u8;  // typedef void (* GLFWcursorenterfun)(*GLFWwindow,int);
pub type GLFWscrollfun          = *u8;  // typedef void (* GLFWscrollfun)(*GLFWwindow,double,double);
pub type GLFWkeyfun             = *u8;  // typedef void (* GLFWkeyfun)(*GLFWwindow,int,int,int);
pub type GLFWcharfun            = *u8;  // typedef void (* GLFWcharfun)(*GLFWwindow,unsigned int);
pub type GLFWmonitorfun         = *u8;  // typedef void (* GLFWmonitorfun)(*GLFWmonitor,int);

pub struct GLFWmonitor;

pub struct GLFWwindow;

pub struct GLFWgammaramp {
    red:    *c_ushort,
    green:  *c_ushort,
    blue:   *c_ushort,
    size:   c_uint,
}

pub struct GLFWvidmode {
    width:       c_int,
    height:      c_int,
    redBits:     c_int,
    greenBits:   c_int,
    blueBits:    c_int,
    refreshRate: c_int,
}

// Linking

#[nolink]
#[cfg(target_os = "macos")]
#[link_args="-lglfw -framework Cocoa -framework OpenGL -framework IOKit -framework CoreFoundation"]
pub extern { }

#[nolink]
#[cfg(target_os = "linux")]
#[link_args="-lglfw -lX11 -lXrandr -lXi -lXxf86vm"]
pub extern { }

// C function bindings

pub extern "C" {
    pub fn glfwInit() -> c_int;
    pub fn glfwTerminate();
    pub fn glfwGetVersion(major: *c_int, minor: *c_int, rev: *c_int);
    pub fn glfwGetVersionString() -> *c_char;

    pub fn glfwSetErrorCallback(cbfun: GLFWerrorfun) -> GLFWerrorfun;

    pub fn glfwGetMonitors(count: *c_int) -> **GLFWmonitor;
    pub fn glfwGetPrimaryMonitor() -> *GLFWmonitor;
    pub fn glfwGetMonitorPos(monitor: *GLFWmonitor, xpos: *c_int, ypos: *c_int);
    pub fn glfwGetMonitorPhysicalSize(monitor: *GLFWmonitor, width: *c_int, height: *c_int);
    pub fn glfwGetMonitorName(monitor: *GLFWmonitor) -> *c_char;
    pub fn glfwSetMonitorCallback(cbfun: GLFWmonitorfun) -> GLFWmonitorfun;
    pub fn glfwGetVideoModes(monitor: *GLFWmonitor, count: *c_int) -> *GLFWvidmode;
    pub fn glfwGetVideoMode(monitor: *GLFWmonitor) -> *GLFWvidmode;
    pub fn glfwSetGamma(monitor: *GLFWmonitor, gamma: c_float);
    pub fn glfwGetGammaRamp(monitor: *GLFWmonitor) -> *GLFWgammaramp;
    pub fn glfwSetGammaRamp(monitor: *GLFWmonitor, ramp: *GLFWgammaramp);

    pub fn glfwDefaultWindowHints();
    pub fn glfwWindowHint(target: c_int, hint: c_int);
    pub fn glfwCreateWindow(width: c_int, height: c_int, title: *c_char, monitor: *GLFWmonitor, share: *GLFWwindow) -> *GLFWwindow;
    pub fn glfwDestroyWindow(window: *GLFWwindow);
    pub fn glfwWindowShouldClose(window: *GLFWwindow) -> c_int;
    pub fn glfwSetWindowShouldClose(window: *GLFWwindow, value: c_int);
    pub fn glfwSetWindowTitle(window: *GLFWwindow, title: *c_char);
    pub fn glfwGetWindowPos(window: *GLFWwindow, xpos: *c_int, ypos: *c_int);
    pub fn glfwSetWindowPos(window: *GLFWwindow, xpos: c_int, ypos: c_int);
    pub fn glfwGetWindowSize(window: *GLFWwindow, width: *c_int, height: *c_int);
    pub fn glfwSetWindowSize(window: *GLFWwindow, width: c_int, height: c_int);
    pub fn glfwGetFramebufferSize(window: *GLFWwindow, width: *c_int, height: *c_int);
    pub fn glfwIconifyWindow(window: *GLFWwindow);
    pub fn glfwRestoreWindow(window: *GLFWwindow);
    pub fn glfwShowWindow(window: *GLFWwindow);
    pub fn glfwHideWindow(window: *GLFWwindow);
    pub fn glfwGetWindowMonitor(window: *GLFWwindow) -> *GLFWmonitor;
    pub fn glfwGetWindowAttrib(window: *GLFWwindow, attrib: c_int) -> c_int;
    pub fn glfwSetWindowUserPointer(window: *GLFWwindow, pointer: *c_void);
    pub fn glfwGetWindowUserPointer(window: *GLFWwindow) -> *c_void;
    pub fn glfwSetWindowPosCallback(window: *GLFWwindow, cbfun: GLFWwindowposfun) -> GLFWwindowposfun;
    pub fn glfwSetWindowSizeCallback(window: *GLFWwindow, cbfun: GLFWwindowsizefun) -> GLFWwindowsizefun;
    pub fn glfwSetWindowCloseCallback(window: *GLFWwindow, cbfun: GLFWwindowclosefun) -> GLFWwindowclosefun;
    pub fn glfwSetWindowRefreshCallback(window: *GLFWwindow, cbfun: GLFWwindowrefreshfun) -> GLFWwindowrefreshfun;
    pub fn glfwSetWindowFocusCallback(window: *GLFWwindow, cbfun: GLFWwindowfocusfun) -> GLFWwindowfocusfun;
    pub fn glfwSetWindowIconifyCallback(window: *GLFWwindow, cbfun: GLFWwindowiconifyfun) -> GLFWwindowiconifyfun;
    pub fn glfwSetFramebufferSizeCallback(window: *GLFWwindow, cbfun: GLFWframebuffersizefun) -> GLFWframebuffersizefun;

    pub fn glfwPollEvents();
    pub fn glfwWaitEvents();

    pub fn glfwGetInputMode(window: *GLFWwindow, mode: c_int) -> c_int;
    pub fn glfwSetInputMode(window: *GLFWwindow, mode: c_int, value: c_int);
    pub fn glfwGetKey(window: *GLFWwindow, key: c_int) -> c_int;
    pub fn glfwGetMouseButton(window: *GLFWwindow, button: c_int) -> c_int;
    pub fn glfwGetCursorPos(window: *GLFWwindow, xpos: *c_double, ypos: *c_double);
    pub fn glfwSetCursorPos(window: *GLFWwindow, xpos: c_double, ypos: c_double);
    pub fn glfwSetKeyCallback(window: *GLFWwindow, cbfun: GLFWkeyfun) -> GLFWkeyfun;
    pub fn glfwSetCharCallback(window: *GLFWwindow, cbfun: GLFWcharfun) -> GLFWcharfun;
    pub fn glfwSetMouseButtonCallback(window: *GLFWwindow, cbfun: GLFWmousebuttonfun) -> GLFWmousebuttonfun;
    pub fn glfwSetCursorPosCallback(window: *GLFWwindow, cbfun: GLFWcursorposfun) -> GLFWcursorposfun;
    pub fn glfwSetCursorEnterCallback(window: *GLFWwindow, cbfun: GLFWcursorenterfun) -> GLFWcursorenterfun;
    pub fn glfwSetScrollCallback(window: *GLFWwindow, cbfun: GLFWscrollfun) -> GLFWscrollfun;

    pub fn glfwJoystickPresent(joy: c_int) -> c_int;
    pub fn glfwGetJoystickAxes(joy: c_int, count: *c_int) -> *c_float;
    pub fn glfwGetJoystickButtons(joy: c_int, count: *c_int) -> *c_uchar;
    pub fn glfwGetJoystickName(joy: c_int) -> *c_char;

    pub fn glfwSetClipboardString(window: *GLFWwindow, string: *c_char);
    pub fn glfwGetClipboardString(window: *GLFWwindow) -> *c_char;

    pub fn glfwGetTime() -> c_double;
    pub fn glfwSetTime(time: c_double);

    pub fn glfwMakeContextCurrent(window: *GLFWwindow);
    pub fn glfwGetCurrentContext() -> *GLFWwindow;
    pub fn glfwSwapBuffers(window: *GLFWwindow);
    pub fn glfwSwapInterval(interval: c_int);
    pub fn glfwExtensionSupported(extension: *c_char) -> c_int;
    pub fn glfwGetProcAddress(procname: *c_char) -> GLFWglproc;

    // native APIs

    #[cfg(target_os="win32")] pub fn glfwGetWin32Window(window: *GLFWwindow) -> *c_void;
    #[cfg(target_os="win32")] pub fn glfwGetWGLContext(window: *GLFWwindow) -> *c_void;

    #[cfg(target_os="macos")] pub fn glfwGetCocoaWindow(window: *GLFWwindow) -> *c_void;
    #[cfg(target_os="macos")] pub fn glfwGetNSGLContext(window: *GLFWwindow) -> *c_void;

    #[cfg(target_os="linux")] pub fn glfwGetX11Window(window: *GLFWwindow) -> *c_void;
    #[cfg(target_os="linux")] pub fn glfwGetX11Display() -> *c_void;
    #[cfg(target_os="linux")] pub fn glfwGetGLXContext(window: *GLFWwindow) -> *c_void;
}
<|endoftext|>