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

//! Math helper functions

use rand::Rng;
use crate::ziggurat_tables;
use rand::distributions::hidden_export::IntoFloat;
use core::{cmp, ops};

/// Trait for floating-point scalar types
///
/// This allows many distributions to work with `f32` or `f64` parameters and is
/// potentially extensible. Note however that the `Exp1` and `StandardNormal`
/// distributions are implemented exclusively for `f32` and `f64`.
///
/// The bounds and methods are based purely on internal
/// requirements, and will change as needed.
pub trait Float: Copy + Sized + cmp::PartialOrd
    + ops::Neg<Output = Self>
    + ops::Add<Output = Self>
    + ops::Sub<Output = Self>
    + ops::Mul<Output = Self>
    + ops::Div<Output = Self>
    + ops::AddAssign + ops::SubAssign + ops::MulAssign + ops::DivAssign
{
    /// The constant π
    fn pi() -> Self;
    /// Support approximate representation of a f64 value
    fn from(x: f64) -> Self;
    /// Support converting to an unsigned integer.
    fn to_u64(self) -> Option<u64>;

    /// Take the absolute value of self
    fn abs(self) -> Self;
    /// Take the largest integer less than or equal to self
    fn floor(self) -> Self;

    /// Take the exponential of self
    fn exp(self) -> Self;
    /// Take the natural logarithm of self
    fn ln(self) -> Self;
    /// Take square root of self
    fn sqrt(self) -> Self;
    /// Take self to a floating-point power
    fn powf(self, power: Self) -> Self;

    /// Take the tangent of self
    fn tan(self) -> Self;
    /// Take the logarithm of the gamma function of self
    fn log_gamma(self) -> Self;
}

impl Float for f32 {
    #[inline]
    fn pi() -> Self { core::f32::consts::PI }
    #[inline]
    fn from(x: f64) -> Self { x as f32 }
    #[inline]
    fn to_u64(self) -> Option<u64> {
        if self >= 0. && self <= ::core::u64::MAX as f32 {
            Some(self as u64)
        } else {
            None
        }
    }

    #[inline]
    fn abs(self) -> Self { self.abs() }
    #[inline]
    fn floor(self) -> Self { self.floor() }

    #[inline]
    fn exp(self) -> Self { self.exp() }
    #[inline]
    fn ln(self) -> Self { self.ln() }
    #[inline]
    fn sqrt(self) -> Self { self.sqrt() }
    #[inline]
    fn powf(self, power: Self) -> Self { self.powf(power) }

    #[inline]
    fn tan(self) -> Self { self.tan() }
    #[inline]
    fn log_gamma(self) -> Self {
        let result = log_gamma(self as f64);
        assert!(result <= ::core::f32::MAX as f64);
        assert!(result >= ::core::f32::MIN as f64);
        result as f32
    }
}

impl Float for f64 {
    #[inline]
    fn pi() -> Self { core::f64::consts::PI }
    #[inline]
    fn from(x: f64) -> Self { x }
    #[inline]
    fn to_u64(self) -> Option<u64> {
        if self >= 0. && self <= ::core::u64::MAX as f64 {
            Some(self as u64)
        } else {
            None
        }
    }

    #[inline]
    fn abs(self) -> Self { self.abs() }
    #[inline]
    fn floor(self) -> Self { self.floor() }

    #[inline]
    fn exp(self) -> Self { self.exp() }
    #[inline]
    fn ln(self) -> Self { self.ln() }
    #[inline]
    fn sqrt(self) -> Self { self.sqrt() }
    #[inline]
    fn powf(self, power: Self) -> Self { self.powf(power) }

    #[inline]
    fn tan(self) -> Self { self.tan() }
    #[inline]
    fn log_gamma(self) -> Self { log_gamma(self) }
}

/// Calculates ln(gamma(x)) (natural logarithm of the gamma
/// function) using the Lanczos approximation.
///
/// The approximation expresses the gamma function as:
/// `gamma(z+1) = sqrt(2*pi)*(z+g+0.5)^(z+0.5)*exp(-z-g-0.5)*Ag(z)`
/// `g` is an arbitrary constant; we use the approximation with `g=5`.
///
/// Noting that `gamma(z+1) = z*gamma(z)` and applying `ln` to both sides:
/// `ln(gamma(z)) = (z+0.5)*ln(z+g+0.5)-(z+g+0.5) + ln(sqrt(2*pi)*Ag(z)/z)`
///
/// `Ag(z)` is an infinite series with coefficients that can be calculated
/// ahead of time - we use just the first 6 terms, which is good enough
/// for most purposes.
pub(crate) fn log_gamma(x: f64) -> f64 {
    // precalculated 6 coefficients for the first 6 terms of the series
    let coefficients: [f64; 6] = [
        76.18009172947146,
        -86.50532032941677,
        24.01409824083091,
        -1.231739572450155,
        0.1208650973866179e-2,
        -0.5395239384953e-5,
    ];

    // (x+0.5)*ln(x+g+0.5)-(x+g+0.5)
    let tmp = x + 5.5;
    let log = (x + 0.5) * tmp.ln() - tmp;

    // the first few terms of the series for Ag(x)
    let mut a = 1.000000000190015;
    let mut denom = x;
    for &coeff in &coefficients {
        denom += 1.0;
        a += coeff / denom;
    }

    // get everything together
    // a is Ag(x)
    // 2.5066... is sqrt(2pi)
    log + (2.5066282746310005 * a / x).ln()
}

/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
///    bottom box (i.e. i == 0)

// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
pub(crate) fn ziggurat<R: Rng + ?Sized, P, Z>(
            rng: &mut R,
            symmetric: bool,
            x_tab: ziggurat_tables::ZigTable,
            f_tab: ziggurat_tables::ZigTable,
            mut pdf: P,
            mut zero_case: Z)
            -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
    loop {
        // As an optimisation we re-implement the conversion to a f64.
        // From the remaining 12 most significant bits we use 8 to construct `i`.
        // This saves us generating a whole extra random number, while the added
        // precision of using 64 bits for f64 does not buy us much.
        let bits = rng.next_u64();
        let i = bits as usize & 0xff;

        let u = if symmetric {
            // Convert to a value in the range [2,4) and substract to get [-1,1)
            // We can't convert to an open range directly, that would require
            // substracting `3.0 - EPSILON`, which is not representable.
            // It is possible with an extra step, but an open range does not
            // seem neccesary for the ziggurat algorithm anyway.
            (bits >> 12).into_float_with_exponent(1) - 3.0
        } else {
            // Convert to a value in the range [1,2) and substract to get (0,1)
            (bits >> 12).into_float_with_exponent(0)
            - (1.0 - std::f64::EPSILON / 2.0)
        };
        let x = u * x_tab[i];

        let test_x = if symmetric { x.abs() } else {x};

        // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
        if test_x < x_tab[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
            return x;
        }
    }
}
<commit_msg>rand_distr: Prefer `Into` over `as`<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Math helper functions

use rand::Rng;
use crate::ziggurat_tables;
use rand::distributions::hidden_export::IntoFloat;
use core::{cmp, ops};

/// Trait for floating-point scalar types
///
/// This allows many distributions to work with `f32` or `f64` parameters and is
/// potentially extensible. Note however that the `Exp1` and `StandardNormal`
/// distributions are implemented exclusively for `f32` and `f64`.
///
/// The bounds and methods are based purely on internal
/// requirements, and will change as needed.
pub trait Float: Copy + Sized + cmp::PartialOrd
    + ops::Neg<Output = Self>
    + ops::Add<Output = Self>
    + ops::Sub<Output = Self>
    + ops::Mul<Output = Self>
    + ops::Div<Output = Self>
    + ops::AddAssign + ops::SubAssign + ops::MulAssign + ops::DivAssign
{
    /// The constant π
    fn pi() -> Self;
    /// Support approximate representation of a f64 value
    fn from(x: f64) -> Self;
    /// Support converting to an unsigned integer.
    fn to_u64(self) -> Option<u64>;

    /// Take the absolute value of self
    fn abs(self) -> Self;
    /// Take the largest integer less than or equal to self
    fn floor(self) -> Self;

    /// Take the exponential of self
    fn exp(self) -> Self;
    /// Take the natural logarithm of self
    fn ln(self) -> Self;
    /// Take square root of self
    fn sqrt(self) -> Self;
    /// Take self to a floating-point power
    fn powf(self, power: Self) -> Self;

    /// Take the tangent of self
    fn tan(self) -> Self;
    /// Take the logarithm of the gamma function of self
    fn log_gamma(self) -> Self;
}

impl Float for f32 {
    #[inline]
    fn pi() -> Self { core::f32::consts::PI }
    #[inline]
    fn from(x: f64) -> Self { x as f32 }
    #[inline]
    fn to_u64(self) -> Option<u64> {
        if self >= 0. && self <= ::core::u64::MAX as f32 {
            Some(self as u64)
        } else {
            None
        }
    }

    #[inline]
    fn abs(self) -> Self { self.abs() }
    #[inline]
    fn floor(self) -> Self { self.floor() }

    #[inline]
    fn exp(self) -> Self { self.exp() }
    #[inline]
    fn ln(self) -> Self { self.ln() }
    #[inline]
    fn sqrt(self) -> Self { self.sqrt() }
    #[inline]
    fn powf(self, power: Self) -> Self { self.powf(power) }

    #[inline]
    fn tan(self) -> Self { self.tan() }
    #[inline]
    fn log_gamma(self) -> Self {
        let result = log_gamma(self.into());
        assert!(result <= ::core::f32::MAX.into());
        assert!(result >= ::core::f32::MIN.into());
        result as f32
    }
}

impl Float for f64 {
    #[inline]
    fn pi() -> Self { core::f64::consts::PI }
    #[inline]
    fn from(x: f64) -> Self { x }
    #[inline]
    fn to_u64(self) -> Option<u64> {
        if self >= 0. && self <= ::core::u64::MAX as f64 {
            Some(self as u64)
        } else {
            None
        }
    }

    #[inline]
    fn abs(self) -> Self { self.abs() }
    #[inline]
    fn floor(self) -> Self { self.floor() }

    #[inline]
    fn exp(self) -> Self { self.exp() }
    #[inline]
    fn ln(self) -> Self { self.ln() }
    #[inline]
    fn sqrt(self) -> Self { self.sqrt() }
    #[inline]
    fn powf(self, power: Self) -> Self { self.powf(power) }

    #[inline]
    fn tan(self) -> Self { self.tan() }
    #[inline]
    fn log_gamma(self) -> Self { log_gamma(self) }
}

/// Calculates ln(gamma(x)) (natural logarithm of the gamma
/// function) using the Lanczos approximation.
///
/// The approximation expresses the gamma function as:
/// `gamma(z+1) = sqrt(2*pi)*(z+g+0.5)^(z+0.5)*exp(-z-g-0.5)*Ag(z)`
/// `g` is an arbitrary constant; we use the approximation with `g=5`.
///
/// Noting that `gamma(z+1) = z*gamma(z)` and applying `ln` to both sides:
/// `ln(gamma(z)) = (z+0.5)*ln(z+g+0.5)-(z+g+0.5) + ln(sqrt(2*pi)*Ag(z)/z)`
///
/// `Ag(z)` is an infinite series with coefficients that can be calculated
/// ahead of time - we use just the first 6 terms, which is good enough
/// for most purposes.
pub(crate) fn log_gamma(x: f64) -> f64 {
    // precalculated 6 coefficients for the first 6 terms of the series
    let coefficients: [f64; 6] = [
        76.18009172947146,
        -86.50532032941677,
        24.01409824083091,
        -1.231739572450155,
        0.1208650973866179e-2,
        -0.5395239384953e-5,
    ];

    // (x+0.5)*ln(x+g+0.5)-(x+g+0.5)
    let tmp = x + 5.5;
    let log = (x + 0.5) * tmp.ln() - tmp;

    // the first few terms of the series for Ag(x)
    let mut a = 1.000000000190015;
    let mut denom = x;
    for &coeff in &coefficients {
        denom += 1.0;
        a += coeff / denom;
    }

    // get everything together
    // a is Ag(x)
    // 2.5066... is sqrt(2pi)
    log + (2.5066282746310005 * a / x).ln()
}

/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
///    bottom box (i.e. i == 0)

// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
pub(crate) fn ziggurat<R: Rng + ?Sized, P, Z>(
            rng: &mut R,
            symmetric: bool,
            x_tab: ziggurat_tables::ZigTable,
            f_tab: ziggurat_tables::ZigTable,
            mut pdf: P,
            mut zero_case: Z)
            -> f64 where P: FnMut(f64) -> f64, Z: FnMut(&mut R, f64) -> f64 {
    loop {
        // As an optimisation we re-implement the conversion to a f64.
        // From the remaining 12 most significant bits we use 8 to construct `i`.
        // This saves us generating a whole extra random number, while the added
        // precision of using 64 bits for f64 does not buy us much.
        let bits = rng.next_u64();
        let i = bits as usize & 0xff;

        let u = if symmetric {
            // Convert to a value in the range [2,4) and substract to get [-1,1)
            // We can't convert to an open range directly, that would require
            // substracting `3.0 - EPSILON`, which is not representable.
            // It is possible with an extra step, but an open range does not
            // seem neccesary for the ziggurat algorithm anyway.
            (bits >> 12).into_float_with_exponent(1) - 3.0
        } else {
            // Convert to a value in the range [1,2) and substract to get (0,1)
            (bits >> 12).into_float_with_exponent(0)
            - (1.0 - std::f64::EPSILON / 2.0)
        };
        let x = u * x_tab[i];

        let test_x = if symmetric { x.abs() } else {x};

        // algebraically equivalent to |u| < x_tab[i+1]/x_tab[i] (or u < x_tab[i+1]/x_tab[i])
        if test_x < x_tab[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if f_tab[i + 1] + (f_tab[i] - f_tab[i + 1]) * rng.gen::<f64>() < pdf(x) {
            return x;
        }
    }
}
<|endoftext|>


<commit_before>
//! A priority queue implemented with a binary heap

use core::cmp::Ord;
use ptr::addr_of;

#[abi = "rust-intrinsic"]
extern "C" mod rusti {
    fn move_val_init<T>(dst: &mut T, -src: T);
}

pub struct PriorityQueue <T: Ord>{
    priv data: ~[T],
}

impl <T: Ord> PriorityQueue<T> {
    /// Returns the greatest item in the queue - fails if empty
    pure fn top(&self) -> &self/T { &self.data[0] }

    /// Returns the greatest item in the queue - None if empty
    pure fn maybe_top(&self) -> Option<&self/T> {
        if self.is_empty() { None } else { Some(self.top()) }
    }

    /// Returns the length of the queue
    pure fn len(&self) -> uint { self.data.len() }

    /// Returns true if a queue contains no elements
    pure fn is_empty(&self) -> bool { self.data.is_empty() }

    /// Returns true if a queue contains some elements
    pure fn is_not_empty(&self) -> bool { self.data.is_not_empty() }

    /// Returns the number of elements the queue can hold without reallocating
    pure fn capacity(&self) -> uint { vec::capacity(&self.data) }

    fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) }

    fn reserve_at_least(&mut self, n: uint) {
        vec::reserve_at_least(&mut self.data, n)
    }

    /// Drop all items from the queue
    fn clear(&mut self) { self.data.truncate(0) }

    /// Pop the greatest item from the queue - fails if empty
    fn pop(&mut self) -> T {
        let mut item = self.data.pop();
        if self.is_not_empty() { item <-> self.data[0]; self.siftdown(0); }
        item
    }

    /// Pop the greatest item from the queue - None if empty
    fn maybe_pop(&mut self) -> Option<T> {
        if self.is_empty() { None } else { Some(self.pop()) }
    }

    /// Push an item onto the queue
    fn push(&mut self, item: T) {
        self.data.push(item);
        self.siftup(0, self.len() - 1);
    }

    /// Optimized version of a push followed by a pop
    fn push_pop(&mut self, item: T) -> T {
        let mut item = item;
        if self.is_not_empty() && self.data[0] > item {
            item <-> self.data[0];
            self.siftdown(0);
        }
        item
    }

    /// Optimized version of a pop followed by a push - fails if empty
    fn replace(&mut self, item: T) -> T {
        let mut item = item;
        item <-> self.data[0];
        self.siftdown(0);
        item
    }

    /// Consume the PriorityQueue and return the underlying vector
    #[cfg(stage0)]
    pure fn to_vec(self) -> ~[T] { fail }
    #[cfg(stage1)]
    #[cfg(stage2)]
    #[cfg(stage3)]
    pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v }

    /// Consume the PriorityQueue and return a vector in sorted
    /// (ascending) order
    #[cfg(stage0)]
    pure fn to_sorted_vec(self) -> ~[T] { fail }
    #[cfg(stage1)]
    #[cfg(stage2)]
    #[cfg(stage3)]
    pure fn to_sorted_vec(self) -> ~[T] {
        let mut q = self;
        let mut end = q.len();
        while end > 1 {
            end -= 1;
            q.data[end] <-> q.data[0];
            unsafe { q.siftdown_range(0, end) } // purity-checking workaround
        }
        q.to_vec()
    }

    /// Create a PriorityQueue from a vector (heapify)
    static pub pure fn from_vec(xs: ~[T]) -> PriorityQueue<T> {
        let mut q = PriorityQueue{data: xs,};
        let mut n = q.len() / 2;
        while n > 0 {
            n -= 1;
            unsafe { q.siftdown(n) }; // purity-checking workaround
        }
        q
    }

    // The implementations of siftup and siftdown use unsafe blocks in
    // order to move an element out of the vector (leaving behind a
    // junk element), shift along the others and move it back into the
    // vector over the junk element.  This reduces the constant factor
    // compared to using swaps, which involves twice as many moves.

    priv fn siftup(&mut self, start: uint, pos: uint) unsafe {
        let mut pos = pos;
        let new = move *addr_of(&self.data[pos]);

        while pos > start {
            let parent = (pos - 1) >> 1;
            if new > self.data[parent] {
                rusti::move_val_init(&mut self.data[pos],
                                     move *addr_of(&self.data[parent]));
                pos = parent;
                loop
            }
            break
        }
        rusti::move_val_init(&mut self.data[pos], move new);
    }

    priv fn siftdown_range(&mut self, pos: uint, end: uint) unsafe {
        let mut pos = pos;
        let start = pos;
        let new = move *addr_of(&self.data[pos]);

        let mut child = 2 * pos + 1;
        while child < end {
            let right = child + 1;
            if right < end && !(self.data[child] > self.data[right]) {
                child = right;
            }
            rusti::move_val_init(&mut self.data[pos],
                                 move *addr_of(&self.data[child]));
            pos = child;
            child = 2 * pos + 1;
        }
        rusti::move_val_init(&mut self.data[pos], move new);
        self.siftup(start, pos);
    }

    priv fn siftdown(&mut self, pos: uint) {
        self.siftdown_range(pos, self.len());
    }
}

#[cfg(test)]
mod tests {
    use sort::merge_sort;
    use core::cmp::le;
    use priority_queue::PriorityQueue::from_vec;

    #[test]
    fn test_top_and_pop() {
        let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
        let mut sorted = merge_sort(data, le);
        let mut heap = from_vec(data);
        while heap.is_not_empty() {
            assert *heap.top() == sorted.last();
            assert heap.pop() == sorted.pop();
        }
    }

    #[test]
    fn test_push() {
        let mut heap = from_vec(~[2, 4, 9]);
        assert heap.len() == 3;
        assert *heap.top() == 9;
        heap.push(11);
        assert heap.len() == 4;
        assert *heap.top() == 11;
        heap.push(5);
        assert heap.len() == 5;
        assert *heap.top() == 11;
        heap.push(27);
        assert heap.len() == 6;
        assert *heap.top() == 27;
        heap.push(3);
        assert heap.len() == 7;
        assert *heap.top() == 27;
        heap.push(103);
        assert heap.len() == 8;
        assert *heap.top() == 103;
    }

    #[test]
    fn test_push_unique() {
        let mut heap = from_vec(~[~2, ~4, ~9]);
        assert heap.len() == 3;
        assert *heap.top() == ~9;
        heap.push(~11);
        assert heap.len() == 4;
        assert *heap.top() == ~11;
        heap.push(~5);
        assert heap.len() == 5;
        assert *heap.top() == ~11;
        heap.push(~27);
        assert heap.len() == 6;
        assert *heap.top() == ~27;
        heap.push(~3);
        assert heap.len() == 7;
        assert *heap.top() == ~27;
        heap.push(~103);
        assert heap.len() == 8;
        assert *heap.top() == ~103;
    }

    #[test]
    fn test_push_pop() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.push_pop(6) == 6;
        assert heap.len() == 5;
        assert heap.push_pop(0) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(4) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(1) == 4;
        assert heap.len() == 5;
    }

    #[test]
    fn test_replace() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.replace(6) == 5;
        assert heap.len() == 5;
        assert heap.replace(0) == 6;
        assert heap.len() == 5;
        assert heap.replace(4) == 5;
        assert heap.len() == 5;
        assert heap.replace(1) == 4;
        assert heap.len() == 5;
    }

    fn check_to_vec(data: ~[int]) {
        let heap = from_vec(data);
        assert merge_sort(heap.to_vec(), le) == merge_sort(data, le);
        assert heap.to_sorted_vec() == merge_sort(data, le);
    }

    #[test]
    fn test_to_vec() {
        check_to_vec(~[]);
        check_to_vec(~[5]);
        check_to_vec(~[3, 2]);
        check_to_vec(~[2, 3]);
        check_to_vec(~[5, 1, 2]);
        check_to_vec(~[1, 100, 2, 3]);
        check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
        check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
        check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
        check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_pop() { let mut heap = from_vec::<int>(~[]); heap.pop(); }

    #[test]
    fn test_empty_maybe_pop() {
        let mut heap = from_vec::<int>(~[]);
        assert heap.maybe_pop().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_top() { let empty = from_vec::<int>(~[]); empty.top(); }

    #[test]
    fn test_empty_maybe_top() {
        let empty = from_vec::<int>(~[]);
        assert empty.maybe_top().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_replace() {
        let mut heap = from_vec::<int>(~[]);
        heap.replace(5);
    }
}
<commit_msg>add an empty PriorityQueue constructor<commit_after>
//! A priority queue implemented with a binary heap

use core::cmp::Ord;
use ptr::addr_of;

#[abi = "rust-intrinsic"]
extern "C" mod rusti {
    fn move_val_init<T>(dst: &mut T, -src: T);
}

pub struct PriorityQueue <T: Ord>{
    priv data: ~[T],
}

impl <T: Ord> PriorityQueue<T> {
    /// Returns the greatest item in the queue - fails if empty
    pure fn top(&self) -> &self/T { &self.data[0] }

    /// Returns the greatest item in the queue - None if empty
    pure fn maybe_top(&self) -> Option<&self/T> {
        if self.is_empty() { None } else { Some(self.top()) }
    }

    /// Returns the length of the queue
    pure fn len(&self) -> uint { self.data.len() }

    /// Returns true if a queue contains no elements
    pure fn is_empty(&self) -> bool { self.data.is_empty() }

    /// Returns true if a queue contains some elements
    pure fn is_not_empty(&self) -> bool { self.data.is_not_empty() }

    /// Returns the number of elements the queue can hold without reallocating
    pure fn capacity(&self) -> uint { vec::capacity(&self.data) }

    fn reserve(&mut self, n: uint) { vec::reserve(&mut self.data, n) }

    fn reserve_at_least(&mut self, n: uint) {
        vec::reserve_at_least(&mut self.data, n)
    }

    /// Drop all items from the queue
    fn clear(&mut self) { self.data.truncate(0) }

    /// Pop the greatest item from the queue - fails if empty
    fn pop(&mut self) -> T {
        let mut item = self.data.pop();
        if self.is_not_empty() { item <-> self.data[0]; self.siftdown(0); }
        item
    }

    /// Pop the greatest item from the queue - None if empty
    fn maybe_pop(&mut self) -> Option<T> {
        if self.is_empty() { None } else { Some(self.pop()) }
    }

    /// Push an item onto the queue
    fn push(&mut self, item: T) {
        self.data.push(item);
        self.siftup(0, self.len() - 1);
    }

    /// Optimized version of a push followed by a pop
    fn push_pop(&mut self, item: T) -> T {
        let mut item = item;
        if self.is_not_empty() && self.data[0] > item {
            item <-> self.data[0];
            self.siftdown(0);
        }
        item
    }

    /// Optimized version of a pop followed by a push - fails if empty
    fn replace(&mut self, item: T) -> T {
        let mut item = item;
        item <-> self.data[0];
        self.siftdown(0);
        item
    }

    /// Consume the PriorityQueue and return the underlying vector
    #[cfg(stage0)]
    pure fn to_vec(self) -> ~[T] { fail }
    #[cfg(stage1)]
    #[cfg(stage2)]
    #[cfg(stage3)]
    pure fn to_vec(self) -> ~[T] { let PriorityQueue{data: v} = self; v }

    /// Consume the PriorityQueue and return a vector in sorted
    /// (ascending) order
    #[cfg(stage0)]
    pure fn to_sorted_vec(self) -> ~[T] { fail }
    #[cfg(stage1)]
    #[cfg(stage2)]
    #[cfg(stage3)]
    pure fn to_sorted_vec(self) -> ~[T] {
        let mut q = self;
        let mut end = q.len();
        while end > 1 {
            end -= 1;
            q.data[end] <-> q.data[0];
            unsafe { q.siftdown_range(0, end) } // purity-checking workaround
        }
        q.to_vec()
    }

    /// Create an empty PriorityQueue
    static pure fn new() -> PriorityQueue<T> { PriorityQueue{data: ~[],} }

    /// Create a PriorityQueue from a vector (heapify)
    static pure fn from_vec(xs: ~[T]) -> PriorityQueue<T> {
        let mut q = PriorityQueue{data: xs,};
        let mut n = q.len() / 2;
        while n > 0 {
            n -= 1;
            unsafe { q.siftdown(n) }; // purity-checking workaround
        }
        q
    }

    // The implementations of siftup and siftdown use unsafe blocks in
    // order to move an element out of the vector (leaving behind a
    // junk element), shift along the others and move it back into the
    // vector over the junk element.  This reduces the constant factor
    // compared to using swaps, which involves twice as many moves.

    priv fn siftup(&mut self, start: uint, pos: uint) unsafe {
        let mut pos = pos;
        let new = move *addr_of(&self.data[pos]);

        while pos > start {
            let parent = (pos - 1) >> 1;
            if new > self.data[parent] {
                rusti::move_val_init(&mut self.data[pos],
                                     move *addr_of(&self.data[parent]));
                pos = parent;
                loop
            }
            break
        }
        rusti::move_val_init(&mut self.data[pos], move new);
    }

    priv fn siftdown_range(&mut self, pos: uint, end: uint) unsafe {
        let mut pos = pos;
        let start = pos;
        let new = move *addr_of(&self.data[pos]);

        let mut child = 2 * pos + 1;
        while child < end {
            let right = child + 1;
            if right < end && !(self.data[child] > self.data[right]) {
                child = right;
            }
            rusti::move_val_init(&mut self.data[pos],
                                 move *addr_of(&self.data[child]));
            pos = child;
            child = 2 * pos + 1;
        }
        rusti::move_val_init(&mut self.data[pos], move new);
        self.siftup(start, pos);
    }

    priv fn siftdown(&mut self, pos: uint) {
        self.siftdown_range(pos, self.len());
    }
}

#[cfg(test)]
mod tests {
    use sort::merge_sort;
    use core::cmp::le;
    use priority_queue::PriorityQueue::{from_vec, new};

    #[test]
    fn test_top_and_pop() {
        let data = ~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1];
        let mut sorted = merge_sort(data, le);
        let mut heap = from_vec(data);
        while heap.is_not_empty() {
            assert *heap.top() == sorted.last();
            assert heap.pop() == sorted.pop();
        }
    }

    #[test]
    fn test_push() {
        let mut heap = from_vec(~[2, 4, 9]);
        assert heap.len() == 3;
        assert *heap.top() == 9;
        heap.push(11);
        assert heap.len() == 4;
        assert *heap.top() == 11;
        heap.push(5);
        assert heap.len() == 5;
        assert *heap.top() == 11;
        heap.push(27);
        assert heap.len() == 6;
        assert *heap.top() == 27;
        heap.push(3);
        assert heap.len() == 7;
        assert *heap.top() == 27;
        heap.push(103);
        assert heap.len() == 8;
        assert *heap.top() == 103;
    }

    #[test]
    fn test_push_unique() {
        let mut heap = from_vec(~[~2, ~4, ~9]);
        assert heap.len() == 3;
        assert *heap.top() == ~9;
        heap.push(~11);
        assert heap.len() == 4;
        assert *heap.top() == ~11;
        heap.push(~5);
        assert heap.len() == 5;
        assert *heap.top() == ~11;
        heap.push(~27);
        assert heap.len() == 6;
        assert *heap.top() == ~27;
        heap.push(~3);
        assert heap.len() == 7;
        assert *heap.top() == ~27;
        heap.push(~103);
        assert heap.len() == 8;
        assert *heap.top() == ~103;
    }

    #[test]
    fn test_push_pop() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.push_pop(6) == 6;
        assert heap.len() == 5;
        assert heap.push_pop(0) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(4) == 5;
        assert heap.len() == 5;
        assert heap.push_pop(1) == 4;
        assert heap.len() == 5;
    }

    #[test]
    fn test_replace() {
        let mut heap = from_vec(~[5, 5, 2, 1, 3]);
        assert heap.len() == 5;
        assert heap.replace(6) == 5;
        assert heap.len() == 5;
        assert heap.replace(0) == 6;
        assert heap.len() == 5;
        assert heap.replace(4) == 5;
        assert heap.len() == 5;
        assert heap.replace(1) == 4;
        assert heap.len() == 5;
    }

    fn check_to_vec(data: ~[int]) {
        let heap = from_vec(data);
        assert merge_sort(heap.to_vec(), le) == merge_sort(data, le);
        assert heap.to_sorted_vec() == merge_sort(data, le);
    }

    #[test]
    fn test_to_vec() {
        check_to_vec(~[]);
        check_to_vec(~[5]);
        check_to_vec(~[3, 2]);
        check_to_vec(~[2, 3]);
        check_to_vec(~[5, 1, 2]);
        check_to_vec(~[1, 100, 2, 3]);
        check_to_vec(~[1, 3, 5, 7, 9, 2, 4, 6, 8, 0]);
        check_to_vec(~[2, 4, 6, 2, 1, 8, 10, 3, 5, 7, 0, 9, 1]);
        check_to_vec(~[9, 11, 9, 9, 9, 9, 11, 2, 3, 4, 11, 9, 0, 0, 0, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
        check_to_vec(~[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]);
        check_to_vec(~[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 1, 2]);
        check_to_vec(~[5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]);
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_pop() { let mut heap = new::<int>(); heap.pop(); }

    #[test]
    fn test_empty_maybe_pop() {
        let mut heap = new::<int>();
        assert heap.maybe_pop().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_top() { let empty = new::<int>(); empty.top(); }

    #[test]
    fn test_empty_maybe_top() {
        let empty = new::<int>();
        assert empty.maybe_top().is_none();
    }

    #[test]
    #[should_fail]
    #[ignore(cfg(windows))]
    fn test_empty_replace() { let mut heap = new(); heap.replace(5); }
}
<|endoftext|>


<commit_before>#[doc="
A process-wide libuv event loop for library use.
"];

import ll = uv_ll;
import hl = uv_hl;
import get_gl = get;

export get, get_single_task_gl, get_monitor_task_gl;

native mod rustrt {
    fn rust_uv_get_kernel_global_chan_ptr() -> *libc::uintptr_t;
    fn rust_uv_get_kernel_monitor_global_chan_ptr() -> *libc::uintptr_t;
    fn rust_uv_get_kernel_global_async_handle() -> *libc::uintptr_t;
    fn rust_compare_and_swap_ptr(address: *libc::uintptr_t,
                                 oldval: libc::uintptr_t,
                                 newval: libc::uintptr_t) -> bool;
}

#[doc ="
Race-free helper to get access to a global task where a libuv
loop is running.

Use `uv::hl::interact`, `uv::hl::ref`, `uv::hl::unref` and
uv `uv::hl::unref_and_close` to do operations against the global
loop that this function returns.

# Return

* A `hl::high_level_loop` that encapsulates communication with the global
loop.
"]
fn get() -> hl::high_level_loop {
    ret get_monitor_task_gl();
}

// WARNING: USE ONLY ONE get_*_task_gl fn in the scope of a process lifetime.
#[doc(hidden)]
fn get_monitor_task_gl() -> hl::high_level_loop {
    let monitor_loop_chan =
        rustrt::rust_uv_get_kernel_monitor_global_chan_ptr();
    ret spawn_global_weak_task(
        monitor_loop_chan,
        {|weak_exit_po, msg_po, loop_ptr, first_msg|
            log(debug, "monitor gl: entering inner loop");
            unsafe {
                monitor_task_loop_body(weak_exit_po, msg_po, loop_ptr,
                                       copy(first_msg))
            }
        },
        {|msg_ch|
            hl::monitor_task_loop({op_chan: msg_ch})
        });
}

// WARNING: USE ONLY ONE get_*_task_gl fn in the scope of a process lifetime.
#[doc(hidden)]
fn get_single_task_gl() -> hl::high_level_loop {
    let global_loop_chan_ptr = rustrt::rust_uv_get_kernel_global_chan_ptr();
    ret spawn_global_weak_task(
        global_loop_chan_ptr,
        {|weak_exit_po, msg_po, loop_ptr, first_msg|
            log(debug, "single-task gl: about to enter inner loop");
            unsafe {
                single_task_loop_body(weak_exit_po, msg_po, loop_ptr,
                                      copy(first_msg))
            }
        },
        {|msg_ch|
            log(debug, "after priv::chan_from_global_ptr");
            unsafe {
                let handle = get_global_async_handle_native_representation()
                    as **ll::uv_async_t;
                hl::single_task_loop(
                    { async_handle: handle, op_chan: msg_ch })
            }
        }
    );
}

// INTERNAL API

fn spawn_global_weak_task(
        global_loop_chan_ptr: *libc::uintptr_t,
        weak_task_body_cb: fn~(
            comm::port<()>,
            comm::port<hl::high_level_msg>,
            *libc::c_void,
            hl::high_level_msg) -> bool,
        after_task_spawn_cb: fn~(comm::chan<hl::high_level_msg>)
          -> hl::high_level_loop) -> hl::high_level_loop {
    log(debug, #fmt("ENTERING global_loop::get() loop chan: %?",
       global_loop_chan_ptr));

    let builder_fn = {||
        let builder = task::builder();
        let opts = {
            supervise: false,
            notify_chan: none,
            sched:
                some({mode: task::manual_threads(1u),
                      native_stack_size: none })
        };
        task::set_opts(builder, opts);
        builder
    };
    unsafe {
        log(debug, "before priv::chan_from_global_ptr");
        let msg_ch = priv::chan_from_global_ptr::<hl::high_level_msg>(
            global_loop_chan_ptr,
            builder_fn) {|port|

            // the actual body of our global loop lives here
            log(debug, "initialized global port task!");
            log(debug, "GLOBAL initialized global port task!");
            outer_global_loop_body(port, weak_task_body_cb);
        };
        ret after_task_spawn_cb(msg_ch);
    }
}

unsafe fn outer_global_loop_body(
    msg_po: comm::port<hl::high_level_msg>,
    weak_task_body_cb: fn~(
        comm::port<()>,
        comm::port<hl::high_level_msg>,
        *libc::c_void,
        hl::high_level_msg) -> bool) {
    // we're going to use a single libuv-generated loop ptr
    // for the duration of the process
    let loop_ptr = ll::loop_new();

    // data structure for loop goes here..

    // immediately weaken the task this is running in.
    priv::weaken_task() {|weak_exit_po|
        // when we first enter this loop, we're going
        // to wait on stand-by to receive a request to
        // fire-up the libuv loop
        let mut continue = true;
        while continue {
            log(debug, "in outer_loop...");
            continue = either::either(
                {|left_val|
                    // bail out..
                    // if we catch this msg at this point,
                    // we should just be able to exit because
                    // the loop isn't active
                    log(debug, #fmt("weak_exit_po recv'd msg: %?",
                                   left_val));
                    false
                }, {|right_val|
                    weak_task_body_cb(weak_exit_po, msg_po, loop_ptr,
                                      right_val)
                }, comm::select2(weak_exit_po, msg_po));
            log(debug,#fmt("GLOBAL LOOP EXITED, WAITING TO RESTART? %?",
                       continue));
        }
    };

    ll::loop_delete(loop_ptr);
}

unsafe fn monitor_task_loop_body(weak_exit_po_in: comm::port<()>,
                          msg_po_in: comm::port<hl::high_level_msg>,
                          loop_ptr: *libc::c_void,
                          -first_interaction: hl::high_level_msg) -> bool {
    // resend the msg to be handled in the select2 loop below..
    comm::send(comm::chan(msg_po_in), first_interaction);

    // our async_handle
    let async_handle_po = comm::port::<*ll::uv_async_t>();
    let async_handle_ch = comm::chan(async_handle_po);

    // the msg_po that libuv will be receiving on..
    let loop_msg_po = comm::port::<hl::high_level_msg>();
    let loop_msg_po_ptr = ptr::addr_of(loop_msg_po);
    let loop_msg_ch = comm::chan(loop_msg_po);

    // the question of whether unsupervising this will even do any
    // good is there.. but since this'll go into blocking in libuv with
    // a quickness.. any errors that occur (including inside crust) will
    // be segfaults.. so yeah.
    task::spawn_sched(task::manual_threads(1u)) {||
        let loop_msg_po_in = *loop_msg_po_ptr;
        hl::run_high_level_loop(
            loop_ptr,
            loop_msg_po_in, // here the loop gets handed a different message
                            // port, as we'll be receiving all of the messages
                            // initially and then passing them on..
            // before_run
            {|async_handle|
                log(debug,#fmt("monitor gl: before_run: async_handle %?",
                              async_handle));
                // when this is ran, our async_handle is set up, so let's
                // do an async_send with it.. letting the loop know, once it
                // starts, that is has work
                ll::async_send(async_handle);
                comm::send(async_handle_ch, copy(async_handle));
            },
            // before_msg_drain
            {|async_handle|
                log(debug,#fmt("monitor gl: b4_msg_drain: async_handle %?",
                              async_handle));
                true
            },
            // before_tear_down
            {|async_handle|
                log(debug,#fmt("monitor gl: b4_tear_down: async_handle %?",
                              async_handle));
            });
    };

    // our loop is set up, so let's emit the handle back out to our users..
    let async_handle = comm::recv(async_handle_po);
    // supposed to return a bool to indicate to the enclosing loop whether
    // it should continue or not..
    let mut continue_inner_loop = true;
    let mut didnt_get_hl_bailout = true;
    while continue_inner_loop {
        log(debug, "monitor task inner loop.. about to block on select2");
        continue_inner_loop = either::either(
            {|left_val|
                // bail out..
                log(debug, #fmt("monitor inner weak_exit_po recv'd msg: %?",
                               left_val));
                // TODO: make loop bail out
                didnt_get_hl_bailout = false;
                false
            }, {|right_val|
                // wake up our inner loop and pass it a msg..
                comm::send(loop_msg_ch, copy(right_val));
                ll::async_send(async_handle);
                true
            }, comm::select2(weak_exit_po_in, msg_po_in)
        )
    }
    didnt_get_hl_bailout
}

unsafe fn single_task_loop_body(weak_exit_po_in: comm::port<()>,
                          msg_po_in: comm::port<hl::high_level_msg>,
                          loop_ptr: *libc::c_void,
                          -first_interaction: hl::high_level_msg) -> bool {
    // resend the msg
    comm::send(comm::chan(msg_po_in), first_interaction);

    // black magic
    let weak_exit_po_ptr = ptr::addr_of(weak_exit_po_in);
    hl::run_high_level_loop(
        loop_ptr,
        msg_po_in,
        // before_run
        {|async_handle|
            log(debug,#fmt("global_loop before_run: async_handle %?",
                          async_handle));
            // set the handle as the global
            set_global_async_handle(0u as *ll::uv_async_t,
                                    async_handle);
            // when this is ran, our async_handle is set up, so let's
            // do an async_send with it
            ll::async_send(async_handle);
        },
        // before_msg_drain
        {|async_handle|
            log(debug,#fmt("global_loop before_msg_drain: async_handle %?",
                          async_handle));
            let weak_exit_po = *weak_exit_po_ptr;
            if(comm::peek(weak_exit_po)) {
                // if this is true, immediately bail and return false, causing
                // the libuv loop to start tearing down
                log(debug,"got weak_exit meg inside libuv loop");
                comm::recv(weak_exit_po);
                false
            }
            // if no weak_exit_po msg is received, then we'll let the
            // loop continue
            else {
                true
            }
        },
        // before_tear_down
        {|async_handle|
            log(debug,#fmt("global_loop before_tear_down: async_handle %?",
                          async_handle));
            set_global_async_handle(async_handle,
                                    0 as *ll::uv_async_t);
        });
    // supposed to return a bool to indicate to the enclosing loop whether
    // it should continue or not..
    ret true;
}

unsafe fn get_global_async_handle_native_representation()
    -> *libc::uintptr_t {
    ret rustrt::rust_uv_get_kernel_global_async_handle();
}

unsafe fn get_global_async_handle() -> *ll::uv_async_t {
    ret (*get_global_async_handle_native_representation()) as *ll::uv_async_t;
}

unsafe fn set_global_async_handle(old: *ll::uv_async_t,
                           new_ptr: *ll::uv_async_t) {
    rustrt::rust_compare_and_swap_ptr(
        get_global_async_handle_native_representation(),
        old as libc::uintptr_t,
        new_ptr as libc::uintptr_t);
}

#[cfg(test)]
mod test {
    crust fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe {
        let exit_ch_ptr = ll::get_data_for_uv_handle(
            timer_ptr as *libc::c_void) as *comm::chan<bool>;
        let exit_ch = *exit_ch_ptr;
        comm::send(exit_ch, true);
        log(debug, #fmt("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
                       exit_ch_ptr));
    }
    crust fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
                             status: libc::c_int) unsafe {
        log(debug, "in simple timer cb");
        ll::timer_stop(timer_ptr);
        let hl_loop = get_gl();
        hl::interact(hl_loop) {|loop_ptr|
            log(debug, "closing timer");
            //ll::close(timer_ptr as *libc::c_void, simple_timer_close_cb);
            hl::unref_and_close(hl_loop, timer_ptr, simple_timer_close_cb);
            log(debug, "about to deref exit_ch_ptr");
            log(debug, "after msg sent on deref'd exit_ch");
        };
        log(debug, "exiting simple timer cb");
    }

    fn impl_uv_hl_simple_timer(hl_loop: hl::high_level_loop) unsafe {
        let exit_po = comm::port::<bool>();
        let exit_ch = comm::chan(exit_po);
        let exit_ch_ptr = ptr::addr_of(exit_ch);
        log(debug, #fmt("EXIT_CH_PTR newly created exit_ch_ptr: %?",
                       exit_ch_ptr));
        let timer_handle = ll::timer_t();
        let timer_ptr = ptr::addr_of(timer_handle);
        hl::interact(hl_loop) {|loop_ptr|
            log(debug, "user code inside interact loop!!!");
            let init_status = ll::timer_init(loop_ptr, timer_ptr);
            if(init_status == 0i32) {
                hl::ref(hl_loop, timer_ptr);
                ll::set_data_for_uv_handle(
                    timer_ptr as *libc::c_void,
                    exit_ch_ptr as *libc::c_void);
                let start_status = ll::timer_start(timer_ptr, simple_timer_cb,
                                                   1u, 0u);
                if(start_status == 0i32) {
                }
                else {
                    fail "failure on ll::timer_start()";
                }
            }
            else {
                fail "failure on ll::timer_init()";
            }
        };
        comm::recv(exit_po);
        log(debug, "global_loop timer test: msg recv on exit_po, done..");
    }
    #[test]
    #[ignore]
    fn test_uv_global_loop_high_level_global_timer() unsafe {
        let hl_loop = get_gl();
        task::spawn_sched(task::manual_threads(1u), {||
            impl_uv_hl_simple_timer(hl_loop);
        });
        impl_uv_hl_simple_timer(hl_loop);
    }
}<commit_msg>std: get rid of some un-needed rustrt native fns for the global loop<commit_after>#[doc="
A process-wide libuv event loop for library use.
"];

import ll = uv_ll;
import hl = uv_hl;
import get_gl = get;

export get, get_single_task_gl, get_monitor_task_gl;

native mod rustrt {
    fn rust_uv_get_kernel_global_chan_ptr() -> *libc::uintptr_t;
}

#[doc ="
Race-free helper to get access to a global task where a libuv
loop is running.

Use `uv::hl::interact`, `uv::hl::ref`, `uv::hl::unref` and
uv `uv::hl::unref_and_close` to do operations against the global
loop that this function returns.

# Return

* A `hl::high_level_loop` that encapsulates communication with the global
loop.
"]
fn get() -> hl::high_level_loop {
    ret get_monitor_task_gl();
}

// WARNING: USE ONLY ONE get_*_task_gl fn in the scope of a process lifetime.
#[doc(hidden)]
fn get_monitor_task_gl() -> hl::high_level_loop {
    let monitor_loop_chan =
        rustrt::rust_uv_get_kernel_monitor_global_chan_ptr();
    ret spawn_global_weak_task(
        monitor_loop_chan,
        {|weak_exit_po, msg_po, loop_ptr, first_msg|
            log(debug, "monitor gl: entering inner loop");
            unsafe {
                monitor_task_loop_body(weak_exit_po, msg_po, loop_ptr,
                                       copy(first_msg))
            }
        },
        {|msg_ch|
            hl::monitor_task_loop({op_chan: msg_ch})
        });
}

// WARNING: USE ONLY ONE get_*_task_gl fn in the scope of a process lifetime.
#[doc(hidden)]
fn get_single_task_gl() -> hl::high_level_loop {
    let global_loop_chan_ptr = rustrt::rust_uv_get_kernel_global_chan_ptr();
    ret spawn_global_weak_task(
        global_loop_chan_ptr,
        {|weak_exit_po, msg_po, loop_ptr, first_msg|
            log(debug, "single-task gl: about to enter inner loop");
            unsafe {
                single_task_loop_body(weak_exit_po, msg_po, loop_ptr,
                                      copy(first_msg))
            }
        },
        {|msg_ch|
            log(debug, "after priv::chan_from_global_ptr");
            unsafe {
                let handle = get_global_async_handle_native_representation()
                    as **ll::uv_async_t;
                hl::single_task_loop(
                    { async_handle: handle, op_chan: msg_ch })
            }
        }
    );
}

// INTERNAL API

fn spawn_global_weak_task(
        global_loop_chan_ptr: *libc::uintptr_t,
        weak_task_body_cb: fn~(
            comm::port<()>,
            comm::port<hl::high_level_msg>,
            *libc::c_void,
            hl::high_level_msg) -> bool,
        after_task_spawn_cb: fn~(comm::chan<hl::high_level_msg>)
          -> hl::high_level_loop) -> hl::high_level_loop {
    log(debug, #fmt("ENTERING global_loop::get() loop chan: %?",
       global_loop_chan_ptr));

    let builder_fn = {||
        let builder = task::builder();
        let opts = {
            supervise: false,
            notify_chan: none,
            sched:
                some({mode: task::manual_threads(1u),
                      native_stack_size: none })
        };
        task::set_opts(builder, opts);
        builder
    };
    unsafe {
        log(debug, "before priv::chan_from_global_ptr");
        let msg_ch = priv::chan_from_global_ptr::<hl::high_level_msg>(
            global_loop_chan_ptr,
            builder_fn) {|port|

            // the actual body of our global loop lives here
            log(debug, "initialized global port task!");
            log(debug, "GLOBAL initialized global port task!");
            outer_global_loop_body(port, weak_task_body_cb);
        };
        ret after_task_spawn_cb(msg_ch);
    }
}

unsafe fn outer_global_loop_body(
    msg_po: comm::port<hl::high_level_msg>,
    weak_task_body_cb: fn~(
        comm::port<()>,
        comm::port<hl::high_level_msg>,
        *libc::c_void,
        hl::high_level_msg) -> bool) {
    // we're going to use a single libuv-generated loop ptr
    // for the duration of the process
    let loop_ptr = ll::loop_new();

    // data structure for loop goes here..

    // immediately weaken the task this is running in.
    priv::weaken_task() {|weak_exit_po|
        // when we first enter this loop, we're going
        // to wait on stand-by to receive a request to
        // fire-up the libuv loop
        let mut continue = true;
        while continue {
            log(debug, "in outer_loop...");
            continue = either::either(
                {|left_val|
                    // bail out..
                    // if we catch this msg at this point,
                    // we should just be able to exit because
                    // the loop isn't active
                    log(debug, #fmt("weak_exit_po recv'd msg: %?",
                                   left_val));
                    false
                }, {|right_val|
                    weak_task_body_cb(weak_exit_po, msg_po, loop_ptr,
                                      right_val)
                }, comm::select2(weak_exit_po, msg_po));
            log(debug,#fmt("GLOBAL LOOP EXITED, WAITING TO RESTART? %?",
                       continue));
        }
    };

    ll::loop_delete(loop_ptr);
}

unsafe fn monitor_task_loop_body(weak_exit_po_in: comm::port<()>,
                          msg_po_in: comm::port<hl::high_level_msg>,
                          loop_ptr: *libc::c_void,
                          -first_interaction: hl::high_level_msg) -> bool {
    // resend the msg to be handled in the select2 loop below..
    comm::send(comm::chan(msg_po_in), first_interaction);

    // our async_handle
    let async_handle_po = comm::port::<*ll::uv_async_t>();
    let async_handle_ch = comm::chan(async_handle_po);

    // the msg_po that libuv will be receiving on..
    let loop_msg_po = comm::port::<hl::high_level_msg>();
    let loop_msg_po_ptr = ptr::addr_of(loop_msg_po);
    let loop_msg_ch = comm::chan(loop_msg_po);

    // the question of whether unsupervising this will even do any
    // good is there.. but since this'll go into blocking in libuv with
    // a quickness.. any errors that occur (including inside crust) will
    // be segfaults.. so yeah.
    task::spawn_sched(task::manual_threads(1u)) {||
        let loop_msg_po_in = *loop_msg_po_ptr;
        hl::run_high_level_loop(
            loop_ptr,
            loop_msg_po_in, // here the loop gets handed a different message
                            // port, as we'll be receiving all of the messages
                            // initially and then passing them on..
            // before_run
            {|async_handle|
                log(debug,#fmt("monitor gl: before_run: async_handle %?",
                              async_handle));
                // when this is ran, our async_handle is set up, so let's
                // do an async_send with it.. letting the loop know, once it
                // starts, that is has work
                ll::async_send(async_handle);
                comm::send(async_handle_ch, copy(async_handle));
            },
            // before_msg_drain
            {|async_handle|
                log(debug,#fmt("monitor gl: b4_msg_drain: async_handle %?",
                              async_handle));
                true
            },
            // before_tear_down
            {|async_handle|
                log(debug,#fmt("monitor gl: b4_tear_down: async_handle %?",
                              async_handle));
            });
    };

    // our loop is set up, so let's emit the handle back out to our users..
    let async_handle = comm::recv(async_handle_po);
    // supposed to return a bool to indicate to the enclosing loop whether
    // it should continue or not..
    let mut continue_inner_loop = true;
    let mut didnt_get_hl_bailout = true;
    while continue_inner_loop {
        log(debug, "monitor task inner loop.. about to block on select2");
        continue_inner_loop = either::either(
            {|left_val|
                // bail out..
                log(debug, #fmt("monitor inner weak_exit_po recv'd msg: %?",
                               left_val));
                // TODO: make loop bail out
                didnt_get_hl_bailout = false;
                false
            }, {|right_val|
                // wake up our inner loop and pass it a msg..
                comm::send(loop_msg_ch, copy(right_val));
                ll::async_send(async_handle);
                true
            }, comm::select2(weak_exit_po_in, msg_po_in)
        )
    }
    didnt_get_hl_bailout
}

unsafe fn single_task_loop_body(weak_exit_po_in: comm::port<()>,
                          msg_po_in: comm::port<hl::high_level_msg>,
                          loop_ptr: *libc::c_void,
                          -first_interaction: hl::high_level_msg) -> bool {
    // resend the msg
    comm::send(comm::chan(msg_po_in), first_interaction);

    // black magic
    let weak_exit_po_ptr = ptr::addr_of(weak_exit_po_in);
    hl::run_high_level_loop(
        loop_ptr,
        msg_po_in,
        // before_run
        {|async_handle|
            log(debug,#fmt("global_loop before_run: async_handle %?",
                          async_handle));
            // set the handle as the global
            set_global_async_handle(0u as *ll::uv_async_t,
                                    async_handle);
            // when this is ran, our async_handle is set up, so let's
            // do an async_send with it
            ll::async_send(async_handle);
        },
        // before_msg_drain
        {|async_handle|
            log(debug,#fmt("global_loop before_msg_drain: async_handle %?",
                          async_handle));
            let weak_exit_po = *weak_exit_po_ptr;
            if(comm::peek(weak_exit_po)) {
                // if this is true, immediately bail and return false, causing
                // the libuv loop to start tearing down
                log(debug,"got weak_exit meg inside libuv loop");
                comm::recv(weak_exit_po);
                false
            }
            // if no weak_exit_po msg is received, then we'll let the
            // loop continue
            else {
                true
            }
        },
        // before_tear_down
        {|async_handle|
            log(debug,#fmt("global_loop before_tear_down: async_handle %?",
                          async_handle));
            set_global_async_handle(async_handle,
                                    0 as *ll::uv_async_t);
        });
    // supposed to return a bool to indicate to the enclosing loop whether
    // it should continue or not..
    ret true;
}

unsafe fn get_global_async_handle_native_representation()
    -> *libc::uintptr_t {
    ret rustrt::rust_uv_get_kernel_global_async_handle();
}

unsafe fn get_global_async_handle() -> *ll::uv_async_t {
    ret (*get_global_async_handle_native_representation()) as *ll::uv_async_t;
}

unsafe fn set_global_async_handle(old: *ll::uv_async_t,
                           new_ptr: *ll::uv_async_t) {
    rustrt::rust_compare_and_swap_ptr(
        get_global_async_handle_native_representation(),
        old as libc::uintptr_t,
        new_ptr as libc::uintptr_t);
}

#[cfg(test)]
mod test {
    crust fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe {
        let exit_ch_ptr = ll::get_data_for_uv_handle(
            timer_ptr as *libc::c_void) as *comm::chan<bool>;
        let exit_ch = *exit_ch_ptr;
        comm::send(exit_ch, true);
        log(debug, #fmt("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
                       exit_ch_ptr));
    }
    crust fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
                             status: libc::c_int) unsafe {
        log(debug, "in simple timer cb");
        ll::timer_stop(timer_ptr);
        let hl_loop = get_gl();
        hl::interact(hl_loop) {|loop_ptr|
            log(debug, "closing timer");
            //ll::close(timer_ptr as *libc::c_void, simple_timer_close_cb);
            hl::unref_and_close(hl_loop, timer_ptr, simple_timer_close_cb);
            log(debug, "about to deref exit_ch_ptr");
            log(debug, "after msg sent on deref'd exit_ch");
        };
        log(debug, "exiting simple timer cb");
    }

    fn impl_uv_hl_simple_timer(hl_loop: hl::high_level_loop) unsafe {
        let exit_po = comm::port::<bool>();
        let exit_ch = comm::chan(exit_po);
        let exit_ch_ptr = ptr::addr_of(exit_ch);
        log(debug, #fmt("EXIT_CH_PTR newly created exit_ch_ptr: %?",
                       exit_ch_ptr));
        let timer_handle = ll::timer_t();
        let timer_ptr = ptr::addr_of(timer_handle);
        hl::interact(hl_loop) {|loop_ptr|
            log(debug, "user code inside interact loop!!!");
            let init_status = ll::timer_init(loop_ptr, timer_ptr);
            if(init_status == 0i32) {
                hl::ref(hl_loop, timer_ptr);
                ll::set_data_for_uv_handle(
                    timer_ptr as *libc::c_void,
                    exit_ch_ptr as *libc::c_void);
                let start_status = ll::timer_start(timer_ptr, simple_timer_cb,
                                                   1u, 0u);
                if(start_status == 0i32) {
                }
                else {
                    fail "failure on ll::timer_start()";
                }
            }
            else {
                fail "failure on ll::timer_init()";
            }
        };
        comm::recv(exit_po);
        log(debug, "global_loop timer test: msg recv on exit_po, done..");
    }
    #[test]
    #[ignore]
    fn test_uv_global_loop_high_level_global_timer() unsafe {
        let hl_loop = get_gl();
        task::spawn_sched(task::manual_threads(1u), {||
            impl_uv_hl_simple_timer(hl_loop);
        });
        impl_uv_hl_simple_timer(hl_loop);
    }
}<|endoftext|>


<commit_before>
import util::interner;
import util::interner::interner;
import std::map::{hashmap, str_hash};

type str_num = uint;

enum binop {
    PLUS,
    MINUS,
    STAR,
    SLASH,
    PERCENT,
    CARET,
    AND,
    OR,
    SHL,
    SHR,
}

enum token {
    /* Expression-operator symbols. */
    EQ,
    LT,
    LE,
    EQEQ,
    NE,
    GE,
    GT,
    ANDAND,
    OROR,
    NOT,
    TILDE,
    BINOP(binop),
    BINOPEQ(binop),

    /* Structural symbols */
    AT,
    DOT,
    ELLIPSIS,
    COMMA,
    SEMI,
    COLON,
    MOD_SEP,
    RARROW,
    LARROW,
    DARROW,
    FAT_ARROW,
    LPAREN,
    RPAREN,
    LBRACKET,
    RBRACKET,
    LBRACE,
    RBRACE,
    POUND,
    DOLLAR,

    /* Literals */
    LIT_INT(i64, ast::int_ty),
    LIT_UINT(u64, ast::uint_ty),
    LIT_INT_UNSUFFIXED(i64, ast::int_ty),
    LIT_FLOAT(str_num, ast::float_ty),
    LIT_STR(str_num),

    /* Name components */
    IDENT(str_num, bool),
    UNDERSCORE,
    EOF,

}

fn binop_to_str(o: binop) -> str {
    alt o {
      PLUS { ret "+"; }
      MINUS { ret "-"; }
      STAR { ret "*"; }
      SLASH { ret "/"; }
      PERCENT { ret "%"; }
      CARET { ret "^"; }
      AND { ret "&"; }
      OR { ret "|"; }
      SHL { ret "<<"; }
      SHR { ret ">>"; }
    }
}

fn to_str(in: interner<@str>, t: token) -> str {
    alt t {
      EQ { ret "="; }
      LT { ret "<"; }
      LE { ret "<="; }
      EQEQ { ret "=="; }
      NE { ret "!="; }
      GE { ret ">="; }
      GT { ret ">"; }
      NOT { ret "!"; }
      TILDE { ret "~"; }
      OROR { ret "||"; }
      ANDAND { ret "&&"; }
      BINOP(op) { ret binop_to_str(op); }
      BINOPEQ(op) { ret binop_to_str(op) + "="; }

      /* Structural symbols */
      AT {
        ret "@";
      }
      DOT { ret "."; }
      ELLIPSIS { ret "..."; }
      COMMA { ret ","; }
      SEMI { ret ";"; }
      COLON { ret ":"; }
      MOD_SEP { ret "::"; }
      RARROW { ret "->"; }
      LARROW { ret "<-"; }
      DARROW { ret "<->"; }
      FAT_ARROW { ret "=>"; }
      LPAREN { ret "("; }
      RPAREN { ret ")"; }
      LBRACKET { ret "["; }
      RBRACKET { ret "]"; }
      LBRACE { ret "{"; }
      RBRACE { ret "}"; }
      POUND { ret "#"; }
      DOLLAR { ret "$"; }

      /* Literals */
      LIT_INT(c, ast::ty_char) {
        ret "'" + char::escape_default(c as char) + "'";
      }
      LIT_INT(i, t) {
        ret int::to_str(i as int, 10u) + ast_util::int_ty_to_str(t);
      }
      LIT_UINT(u, t) {
        ret uint::to_str(u as uint, 10u) + ast_util::uint_ty_to_str(t);
      }
      LIT_INT_UNSUFFIXED(i, t) {
        ret int::to_str(i as int, 10u) + ast_util::int_ty_to_str(t);
      }
      LIT_FLOAT(s, t) {
        ret *interner::get(in, s) +
            ast_util::float_ty_to_str(t);
      }
      LIT_STR(s) {
        ret "\""
            + str::escape_default(*interner::get(in, s))
            + "\"";
      }
      /* Name components */
      IDENT(s, _) {
        ret *interner::get(in, s);
      }
      UNDERSCORE { ret "_"; }
      EOF { ret "<eof>"; }
    }
}

pure fn can_begin_expr(t: token) -> bool {
    alt t {
      LPAREN { true }
      LBRACE { true }
      LBRACKET { true }
      IDENT(_, _) { true }
      UNDERSCORE { true }
      TILDE { true }
      LIT_INT(_, _) { true }
      LIT_UINT(_, _) { true }
      LIT_INT_UNSUFFIXED(_, _) { true }
      LIT_FLOAT(_, _) { true }
      LIT_STR(_) { true }
      POUND { true }
      AT { true }
      NOT { true }
      BINOP(MINUS) { true }
      BINOP(STAR) { true }
      BINOP(AND) { true }
      MOD_SEP { true }
      _ { false }
    }
}

fn is_lit(t: token::token) -> bool {
    ret alt t {
          token::LIT_INT(_, _) { true }
          token::LIT_UINT(_, _) { true }
          token::LIT_INT_UNSUFFIXED(_, _) { true }
          token::LIT_FLOAT(_, _) { true }
          token::LIT_STR(_) { true }
          _ { false }
        }
}

pure fn is_ident(t: token::token) -> bool {
    alt t { token::IDENT(_, _) { ret true; } _ { } }
    ret false;
}

pure fn is_plain_ident(t: token::token) -> bool {
    ret alt t { token::IDENT(_, false) { true } _ { false } };
}

pure fn is_bar(t: token::token) -> bool {
    alt t { token::BINOP(token::OR) | token::OROR { true } _ { false } }
}

#[doc = "
All the valid words that have meaning in the Rust language.

Rust keywords are either 'contextual' or 'restricted'. Contextual
keywords may be used as identifiers because their appearance in
the grammar is unambiguous. Restricted keywords may not appear
in positions that might otherwise contain _value identifiers_.
"]
fn keyword_table() -> hashmap<str, ()> {
    let keywords = str_hash();
    for contextual_keyword_table().each_key {|word|
        keywords.insert(word, ());
    }
    for restricted_keyword_table().each_key {|word|
        keywords.insert(word, ());
    }
    ret keywords;
}

#[doc = "Keywords that may be used as identifiers"]
fn contextual_keyword_table() -> hashmap<str, ()> {
    let words = str_hash();
    let keys = [
        "as",
        "bind",
        "else",
        "implements",
        "move",
        "of",
        "priv", "pub",
        "self", "send", "static",
        "to",
        "use",
        "with"
    ];
    for keys.each {|word|
        words.insert(word, ());
    }
    words
}

#[doc = "
Keywords that may not appear in any position that might otherwise contain a
_value identifier_. Restricted keywords may still be used as other types of
identifiers.

Reasons:

* For some (most?), if used at the start of a line, they will cause the line
  to be interpreted as a specific kind of statement, which would be confusing.

* `true` or `false` as identifiers would always be shadowed by
  the boolean constants
"]
fn restricted_keyword_table() -> hashmap<str, ()> {
    let words = str_hash();
    let keys = [
        "alt",
        "assert",
        "be", "break",
        "check", "claim", "class", "const", "cont", "copy", "crust",
        "drop",
        "else", "enum", "export",
        "fail", "false", "fn", "for",
        "if", "iface", "impl", "import",
        "let", "log", "loop",
        "mod", "mut",
        "native", "new",
        "pure",
        "resource", "ret",
        "true", "trait", "type",
        "unchecked", "unsafe",
        "while"
    ];
    for keys.each {|word|
        words.insert(word, ());
    }
    words
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>syntax: minor cleanups; making things more idiomatic<commit_after>import util::interner;
import util::interner::interner;
import std::map::{hashmap, str_hash};

type str_num = uint;

enum binop {
    PLUS,
    MINUS,
    STAR,
    SLASH,
    PERCENT,
    CARET,
    AND,
    OR,
    SHL,
    SHR,
}

enum token {
    /* Expression-operator symbols. */
    EQ,
    LT,
    LE,
    EQEQ,
    NE,
    GE,
    GT,
    ANDAND,
    OROR,
    NOT,
    TILDE,
    BINOP(binop),
    BINOPEQ(binop),

    /* Structural symbols */
    AT,
    DOT,
    ELLIPSIS,
    COMMA,
    SEMI,
    COLON,
    MOD_SEP,
    RARROW,
    LARROW,
    DARROW,
    FAT_ARROW,
    LPAREN,
    RPAREN,
    LBRACKET,
    RBRACKET,
    LBRACE,
    RBRACE,
    POUND,
    DOLLAR,

    /* Literals */
    LIT_INT(i64, ast::int_ty),
    LIT_UINT(u64, ast::uint_ty),
    LIT_INT_UNSUFFIXED(i64, ast::int_ty),
    LIT_FLOAT(str_num, ast::float_ty),
    LIT_STR(str_num),

    /* Name components */
    IDENT(str_num, bool),
    UNDERSCORE,
    EOF,
}

fn binop_to_str(o: binop) -> str {
    alt o {
      PLUS { "+" }
      MINUS { "-" }
      STAR { "*" }
      SLASH { "/" }
      PERCENT { "%" }
      CARET { "^" }
      AND { "&" }
      OR { "|" }
      SHL { "<<" }
      SHR { ">>" }
    }
}

fn to_str(in: interner<@str>, t: token) -> str {
    alt t {
      EQ { "=" }
      LT { "<" }
      LE { "<=" }
      EQEQ { "==" }
      NE { "!=" }
      GE { ">=" }
      GT { ">" }
      NOT { "!" }
      TILDE { "~" }
      OROR { "||" }
      ANDAND { "&&" }
      BINOP(op) { binop_to_str(op) }
      BINOPEQ(op) { binop_to_str(op) + "=" }

      /* Structural symbols */
      AT { "@" }
      DOT { "." }
      ELLIPSIS { "..." }
      COMMA { "," }
      SEMI { "" }
      COLON { ":" }
      MOD_SEP { "::" }
      RARROW { "->" }
      LARROW { "<-" }
      DARROW { "<->" }
      FAT_ARROW { "=>" }
      LPAREN { "(" }
      RPAREN { ")" }
      LBRACKET { "[" }
      RBRACKET { "]" }
      LBRACE { "{" }
      RBRACE { "}" }
      POUND { "#" }
      DOLLAR { "$" }

      /* Literals */
      LIT_INT(c, ast::ty_char) {
        "'" + char::escape_default(c as char) + "'"
      }
      LIT_INT(i, t) {
        int::to_str(i as int, 10u) + ast_util::int_ty_to_str(t)
      }
      LIT_UINT(u, t) {
        uint::to_str(u as uint, 10u) + ast_util::uint_ty_to_str(t)
      }
      LIT_INT_UNSUFFIXED(i, t) {
        int::to_str(i as int, 10u) + ast_util::int_ty_to_str(t)
      }
      LIT_FLOAT(s, t) {
        *interner::get(in, s) +
            ast_util::float_ty_to_str(t)
      }
      LIT_STR(s) {
        "\""
            + str::escape_default(*interner::get(in, s))
            + "\""
      }
      /* Name components */
      IDENT(s, _) {
        *interner::get(in, s)
      }
      UNDERSCORE { "_" }
      EOF { "<eof>" }
    }
}

pure fn can_begin_expr(t: token) -> bool {
    alt t {
      LPAREN { true }
      LBRACE { true }
      LBRACKET { true }
      IDENT(_, _) { true }
      UNDERSCORE { true }
      TILDE { true }
      LIT_INT(_, _) { true }
      LIT_UINT(_, _) { true }
      LIT_INT_UNSUFFIXED(_, _) { true }
      LIT_FLOAT(_, _) { true }
      LIT_STR(_) { true }
      POUND { true }
      AT { true }
      NOT { true }
      BINOP(MINUS) { true }
      BINOP(STAR) { true }
      BINOP(AND) { true }
      MOD_SEP { true }
      _ { false }
    }
}

fn is_lit(t: token) -> bool {
    alt t {
      LIT_INT(_, _) { true }
      LIT_UINT(_, _) { true }
      LIT_INT_UNSUFFIXED(_, _) { true }
      LIT_FLOAT(_, _) { true }
      LIT_STR(_) { true }
      _ { false }
    }
}

pure fn is_ident(t: token) -> bool {
    alt t { IDENT(_, _) { true } _ { false } }
}

pure fn is_plain_ident(t: token) -> bool {
    alt t { IDENT(_, false) { true } _ { false } }
}

pure fn is_bar(t: token) -> bool {
    alt t { BINOP(OR) | OROR { true } _ { false } }
}

#[doc = "
All the valid words that have meaning in the Rust language.

Rust keywords are either 'contextual' or 'restricted'. Contextual
keywords may be used as identifiers because their appearance in
the grammar is unambiguous. Restricted keywords may not appear
in positions that might otherwise contain _value identifiers_.
"]
fn keyword_table() -> hashmap<str, ()> {
    let keywords = str_hash();
    for contextual_keyword_table().each_key {|word|
        keywords.insert(word, ());
    }
    for restricted_keyword_table().each_key {|word|
        keywords.insert(word, ());
    }
    keywords
}

#[doc = "Keywords that may be used as identifiers"]
fn contextual_keyword_table() -> hashmap<str, ()> {
    let words = str_hash();
    let keys = [
        "as",
        "bind",
        "else",
        "implements",
        "move",
        "of",
        "priv", "pub",
        "self", "send", "static",
        "to",
        "use",
        "with"
    ];
    for keys.each {|word|
        words.insert(word, ());
    }
    words
}

#[doc = "
Keywords that may not appear in any position that might otherwise contain a
_value identifier_. Restricted keywords may still be used as other types of
identifiers.

Reasons:

* For some (most?), if used at the start of a line, they will cause the line
  to be interpreted as a specific kind of statement, which would be confusing.

* `true` or `false` as identifiers would always be shadowed by
  the boolean constants
"]
fn restricted_keyword_table() -> hashmap<str, ()> {
    let words = str_hash();
    let keys = [
        "alt",
        "assert",
        "be", "break",
        "check", "claim", "class", "const", "cont", "copy", "crust",
        "drop",
        "else", "enum", "export",
        "fail", "false", "fn", "for",
        "if", "iface", "impl", "import",
        "let", "log", "loop",
        "mod", "mut",
        "native", "new",
        "pure",
        "resource", "ret",
        "true", "trait", "type",
        "unchecked", "unsafe",
        "while"
    ];
    for keys.each {|word|
        words.insert(word, ());
    }
    words
}

// Local Variables:
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader, BufWriter, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::string;

use mktemp::Temp;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        UnableToCreateTempDir(err: io::Error) {
            description("unable to create temporary directory")
            display("Unable to create temporary directory: {}", err)
            cause(err)
        }
        UnableToCreateSourceFile(err: io::Error) {
            description("unable to create source file")
            display("Unable to create source file: {}", err)
            cause(err)
        }
        UnableToExecuteCompiler(err: io::Error) {
            description("unable to execute the compiler")
            display("Unable to execute the compiler: {}", err)
            cause(err)
        }
        UnableToReadOutput(err: io::Error) {
            description("unable to read output file")
            display("Unable to read output file: {}", err)
            cause(err)
        }
        OutputNotUtf8(err: string::FromUtf8Error) {
            description("output was not valid UTF-8")
            display("Output was not valid UTF-8: {}", err)
            cause(err)
        }
        OutputMissing {
            description("output was missing")
            display("Output was missing")
        }
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub struct Sandbox {
    scratch_dir: Temp,
}

fn vec_to_str(v: Vec<u8>) -> Result<String> {
    String::from_utf8(v).map_err(Error::OutputNotUtf8)
}

impl Sandbox {
    pub fn new() -> Result<Self> {
        Ok(Sandbox {
            scratch_dir: try!(Temp::new_dir().map_err(Error::UnableToCreateTempDir)),
        })
    }

    pub fn compile(&self, req: &CompileRequest) -> Result<CompileResponse> {
        try!(self.write_source_code(&req.code));

        let mut output_path = self.scratch_dir.as_ref().to_path_buf();
        output_path.push("compiler-output");
        let mut command = self.compile_command(req.target, req.channel, req.mode, req.tests);

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(CompileResponse {
            success: output.status.success(),
            code: try!(read(&output_path)).unwrap_or_else(String::new),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    pub fn execute(&self, req: &ExecuteRequest) -> Result<ExecuteResponse> {
        try!(self.write_source_code(&req.code));
        let mut command = self.execute_command(req.channel, req.mode, req.tests);

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(ExecuteResponse {
            success: output.status.success(),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    pub fn format(&self, req: &FormatRequest) -> Result<FormatResponse> {
        let path = try!(self.write_source_code(&req.code));
        let mut command = self.format_command();

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(FormatResponse {
            success: output.status.success(),
            code: try!(try!(read(path.as_path())).ok_or(Error::OutputMissing)),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    fn write_source_code(&self, code: &str) -> Result<PathBuf> {
        let data = code.as_bytes();

        let path = {
            let mut p = self.scratch_dir.to_path_buf();
            p.push("main.rs");
            p
        };

        let file = try!(File::create(&path).map_err(Error::UnableToCreateSourceFile));
        let mut file = BufWriter::new(file);

        try!(file.write_all(data).map_err(Error::UnableToCreateSourceFile));

        debug!("Wrote {} bytes of source to {}", data.len(), path.display());
        Ok(path)
    }

    fn compile_command(&self, target: CompileTarget, channel: Channel, mode: Mode, tests: bool) -> Command {
        let mut cmd = self.docker_command();

        let execution_cmd = build_execution_command(Some((target, "compiler-output")), mode, tests, "main.rs");

        cmd.arg(&channel.container_name()).args(&["bash", "-c", &execution_cmd]);

        debug!("Compilation command is {:?}", cmd);

        cmd
    }

    fn execute_command(&self, channel: Channel, mode: Mode, tests: bool) -> Command {
        let mut cmd = self.docker_command();

        let mut execution_cmd = build_execution_command(None, mode, tests, "main.rs");
        execution_cmd.push_str(" && ./main");

        cmd.arg(&channel.container_name()).args(&["bash", "-c", &execution_cmd]);

        debug!("Execution command is {:?}", cmd);

        cmd
    }

    fn format_command(&self) -> Command {
        let mut cmd = self.docker_command();

        cmd.arg("rustfmt").args(&["main.rs"]);

        debug!("Formatting command is {:?}", cmd);

        cmd
    }

    fn docker_command(&self) -> Command {
        const DIR_INSIDE_CONTAINER: &'static str = "/source";

        let mut mount_source_volume = self.scratch_dir.as_ref().as_os_str().to_os_string();
        mount_source_volume.push(":");
        mount_source_volume.push(DIR_INSIDE_CONTAINER);

        let mut cmd = Command::new("docker");

        cmd
            .arg("run")
            .arg("--volume").arg(&mount_source_volume)
            .args(&["--workdir", DIR_INSIDE_CONTAINER]);

        cmd
    }
}

fn build_execution_command(target: Option<(CompileTarget, &str)>, mode: Mode, tests: bool, source_file: &str) -> String {
    use self::CompileTarget::*;
    use self::Mode::*;

    let mut s = String::from("rustc");

    match mode {
        Debug => s.push_str(" -g"),
        Release => s.push_str(" -C opt-level=3"),
    }

    if tests {
        s.push_str(" --test");
    }

    if let Some((target, filename)) = target {
        match target {
            Assembly => s.push_str(" --emit asm"),
            LlvmIr => s.push_str(" --emit llvm-ir"),
        }
        s.push_str(" -o ");
        s.push_str(filename);
    }

    s.push_str(" ");
    s.push_str(source_file);

    s
}

fn read(path: &Path) -> Result<Option<String>> {
    let f = match File::open(path) {
        Ok(f) => f,
        Err(ref e) if e.kind() == ErrorKind::NotFound => return Ok(None),
        Err(e) => return Err(Error::UnableToReadOutput(e)),
    };
    let mut f = BufReader::new(f);

    let mut s = String::new();
    try!(f.read_to_string(&mut s).map_err(Error::UnableToReadOutput));
    Ok(Some(s))
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CompileTarget {
    Assembly,
    LlvmIr,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Channel {
    Stable,
    Beta,
    Nightly,
}

impl Channel {
    fn container_name(&self) -> &'static str {
        use self::Channel::*;

        match *self {
            Stable => "rust-stable",
            Beta => "rust-beta",
            Nightly => "rust-nightly",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Debug,
    Release,
}

#[derive(Debug, Clone)]
pub struct CompileRequest {
    pub target: CompileTarget,
    pub channel: Channel,
    pub mode: Mode,
    pub tests: bool,
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct CompileResponse {
    pub success: bool,
    pub code: String,
    pub stdout: String,
    pub stderr: String,
}

#[derive(Debug, Clone)]
pub struct ExecuteRequest {
    pub channel: Channel,
    pub mode: Mode,
    pub tests: bool,
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct ExecuteResponse {
    pub success: bool,
    pub stdout: String,
    pub stderr: String,
}

#[derive(Debug, Clone)]
pub struct FormatRequest {
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct FormatResponse {
    pub success: bool,
    pub code: String,
    pub stdout: String,
    pub stderr: String,
}
<commit_msg>Prevent outside network connections<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::{self, BufReader, BufWriter, ErrorKind};
use std::path::{Path, PathBuf};
use std::process::Command;
use std::string;

use mktemp::Temp;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        UnableToCreateTempDir(err: io::Error) {
            description("unable to create temporary directory")
            display("Unable to create temporary directory: {}", err)
            cause(err)
        }
        UnableToCreateSourceFile(err: io::Error) {
            description("unable to create source file")
            display("Unable to create source file: {}", err)
            cause(err)
        }
        UnableToExecuteCompiler(err: io::Error) {
            description("unable to execute the compiler")
            display("Unable to execute the compiler: {}", err)
            cause(err)
        }
        UnableToReadOutput(err: io::Error) {
            description("unable to read output file")
            display("Unable to read output file: {}", err)
            cause(err)
        }
        OutputNotUtf8(err: string::FromUtf8Error) {
            description("output was not valid UTF-8")
            display("Output was not valid UTF-8: {}", err)
            cause(err)
        }
        OutputMissing {
            description("output was missing")
            display("Output was missing")
        }
    }
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub struct Sandbox {
    scratch_dir: Temp,
}

fn vec_to_str(v: Vec<u8>) -> Result<String> {
    String::from_utf8(v).map_err(Error::OutputNotUtf8)
}

impl Sandbox {
    pub fn new() -> Result<Self> {
        Ok(Sandbox {
            scratch_dir: try!(Temp::new_dir().map_err(Error::UnableToCreateTempDir)),
        })
    }

    pub fn compile(&self, req: &CompileRequest) -> Result<CompileResponse> {
        try!(self.write_source_code(&req.code));

        let mut output_path = self.scratch_dir.as_ref().to_path_buf();
        output_path.push("compiler-output");
        let mut command = self.compile_command(req.target, req.channel, req.mode, req.tests);

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(CompileResponse {
            success: output.status.success(),
            code: try!(read(&output_path)).unwrap_or_else(String::new),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    pub fn execute(&self, req: &ExecuteRequest) -> Result<ExecuteResponse> {
        try!(self.write_source_code(&req.code));
        let mut command = self.execute_command(req.channel, req.mode, req.tests);

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(ExecuteResponse {
            success: output.status.success(),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    pub fn format(&self, req: &FormatRequest) -> Result<FormatResponse> {
        let path = try!(self.write_source_code(&req.code));
        let mut command = self.format_command();

        let output = try!(command.output().map_err(Error::UnableToExecuteCompiler));

        Ok(FormatResponse {
            success: output.status.success(),
            code: try!(try!(read(path.as_path())).ok_or(Error::OutputMissing)),
            stdout: try!(vec_to_str(output.stdout)),
            stderr: try!(vec_to_str(output.stderr)),
        })
    }

    fn write_source_code(&self, code: &str) -> Result<PathBuf> {
        let data = code.as_bytes();

        let path = {
            let mut p = self.scratch_dir.to_path_buf();
            p.push("main.rs");
            p
        };

        let file = try!(File::create(&path).map_err(Error::UnableToCreateSourceFile));
        let mut file = BufWriter::new(file);

        try!(file.write_all(data).map_err(Error::UnableToCreateSourceFile));

        debug!("Wrote {} bytes of source to {}", data.len(), path.display());
        Ok(path)
    }

    fn compile_command(&self, target: CompileTarget, channel: Channel, mode: Mode, tests: bool) -> Command {
        let mut cmd = self.docker_command();

        let execution_cmd = build_execution_command(Some((target, "compiler-output")), mode, tests, "main.rs");

        cmd.arg(&channel.container_name()).args(&["bash", "-c", &execution_cmd]);

        debug!("Compilation command is {:?}", cmd);

        cmd
    }

    fn execute_command(&self, channel: Channel, mode: Mode, tests: bool) -> Command {
        let mut cmd = self.docker_command();

        let mut execution_cmd = build_execution_command(None, mode, tests, "main.rs");
        execution_cmd.push_str(" && ./main");

        cmd.arg(&channel.container_name()).args(&["bash", "-c", &execution_cmd]);

        debug!("Execution command is {:?}", cmd);

        cmd
    }

    fn format_command(&self) -> Command {
        let mut cmd = self.docker_command();

        cmd.arg("rustfmt").args(&["main.rs"]);

        debug!("Formatting command is {:?}", cmd);

        cmd
    }

    fn docker_command(&self) -> Command {
        const DIR_INSIDE_CONTAINER: &'static str = "/source";

        let mut mount_source_volume = self.scratch_dir.as_ref().as_os_str().to_os_string();
        mount_source_volume.push(":");
        mount_source_volume.push(DIR_INSIDE_CONTAINER);

        let mut cmd = Command::new("docker");

        cmd
            .arg("run")
            .arg("--volume").arg(&mount_source_volume)
            .args(&["--workdir", DIR_INSIDE_CONTAINER])
            .args(&["--net", "none"]);

        cmd
    }
}

fn build_execution_command(target: Option<(CompileTarget, &str)>, mode: Mode, tests: bool, source_file: &str) -> String {
    use self::CompileTarget::*;
    use self::Mode::*;

    let mut s = String::from("rustc");

    match mode {
        Debug => s.push_str(" -g"),
        Release => s.push_str(" -C opt-level=3"),
    }

    if tests {
        s.push_str(" --test");
    }

    if let Some((target, filename)) = target {
        match target {
            Assembly => s.push_str(" --emit asm"),
            LlvmIr => s.push_str(" --emit llvm-ir"),
        }
        s.push_str(" -o ");
        s.push_str(filename);
    }

    s.push_str(" ");
    s.push_str(source_file);

    s
}

fn read(path: &Path) -> Result<Option<String>> {
    let f = match File::open(path) {
        Ok(f) => f,
        Err(ref e) if e.kind() == ErrorKind::NotFound => return Ok(None),
        Err(e) => return Err(Error::UnableToReadOutput(e)),
    };
    let mut f = BufReader::new(f);

    let mut s = String::new();
    try!(f.read_to_string(&mut s).map_err(Error::UnableToReadOutput));
    Ok(Some(s))
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum CompileTarget {
    Assembly,
    LlvmIr,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Channel {
    Stable,
    Beta,
    Nightly,
}

impl Channel {
    fn container_name(&self) -> &'static str {
        use self::Channel::*;

        match *self {
            Stable => "rust-stable",
            Beta => "rust-beta",
            Nightly => "rust-nightly",
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Mode {
    Debug,
    Release,
}

#[derive(Debug, Clone)]
pub struct CompileRequest {
    pub target: CompileTarget,
    pub channel: Channel,
    pub mode: Mode,
    pub tests: bool,
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct CompileResponse {
    pub success: bool,
    pub code: String,
    pub stdout: String,
    pub stderr: String,
}

#[derive(Debug, Clone)]
pub struct ExecuteRequest {
    pub channel: Channel,
    pub mode: Mode,
    pub tests: bool,
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct ExecuteResponse {
    pub success: bool,
    pub stdout: String,
    pub stderr: String,
}

#[derive(Debug, Clone)]
pub struct FormatRequest {
    pub code: String,
}

#[derive(Debug, Clone)]
pub struct FormatResponse {
    pub success: bool,
    pub code: String,
    pub stdout: String,
    pub stderr: String,
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn network_connections_are_disabled() {
        let code = r#"
            fn main() {
                match ::std::net::TcpStream::connect("google.com:80") {
                    Ok(_) => println!("Able to connect to the outside world"),
                    Err(e) => println!("Failed to connect {}, {:?}", e, e),
                }
            }
        "#;

        let req = ExecuteRequest {
            channel: Channel::Stable,
            mode: Mode::Debug,
            tests: false,
            code: code.to_string(),
        };

        let sb = Sandbox::new().expect("Unable to create sandbox");
        let resp = sb.execute(&req).expect("Unable to execute code");

        assert!(resp.stdout.contains("Failed to connect"));
    }
}
<|endoftext|>


<commit_before><commit_msg>fixed attack list<commit_after><|endoftext|>