<commit_before>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use error::StatsError;
use function::{beta, gamma};
use result::Result;
use super::*;

/// Implements the [Beta](https://en.wikipedia.org/wiki/Beta_distribution) distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Beta};
///
/// let n = Beta::new(2.0, 2.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Beta {
    shape_a: f64,
    shape_b: f64,
}

impl Beta {
    /// Constructs a new beta distribution with shapeA (α) of `shape_a`
    /// and shapeB (β) of `shape_b`
    ///
    /// # Errors
    ///
    /// Returns an error if `shape_a` or `shape_b` are `NaN`.
    /// Also returns an error if `shape_a <= 0.0` or `shape_b <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Beta;
    ///
    /// let mut result = Beta::new(2.0, 2.0);
    /// assert!(result.is_ok());
    ///
    /// result = Beta::new(0.0, 0.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(shape_a: f64, shape_b: f64) -> Result<Beta> {
        let is_nan = shape_a.is_nan() || shape_b.is_nan();
        match (shape_a, shape_b, is_nan) {
            (_, _, true) => Err(StatsError::BadParams),
            (_, _, false) if shape_a <= 0.0 || shape_b <= 0.0 => Err(StatsError::BadParams),
            (_, _, false) => {
                Ok(Beta {
                    shape_a: shape_a,
                    shape_b: shape_b,
                })
            }
        }
    }

    /// Returns the shapeA (α) of the beta distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Beta;
    ///
    /// let n = Beta::new(2.0, 2.0).unwrap();
    /// assert_eq!(n.shape_a(), 2.0);
    /// ```
    pub fn shape_a(&self) -> f64 {
        self.shape_a
    }

    /// Returns the shapeB (β) of the beta distributionβ
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Beta;
    ///
    /// let n = Beta::new(2.0, 2.0).unwrap();
    /// assert_eq!(n.shape_b(), 2.0);
    /// ```
    pub fn shape_b(&self) -> f64 {
        self.shape_b
    }
}

impl Sample<f64> for Beta {
    /// Generate a random sample from a beta distribution
    /// using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details.
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Beta {
    /// Generate a random independent sample from a beta distribution
    /// using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details.
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Beta {
    /// Generate a random sample from a beta distribution using
    /// `r` as the source of randomness. Generated by sampling
    /// two gamma distributions and normalizing.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Beta, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Beta::new(2.0, 2.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        let x = super::gamma::sample_unchecked(r, self.shape_a, 1.0);
        let y = super::gamma::sample_unchecked(r, self.shape_b, 1.0);
        x / (x + y)
    }
}

impl Univariate<f64, f64> for Beta {
    /// Calculates the cumulative distribution function for the beta distribution
    /// at `x`
    ///
    /// # Panics
    ///
    /// If `x < 0.0` or `x > 1.0`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// I_x(α, β)
    /// ```
    ///
    /// where `α` is shapeA, `β` is shapeB, and `I_x` is the regularized
    /// lower incomplete beta function
    fn cdf(&self, x: f64) -> f64 {
        assert!(x >= 0.0 && x <= 1.0,
                format!("{}", StatsError::ArgIntervalIncl("x", 0.0, 1.0)));
        if x == 1.0 {
            1.0
        } else if self.shape_a == f64::INFINITY && self.shape_b == f64::INFINITY {
            if x < 0.5 { 0.0 } else { 1.0 }
        } else if self.shape_a == f64::INFINITY {
            if x < 1.0 { 0.0 } else { 1.0 }
        } else if self.shape_b == f64::INFINITY {
            0.0
        } else if self.shape_a == 1.0 && self.shape_b == 1.0 {
            x
        } else {
            beta::beta_reg(self.shape_a, self.shape_b, x)
        }
    }

    /// Returns the minimum value in the domain of the
    /// beta distribution representable by a double precision
    /// float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 0
    /// ```
    fn min(&self) -> f64 {
        0.0
    }

    /// Returns the maximum value in the domain of the
    /// beta distribution representable by a double precision
    /// float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 1
    /// ```
    fn max(&self) -> f64 {
        1.0
    }
}

impl Mean<f64, f64> for Beta {
    /// Returns the mean of the beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// α / (α + β)
    /// ```
    ///
    /// where `α` is shapeA and `β` is shapeB
    fn mean(&self) -> f64 {
        if self.shape_a == f64::INFINITY && self.shape_b == f64::INFINITY {
            0.5
        } else if self.shape_a == f64::INFINITY {
            1.0
        } else if self.shape_b == f64::INFINITY {
            0.0
        } else {
            self.shape_a / (self.shape_a + self.shape_b)
        }
    }
}

impl Variance<f64, f64> for Beta {
    /// Returns the variance of the beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (α * β) / ((α + β)^2 * (α + β + 1))
    /// ```
    ///
    /// where `α` is shapeA and `β` is shapeB
    fn variance(&self) -> f64 {
        self.shape_a * self.shape_b /
        ((self.shape_a + self.shape_b) * (self.shape_a + self.shape_b) *
         (self.shape_a + self.shape_b + 1.0))
    }

    /// Returns the standard deviation of the beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// sqrt((α * β) / ((α + β)^2 * (α + β + 1)))
    /// ```
    ///
    /// where `α` is shapeA and `β` is shapeB
    fn std_dev(&self) -> f64 {
        self.variance().sqrt()
    }
}

impl Entropy<f64> for Beta {
    /// Returns the entropy of the beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(B(α, β)) - (α - 1)ψ(α) - (β - 1)ψ(β) + (α + β - 2)ψ(α + β)
    /// ```
    ///
    /// where `α` is shapeA, `β` is shapeB and `ψ` is the digamma function
    fn entropy(&self) -> f64 {
        if self.shape_a == f64::INFINITY || self.shape_b == f64::INFINITY {
            0.0
        } else {
            beta::ln_beta(self.shape_a, self.shape_b) -
            (self.shape_a - 1.0) * gamma::digamma(self.shape_a) -
            (self.shape_b - 1.0) * gamma::digamma(self.shape_b) +
            (self.shape_a + self.shape_b - 2.0) * gamma::digamma(self.shape_a + self.shape_b)
        }
    }
}
<commit_msg>complete beta distribution (untested)<commit_after>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use error::StatsError;
use function::{beta, gamma};
use result::Result;
use super::*;

/// Implements the [Beta](https://en.wikipedia.org/wiki/Beta_distribution) distribution
///
/// # Examples
///
/// ```
/// use statrs::distribution::{Beta};
///
/// let n = Beta::new(2.0, 2.0);
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Beta {
    shape_a: f64,
    shape_b: f64,
}

impl Beta {
    /// Constructs a new beta distribution with shapeA (α) of `shape_a`
    /// and shapeB (β) of `shape_b`
    ///
    /// # Errors
    ///
    /// Returns an error if `shape_a` or `shape_b` are `NaN`.
    /// Also returns an error if `shape_a <= 0.0` or `shape_b <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Beta;
    ///
    /// let mut result = Beta::new(2.0, 2.0);
    /// assert!(result.is_ok());
    ///
    /// result = Beta::new(0.0, 0.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(shape_a: f64, shape_b: f64) -> Result<Beta> {
        let is_nan = shape_a.is_nan() || shape_b.is_nan();
        match (shape_a, shape_b, is_nan) {
            (_, _, true) => Err(StatsError::BadParams),
            (_, _, false) if shape_a <= 0.0 || shape_b <= 0.0 => Err(StatsError::BadParams),
            (_, _, false) => {
                Ok(Beta {
                    shape_a: shape_a,
                    shape_b: shape_b,
                })
            }
        }
    }

    /// Returns the shapeA (α) of the beta distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Beta;
    ///
    /// let n = Beta::new(2.0, 2.0).unwrap();
    /// assert_eq!(n.shape_a(), 2.0);
    /// ```
    pub fn shape_a(&self) -> f64 {
        self.shape_a
    }

    /// Returns the shapeB (β) of the beta distributionβ
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Beta;
    ///
    /// let n = Beta::new(2.0, 2.0).unwrap();
    /// assert_eq!(n.shape_b(), 2.0);
    /// ```
    pub fn shape_b(&self) -> f64 {
        self.shape_b
    }
}

impl Sample<f64> for Beta {
    /// Generate a random sample from a beta distribution
    /// using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details.
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Beta {
    /// Generate a random independent sample from a beta distribution
    /// using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details.
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Beta {
    /// Generate a random sample from a beta distribution using
    /// `r` as the source of randomness. Generated by sampling
    /// two gamma distributions and normalizing.
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Beta, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Beta::new(2.0, 2.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        let x = super::gamma::sample_unchecked(r, self.shape_a, 1.0);
        let y = super::gamma::sample_unchecked(r, self.shape_b, 1.0);
        x / (x + y)
    }
}

impl Univariate<f64, f64> for Beta {
    /// Calculates the cumulative distribution function for the beta distribution
    /// at `x`
    ///
    /// # Panics
    ///
    /// If `x < 0.0` or `x > 1.0`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// I_x(α, β)
    /// ```
    ///
    /// where `α` is shapeA, `β` is shapeB, and `I_x` is the regularized
    /// lower incomplete beta function
    fn cdf(&self, x: f64) -> f64 {
        assert!(x >= 0.0 && x <= 1.0,
                format!("{}", StatsError::ArgIntervalIncl("x", 0.0, 1.0)));
        match (self.shape_a, self.shape_b, x) {
            (_, _, 1.0) => 1.0,
            (f64::INFINITY, f64::INFINITY, _) if x < 0.5 => 0.0,
            (f64::INFINITY, f64::INFINITY, _) => 1.0,
            (f64::INFINITY, _, _) if x < 1.0 => 0.0,
            (f64::INFINITY, _, _) => 1.0,
            (_, f64::INFINITY, _) => 0.0,
            (1.0, 1.0, _) => x,
            (_, _, _) => beta::beta_reg(self.shape_a, self.shape_b, x),
        }
    }

    /// Returns the minimum value in the domain of the
    /// beta distribution representable by a double precision
    /// float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 0
    /// ```
    fn min(&self) -> f64 {
        0.0
    }

    /// Returns the maximum value in the domain of the
    /// beta distribution representable by a double precision
    /// float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 1
    /// ```
    fn max(&self) -> f64 {
        1.0
    }
}

impl Mean<f64, f64> for Beta {
    /// Returns the mean of the beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// α / (α + β)
    /// ```
    ///
    /// where `α` is shapeA and `β` is shapeB
    fn mean(&self) -> f64 {
        match (self.shape_a, self.shape_b) {
            (f64::INFINITY, f64::INFINITY) => 0.5,
            (f64::INFINITY, _) => 1.0,
            (_, f64::INFINITY) => 0.0,
            (_, _) => self.shape_a / (self.shape_a + self.shape_b),
        }
    }
}

impl Variance<f64, f64> for Beta {
    /// Returns the variance of the beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (α * β) / ((α + β)^2 * (α + β + 1))
    /// ```
    ///
    /// where `α` is shapeA and `β` is shapeB
    fn variance(&self) -> f64 {
        self.shape_a * self.shape_b /
        ((self.shape_a + self.shape_b) * (self.shape_a + self.shape_b) *
         (self.shape_a + self.shape_b + 1.0))
    }

    /// Returns the standard deviation of the beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// sqrt((α * β) / ((α + β)^2 * (α + β + 1)))
    /// ```
    ///
    /// where `α` is shapeA and `β` is shapeB
    fn std_dev(&self) -> f64 {
        self.variance().sqrt()
    }
}

impl Entropy<f64> for Beta {
    /// Returns the entropy of the beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(B(α, β)) - (α - 1)ψ(α) - (β - 1)ψ(β) + (α + β - 2)ψ(α + β)
    /// ```
    ///
    /// where `α` is shapeA, `β` is shapeB and `ψ` is the digamma function
    fn entropy(&self) -> f64 {
        if self.shape_a == f64::INFINITY || self.shape_b == f64::INFINITY {
            0.0
        } else {
            beta::ln_beta(self.shape_a, self.shape_b) -
            (self.shape_a - 1.0) * gamma::digamma(self.shape_a) -
            (self.shape_b - 1.0) * gamma::digamma(self.shape_b) +
            (self.shape_a + self.shape_b - 2.0) * gamma::digamma(self.shape_a + self.shape_b)
        }
    }
}

impl Skewness<f64, f64> for Beta {
    /// Returns the skewness of the Beta distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 2(β - α) * sqrt(α + β + 1) / ((α + β + 2) * sqrt(αβ))
    /// ```
    ///
    /// where `α` is shapeA and `β` is shapeB
    fn skewness(&self) -> f64 {
        match (self.shape_a, self.shape_b) {
            (f64::INFINITY, f64::INFINITY) => 0.0,
            (f64::INFINITY, _) => -2.0,
            (_, f64::INFINITY) => 2.0,
            (_, _) => {
                2.0 * (self.shape_b - self.shape_a) * (self.shape_a + self.shape_b + 1.0) /
                ((self.shape_a + self.shape_b + 2.0) * (self.shape_a * self.shape_b).sqrt())
            }
        }
    }
}

impl Mode<f64, f64> for Beta {
    /// Returns the mode of the Beta distribution.
    ///
    /// # Remarks
    ///
    /// Since the mode is technically only calculate for `α > 1, β > 1`, those
    /// are the only values we allow. We may consider relaxing this constraint in
    /// the future.
    ///
    /// # Panics
    ///
    /// If `α <= 1` or `β <= 1`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (α - 1) / (α + β - 2)
    /// ```
    ///
    /// where `α` is shapeA and `β` is shapeB
    fn mode(&self) -> f64 {
        // TODO: perhaps relax constraint in order to allow calculation
        // of 'anti-mode;
        assert!(self.shape_a > 1.0,
                format!("{}", StatsError::ArgGt("shape_a", 1.0)));
        assert!(self.shape_b > 1.0,
                format!("{}", StatsError::ArgGt("shape_b", 1.0)));
        match (self.shape_a, self.shape_b) {
            (f64::INFINITY, f64::INFINITY) => 0.5,
            (f64::INFINITY, _) => 1.0,
            (_, f64::INFINITY) => 0.0,
            (_, _) => (self.shape_a - 1.0) / (self.shape_a + self.shape_b - 2.0),
        }
    }
}

impl Continuous<f64, f64> for Beta {
    /// Calculates the probability density function for the beta distribution at `x`.
    ///
    /// # Panics
    ///
    /// If `x < 0.0` or `x > 1.0`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// let B(α, β) = Γ(α)Γ(β)/Γ(α + β)
    ///
    /// x^(α - 1) * (1 - x)^(β - 1) / B(α, β)
    /// ```
    ///
    /// where `α` is shapeA, `β` is shapeB, and `Γ` is the gamma function
    fn pdf(&self, x: f64) -> f64 {
        assert!(x >= 0.0 && x <= 1.0,
                format!("{}", StatsError::ArgIntervalIncl("x", 0.0, 1.0)));
        match (self.shape_a, self.shape_b, x) => {
            (f64::INFINITY, f64::INFINITY, 0.5) => f64::INFINITY,
            (f64::INFINITY, f64::INFINITY, _) => 0.0,
            (f64::INFINITY, _, 1.0) => f64::INFINITY,
            (f64::INFINITY, _, _) => 0.0,
            (_, f64::INFINITY, 0.0) => f64::INFINITY,
            (_, f64::INFINITY, _) => 0.0,
            (1.0, 1.0, _) => 1.0,
            (_, _, _) if self.shape_a > 80.0 || self.shape_b > 80.0 => self.ln_pdf().exp(),
            (_, _, _) => {
                let bb = gamma::gamma(self.shape_a + self.shape_b) / (gamma::gamma(self.shape_a) * gamma::gamma(self.shape_b));
                bb * x.powf(self.shape_a - 1.0) * (1.0 - x).powf(self.shape_b - 1.0)
            }
        }
    }

    /// Calculates the log probability density function for the beta distribution at `x`.
    ///
    /// # Panics
    ///
    /// If `x < 0.0` or `x > 1.0`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// let B(α, β) = Γ(α)Γ(β)/Γ(α + β)
    ///
    /// ln(x^(α - 1) * (1 - x)^(β - 1) / B(α, β))
    /// ```
    ///
    /// where `α` is shapeA, `β` is shapeB, and `Γ` is the gamma function
    fn ln_pdf(&self, x: f64) -> f64 {
        assert!(x >= 0.0 && x <= 1.0,
                format!("{}", StatsError::ArgIntervalIncl("x", 0.0, 1.0)));
        match (self.shape_a, self.shape_b, x) => {
            (f64::INFINITY, f64::INFINITY, 0.5) => f64::INFINITY,
            (f64::INFINITY, f64::INFINITY, _) => f64::NEG_INFINITY,
            (f64::INFINITY, _, 1.0) => f64::INFINITY,
            (f64::INFINITY, _, _) => f64::NEG_INFINITY,
            (_, f64::INFINITY, 0.0) => f64::INFINITY,
            (_, f64::INFINITY, _) => f64::NEG_INFINITY,
            (1.0, 1.0, _) => 0.0,
            (_, _, _) => {
                let aa = gamma::ln_gamma(self.shape_a + self.shape_b) - gamma::ln_gamma(self.shape_a) - gamma::ln_gamma(self.shape_b);
                let bb = match (self.shape_a, x) {
                    (1.0, 0.0) => 0.0,
                    (_, 0.0) => f64::NEG_INFINITY,
                    (_, _) => (self.shape_a - 1.0) * x.ln()
                };
                let cc = match (self.shape_b, x) {
                    (1.0, 1.0) => 0.0,
                    (_, 1.0) => f64::NEG_INFINITY,
                    (_, _) => (self.shape_b - 1.0) * (1.0 - x).ln()
                };
                aa + bb + cc
            }
        }
    }
}<|endoftext|>


<commit_before>use collections::TreeMap;
use syntax::ast::expr::*;
use syntax::ast::op::*;
use syntax::ast::constant::Const;
/**
 * A compiler that transforms expressions into their compiled
 * form, typically through a library such as LibJIT or LLVM.
*/
pub trait Compiler<'a, Compiled> {
    /// Compile an expression
    fn compile(&'a self, expr:&Expr) -> Compiled {
        debug!("Compiling {}", expr);
        match expr.def.clone() {
            UnaryOpExpr(op, ex) =>
                self.compile_unary_op(op, ex),
            BinOpExpr(op, left, right) =>
                self.compile_bin_op(op, left, right),
            ConstExpr(ref c) =>
                self.compile_const(c),
            LocalExpr(l) =>
                self.compile_local(l),
            BlockExpr(vals) =>
                self.compile_block(vals),
            GetConstFieldExpr(obj, field) =>
                self.compile_get_const_field(obj, field),
            GetFieldExpr(obj, field) =>
                self.compile_get_field(obj, field),
            CallExpr(func, args) =>
                self.compile_call(func, args),
            WhileLoopExpr(cond, expr) =>
                self.compile_while_loop(cond, expr),
            IfExpr(cond, if_expr, else_expr) =>
                self.compile_if(cond, if_expr, else_expr),
            SwitchExpr(value, cases, default) =>
                self.compile_switch(value, cases, default),
            ObjectDeclExpr(fields) =>
                self.compile_object_decl(fields),
            ArrayDeclExpr(values) =>
                self.compile_array_decl(values),
            FunctionDeclExpr(name, args, ret) =>
                self.compile_function_decl(name, args, ret),
            ArrowFunctionDeclExpr(args, ret) =>
                self.compile_arrow_function_decl(args, ret),
            ConstructExpr(func, args) =>
                self.compile_construct(func, args),
            ReturnExpr(val) =>
                self.compile_return(val),
            ThrowExpr(val) =>
                self.compile_throw(val),
            AssignExpr(left, right) =>
                self.compile_assign(left, right),
            VarDeclExpr(vars) =>
                self.compile_var_decl(vars),
            TypeOfExpr(expr) =>
                self.compile_typeof(expr)
        }
    }
    /// Compile a unary operation
    fn compile_unary_op(&'a self, _:UnaryOp, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a binary operation
    fn compile_bin_op(&'a self, op:BinOp, left:&Expr, right:&Expr) -> Compiled {
        match op {
            BinNum(num) => self.compile_num_op(num, left, right),
            BinBit(bit) => self.compile_bit_op(bit, left, right),
            BinComp(comp) => self.compile_comp_op(comp, left, right),
            BinLog(log) => self.compile_log_op(log, left, right),
        }
    }
    /// Compile a numeric operation
    fn compile_num_op(&'a self, _:NumOp, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a bitwise operation
    fn compile_bit_op(&'a self, _:BitOp, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a comparitive operation
    fn compile_comp_op(&'a self, _:CompOp, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a logical operation
    fn compile_log_op(&'a self, _:LogOp, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a constant
    fn compile_const(&'a self, _:&Const) -> Compiled {
        unimplemented!()
    }
    /// Compile a local variable
    fn compile_local(&'a self, _:String) -> Compiled {
        unimplemented!()
    }
    /// Compile a block of expressions
    fn compile_block(&'a self, _:Vec<Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile constant field access for an object
    fn compile_get_const_field(&'a self, _:&Expr, _:String) -> Compiled {
        unimplemented!()
    }
    /// Compile field access for an object
    fn compile_get_field(&'a self, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a call to a function with some arguments
    fn compile_call(&'a self, _:&Expr, _:Vec<Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile a while loop
    fn compile_while_loop(&'a self, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile an if statement
    fn compile_if(&'a self, _:&Expr, _:&Expr, _:Option<Box<Expr>>) -> Compiled {
        unimplemented!()
    }
    /// Compile a switch statement
    fn compile_switch(&'a self, _:&Expr, Vec<(Expr, Vec<Expr>)>, Option<Box<Expr>>) -> Compiled {
        unimplemented!()
    }
    /// Compile an object declaration
    fn compile_object_decl(&'a self, &TreeMap<String, Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile an array declaration
    fn compile_array_decl(&'a self, Vec<Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile a function declaration
    fn compile_function_decl(&'a self, _:Option<String>, _:Vec<String>, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile an arrow function declaration
    fn compile_arrow_function_decl(&'a self, _:Vec<String>, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a construction of an object
    fn compile_construct(&'a self, _:&Expr, _:Vec<Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile a return expression
    fn compile_return(&'a self, _:Option<Box<Expr>>) -> Compiled {
        unimplemented!()
    }
    /// Compile a throw expression
    fn compile_throw(&'a self, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile an assignment
    fn compile_assign(&'a self, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a variable declaration
    fn compile_var_decl(&'a self, _:Vec<(String, Option<Expr>)>) -> Compiled {
        unimplemented!()
    }
    /// Compile a typeof expression
    fn compile_typeof(&'a self, _:&Expr) -> Compiled {
        unimplemented!()
    }
}<commit_msg>Get references to boxed expressions<commit_after>use collections::TreeMap;
use syntax::ast::expr::*;
use syntax::ast::op::*;
use syntax::ast::constant::Const;
/**
 * A compiler that transforms expressions into their compiled
 * form, typically through a library such as LibJIT or LLVM.
*/
pub trait Compiler<'a, Compiled> {
    /// Compile an expression
    fn compile(&'a self, expr:&Expr) -> Compiled {
        debug!("Compiling {}", expr);
        match expr.def.clone() {
            UnaryOpExpr(op, box ref ex) =>
                self.compile_unary_op(op, ex),
            BinOpExpr(op, box ref left, box ref right) =>
                self.compile_bin_op(op, left, right),
            ConstExpr(ref c) =>
                self.compile_const(c),
            LocalExpr(l) =>
                self.compile_local(l),
            BlockExpr(vals) =>
                self.compile_block(vals),
            GetConstFieldExpr(box ref obj, field) =>
                self.compile_get_const_field(obj, field),
            GetFieldExpr(box ref obj, box ref field) =>
                self.compile_get_field(obj, field),
            CallExpr(box ref func, args) =>
                self.compile_call(func, args),
            WhileLoopExpr(box ref cond, box ref expr) =>
                self.compile_while_loop(cond, expr),
            IfExpr(box ref cond, box ref if_expr, else_expr) =>
                self.compile_if(cond, if_expr, else_expr),
            SwitchExpr(box ref value, cases, default) =>
                self.compile_switch(value, cases, default),
            ObjectDeclExpr(box ref fields) =>
                self.compile_object_decl(fields),
            ArrayDeclExpr(values) =>
                self.compile_array_decl(values),
            FunctionDeclExpr(name, args, box ref ret) =>
                self.compile_function_decl(name, args, ret),
            ArrowFunctionDeclExpr(args, box ref ret) =>
                self.compile_arrow_function_decl(args, ret),
            ConstructExpr(box ref func, args) =>
                self.compile_construct(func, args),
            ReturnExpr(val) =>
                self.compile_return(val),
            ThrowExpr(box ref val) =>
                self.compile_throw(val),
            AssignExpr(box ref left, box ref right) =>
                self.compile_assign(left, right),
            VarDeclExpr(vars) =>
                self.compile_var_decl(vars),
            TypeOfExpr(box ref expr) =>
                self.compile_typeof(expr)
        }
    }
    /// Compile a unary operation
    fn compile_unary_op(&'a self, _:UnaryOp, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a binary operation
    fn compile_bin_op(&'a self, op:BinOp, left:&Expr, right:&Expr) -> Compiled {
        match op {
            BinNum(num) => self.compile_num_op(num, left, right),
            BinBit(bit) => self.compile_bit_op(bit, left, right),
            BinComp(comp) => self.compile_comp_op(comp, left, right),
            BinLog(log) => self.compile_log_op(log, left, right),
        }
    }
    /// Compile a numeric operation
    fn compile_num_op(&'a self, _:NumOp, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a bitwise operation
    fn compile_bit_op(&'a self, _:BitOp, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a comparitive operation
    fn compile_comp_op(&'a self, _:CompOp, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a logical operation
    fn compile_log_op(&'a self, _:LogOp, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a constant
    fn compile_const(&'a self, _:&Const) -> Compiled {
        unimplemented!()
    }
    /// Compile a local variable
    fn compile_local(&'a self, _:String) -> Compiled {
        unimplemented!()
    }
    /// Compile a block of expressions
    fn compile_block(&'a self, _:Vec<Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile constant field access for an object
    fn compile_get_const_field(&'a self, _:&Expr, _:String) -> Compiled {
        unimplemented!()
    }
    /// Compile field access for an object
    fn compile_get_field(&'a self, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a call to a function with some arguments
    fn compile_call(&'a self, _:&Expr, _:Vec<Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile a while loop
    fn compile_while_loop(&'a self, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile an if statement
    fn compile_if(&'a self, _:&Expr, _:&Expr, _:Option<Box<Expr>>) -> Compiled {
        unimplemented!()
    }
    /// Compile a switch statement
    fn compile_switch(&'a self, _:&Expr, Vec<(Expr, Vec<Expr>)>, Option<Box<Expr>>) -> Compiled {
        unimplemented!()
    }
    /// Compile an object declaration
    fn compile_object_decl(&'a self, &TreeMap<String, Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile an array declaration
    fn compile_array_decl(&'a self, Vec<Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile a function declaration
    fn compile_function_decl(&'a self, _:Option<String>, _:Vec<String>, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile an arrow function declaration
    fn compile_arrow_function_decl(&'a self, _:Vec<String>, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a construction of an object
    fn compile_construct(&'a self, _:&Expr, _:Vec<Expr>) -> Compiled {
        unimplemented!()
    }
    /// Compile a return expression
    fn compile_return(&'a self, _:Option<Box<Expr>>) -> Compiled {
        unimplemented!()
    }
    /// Compile a throw expression
    fn compile_throw(&'a self, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile an assignment
    fn compile_assign(&'a self, _:&Expr, _:&Expr) -> Compiled {
        unimplemented!()
    }
    /// Compile a variable declaration
    fn compile_var_decl(&'a self, _:Vec<(String, Option<Expr>)>) -> Compiled {
        unimplemented!()
    }
    /// Compile a typeof expression
    fn compile_typeof(&'a self, _:&Expr) -> Compiled {
        unimplemented!()
    }
}<|endoftext|>


<commit_before>use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver, SendError};
use std::thread;

use super::storage::Storage;
use super::entry::{Entry, EntryId};
use super::worker::{Command, Listener, spawn_worker};

pub type CommandResult<T> = Result<(), SendError<Command<T>>>;

pub struct Frontend<T: Send + 'static> {
    tx: Sender<Command<T>>,
}

impl<T: Send + 'static> Clone for Frontend<T> {
    fn clone(&self) -> Self {
        Frontend {
            tx: self.tx.clone()
        }
    }
}

impl<T: Send + 'static> Frontend<T> {
    pub fn new(tx: Sender<Command<T>>) -> Self {
        Frontend { tx }
    }

    pub fn build(listener: Box<Listener<T>>) -> (Self, thread::JoinHandle<()>) {
        let (tx, rx): (Sender<Command<T>>, Receiver<Command<T>>) = mpsc::channel();
        let storage = Storage::new();
        let handle = spawn_worker(storage, rx, listener);

        (Self::new(tx), handle)
    }

    pub fn add_entry(&self, entry: Entry<T>) -> CommandResult<T> {
        self.command(Command::AddEntry(entry))
    }

    pub fn remove_entry(&self, id: EntryId) -> CommandResult<T> {
        self.command(Command::RemoveEntry(id))
    }

    fn command(&self, command: Command<T>) -> CommandResult<T> {
        self.tx.send(command)
    }
}
<commit_msg>Add comment<commit_after>use std::sync::mpsc;
use std::sync::mpsc::{Sender, Receiver, SendError};
use std::thread;

use super::storage::Storage;
use super::entry::{Entry, EntryId};
use super::worker::{Command, Listener, spawn_worker};

// TODO: convert to own error type
pub type CommandResult<T> = Result<(), SendError<Command<T>>>;

pub struct Frontend<T: Send + 'static> {
    tx: Sender<Command<T>>,
}

impl<T: Send + 'static> Clone for Frontend<T> {
    fn clone(&self) -> Self {
        Frontend {
            tx: self.tx.clone()
        }
    }
}

impl<T: Send + 'static> Frontend<T> {
    pub fn new(tx: Sender<Command<T>>) -> Self {
        Frontend { tx }
    }

    pub fn build(listener: Box<Listener<T>>) -> (Self, thread::JoinHandle<()>) {
        let (tx, rx): (Sender<Command<T>>, Receiver<Command<T>>) = mpsc::channel();
        let storage = Storage::new();
        let handle = spawn_worker(storage, rx, listener);

        (Self::new(tx), handle)
    }

    pub fn add_entry(&self, entry: Entry<T>) -> CommandResult<T> {
        self.command(Command::AddEntry(entry))
    }

    pub fn remove_entry(&self, id: EntryId) -> CommandResult<T> {
        self.command(Command::RemoveEntry(id))
    }

    fn command(&self, command: Command<T>) -> CommandResult<T> {
        self.tx.send(command)
    }
}
<|endoftext|>


<commit_before><commit_msg>Lol Gold Panda<commit_after><|endoftext|>


<commit_before>use rustc_index::bit_set::BitSet;

use super::*;

/// Preorder traversal of a graph.
///
/// Preorder traversal is when each node is visited before an of it's
/// successors
///
/// ```text
///
///         A
///        / \
///       /   \
///      B     C
///       \   /
///        \ /
///         D
/// ```
///
/// A preorder traversal of this graph is either `A B D C` or `A C D B`
#[derive(Clone)]
pub struct Preorder<'a, 'tcx> {
    body: &'a Body<'tcx>,
    visited: BitSet<BasicBlock>,
    worklist: Vec<BasicBlock>,
    root_is_start_block: bool,
}

impl<'a, 'tcx> Preorder<'a, 'tcx> {
    pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> {
        let worklist = vec![root];

        Preorder {
            body,
            visited: BitSet::new_empty(body.basic_blocks().len()),
            worklist,
            root_is_start_block: root == START_BLOCK,
        }
    }
}

pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> {
    Preorder::new(body, START_BLOCK)
}

impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);

    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
        while let Some(idx) = self.worklist.pop() {
            if !self.visited.insert(idx) {
                continue;
            }

            let data = &self.body[idx];

            if let Some(ref term) = data.terminator {
                self.worklist.extend(term.successors());
            }

            return Some((idx, data));
        }

        None
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // All the blocks, minus the number of blocks we've visited.
        let upper = self.body.basic_blocks().len() - self.visited.count();

        let lower = if self.root_is_start_block {
            // We will visit all remaining blocks exactly once.
            upper
        } else {
            self.worklist.len()
        };

        (lower, Some(upper))
    }
}

/// Postorder traversal of a graph.
///
/// Postorder traversal is when each node is visited after all of it's
/// successors, except when the successor is only reachable by a back-edge
///
///
/// ```text
///
///         A
///        / \
///       /   \
///      B     C
///       \   /
///        \ /
///         D
/// ```
///
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
pub struct Postorder<'a, 'tcx> {
    body: &'a Body<'tcx>,
    visited: BitSet<BasicBlock>,
    visit_stack: Vec<(BasicBlock, Successors<'a>)>,
    root_is_start_block: bool,
}

impl<'a, 'tcx> Postorder<'a, 'tcx> {
    pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
        let mut po = Postorder {
            body,
            visited: BitSet::new_empty(body.basic_blocks().len()),
            visit_stack: Vec::new(),
            root_is_start_block: root == START_BLOCK,
        };

        let data = &po.body[root];

        if let Some(ref term) = data.terminator {
            po.visited.insert(root);
            po.visit_stack.push((root, term.successors()));
            po.traverse_successor();
        }

        po
    }

    fn traverse_successor(&mut self) {
        // This is quite a complex loop due to 1. the borrow checker not liking it much
        // and 2. what exactly is going on is not clear
        //
        // It does the actual traversal of the graph, while the `next` method on the iterator
        // just pops off of the stack. `visit_stack` is a stack containing pairs of nodes and
        // iterators over the successors of those nodes. Each iteration attempts to get the next
        // node from the top of the stack, then pushes that node and an iterator over the
        // successors to the top of the stack. This loop only grows `visit_stack`, stopping when
        // we reach a child that has no children that we haven't already visited.
        //
        // For a graph that looks like this:
        //
        //         A
        //        / \
        //       /   \
        //      B     C
        //      |     |
        //      |     |
        //      D     |
        //       \   /
        //        \ /
        //         E
        //
        // The state of the stack starts out with just the root node (`A` in this case);
        //     [(A, [B, C])]
        //
        // When the first call to `traverse_successor` happens, the following happens:
        //
        //     [(B, [D]),  // `B` taken from the successors of `A`, pushed to the
        //                 // top of the stack along with the successors of `B`
        //      (A, [C])]
        //
        //     [(D, [E]),  // `D` taken from successors of `B`, pushed to stack
        //      (B, []),
        //      (A, [C])]
        //
        //     [(E, []),   // `E` taken from successors of `D`, pushed to stack
        //      (D, []),
        //      (B, []),
        //      (A, [C])]
        //
        // Now that the top of the stack has no successors we can traverse, each item will
        // be popped off during iteration until we get back to `A`. This yields [E, D, B].
        //
        // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but
        // since we've already visited `E`, that child isn't added to the stack. The last
        // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A]
        loop {
            let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() {
                if let Some(&bb) = iter.next() {
                    bb
                } else {
                    break;
                }
            } else {
                break;
            };

            if self.visited.insert(bb) {
                if let Some(term) = &self.body[bb].terminator {
                    self.visit_stack.push((bb, term.successors()));
                }
            }
        }
    }
}

pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> {
    Postorder::new(body, START_BLOCK)
}

impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);

    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
        let next = self.visit_stack.pop();
        if next.is_some() {
            self.traverse_successor();
        }

        next.map(|(bb, _)| (bb, &self.body[bb]))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // All the blocks, minus the number of blocks we've visited.
        let upper = self.body.basic_blocks().len() - self.visited.count();

        let lower = if self.root_is_start_block {
            // We will visit all remaining blocks exactly once.
            upper
        } else {
            self.visit_stack.len()
        };

        (lower, Some(upper))
    }
}

/// Reverse postorder traversal of a graph
///
/// Reverse postorder is the reverse order of a postorder traversal.
/// This is different to a preorder traversal and represents a natural
/// linearization of control-flow.
///
/// ```text
///
///         A
///        / \
///       /   \
///      B     C
///       \   /
///        \ /
///         D
/// ```
///
/// A reverse postorder traversal of this graph is either `A B C D` or `A C B D`
/// Note that for a graph containing no loops (i.e., A DAG), this is equivalent to
/// a topological sort.
///
/// Construction of a `ReversePostorder` traversal requires doing a full
/// postorder traversal of the graph, therefore this traversal should be
/// constructed as few times as possible. Use the `reset` method to be able
/// to re-use the traversal
#[derive(Clone)]
pub struct ReversePostorder<'a, 'tcx> {
    body: &'a Body<'tcx>,
    blocks: Vec<BasicBlock>,
    idx: usize,
}

impl<'a, 'tcx> ReversePostorder<'a, 'tcx> {
    pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> {
        let blocks: Vec<_> = Postorder::new(body, root).map(|(bb, _)| bb).collect();

        let len = blocks.len();

        ReversePostorder { body, blocks, idx: len }
    }

    pub fn reset(&mut self) {
        self.idx = self.blocks.len();
    }
}

pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorder<'a, 'tcx> {
    ReversePostorder::new(body, START_BLOCK)
}

impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> {
    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);

    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
        if self.idx == 0 {
            return None;
        }
        self.idx -= 1;

        self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb]))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.idx, Some(self.idx))
    }
}

impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {}
<commit_msg>Fix a few spelling mistakes<commit_after>use rustc_index::bit_set::BitSet;

use super::*;

/// Preorder traversal of a graph.
///
/// Preorder traversal is when each node is visited before any of its
/// successors
///
/// ```text
///
///         A
///        / \
///       /   \
///      B     C
///       \   /
///        \ /
///         D
/// ```
///
/// A preorder traversal of this graph is either `A B D C` or `A C D B`
#[derive(Clone)]
pub struct Preorder<'a, 'tcx> {
    body: &'a Body<'tcx>,
    visited: BitSet<BasicBlock>,
    worklist: Vec<BasicBlock>,
    root_is_start_block: bool,
}

impl<'a, 'tcx> Preorder<'a, 'tcx> {
    pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Preorder<'a, 'tcx> {
        let worklist = vec![root];

        Preorder {
            body,
            visited: BitSet::new_empty(body.basic_blocks().len()),
            worklist,
            root_is_start_block: root == START_BLOCK,
        }
    }
}

pub fn preorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Preorder<'a, 'tcx> {
    Preorder::new(body, START_BLOCK)
}

impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> {
    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);

    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
        while let Some(idx) = self.worklist.pop() {
            if !self.visited.insert(idx) {
                continue;
            }

            let data = &self.body[idx];

            if let Some(ref term) = data.terminator {
                self.worklist.extend(term.successors());
            }

            return Some((idx, data));
        }

        None
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // All the blocks, minus the number of blocks we've visited.
        let upper = self.body.basic_blocks().len() - self.visited.count();

        let lower = if self.root_is_start_block {
            // We will visit all remaining blocks exactly once.
            upper
        } else {
            self.worklist.len()
        };

        (lower, Some(upper))
    }
}

/// Postorder traversal of a graph.
///
/// Postorder traversal is when each node is visited after all of its
/// successors, except when the successor is only reachable by a back-edge
///
///
/// ```text
///
///         A
///        / \
///       /   \
///      B     C
///       \   /
///        \ /
///         D
/// ```
///
/// A Postorder traversal of this graph is `D B C A` or `D C B A`
pub struct Postorder<'a, 'tcx> {
    body: &'a Body<'tcx>,
    visited: BitSet<BasicBlock>,
    visit_stack: Vec<(BasicBlock, Successors<'a>)>,
    root_is_start_block: bool,
}

impl<'a, 'tcx> Postorder<'a, 'tcx> {
    pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> Postorder<'a, 'tcx> {
        let mut po = Postorder {
            body,
            visited: BitSet::new_empty(body.basic_blocks().len()),
            visit_stack: Vec::new(),
            root_is_start_block: root == START_BLOCK,
        };

        let data = &po.body[root];

        if let Some(ref term) = data.terminator {
            po.visited.insert(root);
            po.visit_stack.push((root, term.successors()));
            po.traverse_successor();
        }

        po
    }

    fn traverse_successor(&mut self) {
        // This is quite a complex loop due to 1. the borrow checker not liking it much
        // and 2. what exactly is going on is not clear
        //
        // It does the actual traversal of the graph, while the `next` method on the iterator
        // just pops off of the stack. `visit_stack` is a stack containing pairs of nodes and
        // iterators over the successors of those nodes. Each iteration attempts to get the next
        // node from the top of the stack, then pushes that node and an iterator over the
        // successors to the top of the stack. This loop only grows `visit_stack`, stopping when
        // we reach a child that has no children that we haven't already visited.
        //
        // For a graph that looks like this:
        //
        //         A
        //        / \
        //       /   \
        //      B     C
        //      |     |
        //      |     |
        //      D     |
        //       \   /
        //        \ /
        //         E
        //
        // The state of the stack starts out with just the root node (`A` in this case);
        //     [(A, [B, C])]
        //
        // When the first call to `traverse_successor` happens, the following happens:
        //
        //     [(B, [D]),  // `B` taken from the successors of `A`, pushed to the
        //                 // top of the stack along with the successors of `B`
        //      (A, [C])]
        //
        //     [(D, [E]),  // `D` taken from successors of `B`, pushed to stack
        //      (B, []),
        //      (A, [C])]
        //
        //     [(E, []),   // `E` taken from successors of `D`, pushed to stack
        //      (D, []),
        //      (B, []),
        //      (A, [C])]
        //
        // Now that the top of the stack has no successors we can traverse, each item will
        // be popped off during iteration until we get back to `A`. This yields [E, D, B].
        //
        // When we yield `B` and call `traverse_successor`, we push `C` to the stack, but
        // since we've already visited `E`, that child isn't added to the stack. The last
        // two iterations yield `C` and finally `A` for a final traversal of [E, D, B, C, A]
        loop {
            let bb = if let Some(&mut (_, ref mut iter)) = self.visit_stack.last_mut() {
                if let Some(&bb) = iter.next() {
                    bb
                } else {
                    break;
                }
            } else {
                break;
            };

            if self.visited.insert(bb) {
                if let Some(term) = &self.body[bb].terminator {
                    self.visit_stack.push((bb, term.successors()));
                }
            }
        }
    }
}

pub fn postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> Postorder<'a, 'tcx> {
    Postorder::new(body, START_BLOCK)
}

impl<'a, 'tcx> Iterator for Postorder<'a, 'tcx> {
    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);

    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
        let next = self.visit_stack.pop();
        if next.is_some() {
            self.traverse_successor();
        }

        next.map(|(bb, _)| (bb, &self.body[bb]))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // All the blocks, minus the number of blocks we've visited.
        let upper = self.body.basic_blocks().len() - self.visited.count();

        let lower = if self.root_is_start_block {
            // We will visit all remaining blocks exactly once.
            upper
        } else {
            self.visit_stack.len()
        };

        (lower, Some(upper))
    }
}

/// Reverse postorder traversal of a graph
///
/// Reverse postorder is the reverse order of a postorder traversal.
/// This is different to a preorder traversal and represents a natural
/// linearization of control-flow.
///
/// ```text
///
///         A
///        / \
///       /   \
///      B     C
///       \   /
///        \ /
///         D
/// ```
///
/// A reverse postorder traversal of this graph is either `A B C D` or `A C B D`
/// Note that for a graph containing no loops (i.e., A DAG), this is equivalent to
/// a topological sort.
///
/// Construction of a `ReversePostorder` traversal requires doing a full
/// postorder traversal of the graph, therefore this traversal should be
/// constructed as few times as possible. Use the `reset` method to be able
/// to re-use the traversal
#[derive(Clone)]
pub struct ReversePostorder<'a, 'tcx> {
    body: &'a Body<'tcx>,
    blocks: Vec<BasicBlock>,
    idx: usize,
}

impl<'a, 'tcx> ReversePostorder<'a, 'tcx> {
    pub fn new(body: &'a Body<'tcx>, root: BasicBlock) -> ReversePostorder<'a, 'tcx> {
        let blocks: Vec<_> = Postorder::new(body, root).map(|(bb, _)| bb).collect();

        let len = blocks.len();

        ReversePostorder { body, blocks, idx: len }
    }

    pub fn reset(&mut self) {
        self.idx = self.blocks.len();
    }
}

pub fn reverse_postorder<'a, 'tcx>(body: &'a Body<'tcx>) -> ReversePostorder<'a, 'tcx> {
    ReversePostorder::new(body, START_BLOCK)
}

impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> {
    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);

    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
        if self.idx == 0 {
            return None;
        }
        self.idx -= 1;

        self.blocks.get(self.idx).map(|&bb| (bb, &self.body[bb]))
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.idx, Some(self.idx))
    }
}

impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {}
<|endoftext|>


<commit_before>use crate::cmp;
use crate::ffi::CStr;
use crate::io;
use crate::mem;
use crate::sys::{unsupported, Void};
use crate::time::Duration;

pub struct Thread(Void);

pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;

impl Thread {
    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
    pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>)
        -> io::Result<Thread>
    {
        unsupported()
    }

    pub fn yield_now() {
        let ret = wasi::sched_yield();
        debug_assert_eq!(ret, Ok(()));
    }

    pub fn set_name(_name: &CStr) {
        // nope
    }

    pub fn sleep(dur: Duration) {
        let nanos = dur.as_nanos();
        assert!(nanos <= u64::max_value() as u128);

        let clock = wasi::raw::__wasi_subscription_u_clock_t {
            identifier: 0x0123_45678,
            clock_id: wasi::CLOCK_MONOTONIC,
            timeout: nanos as u64,
            precision: 0,
            flags: 0,
        };

        let in_ = [wasi::Subscription {
            userdata: 0,
            type_: wasi::EVENTTYPE_CLOCK,
            u: wasi::raw::__wasi_subscription_u { clock: clock },
        }];
        let mut out: [wasi::Event; 1] = [unsafe { mem::zeroed() }];
        let n = wasi::poll_oneoff(&in_, &mut out).unwrap();
        let wasi::Event { userdata, error, type_, .. } = out[0];
        match (n, userdata, error) {
            (1, 0x0123_45678, 0) if type_ == wasi::EVENTTYPE_CLOCK => {}
            _ => panic!("thread::sleep(): unexpected result of poll_oneof"),
        }
    }

    pub fn join(self) {
        match self.0 {}
    }
}

pub mod guard {
    pub type Guard = !;
    pub unsafe fn current() -> Option<Guard> { None }
    pub unsafe fn init() -> Option<Guard> { None }
}
<commit_msg>typo fix<commit_after>use crate::cmp;
use crate::ffi::CStr;
use crate::io;
use crate::mem;
use crate::sys::{unsupported, Void};
use crate::time::Duration;

pub struct Thread(Void);

pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;

impl Thread {
    // unsafe: see thread::Builder::spawn_unchecked for safety requirements
    pub unsafe fn new(_stack: usize, _p: Box<dyn FnOnce()>)
        -> io::Result<Thread>
    {
        unsupported()
    }

    pub fn yield_now() {
        let ret = wasi::sched_yield();
        debug_assert_eq!(ret, Ok(()));
    }

    pub fn set_name(_name: &CStr) {
        // nope
    }

    pub fn sleep(dur: Duration) {
        let nanos = dur.as_nanos();
        assert!(nanos <= u64::max_value() as u128);

        let clock = wasi::raw::__wasi_subscription_u_clock_t {
            identifier: 0x0123_45678,
            clock_id: wasi::CLOCK_MONOTONIC,
            timeout: nanos as u64,
            precision: 0,
            flags: 0,
        };

        let in_ = [wasi::Subscription {
            userdata: 0,
            type_: wasi::EVENTTYPE_CLOCK,
            u: wasi::raw::__wasi_subscription_u { clock: clock },
        }];
        let mut out: [wasi::Event; 1] = [unsafe { mem::zeroed() }];
        let n = wasi::poll_oneoff(&in_, &mut out).unwrap();
        let wasi::Event { userdata, error, type_, .. } = out[0];
        match (n, userdata, error) {
            (1, 0x0123_45678, 0) if type_ == wasi::EVENTTYPE_CLOCK => {}
            _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
        }
    }

    pub fn join(self) {
        match self.0 {}
    }
}

pub mod guard {
    pub type Guard = !;
    pub unsafe fn current() -> Option<Guard> { None }
    pub unsafe fn init() -> Option<Guard> { None }
}
<|endoftext|>


<commit_before>//! This modules contains [Cassandra's errors]
//! (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011)
//! which server could respond to client.

use std::io;
use std::result;

use error;
use consistency::Consistency;
use types::*;
use FromCursor;
use frame::Frame;

/// CDRS specific `Result` which contains a [`Frame`] in case of `Ok` and `CDRSError` if `Err`.
///
/// [`Frame`]: ../frame/struct.Frame.html
pub type Result = result::Result<Frame, CDRSError>;

/// CDRS error which could be returned by Cassandra server as a response. As it goes
/// from the specification it contains an error code and an error message. Apart of those
/// depending of type of error it could contain an additional information about an error.
/// This additional information is represented by `additional_info` property which is `ErrorKind`.
#[derive(Debug)]
pub struct CDRSError {
    /// `i32` that points to a type of error.
    pub error_code: CInt,
    /// Error message string.
    pub message: CString,
    /// Additional information.
    pub additional_info: AdditionalErrorInfo,
}

impl FromCursor for CDRSError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<CDRSError> {
        let error_code = CInt::from_cursor(&mut cursor)?;
        let message = CString::from_cursor(&mut cursor)?;
        let additional_info = AdditionalErrorInfo::from_cursor_with_code(&mut cursor, error_code)?;

        Ok(CDRSError {
               error_code: error_code,
               message: message,
               additional_info: additional_info,
           })
    }
}

/// Additional error info in accordance to
/// [Cassandra protocol v4]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011).
#[derive(Debug)]
pub enum AdditionalErrorInfo {
    Server(SimpleError),
    Protocol(SimpleError),
    Authentication(SimpleError),
    Unavailable(UnavailableError),
    Overloaded(SimpleError),
    IsBootstrapping(SimpleError),
    Truncate(SimpleError),
    WriteTimeout(WriteTimeoutError),
    ReadTimeout(ReadTimeoutError),
    ReadFailure(ReadFailureError),
    FunctionFailure(FunctionFailureError),
    WriteFailure(WriteFailureError),
    Syntax(SimpleError),
    Unauthorized(SimpleError),
    Invalid(SimpleError),
    Config(SimpleError),
    AlreadyExists(AlreadyExistsError),
    Unprepared(UnpreparedError),
}

impl AdditionalErrorInfo {
    pub fn from_cursor_with_code(mut cursor: &mut io::Cursor<&[u8]>,
                                 error_code: CInt)
                                 -> error::Result<AdditionalErrorInfo> {
        Ok(match error_code {
               0x0000 => AdditionalErrorInfo::Server(SimpleError::from_cursor(&mut cursor)?),
               0x000A => AdditionalErrorInfo::Protocol(SimpleError::from_cursor(&mut cursor)?),
               0x0100 => {
                   AdditionalErrorInfo::Authentication(SimpleError::from_cursor(&mut cursor)?)
               }
               0x1000 => {
                   AdditionalErrorInfo::Unavailable(UnavailableError::from_cursor(&mut cursor)?)
               }
               0x1001 => AdditionalErrorInfo::Overloaded(SimpleError::from_cursor(&mut cursor)?),
               0x1002 => {
                   AdditionalErrorInfo::IsBootstrapping(SimpleError::from_cursor(&mut cursor)?)
               }
               0x1003 => AdditionalErrorInfo::Truncate(SimpleError::from_cursor(&mut cursor)?),
               0x1100 => {
                   AdditionalErrorInfo::WriteTimeout(WriteTimeoutError::from_cursor(&mut cursor)?)
               }
               0x1200 => {
                   AdditionalErrorInfo::ReadTimeout(ReadTimeoutError::from_cursor(&mut cursor)?)
               }
               0x1300 => {
                   AdditionalErrorInfo::ReadFailure(ReadFailureError::from_cursor(&mut cursor)?)
               }
               0x1400 => {
                AdditionalErrorInfo::FunctionFailure(FunctionFailureError::from_cursor(&mut cursor)?)
            }
               0x1500 => {
                   AdditionalErrorInfo::WriteFailure(WriteFailureError::from_cursor(&mut cursor)?)
               }
               0x2000 => AdditionalErrorInfo::Syntax(SimpleError::from_cursor(&mut cursor)?),
               0x2100 => AdditionalErrorInfo::Unauthorized(SimpleError::from_cursor(&mut cursor)?),
               0x2200 => AdditionalErrorInfo::Invalid(SimpleError::from_cursor(&mut cursor)?),
               0x2300 => AdditionalErrorInfo::Config(SimpleError::from_cursor(&mut cursor)?),
               0x2400 => {
                   AdditionalErrorInfo::AlreadyExists(AlreadyExistsError::from_cursor(&mut cursor)?)
               }
               0x2500 => {
                   AdditionalErrorInfo::Unprepared(UnpreparedError::from_cursor(&mut cursor)?)
               }
               // TODO: return error-like value
               _ => unreachable!(),
           })
    }
}

/// Is used if error does not contain any additional info.
#[derive(Debug)]
pub struct SimpleError {}

impl FromCursor for SimpleError {
    fn from_cursor(mut _cursor: &mut io::Cursor<&[u8]>) -> error::Result<SimpleError> {
        Ok(SimpleError {})
    }
}

/// Additional info about
/// [unavailable exception]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1025)
#[derive(Debug)]
pub struct UnavailableError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// Number of nodes that should be available to respect `cl`.
    pub required: CInt,
    /// Number of replicas that we were know to be alive.
    pub alive: CInt,
}

impl FromCursor for UnavailableError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnavailableError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let required = CInt::from_cursor(&mut cursor)?;
        let alive = CInt::from_cursor(&mut cursor)?;

        Ok(UnavailableError {
               cl: cl,
               required: required,
               alive: alive,
           })
    }
}

/// Timeout exception during a write request.
#[derive(Debug)]
pub struct WriteTimeoutError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Describes the type of the write that timed out
    pub write_type: WriteType,
}

impl FromCursor for WriteTimeoutError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteTimeoutError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let write_type = WriteType::from_cursor(&mut cursor)?;

        Ok(WriteTimeoutError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               write_type: write_type,
           })
    }
}

/// Timeout exception during a read request.
#[derive(Debug)]
pub struct ReadTimeoutError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    data_present: u8,
}

impl ReadTimeoutError {
    /// Shows if replica has resonded to a query.
    pub fn replica_has_responded(&self) -> bool {
        self.data_present != 0
    }
}

impl FromCursor for ReadTimeoutError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadTimeoutError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1).as_slice())? as u8;

        Ok(ReadTimeoutError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               data_present: data_present,
           })
    }
}

/// A non-timeout exception during a read request.
#[derive(Debug)]
pub struct ReadFailureError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Represents the number of nodes that experience a failure while executing the request.
    pub num_failures: CInt,
    data_present: u8,
}

impl ReadFailureError {
    /// Shows if replica has resonded to a query.
    pub fn replica_has_responded(&self) -> bool {
        self.data_present != 0
    }
}

impl FromCursor for ReadFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadFailureError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let num_failures = CInt::from_cursor(&mut cursor)?;
        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1).as_slice())? as u8;

        Ok(ReadFailureError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               num_failures: num_failures,
               data_present: data_present,
           })
    }
}

/// A (user defined) function failed during execution.
#[derive(Debug)]
pub struct FunctionFailureError {
    /// The keyspace of the failed function.
    pub keyspace: CString,
    /// The name of the failed function
    pub function: CString,
    /// `Vec<CString>` one string for each argument type (as CQL type) of the failed function.
    pub arg_types: CStringList,
}

impl FromCursor for FunctionFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<FunctionFailureError> {
        let keyspace = CString::from_cursor(&mut cursor)?;
        let function = CString::from_cursor(&mut cursor)?;
        let arg_types = CStringList::from_cursor(&mut cursor)?;

        Ok(FunctionFailureError {
               keyspace: keyspace,
               function: function,
               arg_types: arg_types,
           })
    }
}

/// A non-timeout exception during a write request.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1106)
#[derive(Debug)]
pub struct WriteFailureError {
    /// Consistency of the query having triggered the exception.
    pub cl: Consistency,
    /// Represents the number of nodes having answered the request.
    pub received: CInt,
    /// Represents the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Represents the number of nodes that experience a failure while executing the request.
    pub num_failures: CInt,
    /// describes the type of the write that failed.
    pub write_type: WriteType,
}

impl FromCursor for WriteFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteFailureError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let num_failures = CInt::from_cursor(&mut cursor)?;
        let write_type = WriteType::from_cursor(&mut cursor)?;

        Ok(WriteFailureError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               num_failures: num_failures,
               write_type: write_type,
           })
    }
}

/// Describes the type of the write that failed.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1118)
#[derive(Debug)]
pub enum WriteType {
    /// The write was a non-batched non-counter write
    Simple,
    /// The write was a (logged) batch write.
    /// If this type is received, it means the batch log
    /// has been successfully written
    Batch,
    /// The write was an unlogged batch. No batch log write has been attempted.
    UnloggedBatch,
    /// The write was a counter write (batched or not)
    Counter,
    /// The failure occured during the write to the batch log when a (logged) batch
    /// write was requested.
    BatchLog,
}

impl FromCursor for WriteType {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteType> {
        CString::from_cursor(&mut cursor).map(|wt| match wt.as_str() {
                                                  "SIMPLE" => WriteType::Simple,
                                                  "BATCH" => WriteType::Batch,
                                                  "UNLOGGED_BATCH" => WriteType::UnloggedBatch,
                                                  "COUNTER" => WriteType::Counter,
                                                  "BATCH_LOG" => WriteType::BatchLog,
                                                  // TODO: return error instead of panic
                                                  _ => unreachable!(),
                                              })
    }
}

/// The query attempted to create a keyspace or a table that was already existing.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1140)
#[derive(Debug)]
pub struct AlreadyExistsError {
    /// Represents either the keyspace that already exists,
    /// or the keyspace in which the table that already exists is.
    pub ks: CString,
    /// Represents the name of the table that already exists.
    pub table: CString,
}

impl FromCursor for AlreadyExistsError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<AlreadyExistsError> {
        let ks = CString::from_cursor(&mut cursor)?;
        let table = CString::from_cursor(&mut cursor)?;

        Ok(AlreadyExistsError {
               ks: ks,
               table: table,
           })
    }
}

/// Can be thrown while a prepared statement tries to be
/// executed if the provided prepared statement ID is not known by
/// this host. [Read more...]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1150)
#[derive(Debug)]
pub struct UnpreparedError {
    /// Unknown ID.
    pub id: CBytes,
}

impl FromCursor for UnpreparedError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnpreparedError> {
        let id = CBytes::from_cursor(&mut cursor)?;

        Ok(UnpreparedError { id: id })
    }
}
<commit_msg>Divide a line which exceeds 100 chars into 2<commit_after>//! This modules contains [Cassandra's errors]
//! (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011)
//! which server could respond to client.

use std::io;
use std::result;

use error;
use consistency::Consistency;
use types::*;
use FromCursor;
use frame::Frame;

/// CDRS specific `Result` which contains a [`Frame`] in case of `Ok` and `CDRSError` if `Err`.
///
/// [`Frame`]: ../frame/struct.Frame.html
pub type Result = result::Result<Frame, CDRSError>;

/// CDRS error which could be returned by Cassandra server as a response. As it goes
/// from the specification it contains an error code and an error message. Apart of those
/// depending of type of error it could contain an additional information about an error.
/// This additional information is represented by `additional_info` property which is `ErrorKind`.
#[derive(Debug)]
pub struct CDRSError {
    /// `i32` that points to a type of error.
    pub error_code: CInt,
    /// Error message string.
    pub message: CString,
    /// Additional information.
    pub additional_info: AdditionalErrorInfo,
}

impl FromCursor for CDRSError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<CDRSError> {
        let error_code = CInt::from_cursor(&mut cursor)?;
        let message = CString::from_cursor(&mut cursor)?;
        let additional_info = AdditionalErrorInfo::from_cursor_with_code(&mut cursor, error_code)?;

        Ok(CDRSError {
               error_code: error_code,
               message: message,
               additional_info: additional_info,
           })
    }
}

/// Additional error info in accordance to
/// [Cassandra protocol v4]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1011).
#[derive(Debug)]
pub enum AdditionalErrorInfo {
    Server(SimpleError),
    Protocol(SimpleError),
    Authentication(SimpleError),
    Unavailable(UnavailableError),
    Overloaded(SimpleError),
    IsBootstrapping(SimpleError),
    Truncate(SimpleError),
    WriteTimeout(WriteTimeoutError),
    ReadTimeout(ReadTimeoutError),
    ReadFailure(ReadFailureError),
    FunctionFailure(FunctionFailureError),
    WriteFailure(WriteFailureError),
    Syntax(SimpleError),
    Unauthorized(SimpleError),
    Invalid(SimpleError),
    Config(SimpleError),
    AlreadyExists(AlreadyExistsError),
    Unprepared(UnpreparedError),
}

impl AdditionalErrorInfo {
    pub fn from_cursor_with_code(mut cursor: &mut io::Cursor<&[u8]>,
                                 error_code: CInt)
                                 -> error::Result<AdditionalErrorInfo> {
        Ok(match error_code {
               0x0000 => AdditionalErrorInfo::Server(SimpleError::from_cursor(&mut cursor)?),
               0x000A => AdditionalErrorInfo::Protocol(SimpleError::from_cursor(&mut cursor)?),
               0x0100 => {
                   AdditionalErrorInfo::Authentication(SimpleError::from_cursor(&mut cursor)?)
               }
               0x1000 => {
                   AdditionalErrorInfo::Unavailable(UnavailableError::from_cursor(&mut cursor)?)
               }
               0x1001 => AdditionalErrorInfo::Overloaded(SimpleError::from_cursor(&mut cursor)?),
               0x1002 => {
                   AdditionalErrorInfo::IsBootstrapping(SimpleError::from_cursor(&mut cursor)?)
               }
               0x1003 => AdditionalErrorInfo::Truncate(SimpleError::from_cursor(&mut cursor)?),
               0x1100 => {
                   AdditionalErrorInfo::WriteTimeout(WriteTimeoutError::from_cursor(&mut cursor)?)
               }
               0x1200 => {
                   AdditionalErrorInfo::ReadTimeout(ReadTimeoutError::from_cursor(&mut cursor)?)
               }
               0x1300 => {
                   AdditionalErrorInfo::ReadFailure(ReadFailureError::from_cursor(&mut cursor)?)
               }
               0x1400 => {
                   AdditionalErrorInfo::FunctionFailure(
                       FunctionFailureError::from_cursor(&mut cursor)?)
               }
               0x1500 => {
                   AdditionalErrorInfo::WriteFailure(WriteFailureError::from_cursor(&mut cursor)?)
               }
               0x2000 => AdditionalErrorInfo::Syntax(SimpleError::from_cursor(&mut cursor)?),
               0x2100 => AdditionalErrorInfo::Unauthorized(SimpleError::from_cursor(&mut cursor)?),
               0x2200 => AdditionalErrorInfo::Invalid(SimpleError::from_cursor(&mut cursor)?),
               0x2300 => AdditionalErrorInfo::Config(SimpleError::from_cursor(&mut cursor)?),
               0x2400 => {
                   AdditionalErrorInfo::AlreadyExists(AlreadyExistsError::from_cursor(&mut cursor)?)
               }
               0x2500 => {
                   AdditionalErrorInfo::Unprepared(UnpreparedError::from_cursor(&mut cursor)?)
               }
               // TODO: return error-like value
               _ => unreachable!(),
           })
    }
}

/// Is used if error does not contain any additional info.
#[derive(Debug)]
pub struct SimpleError {}

impl FromCursor for SimpleError {
    fn from_cursor(mut _cursor: &mut io::Cursor<&[u8]>) -> error::Result<SimpleError> {
        Ok(SimpleError {})
    }
}

/// Additional info about
/// [unavailable exception]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1025)
#[derive(Debug)]
pub struct UnavailableError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// Number of nodes that should be available to respect `cl`.
    pub required: CInt,
    /// Number of replicas that we were know to be alive.
    pub alive: CInt,
}

impl FromCursor for UnavailableError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnavailableError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let required = CInt::from_cursor(&mut cursor)?;
        let alive = CInt::from_cursor(&mut cursor)?;

        Ok(UnavailableError {
               cl: cl,
               required: required,
               alive: alive,
           })
    }
}

/// Timeout exception during a write request.
#[derive(Debug)]
pub struct WriteTimeoutError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Describes the type of the write that timed out
    pub write_type: WriteType,
}

impl FromCursor for WriteTimeoutError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteTimeoutError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let write_type = WriteType::from_cursor(&mut cursor)?;

        Ok(WriteTimeoutError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               write_type: write_type,
           })
    }
}

/// Timeout exception during a read request.
#[derive(Debug)]
pub struct ReadTimeoutError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    data_present: u8,
}

impl ReadTimeoutError {
    /// Shows if replica has resonded to a query.
    pub fn replica_has_responded(&self) -> bool {
        self.data_present != 0
    }
}

impl FromCursor for ReadTimeoutError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadTimeoutError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1).as_slice())? as u8;

        Ok(ReadTimeoutError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               data_present: data_present,
           })
    }
}

/// A non-timeout exception during a read request.
#[derive(Debug)]
pub struct ReadFailureError {
    /// Consistency level of query.
    pub cl: Consistency,
    /// `i32` representing the number of nodes having acknowledged the request.
    pub received: CInt,
    /// `i32` representing the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Represents the number of nodes that experience a failure while executing the request.
    pub num_failures: CInt,
    data_present: u8,
}

impl ReadFailureError {
    /// Shows if replica has resonded to a query.
    pub fn replica_has_responded(&self) -> bool {
        self.data_present != 0
    }
}

impl FromCursor for ReadFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<ReadFailureError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let num_failures = CInt::from_cursor(&mut cursor)?;
        let data_present = try_from_bytes(cursor_next_value(&mut cursor, 1).as_slice())? as u8;

        Ok(ReadFailureError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               num_failures: num_failures,
               data_present: data_present,
           })
    }
}

/// A (user defined) function failed during execution.
#[derive(Debug)]
pub struct FunctionFailureError {
    /// The keyspace of the failed function.
    pub keyspace: CString,
    /// The name of the failed function
    pub function: CString,
    /// `Vec<CString>` one string for each argument type (as CQL type) of the failed function.
    pub arg_types: CStringList,
}

impl FromCursor for FunctionFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<FunctionFailureError> {
        let keyspace = CString::from_cursor(&mut cursor)?;
        let function = CString::from_cursor(&mut cursor)?;
        let arg_types = CStringList::from_cursor(&mut cursor)?;

        Ok(FunctionFailureError {
               keyspace: keyspace,
               function: function,
               arg_types: arg_types,
           })
    }
}

/// A non-timeout exception during a write request.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1106)
#[derive(Debug)]
pub struct WriteFailureError {
    /// Consistency of the query having triggered the exception.
    pub cl: Consistency,
    /// Represents the number of nodes having answered the request.
    pub received: CInt,
    /// Represents the number of replicas whose acknowledgement is required to achieve `cl`.
    pub blockfor: CInt,
    /// Represents the number of nodes that experience a failure while executing the request.
    pub num_failures: CInt,
    /// describes the type of the write that failed.
    pub write_type: WriteType,
}

impl FromCursor for WriteFailureError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteFailureError> {
        let cl = Consistency::from_cursor(&mut cursor)?;
        let received = CInt::from_cursor(&mut cursor)?;
        let blockfor = CInt::from_cursor(&mut cursor)?;
        let num_failures = CInt::from_cursor(&mut cursor)?;
        let write_type = WriteType::from_cursor(&mut cursor)?;

        Ok(WriteFailureError {
               cl: cl,
               received: received,
               blockfor: blockfor,
               num_failures: num_failures,
               write_type: write_type,
           })
    }
}

/// Describes the type of the write that failed.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1118)
#[derive(Debug)]
pub enum WriteType {
    /// The write was a non-batched non-counter write
    Simple,
    /// The write was a (logged) batch write.
    /// If this type is received, it means the batch log
    /// has been successfully written
    Batch,
    /// The write was an unlogged batch. No batch log write has been attempted.
    UnloggedBatch,
    /// The write was a counter write (batched or not)
    Counter,
    /// The failure occured during the write to the batch log when a (logged) batch
    /// write was requested.
    BatchLog,
}

impl FromCursor for WriteType {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<WriteType> {
        CString::from_cursor(&mut cursor).map(|wt| match wt.as_str() {
                                                  "SIMPLE" => WriteType::Simple,
                                                  "BATCH" => WriteType::Batch,
                                                  "UNLOGGED_BATCH" => WriteType::UnloggedBatch,
                                                  "COUNTER" => WriteType::Counter,
                                                  "BATCH_LOG" => WriteType::BatchLog,
                                                  // TODO: return error instead of panic
                                                  _ => unreachable!(),
                                              })
    }
}

/// The query attempted to create a keyspace or a table that was already existing.
/// [Read more...](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1140)
#[derive(Debug)]
pub struct AlreadyExistsError {
    /// Represents either the keyspace that already exists,
    /// or the keyspace in which the table that already exists is.
    pub ks: CString,
    /// Represents the name of the table that already exists.
    pub table: CString,
}

impl FromCursor for AlreadyExistsError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<AlreadyExistsError> {
        let ks = CString::from_cursor(&mut cursor)?;
        let table = CString::from_cursor(&mut cursor)?;

        Ok(AlreadyExistsError {
               ks: ks,
               table: table,
           })
    }
}

/// Can be thrown while a prepared statement tries to be
/// executed if the provided prepared statement ID is not known by
/// this host. [Read more...]
/// (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1150)
#[derive(Debug)]
pub struct UnpreparedError {
    /// Unknown ID.
    pub id: CBytes,
}

impl FromCursor for UnpreparedError {
    fn from_cursor(mut cursor: &mut io::Cursor<&[u8]>) -> error::Result<UnpreparedError> {
        let id = CBytes::from_cursor(&mut cursor)?;

        Ok(UnpreparedError { id: id })
    }
}
<|endoftext|>


<commit_before>use std;
use std::io::Read;
use std::time::Duration;
use std::collections::HashSet;
use std::net::Ipv4Addr;
use std::net::SocketAddr;
use std::net::UdpSocket;
use std::str;

use rustc_serialize::json;
use hyper::Client;

/// Returns a HashSet of hue bridge SocketAddr's
pub fn discover() -> HashSet<SocketAddr> {

    let string_list = vec![
        "M-SEARCH * HTTP/1.1",
        "HOST:239.255.255.250:1900",
        "MAN:\"ssdp:discover\"",
        "ST:ssdp:all",
        "MX:1"
            ];
    let joined = string_list.join("\r\n");

    let socket =
        UdpSocket::bind("0.0.0.0:0").unwrap();

    let five_second_timeout = Duration::new(5, 0);
    let _ = socket.set_read_timeout(Some(five_second_timeout));
    socket.send_to(joined.as_bytes(), "239.255.255.250:1900").unwrap();

    let mut bridges = HashSet::new();
    loop {
        let mut buf = [0;255];
        let sockread = match socket.recv_from(&mut buf) {
            Ok(val) => val,
            Err(e) => {
                match e.kind() {
                    // a timeout on unix is considered a WouldBlock
                    std::io::ErrorKind::WouldBlock => break,
                    _ => panic!(e),
                }
            }
        };
        let _ = str::from_utf8(&buf).and_then(|s| {
            // Hue docs say to use "IpBridge" over "hue-bridgeid"
            if s.contains("IpBridge") {
                let bridge = sockread.1;
                bridges.insert(bridge);
            }
            Ok(s)
        });
    }

    bridges
}

/// Hue Bridge
#[derive(Debug)]
pub struct Bridge {
    ip: Ipv4Addr,
}

impl Bridge {
    /// Returns a hue bridge with the given ip
    pub fn new(addr: Ipv4Addr) -> Bridge {
        Bridge {
            ip: addr,
        }
    }

    /// Attempt to register with the hue bridge
    pub fn register(&self, name: &str) {
        #[derive(RustcEncodable, RustcDecodable)]
        struct Devicetype {
            devicetype: String,
        }

        let client = Client::new();
        let url = format!("http://{}/api", self.ip);
        let payload = Devicetype { devicetype: name.to_owned() };
        let body = json::encode(&payload).unwrap();

        // TODO handle errors and return username
        let mut response = client.post(&url).body(&body).send().unwrap();
        let mut buf = String::new();
        response.read_to_string(&mut buf).unwrap();
        println!("{}", buf);
    }
}
<commit_msg>Bridge discover should return IpAddr<commit_after>use std;
use std::io::Read;
use std::time::Duration;
use std::collections::HashSet;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::UdpSocket;
use std::str;

use rustc_serialize::json;
use hyper::Client;

/// Returns a HashSet of hue bridge SocketAddr's
pub fn discover() -> HashSet<IpAddr> {

    let string_list = vec![
        "M-SEARCH * HTTP/1.1",
        "HOST:239.255.255.250:1900",
        "MAN:\"ssdp:discover\"",
        "ST:ssdp:all",
        "MX:1"
            ];
    let joined = string_list.join("\r\n");

    let socket =
        UdpSocket::bind("0.0.0.0:0").unwrap();

    let five_second_timeout = Duration::new(5, 0);
    let _ = socket.set_read_timeout(Some(five_second_timeout));
    socket.send_to(joined.as_bytes(), "239.255.255.250:1900").unwrap();

    let mut bridges = HashSet::new();
    loop {
        let mut buf = [0;255];
        let sockread = match socket.recv_from(&mut buf) {
            Ok(val) => val,
            Err(e) => {
                match e.kind() {
                    // a timeout on unix is considered a WouldBlock
                    std::io::ErrorKind::WouldBlock => break,
                    _ => panic!(e),
                }
            }
        };
        let _ = str::from_utf8(&buf).and_then(|s| {
            // Hue docs say to use "IpBridge" over "hue-bridgeid"
            if s.contains("IpBridge") {
                let bridge = sockread.1.ip();
                bridges.insert(bridge);
            }
            Ok(s)
        });
    }

    bridges
}

/// Hue Bridge
#[derive(Debug)]
pub struct Bridge {
    ip: Ipv4Addr,
}

impl Bridge {
    /// Returns a hue bridge with the given ip
    pub fn new(addr: Ipv4Addr) -> Bridge {
        Bridge {
            ip: addr,
        }
    }

    /// Attempt to register with the hue bridge
    pub fn register(&self, name: &str) {
        #[derive(RustcEncodable, RustcDecodable)]
        struct Devicetype {
            devicetype: String,
        }

        let client = Client::new();
        let url = format!("http://{}/api", self.ip);
        let payload = Devicetype { devicetype: name.to_owned() };
        let body = json::encode(&payload).unwrap();

        // TODO handle errors and return username
        let mut response = client.post(&url).body(&body).send().unwrap();
        let mut buf = String::new();
        response.read_to_string(&mut buf).unwrap();
        println!("{}", buf);
    }
}
<|endoftext|>