<commit_before>// Copyright 2013 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.

/*!
Sampling from random distributions.

This is a generalization of `Rand` to allow parameters to control the
exact properties of the generated values, e.g. the mean and standard
deviation of a normal distribution. The `Sample` trait is the most
general, and allows for generating values that change some state
internally. The `IndependentSample` trait is for generating values
that do not need to record state.

*/

#![experimental]

use core::prelude::*;

use {Rng, Rand};

pub use self::range::Range;
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
pub use self::normal::{Normal, LogNormal};
pub use self::exponential::Exp;

pub mod range;
pub mod gamma;
pub mod normal;
pub mod exponential;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
    /// Generate a random value of `Support`, using `rng` as the
    /// source of randomness.
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}

/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// FIXME maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
    /// Generate a random value.
    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}

/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup>;

impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}

impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        rng.gen()
    }
}

/// A value with a particular weight for use with `WeightedChoice`.
pub struct Weighted<T> {
    /// The numerical weight of this item
    pub weight: uint,
    /// The actual item which is being weighted
    pub item: T,
}

/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// is to be chosen: higher weight is more likely.
///
/// The `Clone` restriction is a limitation of the `Sample` and
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `uint`, so one can store references or indices into
/// another vector.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{Weighted, WeightedChoice, IndependentSample};
///
/// let mut items = vec!(Weighted { weight: 2, item: 'a' },
///                      Weighted { weight: 4, item: 'b' },
///                      Weighted { weight: 1, item: 'c' });
/// let wc = WeightedChoice::new(items.as_mut_slice());
/// let mut rng = rand::task_rng();
/// for _ in range(0u, 16) {
///      // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
///      println!("{}", wc.ind_sample(&mut rng));
/// }
/// ```
pub struct WeightedChoice<'a, T:'a> {
    items: &'a mut [Weighted<T>],
    weight_range: Range<uint>
}

impl<'a, T: Clone> WeightedChoice<'a, T> {
    /// Create a new `WeightedChoice`.
    ///
    /// Fails if:
    /// - `v` is empty
    /// - the total weight is 0
    /// - the total weight is larger than a `uint` can contain.
    pub fn new<'a>(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
        // strictly speaking, this is subsumed by the total weight == 0 case
        assert!(!items.is_empty(), "WeightedChoice::new called with no items");

        let mut running_total = 0u;

        // we convert the list from individual weights to cumulative
        // weights so we can binary search. This *could* drop elements
        // with weight == 0 as an optimisation.
        for item in items.iter_mut() {
            running_total = match running_total.checked_add(&item.weight) {
                Some(n) => n,
                None => panic!("WeightedChoice::new called with a total weight \
                               larger than a uint can contain")
            };

            item.weight = running_total;
        }
        assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");

        WeightedChoice {
            items: items,
            // we're likely to be generating numbers in this range
            // relatively often, so might as well cache it
            weight_range: Range::new(0, running_total)
        }
    }
}

impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
}

impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
        // we want to find the first element that has cumulative
        // weight > sample_weight, which we do by binary since the
        // cumulative weights of self.items are sorted.

        // choose a weight in [0, total_weight)
        let sample_weight = self.weight_range.ind_sample(rng);

        // short circuit when it's the first item
        if sample_weight < self.items[0].weight {
            return self.items[0].item.clone();
        }

        let mut idx = 0;
        let mut modifier = self.items.len();

        // now we know that every possibility has an element to the
        // left, so we can just search for the last element that has
        // cumulative weight <= sample_weight, then the next one will
        // be "it". (Note that this greatest element will never be the
        // last element of the vector, since sample_weight is chosen
        // in [0, total_weight) and the cumulative weight of the last
        // one is exactly the total weight.)
        while modifier > 1 {
            let i = idx + modifier / 2;
            if self.items[i].weight <= sample_weight {
                // we're small, so look to the right, but allow this
                // exact element still.
                idx = i;
                // we need the `/ 2` to round up otherwise we'll drop
                // the trailing elements when `modifier` is odd.
                modifier += 1;
            } else {
                // otherwise we're too big, so go left. (i.e. do
                // nothing)
            }
            modifier /= 2;
        }
        return self.items[idx + 1].item.clone();
    }
}

mod ziggurat_tables;

/// 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)]
fn ziggurat<R:Rng>(
            rng: &mut R,
            symmetric: bool,
            x_tab: ziggurat_tables::ZigTable,
            f_tab: ziggurat_tables::ZigTable,
            pdf: |f64|: 'static -> f64,
            zero_case: |&mut R, f64|: 'static -> f64)
            -> f64 {
    static SCALE: f64 = (1u64 << 53) as f64;
    loop {
        // reimplement the f64 generation as an optimisation suggested
        // by the Doornik paper: we have a lot of precision-space
        // (i.e. there are 11 bits of the 64 of a u64 to use after
        // creating a f64), so we might as well reuse some to save
        // generating a whole extra random number. (Seems to be 15%
        // faster.)
        //
        // This unfortunately misses out on the benefits of direct
        // floating point generation if an RNG like dSMFT is
        // used. (That is, such RNGs create floats directly, highly
        // efficiently and overload next_f32/f64, so by not calling it
        // this may be slower than it would be otherwise.)
        // FIXME: investigate/optimise for the above.
        let bits: u64 = rng.gen();
        let i = (bits & 0xff) as uint;
        let f = (bits >> 11) as f64 / SCALE;

        // u is either U(-1, 1) or U(0, 1) depending on if this is a
        // symmetric distribution or not.
        let u = if symmetric {2.0 * f - 1.0} else {f};
        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() < pdf(x) {
            return x;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::*;

    use {Rng, Rand};
    use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};

    #[deriving(PartialEq, Show)]
    struct ConstRand(uint);
    impl Rand for ConstRand {
        fn rand<R: Rng>(_: &mut R) -> ConstRand {
            ConstRand(0)
        }
    }

    // 0, 1, 2, 3, ...
    struct CountingRng { i: u32 }
    impl Rng for CountingRng {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            self.i - 1
        }
        fn next_u64(&mut self) -> u64 {
            self.next_u32() as u64
        }
    }

    #[test]
    fn test_rand_sample() {
        let mut rand_sample = RandSample::<ConstRand>;

        assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
        assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
    }
    #[test]
    fn test_weighted_choice() {
        // this makes assumptions about the internal implementation of
        // WeightedChoice, specifically: it doesn't reorder the items,
        // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
        // 1, internally; modulo a modulo operation).

        macro_rules! t (
            ($items:expr, $expected:expr) => {{
                let mut items = $items;
                let wc = WeightedChoice::new(items.as_mut_slice());
                let expected = $expected;

                let mut rng = CountingRng { i: 0 };

                for &val in expected.iter() {
                    assert_eq!(wc.ind_sample(&mut rng), val)
                }
            }}
        );

        t!(vec!(Weighted { weight: 1, item: 10i}), [10]);

        // skip some
        t!(vec!(Weighted { weight: 0, item: 20i},
                Weighted { weight: 2, item: 21i},
                Weighted { weight: 0, item: 22i},
                Weighted { weight: 1, item: 23i}),
           [21,21, 23]);

        // different weights
        t!(vec!(Weighted { weight: 4, item: 30i},
                Weighted { weight: 3, item: 31i}),
           [30,30,30,30, 31,31,31]);

        // check that we're binary searching
        // correctly with some vectors of odd
        // length.
        t!(vec!(Weighted { weight: 1, item: 40i},
                Weighted { weight: 1, item: 41i},
                Weighted { weight: 1, item: 42i},
                Weighted { weight: 1, item: 43i},
                Weighted { weight: 1, item: 44i}),
           [40, 41, 42, 43, 44]);
        t!(vec!(Weighted { weight: 1, item: 50i},
                Weighted { weight: 1, item: 51i},
                Weighted { weight: 1, item: 52i},
                Weighted { weight: 1, item: 53i},
                Weighted { weight: 1, item: 54i},
                Weighted { weight: 1, item: 55i},
                Weighted { weight: 1, item: 56i}),
           [50, 51, 52, 53, 54, 55, 56]);
    }

    #[test] #[should_fail]
    fn test_weighted_choice_no_items() {
        WeightedChoice::<int>::new([]);
    }
    #[test] #[should_fail]
    fn test_weighted_choice_zero_weight() {
        WeightedChoice::new(&mut [Weighted { weight: 0, item: 0i},
                                  Weighted { weight: 0, item: 1i}]);
    }
    #[test] #[should_fail]
    fn test_weighted_choice_weight_overflows() {
        let x = (-1) as uint / 2; // x + x + 2 is the overflow
        WeightedChoice::new(&mut [Weighted { weight: x, item: 0i },
                                  Weighted { weight: 1, item: 1i },
                                  Weighted { weight: x, item: 2i },
                                  Weighted { weight: 1, item: 3i }]);
    }
}
<commit_msg>Move checked arithmetic operators into Int trait<commit_after>// Copyright 2013 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.

/*!
Sampling from random distributions.

This is a generalization of `Rand` to allow parameters to control the
exact properties of the generated values, e.g. the mean and standard
deviation of a normal distribution. The `Sample` trait is the most
general, and allows for generating values that change some state
internally. The `IndependentSample` trait is for generating values
that do not need to record state.

*/

#![experimental]

use core::prelude::*;

use {Rng, Rand};

pub use self::range::Range;
pub use self::gamma::{Gamma, ChiSquared, FisherF, StudentT};
pub use self::normal::{Normal, LogNormal};
pub use self::exponential::Exp;

pub mod range;
pub mod gamma;
pub mod normal;
pub mod exponential;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
    /// Generate a random value of `Support`, using `rng` as the
    /// source of randomness.
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}

/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recorded, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// FIXME maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
    /// Generate a random value.
    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}

/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup>;

impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}

impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        rng.gen()
    }
}

/// A value with a particular weight for use with `WeightedChoice`.
pub struct Weighted<T> {
    /// The numerical weight of this item
    pub weight: uint,
    /// The actual item which is being weighted
    pub item: T,
}

/// A distribution that selects from a finite collection of weighted items.
///
/// Each item has an associated weight that influences how likely it
/// is to be chosen: higher weight is more likely.
///
/// The `Clone` restriction is a limitation of the `Sample` and
/// `IndependentSample` traits. Note that `&T` is (cheaply) `Clone` for
/// all `T`, as is `uint`, so one can store references or indices into
/// another vector.
///
/// # Example
///
/// ```rust
/// use std::rand;
/// use std::rand::distributions::{Weighted, WeightedChoice, IndependentSample};
///
/// let mut items = vec!(Weighted { weight: 2, item: 'a' },
///                      Weighted { weight: 4, item: 'b' },
///                      Weighted { weight: 1, item: 'c' });
/// let wc = WeightedChoice::new(items.as_mut_slice());
/// let mut rng = rand::task_rng();
/// for _ in range(0u, 16) {
///      // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
///      println!("{}", wc.ind_sample(&mut rng));
/// }
/// ```
pub struct WeightedChoice<'a, T:'a> {
    items: &'a mut [Weighted<T>],
    weight_range: Range<uint>
}

impl<'a, T: Clone> WeightedChoice<'a, T> {
    /// Create a new `WeightedChoice`.
    ///
    /// Fails if:
    /// - `v` is empty
    /// - the total weight is 0
    /// - the total weight is larger than a `uint` can contain.
    pub fn new<'a>(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
        // strictly speaking, this is subsumed by the total weight == 0 case
        assert!(!items.is_empty(), "WeightedChoice::new called with no items");

        let mut running_total = 0u;

        // we convert the list from individual weights to cumulative
        // weights so we can binary search. This *could* drop elements
        // with weight == 0 as an optimisation.
        for item in items.iter_mut() {
            running_total = match running_total.checked_add(item.weight) {
                Some(n) => n,
                None => panic!("WeightedChoice::new called with a total weight \
                               larger than a uint can contain")
            };

            item.weight = running_total;
        }
        assert!(running_total != 0, "WeightedChoice::new called with a total weight of 0");

        WeightedChoice {
            items: items,
            // we're likely to be generating numbers in this range
            // relatively often, so might as well cache it
            weight_range: Range::new(0, running_total)
        }
    }
}

impl<'a, T: Clone> Sample<T> for WeightedChoice<'a, T> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> T { self.ind_sample(rng) }
}

impl<'a, T: Clone> IndependentSample<T> for WeightedChoice<'a, T> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> T {
        // we want to find the first element that has cumulative
        // weight > sample_weight, which we do by binary since the
        // cumulative weights of self.items are sorted.

        // choose a weight in [0, total_weight)
        let sample_weight = self.weight_range.ind_sample(rng);

        // short circuit when it's the first item
        if sample_weight < self.items[0].weight {
            return self.items[0].item.clone();
        }

        let mut idx = 0;
        let mut modifier = self.items.len();

        // now we know that every possibility has an element to the
        // left, so we can just search for the last element that has
        // cumulative weight <= sample_weight, then the next one will
        // be "it". (Note that this greatest element will never be the
        // last element of the vector, since sample_weight is chosen
        // in [0, total_weight) and the cumulative weight of the last
        // one is exactly the total weight.)
        while modifier > 1 {
            let i = idx + modifier / 2;
            if self.items[i].weight <= sample_weight {
                // we're small, so look to the right, but allow this
                // exact element still.
                idx = i;
                // we need the `/ 2` to round up otherwise we'll drop
                // the trailing elements when `modifier` is odd.
                modifier += 1;
            } else {
                // otherwise we're too big, so go left. (i.e. do
                // nothing)
            }
            modifier /= 2;
        }
        return self.items[idx + 1].item.clone();
    }
}

mod ziggurat_tables;

/// 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)]
fn ziggurat<R:Rng>(
            rng: &mut R,
            symmetric: bool,
            x_tab: ziggurat_tables::ZigTable,
            f_tab: ziggurat_tables::ZigTable,
            pdf: |f64|: 'static -> f64,
            zero_case: |&mut R, f64|: 'static -> f64)
            -> f64 {
    static SCALE: f64 = (1u64 << 53) as f64;
    loop {
        // reimplement the f64 generation as an optimisation suggested
        // by the Doornik paper: we have a lot of precision-space
        // (i.e. there are 11 bits of the 64 of a u64 to use after
        // creating a f64), so we might as well reuse some to save
        // generating a whole extra random number. (Seems to be 15%
        // faster.)
        //
        // This unfortunately misses out on the benefits of direct
        // floating point generation if an RNG like dSMFT is
        // used. (That is, such RNGs create floats directly, highly
        // efficiently and overload next_f32/f64, so by not calling it
        // this may be slower than it would be otherwise.)
        // FIXME: investigate/optimise for the above.
        let bits: u64 = rng.gen();
        let i = (bits & 0xff) as uint;
        let f = (bits >> 11) as f64 / SCALE;

        // u is either U(-1, 1) or U(0, 1) depending on if this is a
        // symmetric distribution or not.
        let u = if symmetric {2.0 * f - 1.0} else {f};
        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() < pdf(x) {
            return x;
        }
    }
}

#[cfg(test)]
mod tests {
    use std::prelude::*;

    use {Rng, Rand};
    use super::{RandSample, WeightedChoice, Weighted, Sample, IndependentSample};

    #[deriving(PartialEq, Show)]
    struct ConstRand(uint);
    impl Rand for ConstRand {
        fn rand<R: Rng>(_: &mut R) -> ConstRand {
            ConstRand(0)
        }
    }

    // 0, 1, 2, 3, ...
    struct CountingRng { i: u32 }
    impl Rng for CountingRng {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            self.i - 1
        }
        fn next_u64(&mut self) -> u64 {
            self.next_u32() as u64
        }
    }

    #[test]
    fn test_rand_sample() {
        let mut rand_sample = RandSample::<ConstRand>;

        assert_eq!(rand_sample.sample(&mut ::test::rng()), ConstRand(0));
        assert_eq!(rand_sample.ind_sample(&mut ::test::rng()), ConstRand(0));
    }
    #[test]
    fn test_weighted_choice() {
        // this makes assumptions about the internal implementation of
        // WeightedChoice, specifically: it doesn't reorder the items,
        // it doesn't do weird things to the RNG (so 0 maps to 0, 1 to
        // 1, internally; modulo a modulo operation).

        macro_rules! t (
            ($items:expr, $expected:expr) => {{
                let mut items = $items;
                let wc = WeightedChoice::new(items.as_mut_slice());
                let expected = $expected;

                let mut rng = CountingRng { i: 0 };

                for &val in expected.iter() {
                    assert_eq!(wc.ind_sample(&mut rng), val)
                }
            }}
        );

        t!(vec!(Weighted { weight: 1, item: 10i}), [10]);

        // skip some
        t!(vec!(Weighted { weight: 0, item: 20i},
                Weighted { weight: 2, item: 21i},
                Weighted { weight: 0, item: 22i},
                Weighted { weight: 1, item: 23i}),
           [21,21, 23]);

        // different weights
        t!(vec!(Weighted { weight: 4, item: 30i},
                Weighted { weight: 3, item: 31i}),
           [30,30,30,30, 31,31,31]);

        // check that we're binary searching
        // correctly with some vectors of odd
        // length.
        t!(vec!(Weighted { weight: 1, item: 40i},
                Weighted { weight: 1, item: 41i},
                Weighted { weight: 1, item: 42i},
                Weighted { weight: 1, item: 43i},
                Weighted { weight: 1, item: 44i}),
           [40, 41, 42, 43, 44]);
        t!(vec!(Weighted { weight: 1, item: 50i},
                Weighted { weight: 1, item: 51i},
                Weighted { weight: 1, item: 52i},
                Weighted { weight: 1, item: 53i},
                Weighted { weight: 1, item: 54i},
                Weighted { weight: 1, item: 55i},
                Weighted { weight: 1, item: 56i}),
           [50, 51, 52, 53, 54, 55, 56]);
    }

    #[test] #[should_fail]
    fn test_weighted_choice_no_items() {
        WeightedChoice::<int>::new([]);
    }
    #[test] #[should_fail]
    fn test_weighted_choice_zero_weight() {
        WeightedChoice::new(&mut [Weighted { weight: 0, item: 0i},
                                  Weighted { weight: 0, item: 1i}]);
    }
    #[test] #[should_fail]
    fn test_weighted_choice_weight_overflows() {
        let x = (-1) as uint / 2; // x + x + 2 is the overflow
        WeightedChoice::new(&mut [Weighted { weight: x, item: 0i },
                                  Weighted { weight: 1, item: 1i },
                                  Weighted { weight: x, item: 2i },
                                  Weighted { weight: 1, item: 3i }]);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate parsetree;

use log::LogLevelFilter;

use parsetree::Tree;
use parsetree::packet::prelude::*;

static PACKET_ETH_IPV4_TCP: &'static [u8] =
    &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34,
      0x73, 0x22, 0x40, 0x00, 0x3f, 0x06, 0x3a, 0x09, 0x0a, 0x00, 0x00, 0x65, 0x42, 0xc4, 0x41, 0x70, 0xca, 0x45,
      0x01, 0xbb, 0x98, 0x66, 0x5f, 0x0a, 0x44, 0x9d, 0x7f, 0x05, 0x80, 0x10, 0x20, 0x00, 0xbf, 0xf2, 0x00, 0x00,
      0x01, 0x01, 0x08, 0x0a, 0x00, 0x02, 0x2c, 0x2c, 0x63, 0x93, 0xf1, 0x5b];

static PACKET_ETH_IPV6_UDP: &'static [u8] =
    &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00,
      0x00, 0x24, 0x11, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05,
      0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x48, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
      0x09, 0x5c, 0x00, 0x35, 0x00, 0x24, 0xf0, 0x09];

static TLS_HEADER: &'static [u8] =
    &[0x16, 0x03, 0x01, 0x00, 0xf4, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x03, 0x14, 0x5b, 0x92, 0xc3, 0xcd, 0x27, 0xe0,
      0xa7, 0x09, 0x1d, 0x3a, 0x14, 0xda, 0x13, 0x8f, 0x19, 0x92, 0x9b, 0x5f, 0xd9, 0x75, 0x34, 0xe7, 0x45, 0xd8,
      0x2d, 0x1c, 0xa9, 0xb0, 0x89, 0x3c, 0xac, 0x20, 0x58, 0x44, 0x00, 0x00, 0x68, 0x46, 0xcb, 0x02, 0xee, 0xfd,
      0x82, 0x22, 0x32, 0x12, 0x89, 0x20, 0x73, 0xbe, 0x5d, 0x4b, 0xdb, 0x0b, 0xe5, 0x2f, 0x2c, 0xf6, 0x41, 0x1f,
      0x27, 0xcb, 0xf1, 0x21, 0x00, 0x20, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15,
      0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f,
      0x00, 0x0a, 0x01, 0x00, 0x00, 0x87, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x14, 0x00,
      0x00, 0x11, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x63, 0x6f,
      0x6d, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x06, 0x01, 0x06,
      0x03, 0x05, 0x01, 0x05, 0x03, 0x04, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x03, 0x02, 0x01, 0x02, 0x03, 0x00,
      0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10,
      0x00, 0x1d, 0x00, 0x1b, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x08, 0x73, 0x70, 0x64, 0x79,
      0x2f, 0x33, 0x2e, 0x31, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, 0x75, 0x50, 0x00, 0x00, 0x00,
      0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x04, 0x00, 0x17, 0x00, 0x18];

fn get_default_tree() -> Tree<Layer, ParserVariant> {
    // Create a tree
    let mut tree = Tree::new();
    tree.set_log_level(LogLevelFilter::Trace);

    // Create some parsers
    let eth = tree.new_parser(EthernetParser);
    let ipv4 = tree.new_parser(Ipv4Parser);
    let ipv6 = tree.new_parser(Ipv6Parser);
    let tcp = tree.new_parser(TcpParser);
    let udp = tree.new_parser(UdpParser);
    let tls = tree.new_parser(TlsParser);

    // Connect the parsers
    tree.link(eth, ipv4);
    tree.link(eth, ipv6);

    tree.link(ipv4, tcp);
    tree.link(ipv4, udp);

    tree.link(tcp, tls);

    tree.link(ipv6, tcp);
    tree.link(ipv6, udp);

    tree
}

#[test]
fn tcp() {
    let tree = get_default_tree();
    let result = tree.traverse(PACKET_ETH_IPV4_TCP, vec![]);
    info!("Result [ETH, IPV4, TCP]: {:?}", result);
}

#[test]
fn tls() {
    let tree = get_default_tree();
    let mut packet = Vec::from(PACKET_ETH_IPV4_TCP);
    packet.extend_from_slice(TLS_HEADER);
    let result = tree.traverse(&packet, vec![]);
    info!("Result [ETH, IPV4, TCP, TLS]: {:?}", result);
}

#[test]
fn udp() {
    let tree = get_default_tree();
    let result = tree.traverse(PACKET_ETH_IPV6_UDP, vec![]);
    info!("Result [ETH, IPV6, UDP]: {:?}", result);
}

<commit_msg>Fixed unit tests<commit_after>#[macro_use]
extern crate log;
extern crate parsetree;

use std::iter;
use log::LogLevelFilter;

use parsetree::Tree;
use parsetree::structures::NodeId;
use parsetree::packet::prelude::*;

static PACKET_ETH_IPV4_TCP: &'static [u8] =
    &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x45, 0x00, 0x00, 0x34,
      0x73, 0x22, 0x40, 0x00, 0x3f, 0x06, 0x3a, 0x09, 0x0a, 0x00, 0x00, 0x65, 0x42, 0xc4, 0x41, 0x70, 0xca, 0x45,
      0x01, 0xbb, 0x98, 0x66, 0x5f, 0x0a, 0x44, 0x9d, 0x7f, 0x05, 0x80, 0x10, 0x20, 0x00, 0xbf, 0xf2, 0x00, 0x00,
      0x01, 0x01, 0x08, 0x0a, 0x00, 0x02, 0x2c, 0x2c, 0x63, 0x93, 0xf1, 0x5b];

static PACKET_ETH_IPV6_UDP: &'static [u8] =
    &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00,
      0x00, 0x24, 0x11, 0x40, 0x3f, 0xfe, 0x05, 0x07, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x86, 0xff, 0xfe, 0x05,
      0x80, 0xda, 0x3f, 0xfe, 0x05, 0x01, 0x48, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42,
      0x09, 0x5c, 0x00, 0x35, 0x00, 0x24, 0xf0, 0x09];

static TLS_HEADER: &'static [u8] =
    &[0x16, 0x03, 0x01, 0x00, 0xf4, 0x01, 0x00, 0x00, 0xf0, 0x03, 0x03, 0x14, 0x5b, 0x92, 0xc3, 0xcd, 0x27, 0xe0,
      0xa7, 0x09, 0x1d, 0x3a, 0x14, 0xda, 0x13, 0x8f, 0x19, 0x92, 0x9b, 0x5f, 0xd9, 0x75, 0x34, 0xe7, 0x45, 0xd8,
      0x2d, 0x1c, 0xa9, 0xb0, 0x89, 0x3c, 0xac, 0x20, 0x58, 0x44, 0x00, 0x00, 0x68, 0x46, 0xcb, 0x02, 0xee, 0xfd,
      0x82, 0x22, 0x32, 0x12, 0x89, 0x20, 0x73, 0xbe, 0x5d, 0x4b, 0xdb, 0x0b, 0xe5, 0x2f, 0x2c, 0xf6, 0x41, 0x1f,
      0x27, 0xcb, 0xf1, 0x21, 0x00, 0x20, 0xc0, 0x2b, 0xc0, 0x2f, 0x00, 0x9e, 0xcc, 0x14, 0xcc, 0x13, 0xcc, 0x15,
      0xc0, 0x0a, 0xc0, 0x14, 0x00, 0x39, 0xc0, 0x09, 0xc0, 0x13, 0x00, 0x33, 0x00, 0x9c, 0x00, 0x35, 0x00, 0x2f,
      0x00, 0x0a, 0x01, 0x00, 0x00, 0x87, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x14, 0x00,
      0x00, 0x11, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x73, 0x69, 0x74, 0x65, 0x2e, 0x63, 0x6f,
      0x6d, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x16, 0x00, 0x14, 0x06, 0x01, 0x06,
      0x03, 0x05, 0x01, 0x05, 0x03, 0x04, 0x01, 0x04, 0x03, 0x03, 0x01, 0x03, 0x03, 0x02, 0x01, 0x02, 0x03, 0x00,
      0x05, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x33, 0x74, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x10,
      0x00, 0x1d, 0x00, 0x1b, 0x08, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x31, 0x2e, 0x31, 0x08, 0x73, 0x70, 0x64, 0x79,
      0x2f, 0x33, 0x2e, 0x31, 0x05, 0x68, 0x32, 0x2d, 0x31, 0x34, 0x02, 0x68, 0x32, 0x75, 0x50, 0x00, 0x00, 0x00,
      0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x06, 0x00, 0x04, 0x00, 0x17, 0x00, 0x18];

fn get_default_tree() -> Tree<Layer, ParserVariant> {
    // Create a tree
    let mut tree = Tree::new();
    tree.set_log_level(LogLevelFilter::Trace);

    // Create some parsers
    let eth = tree.new_parser(EthernetParser);
    let ipv4 = tree.new_parser(Ipv4Parser);
    let ipv6 = tree.new_parser(Ipv6Parser);

    let tcp_ipv4 = tree.new_parser(TcpParser);
    let tcp_ipv6 = tree.new_parser(TcpParser);

    let udp_ipv4 = tree.new_parser(UdpParser);
    let udp_ipv6 = tree.new_parser(UdpParser);

    let tls_ipv4 = tree.new_parser(TlsParser);
    let tls_ipv6 = tree.new_parser(TlsParser);

    // Connect the parsers
    tree.link(eth, ipv4);
    tree.link(eth, ipv6);

    tree.link(ipv4, tcp_ipv4);
    tree.link(ipv4, udp_ipv4);

    tree.link(tcp_ipv4, tls_ipv4);
    tree.link(tcp_ipv6, tls_ipv6);

    tree.link(ipv6, tcp_ipv6);
    tree.link(ipv6, udp_ipv6);

    info!("The tree looks like:");
    info!("- Eth");
    log_children(&tree, eth, 0);

    tree
}

fn log_children(tree: &Tree<Layer, ParserVariant>, node: NodeId, mut level: usize) {
    level += 2;
    for child in node.children(&tree.arena) {
        let indent = iter::repeat(' ').take(level).collect::<String>();
        let ref parser = tree.arena[child].data;
        info!("{}- {}", indent, parser.variant());
        log_children(tree, child, level);
    }
}

#[test]
fn tcp() {
    let tree = get_default_tree();
    let result = tree.traverse(PACKET_ETH_IPV4_TCP, vec![]);
    info!("Result [ETH, IPV4, TCP]: {:?}", result);
}

#[test]
fn tls() {
    let tree = get_default_tree();
    let mut packet = Vec::from(PACKET_ETH_IPV4_TCP);
    packet.extend_from_slice(TLS_HEADER);
    let result = tree.traverse(&packet, vec![]);
    info!("Result [ETH, IPV4, TCP, TLS]: {:?}", result);
}

#[test]
fn udp() {
    let tree = get_default_tree();
    let result = tree.traverse(PACKET_ETH_IPV6_UDP, vec![]);
    info!("Result [ETH, IPV6, UDP]: {:?}", result);
}

<|endoftext|>


<commit_before>pub const MAX_FIXED_ORDER: usize = 4;
pub const MAX_LPC_ORDER: usize   = 32;

pub struct SubFrame {
  pub data: Data,
  pub wasted_bits: u32,
}

pub enum Data {
  Constant(i32),
  Verbatim(Vec<i32>),
  Fixed(Fixed),
  LPC(LPC),
}

pub struct Fixed {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub warmup: [i32; MAX_FIXED_ORDER],
  pub residual: Vec<i32>,
}

pub struct LPC {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub qlp_coeff_precision: u8,
  pub quantization_level: i8,
  pub qlp_coefficients: [i32; MAX_LPC_ORDER],
  pub warmup: [i32; MAX_LPC_ORDER],
  pub residual: Vec<i32>,
}

pub struct EntropyCodingMethod {
  pub method_type: CodingMethod,
  pub data: PartitionedRice,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  PartitionedRice,
  PartitionedRice2,
}

pub struct PartitionedRice {
  pub order: u32,
  pub contents: PartitionedRiceContents,
}

pub struct PartitionedRiceContents {
  pub parameters: Vec<u32>,
  pub raw_bits: Vec<u32>,
  pub capacity_by_order: u32,
}

impl PartitionedRiceContents {
  pub fn new(capacity_by_order: u32) -> PartitionedRiceContents {
    let capacity       = 2_usize.pow(capacity_by_order);
    let mut parameters = Vec::with_capacity(capacity);
    let mut raw_bits   = Vec::with_capacity(capacity);

    unsafe {
      parameters.set_len(capacity);
      raw_bits.set_len(capacity);
    }

    PartitionedRiceContents {
      parameters: parameters,
      raw_bits: raw_bits,
      capacity_by_order: capacity_by_order,
    }
  }
}
<commit_msg>Add dervied traits for testing values<commit_after>pub const MAX_FIXED_ORDER: usize = 4;
pub const MAX_LPC_ORDER: usize   = 32;

pub struct SubFrame {
  pub data: Data,
  pub wasted_bits: u32,
}

#[derive(Debug, PartialEq, Eq)]
pub enum Data {
  Constant(i32),
  Verbatim(Vec<i32>),
  Fixed(Fixed),
  LPC(LPC),
}

#[derive(Debug, PartialEq, Eq)]
pub struct Fixed {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub warmup: [i32; MAX_FIXED_ORDER],
  pub residual: Vec<i32>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct LPC {
  pub entropy_coding_method: EntropyCodingMethod,
  pub order: u8,
  pub qlp_coeff_precision: u8,
  pub quantization_level: i8,
  pub qlp_coefficients: [i32; MAX_LPC_ORDER],
  pub warmup: [i32; MAX_LPC_ORDER],
  pub residual: Vec<i32>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct EntropyCodingMethod {
  pub method_type: CodingMethod,
  pub data: PartitionedRice,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum CodingMethod {
  PartitionedRice,
  PartitionedRice2,
}

#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRice {
  pub order: u32,
  pub contents: PartitionedRiceContents,
}

#[derive(Debug, PartialEq, Eq)]
pub struct PartitionedRiceContents {
  pub parameters: Vec<u32>,
  pub raw_bits: Vec<u32>,
  pub capacity_by_order: u32,
}

impl PartitionedRiceContents {
  pub fn new(capacity_by_order: u32) -> PartitionedRiceContents {
    let capacity       = 2_usize.pow(capacity_by_order);
    let mut parameters = Vec::with_capacity(capacity);
    let mut raw_bits   = Vec::with_capacity(capacity);

    unsafe {
      parameters.set_len(capacity);
      raw_bits.set_len(capacity);
    }

    PartitionedRiceContents {
      parameters: parameters,
      raw_bits: raw_bits,
      capacity_by_order: capacity_by_order,
    }
  }
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Function_composition
#[cfg(not(test))]
use std::f32::consts;

#[cfg(not(test))]
fn main() {
    fn f(x: uint) -> String { x.to_string() }
    fn g(x: f32) -> uint { x as uint }

    // just a silly example
    // turn PI to a uint and then
    // the the uint to a String
    // via funciton composition
    let comp = compose(f, g);
    println!("{}", comp(consts::PI));
}

// the future unboxed closures should
// allow to compose closures, not just bare functions (so that environment can be captured)
// Also returning a proc has the limitation that the composed function can only be called once
fn compose<A, B, C>(f: fn(A) -> B, g: fn(C) -> A) -> proc(C) -> B {
    proc(x: C) {f(g(x))}
}

#[test]
fn test_compose() {
    fn inc(x: uint) -> uint { x + 1 }
    fn mul(x: uint) -> uint { x * 3 }

    let comp = compose(inc, mul);
    assert_eq!(comp(3), 10);
}
<commit_msg>fix typos in comment<commit_after>// http://rosettacode.org/wiki/Function_composition
#[cfg(not(test))]
use std::f32::consts;

#[cfg(not(test))]
fn main() {
    fn f(x: uint) -> String { x.to_string() }
    fn g(x: f32) -> uint { x as uint }

    // just a silly example
    // turn PI to a uint and then
    // the uint to a String
    // via function composition
    let comp = compose(f, g);
    println!("{}", comp(consts::PI));
}

// the future unboxed closures should
// allow to compose closures, not just bare functions (so that environment can be captured)
// Also returning a proc has the limitation that the composed function can only be called once
fn compose<A, B, C>(f: fn(A) -> B, g: fn(C) -> A) -> proc(C) -> B {
    proc(x: C) {f(g(x))}
}

#[test]
fn test_compose() {
    fn inc(x: uint) -> uint { x + 1 }
    fn mul(x: uint) -> uint { x * 3 }

    let comp = compose(inc, mul);
    assert_eq!(comp(3), 10);
}
<|endoftext|>


<commit_before>use geom::{line, Line, Quad};
use math::{BaseFloat, Point2};

/// An iterator yielding the normal vertices of a miter polyline.
///
/// This iterator can be used in combination with the `Indices` iterator to triangulate a miter
/// polyline.
///
/// For example, given the following line abcd:
///
/// ```ignore
/// a-----------------------b
///                        /
///                       /
///                      /
///                     /
///                    /
///                   /
///                  c----------------------------d
/// ```
///
/// With some `half_thickness` of the line, the following points are produced:
///
/// ```ignore
/// 0----------------------------2  ^
///                             /   | half_thickness
/// a-----------------------b  /    v
///                        /  /
/// 1------------------3  /  /
///                   /  /  /
///                  /  /  /
///                 /  /  4-----------------------6
///                /  /
///               /  c----------------------------d
///              /
///             5---------------------------------7
/// ```
///
/// ## Example
///
/// ```
/// extern crate nannou;
///
/// use nannou::prelude::*;
/// use nannou::geom::line;
///
/// fn main() {
///     let half_thickness = 1.0;
///     let points = vec![
///         pt2(0.0, 0.0),
///         pt2(2.0, 0.0),
///         pt2(2.0, 2.0),
///     ];
///     let expected = vec![
///         [pt2(0.0, 1.0), pt2(0.0, -1.0)],
///         [pt2(1.0, 1.0), pt2(3.0, -1.0)],
///         [pt2(1.0, 2.0), pt2(3.0, 2.0)],
///     ];
///     let result: Vec<_> = line::join::miter::vertices(points, half_thickness).collect();
///     assert_eq!(result, expected);
/// }
/// ```
#[derive(Clone, Debug)]
pub struct Vertices<I, S> {
    half_thickness: S,
    points: I,
    // The point yielded prior to `point_b`.
    point_a: Option<Point2<S>>,
    // The point for which each iteration yields normal vertices.
    point_b: Option<Point2<S>>,
}

/// An iterator yielding the indices necessary to triangulate a miter polyline from a sequence of
/// normal vertices.
#[derive(Clone, Debug)]
pub struct TriangleIndices {
    i: usize,
    n_tris: usize,
    // Every second triangle requires a slightly different vertex order.
    second: bool,
}

impl<I, S> Vertices<I, S> {
    /// Produces an iterator yeilding the miter normal vertices for each point in the given
    /// iterator.
    pub fn new<P>(points: P, half_thickness: S) -> Self
    where
        I: Iterator<Item = Point2<S>>,
        P: IntoIterator<IntoIter = I, Item = Point2<S>>,
        S: BaseFloat,
    {
        let mut points = points.into_iter();
        let point_a = None;
        let point_b = points.next();
        Vertices {
            half_thickness,
            points,
            point_a,
            point_b,
        }
    }
}

impl TriangleIndices {
    /// Produce an iterator yielding the indices necessary to triangulate a miter polyline from a
    /// sequence of normal vertices.
    pub fn new(n_points: usize) -> Self {
        let n_normals = n_points * 2;
        let n_tris = n_normals - 2;
        TriangleIndices { i: 0, n_tris, second: false }
    }
}

impl<I, S> Iterator for Vertices<I, S>
where
    I: Iterator<Item = Point2<S>>,
    S: BaseFloat,
{
    type Item = [Point2<S>; 2];
    fn next(&mut self) -> Option<Self::Item> {
        let Vertices {
            half_thickness,
            ref mut points,
            ref mut point_a,
            ref mut point_b,
        } = *self;

        let a = point_a.take();
        let b = point_b.take();
        match (a, b) {
            // Only occurs if there were no points in the given iterator or if the last has already
            // been yeilded.
            (None, None) | (Some(_), None) => None,

            // Only occurs on the first iteration.
            (None, Some(b)) => {
                let c = match points.next() {
                    Some(c) => c,
                    // Only occurs if there was only point, in which case we cannot give valid
                    // vertices.
                    None => return None,
                };
                // Get the line quad between the two points.
                let line = Line { start: b, end: c, half_thickness };
                let Quad([r, l, _, _]) = line.quad_corners();
                *point_a = Some(b);
                *point_b = Some(c);
                Some([l, r])
            },

            // Every other point.
            (Some(a), Some(b)) => {
                let c = match points.next() {
                    Some(c) => c,
                    // If this is the last point.
                    None => {
                        // Get the line quad between the two points.
                        let line = Line { start: a, end: b, half_thickness };
                        let Quad([_, _, l, r]) = line.quad_corners();
                        *point_a = Some(b);
                        return Some([l, r]);
                    },
                };
                let ab = Line { start: a, end: b, half_thickness };
                let bc = Line { start: b, end: c, half_thickness };
                let Quad([ar, al, bl_ab, br_ab]) = ab.quad_corners();
                let Quad([br_bc, bl_bc, cl, cr]) = bc.quad_corners();
                let mut il = match line::join::intersect((al, bl_ab), (cl, bl_bc)) {
                    Some(il) => il,
                    // If the lines are parallel, produce the join vertices.
                    None => {
                        bl_ab
                    },
                };
                let mut ir = match line::join::intersect((ar, br_ab), (cr, br_bc)) {
                    Some(ir) => ir,
                    None => {
                        br_ab
                    },
                };
                *point_a = Some(b);
                *point_b = Some(c);
                Some([il, ir])
            },
        }
    }
}

impl Iterator for TriangleIndices {
    type Item = [usize; 3];
    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= self.n_tris {
            return None;
        }
        let trio = if self.second {
            [self.i, self.i + 2, self.i + 1]
        } else {
            [self.i, self.i + 1, self.i + 2]
        };
        self.second = !self.second;
        self.i += 1;
        Some(trio)
    }
}

/// Produces an iterator yeilding the miter normal vertices for each point in the given iterator.
pub fn vertices<I, S>(points: I, half_thickness: S) -> Vertices<I::IntoIter, S>
where
    I: IntoIterator<Item = Point2<S>>,
    S: BaseFloat,
{
    Vertices::new(points, half_thickness)
}

/// Produce an iterator yielding the indices necessary to triangulate a miter polyline from a
/// sequence of normal vertices.
pub fn triangle_indices(n_points: usize) -> TriangleIndices {
    TriangleIndices::new(n_points)
}
<commit_msg>Add `miter::Vertices` iterator. Add `next_pair` fn. ExactSizeIterators.<commit_after>use geom::{line, Line, Quad};
use math::{BaseFloat, Point2};

/// An iterator yielding the normal vertices of a miter polyline.
///
/// This iterator can be used in combination with the `Indices` iterator to triangulate a miter
/// polyline.
///
/// For example, given the following line abcd:
///
/// ```ignore
/// a-----------------------b
///                        /
///                       /
///                      /
///                     /
///                    /
///                   /
///                  c----------------------------d
/// ```
///
/// With some `half_thickness` of the line, the following points are produced:
///
/// ```ignore
/// 0----------------------------2  ^
///                             /   | half_thickness
/// a-----------------------b  /    v
///                        /  /
/// 1------------------3  /  /
///                   /  /  /
///                  /  /  /
///                 /  /  4-----------------------6
///                /  /
///               /  c----------------------------d
///              /
///             5---------------------------------7
/// ```
///
/// ## Example
///
/// ```
/// extern crate nannou;
///
/// use nannou::prelude::*;
/// use nannou::geom::line;
///
/// fn main() {
///     let half_thickness = 1.0;
///     let points = vec![
///         pt2(0.0, 0.0),
///         pt2(2.0, 0.0),
///         pt2(2.0, 2.0),
///     ];
///     let expected = vec![
///         [pt2(0.0, 1.0), pt2(0.0, -1.0)],
///         [pt2(1.0, 1.0), pt2(3.0, -1.0)],
///         [pt2(1.0, 2.0), pt2(3.0, 2.0)],
///     ];
///     let result: Vec<_> = line::join::miter::vertices(points, half_thickness).collect();
///     assert_eq!(result, expected);
/// }
/// ```
#[derive(Clone, Debug)]
pub struct VertexPairs<I, S> {
    half_thickness: S,
    points: I,
    // The point yielded prior to `point_b`.
    point_a: Option<Point2<S>>,
    // The point for which each iteration yields normal vertices.
    point_b: Option<Point2<S>>,
}

/// The same as the **VertexPairs** iterator, but flattened in order to produce a single vertex at
/// a time.
#[derive(Clone, Debug)]
pub struct Vertices<I, S> {
    pairs: VertexPairs<I, S>,
    next: Option<Point2<S>>,
}

/// An iterator yielding the indices necessary to triangulate a miter polyline from a sequence of
/// normal vertices.
#[derive(Clone, Debug)]
pub struct TriangleIndices {
    i: usize,
    n_tris: usize,
    // Every second triangle requires a slightly different vertex order.
    second: bool,
}

impl<I, S> VertexPairs<I, S> {
    /// Produces an iterator yeilding the miter normal vertices for each point in the given
    /// iterator.
    pub fn new<P>(points: P, half_thickness: S) -> Self
    where
        I: Iterator<Item = Point2<S>>,
        P: IntoIterator<IntoIter = I, Item = Point2<S>>,
        S: BaseFloat,
    {
        let mut points = points.into_iter();
        let point_a = None;
        let point_b = points.next();
        VertexPairs {
            half_thickness,
            points,
            point_a,
            point_b,
        }
    }

    /// Flatten this iterator yielding vertex pairs into an iterator that yields a single vertex at
    /// a time.
    pub fn flatten(self) -> Vertices<I, S> {
        Vertices {
            pairs: self,
            next: None,
        }
    }
}

impl TriangleIndices {
    /// Produce an iterator yielding the indices necessary to triangulate a miter polyline from a
    /// sequence of normal vertices.
    pub fn new(n_points: usize) -> Self {
        let n_normals = n_points * 2;
        let n_tris = n_normals - 2;
        TriangleIndices { i: 0, n_tris, second: false }
    }
}

impl<I, S> Iterator for VertexPairs<I, S>
where
    I: Iterator<Item = Point2<S>>,
    S: BaseFloat,
{
    type Item = [Point2<S>; 2];
    fn next(&mut self) -> Option<Self::Item> {
        let VertexPairs {
            half_thickness,
            ref mut points,
            ref mut point_a,
            ref mut point_b,
        } = *self;
        next_pair(half_thickness, point_a, point_b, points.next())
    }
}

/// Determine the next vertex pair in the miter sequence given the two previous points and the next
/// if one exists.
///
/// - `half_thickness`: half the thickness of the line.
/// - `point_a`: the point in the sequence prior to the last point.
/// - `point_b`: the last point in the sequence.
/// - `next_point`: the next point in the sequence.
///
/// This function expects that `point_a` is `None` and `point_b` is `Some` (containing the first
/// point in the sequence) when beginning the sequence.
///
/// This function is used within both the `VertexPairs` iterator and the `polyline().vertices()`
/// draw builder method.
pub fn next_pair<S>(
    half_thickness: S,
    point_a: &mut Option<Point2<S>>,
    point_b: &mut Option<Point2<S>>,
    next_point: Option<Point2<S>>,
) -> Option<[Point2<S>; 2]>
where
    S: BaseFloat,
{
    let a = point_a.take();
    let b = point_b.take();
    match (a, b) {
        // Only occurs if there were no points in the sequence or if the last point has already
        // been yeilded.
        (None, None) | (Some(_), None) => None,

        // Should only occur on the first iteration.
        (None, Some(b)) => {
            let c = match next_point {
                Some(c) => c,
                // Only occurs if there was only point, in which case we cannot give valid
                // vertices.
                None => return None,
            };
            // Get the line quad between the two points.
            let line = Line { start: b, end: c, half_thickness };
            let Quad([r, l, _, _]) = line.quad_corners();
            *point_a = Some(b);
            *point_b = Some(c);
            Some([l, r])
        },

        // Every other point.
        (Some(a), Some(b)) => {
            let c = match next_point {
                Some(c) => c,
                // If this is the last point.
                None => {
                    // Get the line quad between the two points.
                    let line = Line { start: a, end: b, half_thickness };
                    let Quad([_, _, l, r]) = line.quad_corners();
                    *point_a = Some(b);
                    return Some([l, r]);
                },
            };
            let ab = Line { start: a, end: b, half_thickness };
            let bc = Line { start: b, end: c, half_thickness };
            let Quad([ar, al, bl_ab, br_ab]) = ab.quad_corners();
            let Quad([br_bc, bl_bc, cl, cr]) = bc.quad_corners();
            let mut il = match line::join::intersect((al, bl_ab), (cl, bl_bc)) {
                Some(il) => il,
                // If the lines are parallel, produce the join vertices.
                None => {
                    bl_ab
                },
            };
            let mut ir = match line::join::intersect((ar, br_ab), (cr, br_bc)) {
                Some(ir) => ir,
                None => {
                    br_ab
                },
            };
            *point_a = Some(b);
            *point_b = Some(c);
            Some([il, ir])
        },
    }
}

impl<I, S> ExactSizeIterator for VertexPairs<I, S>
where
    I: Iterator<Item = Point2<S>> + ExactSizeIterator,
    S: BaseFloat,
{
    fn len(&self) -> usize {
        let remaining_points = self.points.len();
        let a = self.point_a.is_some();
        let b = self.point_b.is_some();
        match (a, b) {
            (false, true) => if remaining_points <= 1 { 0 } else { remaining_points },
            (true, true) => remaining_points + 1,
            _ => 0,
        }
    }
}

impl<I, S> Iterator for Vertices<I, S>
where
    I: Iterator<Item = Point2<S>>,
    S: BaseFloat,
{
    type Item = Point2<S>;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(next) = self.next.take() {
            return Some(next);
        }
        if let Some([this, next]) = self.pairs.next() {
            self.next = Some(next);
            return Some(this);
        }
        None
    }
}

impl<I, S> ExactSizeIterator for Vertices<I, S>
where
    I: Iterator<Item = Point2<S>> + ExactSizeIterator,
    S: BaseFloat,
{
    fn len(&self) -> usize {
        self.pairs.len() * 2 + if self.next.is_some() { 1 } else { 0 }
    }
}

impl Iterator for TriangleIndices {
    type Item = [usize; 3];
    fn next(&mut self) -> Option<Self::Item> {
        if self.i >= self.n_tris {
            return None;
        }
        let trio = if self.second {
            [self.i, self.i + 2, self.i + 1]
        } else {
            [self.i, self.i + 1, self.i + 2]
        };
        self.second = !self.second;
        self.i += 1;
        Some(trio)
    }
}

impl ExactSizeIterator for TriangleIndices {
    fn len(&self) -> usize {
        self.n_tris - self.i
    }
}

/// Produces an iterator yeilding the miter normal vertices for each point in the given iterator.
pub fn vertices<I, S>(points: I, half_thickness: S) -> VertexPairs<I::IntoIter, S>
where
    I: IntoIterator<Item = Point2<S>>,
    S: BaseFloat,
{
    VertexPairs::new(points, half_thickness)
}

/// Produce an iterator yielding the indices necessary to triangulate a miter polyline from a
/// sequence of normal vertices.
pub fn triangle_indices(n_points: usize) -> TriangleIndices {
    TriangleIndices::new(n_points)
}
<|endoftext|>


<commit_before>/// Compute the real-valued digamma function.
///
/// The digamma function is defined by
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the Gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// ## Examples
///
/// ```
/// use special::digamma;
///
/// let euler_mascheroni = 0.5772156649015325;
/// assert_eq!(-euler_mascheroni, digamma(1.0));
/// ```
///
/// ## References
///
/// 1. M. J. Beal, Variational algorithms for approximate Bayesian inference.
///    University of London, 2003, pp. 265–266.
pub fn digamma(x: f64)-> f64 {
    macro_rules! evaluate_polynomial(
        ($x:expr, $coefficients:expr) => (
            $coefficients.iter().rev().fold(0.0, |sum, &c| $x * sum + c)
        );
    );

    if x <= 8.0 {
        return digamma(x + 1.0) - x.recip();
    }

    let inv_x = x.recip();
    let inv_x_2 = inv_x * inv_x;
    x.ln() - 0.5 * inv_x - inv_x_2 * evaluate_polynomial!(inv_x_2, [
        1.0 / 12.0, -1.0 / 120.0, 1.0 / 252.0, -1.0 / 240.0,
        5.0 / 660.0, -691.0 / 32760.0, 1.0 / 12.0, -3617.0 / 8160.0,
    ])
}

/// Compute the lower incomplete gamma function.
///
/// The code is based on a [C implementation][1] by John Burkardt. The original
/// algorithm was published in Applied Statistics and is known as
/// [Algorithm AS 239][2].
///
/// [1]: http://people.sc.fsu.edu/~jburkardt/c_src/asa239/asa239.html
/// [2]: http://www.jstor.org/stable/2347328
pub fn inc_gamma(p: f64, x: f64) -> f64 {

    debug_assert!(p > 0.0 && x >= 0.0);

    const ELIMIT: f64 = -88.0;
    const OFLO: f64 = 1.0e+37;
    const TOL: f64 = 1.0e-14;
    const XBIG: f64 = 1.0E+08;

    if x == 0.0 {
        return 0.0;
    }

    // For `p ≥ 1000`, the original algorithm uses an approximation shown below.
    // However, it introduces a substantial accuracy loss.
    //
    // ```
    // use m::erf;
    // use std::f64::consts::FRAC_1_SQRT_2;
    //
    // const PLIMIT: f64 = 1000.0;
    //
    // if PLIMIT < p {
    //     let pn1 = 3.0 * p.sqrt() * ((x / p).powf(1.0 / 3.0) + 1.0 / (9.0 * p) - 1.0);
    //     return 0.5 * (1.0 + unsafe { erf(FRAC_1_SQRT_2 * pn1) });
    // }
    // ```

    if XBIG < x {
        return 1.0;
    }

    if x <= 1.0 || x < p {
        let mut arg = p * x.ln() - x - ln_gamma(p + 1.0).0;
        let mut c = 1.0;
        let mut value = 1.0;
        let mut a = p;

        loop {
            a = a + 1.0;
            c = c * x / a;
            value = value + c;

            if c <= TOL {
                break;
            }
        }

        arg = arg + value.ln();

        if ELIMIT <= arg {
            return arg.exp();
        } else {
            return 0.0;
        };
    } else {
        let mut arg = p * x.ln() - x - ln_gamma(p).0;
        let mut a = 1.0 - p;
        let mut b = a + x + 1.0;
        let mut c = 0.0;
        let mut pn1 = 1.0;
        let mut pn2 = x;
        let mut pn3 = x + 1.0;
        let mut pn4 = x * b;
        let mut value = pn3 / pn4;

        loop {
            a = a + 1.0;
            b = b + 2.0;
            c = c + 1.0;
            let an = a * c;
            let pn5 = b * pn3 - an * pn1;
            let pn6 = b * pn4 - an * pn2;

            if pn6 != 0.0 {
                let rn = pn5 / pn6;

                if (value - rn).abs() <= TOL.min(TOL * rn) {
                    break;
                }
                value = rn;
            }

            pn1 = pn3;
            pn2 = pn4;
            pn3 = pn5;
            pn4 = pn6;

            if OFLO <= pn5.abs() {
                pn1 = pn1 / OFLO;
                pn2 = pn2 / OFLO;
                pn3 = pn3 / OFLO;
                pn4 = pn4 / OFLO;
            }
        }

        arg = arg + value.ln();

        if ELIMIT <= arg {
            return 1.0 - arg.exp();
        } else {
            return 1.0;
        }
    }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    use m::lgamma_r;
    let mut sign: i32 = 0;
    let value = unsafe { lgamma_r(x, &mut sign) };
    (value, sign)
}

#[cfg(test)]
mod tests {
    use assert;

    #[test]
    fn digamma() {
        use std::f64::consts::{FRAC_PI_2, LN_2};
        let euler_mascheroni = 0.577215664901533;
        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - euler_mascheroni, super::digamma(0.25));
    }

    #[test]
    fn inc_gamma_small_p() {
        const P: f64 = 4.2;
        let x = vec![
            0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5,
            5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5,
        ];
        let y = vec![
            0.000000000000000e+00, 1.118818097571853e-03, 1.386936454406691e-02,
            5.173931341260211e-02, 1.186345016135447e-01, 2.092219100370761e-01,
            3.137074857845146e-01, 4.219736975484903e-01, 5.258832878449179e-01,
            6.200417684429613e-01, 7.016346974530381e-01, 7.698559854309833e-01,
            8.252531208548146e-01, 8.691540627528154e-01, 9.032348314835232e-01,
            9.292289044193606e-01, 9.487539837941871e-01, 9.632249236076943e-01,
            9.738240752336722e-01, 9.815062931491536e-01,
        ];

        let z = x.iter().map(|&x| super::inc_gamma(P, x)).collect::<Vec<_>>();
        assert::close(&z, &y, 1e-14);
    }

    #[test]
    fn inc_gamma_large_p() {
        const P: f64 = 1500.0;
        let x = vec![
            1400.0, 1410.0, 1420.0, 1430.0, 1440.0, 1450.0, 1460.0, 1470.0, 1480.0, 1490.0,
            1500.0, 1510.0, 1520.0, 1530.0, 1540.0, 1550.0, 1560.0, 1570.0, 1580.0, 1590.0,
        ];
        let y = vec![
            4.231080348517120e-03, 9.056183893278287e-03, 1.809200095269094e-02,
            3.380047876608895e-02, 5.917825204288418e-02, 9.731671903009434e-02,
            1.506860564044825e-01, 2.202940362119810e-01, 3.049926190158564e-01,
            4.012305141433336e-01, 5.034335611603484e-01, 6.049687028759408e-01,
            6.994146092246781e-01, 7.817404371226420e-01, 8.490443067241588e-01,
            9.006922020203059e-01, 9.379249194843459e-01, 9.631597573132408e-01,
            9.792520392189441e-01, 9.889149370075309e-01,
        ];

        let z = x.iter().map(|&x| super::inc_gamma(P, x)).collect::<Vec<_>>();
        assert::close(&z, &y, 1e-12);
    }
}
<commit_msg>Show the Euler–Mascheroni constant up to 50 decimal places<commit_after>/// Compute the real-valued digamma function.
///
/// The digamma function is defined by
///
/// ```math
///        d ln(Γ(x))
/// ψ(x) = ----------
///            dx
/// ```
///
/// where Γ is the Gamma function. The computation is based on an approximation
/// as described in the reference below.
///
/// ## Examples
///
/// ```
/// use special::digamma;
///
/// const EULER_MASCHERONI: f64 = 0.57721566490153286060651209008240243104215933593992;
/// assert!((digamma(1.0) + EULER_MASCHERONI).abs() < 1e-15);
/// ```
///
/// ## References
///
/// 1. M. J. Beal, Variational algorithms for approximate Bayesian inference.
///    University of London, 2003, pp. 265–266.
pub fn digamma(x: f64)-> f64 {
    macro_rules! evaluate_polynomial(
        ($x:expr, $coefficients:expr) => (
            $coefficients.iter().rev().fold(0.0, |sum, &c| $x * sum + c)
        );
    );

    if x <= 8.0 {
        return digamma(x + 1.0) - x.recip();
    }

    let inv_x = x.recip();
    let inv_x_2 = inv_x * inv_x;
    x.ln() - 0.5 * inv_x - inv_x_2 * evaluate_polynomial!(inv_x_2, [
        1.0 / 12.0, -1.0 / 120.0, 1.0 / 252.0, -1.0 / 240.0,
        5.0 / 660.0, -691.0 / 32760.0, 1.0 / 12.0, -3617.0 / 8160.0,
    ])
}

/// Compute the lower incomplete gamma function.
///
/// The code is based on a [C implementation][1] by John Burkardt. The original
/// algorithm was published in Applied Statistics and is known as
/// [Algorithm AS 239][2].
///
/// [1]: http://people.sc.fsu.edu/~jburkardt/c_src/asa239/asa239.html
/// [2]: http://www.jstor.org/stable/2347328
pub fn inc_gamma(p: f64, x: f64) -> f64 {

    debug_assert!(p > 0.0 && x >= 0.0);

    const ELIMIT: f64 = -88.0;
    const OFLO: f64 = 1.0e+37;
    const TOL: f64 = 1.0e-14;
    const XBIG: f64 = 1.0E+08;

    if x == 0.0 {
        return 0.0;
    }

    // For `p ≥ 1000`, the original algorithm uses an approximation shown below.
    // However, it introduces a substantial accuracy loss.
    //
    // ```
    // use m::erf;
    // use std::f64::consts::FRAC_1_SQRT_2;
    //
    // const PLIMIT: f64 = 1000.0;
    //
    // if PLIMIT < p {
    //     let pn1 = 3.0 * p.sqrt() * ((x / p).powf(1.0 / 3.0) + 1.0 / (9.0 * p) - 1.0);
    //     return 0.5 * (1.0 + unsafe { erf(FRAC_1_SQRT_2 * pn1) });
    // }
    // ```

    if XBIG < x {
        return 1.0;
    }

    if x <= 1.0 || x < p {
        let mut arg = p * x.ln() - x - ln_gamma(p + 1.0).0;
        let mut c = 1.0;
        let mut value = 1.0;
        let mut a = p;

        loop {
            a = a + 1.0;
            c = c * x / a;
            value = value + c;

            if c <= TOL {
                break;
            }
        }

        arg = arg + value.ln();

        if ELIMIT <= arg {
            return arg.exp();
        } else {
            return 0.0;
        };
    } else {
        let mut arg = p * x.ln() - x - ln_gamma(p).0;
        let mut a = 1.0 - p;
        let mut b = a + x + 1.0;
        let mut c = 0.0;
        let mut pn1 = 1.0;
        let mut pn2 = x;
        let mut pn3 = x + 1.0;
        let mut pn4 = x * b;
        let mut value = pn3 / pn4;

        loop {
            a = a + 1.0;
            b = b + 2.0;
            c = c + 1.0;
            let an = a * c;
            let pn5 = b * pn3 - an * pn1;
            let pn6 = b * pn4 - an * pn2;

            if pn6 != 0.0 {
                let rn = pn5 / pn6;

                if (value - rn).abs() <= TOL.min(TOL * rn) {
                    break;
                }
                value = rn;
            }

            pn1 = pn3;
            pn2 = pn4;
            pn3 = pn5;
            pn4 = pn6;

            if OFLO <= pn5.abs() {
                pn1 = pn1 / OFLO;
                pn2 = pn2 / OFLO;
                pn3 = pn3 / OFLO;
                pn4 = pn4 / OFLO;
            }
        }

        arg = arg + value.ln();

        if ELIMIT <= arg {
            return 1.0 - arg.exp();
        } else {
            return 1.0;
        }
    }
}

/// Compute the natural logarithm of the gamma function.
#[inline]
pub fn ln_gamma(x: f64) -> (f64, i32) {
    use m::lgamma_r;
    let mut sign: i32 = 0;
    let value = unsafe { lgamma_r(x, &mut sign) };
    (value, sign)
}

#[cfg(test)]
mod tests {
    use assert;

    #[test]
    fn digamma() {
        use std::f64::consts::{FRAC_PI_2, LN_2};
        const EULER_MASCHERONI: f64 = 0.57721566490153286060651209008240243104215933593992;
        assert_eq!(-FRAC_PI_2 - 3.0 * LN_2 - EULER_MASCHERONI, super::digamma(0.25));
    }

    #[test]
    fn inc_gamma_small_p() {
        const P: f64 = 4.2;
        let x = vec![
            0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5,
            5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5,
        ];
        let y = vec![
            0.000000000000000e+00, 1.118818097571853e-03, 1.386936454406691e-02,
            5.173931341260211e-02, 1.186345016135447e-01, 2.092219100370761e-01,
            3.137074857845146e-01, 4.219736975484903e-01, 5.258832878449179e-01,
            6.200417684429613e-01, 7.016346974530381e-01, 7.698559854309833e-01,
            8.252531208548146e-01, 8.691540627528154e-01, 9.032348314835232e-01,
            9.292289044193606e-01, 9.487539837941871e-01, 9.632249236076943e-01,
            9.738240752336722e-01, 9.815062931491536e-01,
        ];

        let z = x.iter().map(|&x| super::inc_gamma(P, x)).collect::<Vec<_>>();
        assert::close(&z, &y, 1e-14);
    }

    #[test]
    fn inc_gamma_large_p() {
        const P: f64 = 1500.0;
        let x = vec![
            1400.0, 1410.0, 1420.0, 1430.0, 1440.0, 1450.0, 1460.0, 1470.0, 1480.0, 1490.0,
            1500.0, 1510.0, 1520.0, 1530.0, 1540.0, 1550.0, 1560.0, 1570.0, 1580.0, 1590.0,
        ];
        let y = vec![
            4.231080348517120e-03, 9.056183893278287e-03, 1.809200095269094e-02,
            3.380047876608895e-02, 5.917825204288418e-02, 9.731671903009434e-02,
            1.506860564044825e-01, 2.202940362119810e-01, 3.049926190158564e-01,
            4.012305141433336e-01, 5.034335611603484e-01, 6.049687028759408e-01,
            6.994146092246781e-01, 7.817404371226420e-01, 8.490443067241588e-01,
            9.006922020203059e-01, 9.379249194843459e-01, 9.631597573132408e-01,
            9.792520392189441e-01, 9.889149370075309e-01,
        ];

        let z = x.iter().map(|&x| super::inc_gamma(P, x)).collect::<Vec<_>>();
        assert::close(&z, &y, 1e-12);
    }
}
<|endoftext|>


<commit_before>use proc_macro2::{Ident, Span, TokenStream};

use syn;
use try;

pub fn wrap_in_const(
    serde_path: Option<&syn::Path>,
    trait_: &str,
    ty: &Ident,
    code: TokenStream,
) -> TokenStream {
    let try_replacement = try::replacement();

    let dummy_const = Ident::new(
        &format!("_IMPL_{}_FOR_{}", trait_, unraw(ty)),
        Span::call_site(),
    );

    let use_serde = match serde_path {
        Some(path) => quote! {
            use #path as _serde;
        },
        None => quote! {
            #[allow(unknown_lints)]
            #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
            #[allow(rust_2018_idioms)]
            extern crate serde as _serde;
        },
    };

    quote! {
        #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
        const #dummy_const: () = {
            #use_serde
            #try_replacement
            #code
        };
    }
}

#[allow(deprecated)]
fn unraw(ident: &Ident) -> String {
    // str::trim_start_matches was added in 1.30, trim_left_matches deprecated
    // in 1.33. We currently support rustc back to 1.15 so we need to continue
    // to use the deprecated one.
    ident.to_string().trim_left_matches("r#").to_owned()
}
<commit_msg>Hide generated dummy const in rustdoc<commit_after>use proc_macro2::{Ident, Span, TokenStream};

use syn;
use try;

pub fn wrap_in_const(
    serde_path: Option<&syn::Path>,
    trait_: &str,
    ty: &Ident,
    code: TokenStream,
) -> TokenStream {
    let try_replacement = try::replacement();

    let dummy_const = Ident::new(
        &format!("_IMPL_{}_FOR_{}", trait_, unraw(ty)),
        Span::call_site(),
    );

    let use_serde = match serde_path {
        Some(path) => quote! {
            use #path as _serde;
        },
        None => quote! {
            #[allow(unknown_lints)]
            #[cfg_attr(feature = "cargo-clippy", allow(useless_attribute))]
            #[allow(rust_2018_idioms)]
            extern crate serde as _serde;
        },
    };

    quote! {
        #[doc(hidden)]
        #[allow(non_upper_case_globals, unused_attributes, unused_qualifications)]
        const #dummy_const: () = {
            #use_serde
            #try_replacement
            #code
        };
    }
}

#[allow(deprecated)]
fn unraw(ident: &Ident) -> String {
    // str::trim_start_matches was added in 1.30, trim_left_matches deprecated
    // in 1.33. We currently support rustc back to 1.15 so we need to continue
    // to use the deprecated one.
    ident.to_string().trim_left_matches("r#").to_owned()
}
<|endoftext|>


<commit_before>//! Provides a way to link `AudioDevice`s into an acyclic graph.

use std::collections::VecDeque;

use types::{AudioDevice, Sample, Time};
use utils::tick::Tick;

pub struct DeviceGraph {
    nodes: Vec<AudioNode>, // the actual nodes
    topology: Vec<usize>, // the order to tick the nodes
    bus: Vec<Sample>, // the audio bus to write samples to
    time: Time // the next timestep
}

impl DeviceGraph {
    pub fn new() -> DeviceGraph {
        DeviceGraph {
            nodes: Vec::new(),
            topology: Vec::new(),
            bus: Vec::new(),
            time: 0
        }
    }

    pub fn add_node<D>(&mut self, device: D) -> AudioNodeIdx
            where D: 'static+AudioDevice {
        let node = AudioNode::new(device, &mut self.bus);
        let idx = self.nodes.len();
        self.nodes.push(node);
        self.topology.push(idx);
        AudioNodeIdx(idx)
    }

    pub fn add_edge(&mut self, from: AudioNodeIdx, from_ch: usize,
                    to: AudioNodeIdx, to_ch: usize) -> Result<(), GraphError> {
        // Check device indices
        let AudioNodeIdx(from_i) = from;
        let AudioNodeIdx(to_i) = to;
        if from_i >= self.nodes.len() {
            return Err(GraphError::FromOutOfRange);
        } else if to_i >= self.nodes.len() {
            return Err(GraphError::ToOutOfRange);
        }

        // Check channels
        if self.nodes[from_i].device.num_outputs() <= from_ch {
            return Err(GraphError::FromChOutOfRange);
        }
        if self.nodes[to_i].device.num_inputs() <= to_ch {
            return Err(GraphError::ToChOutOfRange);
        }
        while self.nodes[to_i].inputs.len() < to_ch {
            self.nodes[to_i].inputs.push(None);
        }

        // Set input
        let (start,_) = self.nodes[from_i].outputs;
        self.nodes[to_i].inputs[to_ch] = Some(start+from_ch);
        self.topological_sort(to_i, to_ch)
    }

    /// Determines the topology of our device graph. If the graph has a cycle,
    /// then we remove the last edge. Otherwise, we set self.topology to
    /// a topologically sorted order.
    fn topological_sort(&mut self, to_i: usize, to_ch: usize) ->
            Result<(), GraphError> {
        // Intialize our set of input edges, and our set of edgeless nodes
        let mut topology = Vec::new();
        let mut inputs: Vec<Vec<_>> = self.nodes.iter().map(
            |node| node.inputs.iter().filter_map(|&o| o).collect()
        ).collect();
        let mut no_inputs: VecDeque<_> = inputs.iter().enumerate().filter_map(
            |(i, ins)| if ins.len() == 0 { Some(i) } else { None }
        ).collect();

        // While there are nodes with no input, we choose one, add it as the
        // next node in our topology, and remove all edges from that node. Any
        // nodes that lose their final edge are added to the edgeless set.
        loop {
            match no_inputs.pop_front() {
                Some(i) => {
                    topology.push(i);
                    for (j, ins) in inputs.iter_mut().enumerate() {
                        let mut idx = None;
                        for k in 0..ins.len() {
                            if ins[k] == i {
                                idx = Some(k);
                                break;
                            }
                        }
                        match idx {
                            Some(k) => {
                                ins.swap_remove(k);
                                if ins.len() == 0 {
                                    no_inputs.push_back(j);
                                }
                            },
                            None => ()
                        }
                    }
                },
                None => break
            }
        }

        if topology.len() == self.nodes.len() {
            self.topology = topology;
            Ok(())
        } else {
            self.nodes[to_i].inputs[to_ch] = None;
            Err(GraphError::CreatesCycle)
        }
    }
}

impl Tick for DeviceGraph {
    fn tick(&mut self) {
        for &i in self.topology.iter() {
            let inputs: Vec<Sample> = self.nodes[i].inputs.iter().map(|input|
                input.map_or(0.0, |ch| self.bus[ch])).collect();
            let (start, end) = self.nodes[i].outputs;
            self.nodes[i].device.tick(self.time, &inputs,
                                        &mut self.bus[start..end]);
        }
        self.time += 1;
    }
}

#[derive(Copy, Clone, Debug)]
pub enum GraphError {
    FromOutOfRange, FromChOutOfRange, ToOutOfRange, ToChOutOfRange, CreatesCycle
}

#[derive(Copy, Clone, Debug)]
pub struct AudioNodeIdx(usize);
struct AudioNode {
    device: Box<AudioDevice>,
    inputs: Vec<Option<usize>>,
    outputs: (usize, usize)
}

impl AudioNode {
    fn new<D>(device: D, bus: &mut Vec<Sample>) -> AudioNode
            where D: 'static+AudioDevice {
        let num_in = device.num_inputs();
        let mut inputs = Vec::with_capacity(num_in);
        for _ in 0..num_in {
            inputs.push(None)
        }

        let num_out = device.num_outputs();
        let start = bus.len();
        for _ in 0..num_out {
            bus.push(0.0);
        }
        let end = bus.len();

        AudioNode {
            device: Box::new(device),
            inputs: inputs,
            outputs: (start, end)
        }
    }
}
<commit_msg>Fix graph cycle detection.<commit_after>//! Provides a way to link `AudioDevice`s into an acyclic graph.

use std::collections::VecDeque;

use types::{AudioDevice, Sample, Time};
use utils::tick::Tick;

pub struct DeviceGraph {
    nodes: Vec<AudioNode>, // the actual nodes
    topology: Vec<usize>, // the order to tick the nodes
    bus: Vec<Sample>, // the audio bus to write samples to
    time: Time // the next timestep
}

impl DeviceGraph {
    pub fn new() -> DeviceGraph {
        DeviceGraph {
            nodes: Vec::new(),
            topology: Vec::new(),
            bus: Vec::new(),
            time: 0
        }
    }

    pub fn add_node<D>(&mut self, device: D) -> AudioNodeIdx
            where D: 'static+AudioDevice {
        let node = AudioNode::new(device, &mut self.bus);
        let idx = self.nodes.len();
        self.nodes.push(node);
        self.topology.push(idx);
        AudioNodeIdx(idx)
    }

    pub fn add_edge(&mut self, from: AudioNodeIdx, from_ch: usize,
                    to: AudioNodeIdx, to_ch: usize) -> Result<(), GraphError> {
        // Check device indices
        let AudioNodeIdx(from_i) = from;
        let AudioNodeIdx(to_i) = to;
        if from_i >= self.nodes.len() {
            return Err(GraphError::FromOutOfRange);
        } else if to_i >= self.nodes.len() {
            return Err(GraphError::ToOutOfRange);
        }

        // Check channels
        if self.nodes[from_i].device.num_outputs() <= from_ch {
            return Err(GraphError::FromChOutOfRange);
        }
        if self.nodes[to_i].device.num_inputs() <= to_ch {
            return Err(GraphError::ToChOutOfRange);
        }
        while self.nodes[to_i].inputs.len() < to_ch {
            self.nodes[to_i].inputs.push(None);
        }

        // Set input
        let (start,_) = self.nodes[from_i].outputs;
        self.nodes[to_i].inputs[to_ch] = Some(start+from_ch);
        self.topological_sort(to_i, to_ch)
    }

    /// Determines the topology of our device graph. If the graph has a cycle,
    /// then we remove the last edge. Otherwise, we set self.topology to
    /// a topologically sorted order.
    fn topological_sort(&mut self, to_i: usize, to_ch: usize) ->
            Result<(), GraphError> {
        // Intialize our set of input edges, and our set of edgeless nodes
        let mut topology = Vec::new();
        let mut inputs: Vec<Vec<_>> = self.nodes.iter().map(
            |node| node.inputs.iter().filter_map(|&o| o).collect()
        ).collect();
        let mut no_inputs: VecDeque<_> = inputs.iter().enumerate().filter_map(
            |(i, ins)| if ins.len() == 0 { Some(i) } else { None }
        ).collect();

        // While there are nodes with no input, we choose one, add it as the
        // next node in our topology, and remove all edges from that node. Any
        // nodes that lose their final edge are added to the edgeless set.
        loop {
            match no_inputs.pop_front() {
                Some(i) => {
                    topology.push(i);
                    let (out_start, out_end) = self.nodes[i].outputs;
                    for out in out_start..out_end {
                        for (j, ins) in inputs.iter_mut().enumerate() {
                            let mut idx = None;
                            for k in 0..ins.len() {
                                if ins[k] == out {
                                    idx = Some(k);
                                    break;
                                }
                            }
                            match idx {
                                Some(k) => {
                                    ins.swap_remove(k);
                                    if ins.len() == 0 {
                                        no_inputs.push_back(j);
                                    }
                                },
                                None => ()
                            }
                        }
                    }
                },
                None => break
            }
        }

        if topology.len() == self.nodes.len() {
            self.topology = topology;
            Ok(())
        } else {
            self.nodes[to_i].inputs[to_ch] = None;
            Err(GraphError::CreatesCycle)
        }
    }
}

impl Tick for DeviceGraph {
    fn tick(&mut self) {
        for &i in self.topology.iter() {
            let inputs: Vec<Sample> = self.nodes[i].inputs.iter().map(|input|
                input.map_or(0.0, |ch| self.bus[ch])).collect();
            let (start, end) = self.nodes[i].outputs;
            self.nodes[i].device.tick(self.time, &inputs,
                                        &mut self.bus[start..end]);
        }
        self.time += 1;
    }
}

#[derive(Copy, Clone, Debug)]
pub enum GraphError {
    FromOutOfRange, FromChOutOfRange, ToOutOfRange, ToChOutOfRange, CreatesCycle
}

#[derive(Copy, Clone, Debug)]
pub struct AudioNodeIdx(usize);
struct AudioNode {
    device: Box<AudioDevice>,
    inputs: Vec<Option<usize>>,
    outputs: (usize, usize)
}

impl AudioNode {
    fn new<D>(device: D, bus: &mut Vec<Sample>) -> AudioNode
            where D: 'static+AudioDevice {
        let num_in = device.num_inputs();
        let mut inputs = Vec::with_capacity(num_in);
        for _ in 0..num_in {
            inputs.push(None)
        }

        let num_out = device.num_outputs();
        let start = bus.len();
        for _ in 0..num_out {
            bus.push(0.0);
        }
        let end = bus.len();

        AudioNode {
            device: Box::new(device),
            inputs: inputs,
            outputs: (start, end)
        }
    }
}
<|endoftext|>


<commit_before>use env_logger;
use failure;

use gluon;
use hubcaps;

#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;

#[allow(unused_imports)]
#[macro_use]
extern crate structopt;
use tokio;

use gluon_crates_io;
use gluon_master;

#[macro_use]
extern crate gluon_vm;
#[macro_use]
extern crate gluon_codegen;

use std::fs;
use std::ops::Deref;

use futures::{future, prelude::*};

use hyper::client::HttpConnector;
use hyper_tls::HttpsConnector;

use gluon::{
    vm::{
        self,
        api::{OwnedFunction, RuntimeResult, IO},
        ExternModule,
    },
    Thread,
};

use structopt::StructOpt;

pub fn load_master(thread: &Thread) -> vm::Result<ExternModule> {
    #[derive(Debug, VmType, Userdata, Trace)]
    #[gluon(vm_type = "MasterTryThread")]
    #[gluon_trace(skip)]
    pub struct TryThread(gluon_master::RootedThread);

    impl Deref for TryThread {
        type Target = gluon_master::Thread;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    thread.register_type::<TryThread>("MasterTryThread", &[])?;

    ExternModule::new(
        thread,
        record! {
            make_eval_vm => primitive!(1, "make_eval_vm", |()| {
                RuntimeResult::from(gluon_master::make_eval_vm().map(TryThread))
            }),
            eval => primitive!(2, "eval", |t: &TryThread, s: &str| gluon_master::eval(t, s)),
            format_expr => primitive!(2, |t: &TryThread, s: &str| gluon_master::format_expr(t, s))
        },
    )
}

pub fn load(thread: &Thread) -> vm::Result<ExternModule> {
    #[derive(Debug, VmType, Userdata, Trace)]
    #[gluon(vm_type = "TryThread")]
    #[gluon_trace(skip)]
    pub struct TryThread(gluon_crates_io::RootedThread);

    impl Deref for TryThread {
        type Target = gluon_crates_io::Thread;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    thread.register_type::<TryThread>("TryThread", &[])?;

    ExternModule::new(
        thread,
        record! {
            make_eval_vm => primitive!(1, "make_eval_vm", |()| {
                RuntimeResult::from(gluon_crates_io::make_eval_vm().map(TryThread))
            }),
            eval => primitive!(2, "eval", |t: &TryThread, s: &str| gluon_crates_io::eval(t, s)),
            format_expr => primitive!(2, |t: &TryThread, s: &str| gluon_crates_io::format_expr(t, s))
        },
    )
}

#[derive(Debug, Default, Getable, VmType)]
pub struct Gist<'a> {
    pub code: &'a str,
}

#[derive(Debug, Default, Serialize, Pushable, VmType)]
pub struct PostGist {
    pub id: String,
    pub html_url: String,
}

#[derive(Debug, VmType, Userdata, Trace)]
#[gluon(vm_type = "Github")]
#[gluon_trace(skip)]
struct Github(hubcaps::Github<HttpsConnector<HttpConnector>>);

fn new_github(gist_access_token: &str) -> Github {
    Github(hubcaps::Github::new(
        "try_gluon".to_string(),
        hubcaps::Credentials::Token(gist_access_token.into()),
    ))
}

fn share(
    github: &Github,
    gist: Gist<'_>,
) -> impl Future<Item = Result<PostGist, String>, Error = vm::Error> {
    info!("Share: `{}`", gist.code);

    github
        .0
        .gists()
        .create(&hubcaps::gists::GistOptions {
            description: Some("Gluon code shared from try_gluon".into()),
            public: Some(true),
            files: Some((
                "try_gluon.glu".into(),
                hubcaps::gists::Content {
                    filename: None,
                    content: gist.code.into(),
                },
            ))
            .into_iter()
            .collect(),
        })
        .map_err(|err| err.to_string())
        .map(|response| PostGist {
            id: response.id,
            html_url: response.html_url,
        })
        .then(Ok)
}

#[derive(StructOpt, Pushable, VmType)]
struct Opts {
    #[structopt(
        long = "gist-access-token",
        env = "GIST_ACCESS_TOKEN",
        help = "The access tokens used to create gists"
    )]
    gist_access_token: Option<String>,
    #[structopt(short = "p", long = "port", help = "The port to start the server on")]
    port: Option<u16>,
    #[structopt(long = "https", help = "Whether to run the server with https")]
    https: bool,
    #[structopt(
        long = "host",
        default_value = "gluon-lang.org",
        help = "The hostname for the server"
    )]
    host: String,
    #[structopt(
        long = "staging",
        help = "Whether to use letsencrypt's staging environment"
    )]
    staging: bool,
}

fn main() {
    if let Err(err) = main_() {
        eprintln!("{}\n{}", err, err.backtrace());
    }
}

#[cfg(unix)]
fn exit_server() -> impl Future<Item = (), Error = failure::Error> {
    use tokio_signal::unix::{Signal, SIGINT, SIGTERM};
    Signal::new(SIGINT)
        .flatten_stream()
        .select(Signal::new(SIGTERM).flatten_stream())
        .into_future()
        .map(|_| {
            eprintln!("Signal received. Shutting down");
        })
        .map_err(|(err, _)| failure::format_err!("{}", err))
}

#[cfg(not(unix))]
fn exit_server() -> impl Future<Item = (), Error = failure::Error> {
    tokio_signal::ctrl_c()
        .flatten_stream()
        .into_future()
        .map(|_| ())
        .map_err(|(err, _)| failure::format_err!("{}", err))
}

fn main_() -> Result<(), failure::Error> {
    env_logger::init();

    let opts = Opts::from_args();

    let mut runtime = tokio::runtime::Runtime::new()?;

    let vm = gluon::new_vm();
    gluon::import::add_extern_module(&vm, "gluon.try", load);
    gluon::import::add_extern_module(&vm, "gluon.try.master", load_master);
    gluon::import::add_extern_module(&vm, "gluon.http_server", |vm| {
        ExternModule::new(
            vm,
            record! {
                type Opts => Opts,
                log => record! {
                    error => primitive!(1, "log.error", |s: &str| {
                        error!("{}", s);
                        IO::Value(())
                    }),
                    warn => primitive!(1, "log.warn", |s: &str| {
                        warn!("{}", s);
                        IO::Value(())
                    }),
                    info => primitive!(1, "log.info", |s: &str| {
                        info!("{}", s);
                        IO::Value(())
                    }),
                    debug => primitive!(1, "log.debug", |s: &str| {
                        debug!("{}", s);
                        IO::Value(())
                    })
                }
            },
        )
    });
    gluon::import::add_extern_module(&vm, "github", |vm| {
        vm.register_type::<Github>("Github", &[])?;
        ExternModule::new(
            vm,
            record! {
                new_github => primitive!(1, new_github),
                share => primitive!(2, async fn share)
            },
        )
    });

    let server_source = fs::read_to_string("src/app/server.glu")?;

    let (_, _) = runtime.block_on(
        future::lazy(move || {
            gluon::Compiler::new()
                .run_expr_async::<OwnedFunction<fn(Opts) -> IO<()>>>(
                    &vm,
                    "src.app.server",
                    &server_source,
                )
                .and_then(|(mut f, _)| f.call_async(opts).from_err())
                .map_err(|err| failure::Error::from(err))
                .map(|_| ())
        })
        .select(exit_server())
        .map_err(|(err, _)| err),
    )?;

    Ok(())
}
<commit_msg>More idiomatic code<commit_after>#[macro_use]
extern crate log;

use std::{fs, ops::Deref};

use {
    futures::{future, prelude::*},
    hyper::client::HttpConnector,
    hyper_tls::HttpsConnector,
    serde::Serialize,
};

use gluon_codegen::{Getable, Pushable, Trace, Userdata, VmType};
use gluon_vm::{primitive, record};

use gluon::{
    vm::{
        self,
        api::{OwnedFunction, RuntimeResult, IO},
        ExternModule,
    },
    Thread,
};

use structopt::StructOpt;

pub fn load_master(thread: &Thread) -> vm::Result<ExternModule> {
    #[derive(Debug, VmType, Userdata, Trace)]
    #[gluon(vm_type = "MasterTryThread")]
    #[gluon_trace(skip)]
    pub struct TryThread(gluon_master::RootedThread);

    impl Deref for TryThread {
        type Target = gluon_master::Thread;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    thread.register_type::<TryThread>("MasterTryThread", &[])?;

    ExternModule::new(
        thread,
        record! {
            make_eval_vm => primitive!(1, "make_eval_vm", |()| {
                RuntimeResult::from(gluon_master::make_eval_vm().map(TryThread))
            }),
            eval => primitive!(2, "eval", |t: &TryThread, s: &str| gluon_master::eval(t, s)),
            format_expr => primitive!(2, |t: &TryThread, s: &str| gluon_master::format_expr(t, s))
        },
    )
}

pub fn load(thread: &Thread) -> vm::Result<ExternModule> {
    #[derive(Debug, VmType, Userdata, Trace)]
    #[gluon(vm_type = "TryThread")]
    #[gluon_trace(skip)]
    pub struct TryThread(gluon_crates_io::RootedThread);

    impl Deref for TryThread {
        type Target = gluon_crates_io::Thread;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    thread.register_type::<TryThread>("TryThread", &[])?;

    ExternModule::new(
        thread,
        record! {
            make_eval_vm => primitive!(1, "make_eval_vm", |()| {
                RuntimeResult::from(gluon_crates_io::make_eval_vm().map(TryThread))
            }),
            eval => primitive!(2, "eval", |t: &TryThread, s: &str| gluon_crates_io::eval(t, s)),
            format_expr => primitive!(2, |t: &TryThread, s: &str| gluon_crates_io::format_expr(t, s))
        },
    )
}

#[derive(Debug, Default, Getable, VmType)]
pub struct Gist<'a> {
    pub code: &'a str,
}

#[derive(Debug, Default, Serialize, Pushable, VmType)]
pub struct PostGist {
    pub id: String,
    pub html_url: String,
}

#[derive(Debug, VmType, Userdata, Trace)]
#[gluon(vm_type = "Github")]
#[gluon_trace(skip)]
struct Github(hubcaps::Github<HttpsConnector<HttpConnector>>);

fn new_github(gist_access_token: &str) -> Github {
    Github(hubcaps::Github::new(
        "try_gluon".to_string(),
        hubcaps::Credentials::Token(gist_access_token.into()),
    ))
}

fn share(
    github: &Github,
    gist: Gist<'_>,
) -> impl Future<Item = Result<PostGist, String>, Error = vm::Error> {
    info!("Share: `{}`", gist.code);

    github
        .0
        .gists()
        .create(&hubcaps::gists::GistOptions {
            description: Some("Gluon code shared from try_gluon".into()),
            public: Some(true),
            files: Some((
                "try_gluon.glu".into(),
                hubcaps::gists::Content {
                    filename: None,
                    content: gist.code.into(),
                },
            ))
            .into_iter()
            .collect(),
        })
        .map_err(|err| err.to_string())
        .map(|response| PostGist {
            id: response.id,
            html_url: response.html_url,
        })
        .then(Ok)
}

#[derive(StructOpt, Pushable, VmType)]
struct Opts {
    #[structopt(
        long = "gist-access-token",
        env = "GIST_ACCESS_TOKEN",
        help = "The access tokens used to create gists"
    )]
    gist_access_token: Option<String>,
    #[structopt(short = "p", long = "port", help = "The port to start the server on")]
    port: Option<u16>,
    #[structopt(long = "https", help = "Whether to run the server with https")]
    https: bool,
    #[structopt(
        long = "host",
        default_value = "gluon-lang.org",
        help = "The hostname for the server"
    )]
    host: String,
    #[structopt(
        long = "staging",
        help = "Whether to use letsencrypt's staging environment"
    )]
    staging: bool,
}

fn main() {
    if let Err(err) = main_() {
        eprintln!("{}\n{}", err, err.backtrace());
    }
}

#[cfg(unix)]
fn exit_server() -> impl Future<Item = (), Error = failure::Error> {
    use tokio_signal::unix::{Signal, SIGINT, SIGTERM};
    Signal::new(SIGINT)
        .flatten_stream()
        .select(Signal::new(SIGTERM).flatten_stream())
        .into_future()
        .map(|_| {
            eprintln!("Signal received. Shutting down");
        })
        .map_err(|(err, _)| failure::format_err!("{}", err))
}

#[cfg(not(unix))]
fn exit_server() -> impl Future<Item = (), Error = failure::Error> {
    tokio_signal::ctrl_c()
        .flatten_stream()
        .into_future()
        .map(|_| ())
        .map_err(|(err, _)| failure::format_err!("{}", err))
}

fn main_() -> Result<(), failure::Error> {
    env_logger::init();

    let opts = Opts::from_args();

    let mut runtime = tokio::runtime::Runtime::new()?;

    let vm = gluon::new_vm();
    gluon::import::add_extern_module(&vm, "gluon.try", load);
    gluon::import::add_extern_module(&vm, "gluon.try.master", load_master);
    gluon::import::add_extern_module(&vm, "gluon.http_server", |vm| {
        ExternModule::new(
            vm,
            record! {
                type Opts => Opts,
                log => record! {
                    error => primitive!(1, "log.error", |s: &str| {
                        error!("{}", s);
                        IO::Value(())
                    }),
                    warn => primitive!(1, "log.warn", |s: &str| {
                        warn!("{}", s);
                        IO::Value(())
                    }),
                    info => primitive!(1, "log.info", |s: &str| {
                        info!("{}", s);
                        IO::Value(())
                    }),
                    debug => primitive!(1, "log.debug", |s: &str| {
                        debug!("{}", s);
                        IO::Value(())
                    })
                }
            },
        )
    });
    gluon::import::add_extern_module(&vm, "github", |vm| {
        vm.register_type::<Github>("Github", &[])?;
        ExternModule::new(
            vm,
            record! {
                new_github => primitive!(1, new_github),
                share => primitive!(2, async fn share)
            },
        )
    });

    let server_source = fs::read_to_string("src/app/server.glu")?;

    let (_, _) = runtime.block_on(
        future::lazy(move || {
            gluon::Compiler::new()
                .run_expr_async::<OwnedFunction<fn(Opts) -> IO<()>>>(
                    &vm,
                    "src.app.server",
                    &server_source,
                )
                .and_then(|(mut f, _)| f.call_async(opts).from_err())
                .map_err(|err| failure::Error::from(err))
                .map(|_| ())
        })
        .select(exit_server())
        .map_err(|(err, _)| err),
    )?;

    Ok(())
}
<|endoftext|>