<commit_before>//! Gaussian Mixture Models
//!
//! Provides implementation of GMMs using the EM algorithm.
//!
//! # Usage
//!
//! ```
//! use rusty_machine::linalg::Matrix;
//! use rusty_machine::learning::gmm::{CovOption, GaussianMixtureModel};
//! use rusty_machine::learning::UnSupModel;
//!
//! let inputs = Matrix::new(4, 2, vec![1.0, 2.0, -3.0, -3.0, 0.1, 1.5, -5.0, -2.5]);
//! let test_inputs = Matrix::new(3, 2, vec![1.0, 2.0, 3.0, 2.9, -4.4, -2.5]);
//!
//! // Create gmm with k(=2) classes.
//! let mut model = GaussianMixtureModel::new(2);
//! model.set_max_iters(10);
//! model.cov_option = CovOption::Diagonal;
//!
//! // Where inputs is a Matrix with features in columns.
//! model.train(&inputs).unwrap();
//!
//! // Print the means and covariances of the GMM
//! println!("{:?}", model.means());
//! println!("{:?}", model.covariances());
//!
//! // Where test_inputs is a Matrix with features in columns.
//! let post_probs = model.predict(&test_inputs).unwrap();
//!
//! // Probabilities that each point comes from each Gaussian.
//! println!("{:?}", post_probs.data());
//! ```

use linalg::{Matrix, MatrixSlice, Vector, BaseMatrix, BaseMatrixMut, Axes};
use rulinalg::utils;

use learning::{LearningResult, UnSupModel};
use learning::toolkit::rand_utils;
use learning::error::{Error, ErrorKind};

/// Covariance options for GMMs.
///
/// - Full : The full covariance structure.
/// - Regularized : Adds a regularization constant to the covariance diagonal.
/// - Diagonal : Only the diagonal covariance structure.
#[derive(Clone, Copy, Debug)]
pub enum CovOption {
    /// The full covariance structure.
    Full,
    /// Adds a regularization constant to the covariance diagonal.
    Regularized(f64),
    /// Only the diagonal covariance structure.
    Diagonal,
}

/// A Gaussian Mixture Model
#[derive(Debug)]
pub struct GaussianMixtureModel {
    comp_count: usize,
    mix_weights: Vector<f64>,
    model_means: Option<Matrix<f64>>,
    model_covars: Option<Vec<Matrix<f64>>>,
    log_lik: f64,
    max_iters: usize,
    /// The covariance options for the GMM.
    pub cov_option: CovOption,
}

impl UnSupModel<Matrix<f64>, Matrix<f64>> for GaussianMixtureModel {
    /// Train the model using inputs.
    fn train(&mut self, inputs: &Matrix<f64>) -> LearningResult<()> {
        let reg_value = if inputs.rows() > 1 {
            1f64 / (inputs.rows() - 1) as f64
        } else {
            return Err(Error::new(ErrorKind::InvalidData, "Only one row of data provided."));
        };

        // Initialization:
        let k = self.comp_count;

        let cov_mat = match self.cov_option {
            CovOption::Diagonal => {
                let variance = try!(inputs.variance(Axes::Row));
                Matrix::from_diag(&variance.data()) * reg_value.sqrt()
            }

            CovOption::Full | CovOption::Regularized(_) => {
                let means = inputs.mean(Axes::Row);
                let mut cov_mat = Matrix::zeros(inputs.cols(), inputs.cols());
                for (j, row) in cov_mat.iter_rows_mut().enumerate() {
                    for (k, elem) in row.iter_mut().enumerate() {
                        *elem = inputs.iter_rows().map(|r| {
                            (r[j] - means[j]) * (r[k] - means[k])
                        }).sum::<f64>();
                    }
                }
                cov_mat *= reg_value;

                if let CovOption::Regularized(eps) = self.cov_option {
                    cov_mat += Matrix::<f64>::identity(cov_mat.cols()) * eps;
                }

                cov_mat
            }
        };

        self.model_covars = Some(vec![cov_mat; k]);

        let random_rows: Vec<usize> =
            rand_utils::reservoir_sample(&(0..inputs.rows()).collect::<Vec<usize>>(), k);
        self.model_means = Some(inputs.select_rows(&random_rows));

        for _ in 0..self.max_iters {
            let log_lik_0 = self.log_lik;

            let (weights, log_lik_1) = self.membership_weights(inputs);

            if (log_lik_1 - log_lik_0).abs() < 1e-15 {
                break;
            }

            self.log_lik = log_lik_1;

            self.update_params(inputs, weights);
        }

        Ok(())
    }

    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> LearningResult<Matrix<f64>> {
        if let (&Some(_), &Some(_)) = (&self.model_means, &self.model_covars) {
            Ok(self.membership_weights(inputs).0)
        } else {
            Err(Error::new_untrained())
        }

    }
}

impl GaussianMixtureModel {
    /// Constructs a new Gaussian Mixture Model
    ///
    /// Defaults to 100 maximum iterations and
    /// full covariance structure.
    ///
    /// # Examples
    /// ```
    /// use rusty_machine::learning::gmm::GaussianMixtureModel;
    ///
    /// let gmm = GaussianMixtureModel::new(3);
    /// ```
    pub fn new(k: usize) -> GaussianMixtureModel {
        GaussianMixtureModel {
            comp_count: k,
            mix_weights: Vector::ones(k) / (k as f64),
            model_means: None,
            model_covars: None,
            log_lik: 0f64,
            max_iters: 100,
            cov_option: CovOption::Full,
        }
    }

    /// Constructs a new GMM with the specified prior mixture weights.
    ///
    /// The mixture weights must have the same length as the number of components.
    /// Each element of the mixture weights must be non-negative.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::gmm::GaussianMixtureModel;
    /// use rusty_machine::linalg::Vector;
    ///
    /// let mix_weights = Vector::new(vec![0.25, 0.25, 0.5]);
    ///
    /// let gmm = GaussianMixtureModel::with_weights(3, mix_weights).unwrap();
    /// ```
    ///
    /// # Failures
    ///
    /// Fails if either of the following conditions are met:
    ///
    /// - Mixture weights do not have length k.
    /// - Mixture weights have a negative entry.
    pub fn with_weights(k: usize, mixture_weights: Vector<f64>) -> LearningResult<GaussianMixtureModel> {
        if mixture_weights.size() != k {
            Err(Error::new(ErrorKind::InvalidParameters, "Mixture weights must have length k."))
        } else if mixture_weights.data().iter().any(|&x| x < 0f64) {
            Err(Error::new(ErrorKind::InvalidParameters, "Mixture weights must have only non-negative entries."))
        } else {
            let sum = mixture_weights.sum();
            let normalized_weights = mixture_weights / sum;

            Ok(GaussianMixtureModel {
                comp_count: k,
                mix_weights: normalized_weights,
                model_means: None,
                model_covars: None,
                log_lik: 0f64,
                max_iters: 100,
                cov_option: CovOption::Full,
            })
        }
    }

    /// The model means
    ///
    /// Returns an Option<&Matrix<f64>> containing
    /// the model means. Each row represents
    /// the mean of one of the Gaussians.
    pub fn means(&self) -> Option<&Matrix<f64>> {
        self.model_means.as_ref()
    }

    /// The model covariances
    ///
    /// Returns an Option<&Vec<Matrix<f64>>> containing
    /// the model covariances. Each Matrix in the vector
    /// is the covariance of one of the Gaussians.
    pub fn covariances(&self) -> Option<&Vec<Matrix<f64>>> {
        self.model_covars.as_ref()
    }

    /// The model mixture weights
    ///
    /// Returns a reference to the model mixture weights.
    /// These are the weighted contributions of each underlying
    /// Gaussian to the model distribution.
    pub fn mixture_weights(&self) -> &Vector<f64> {
        &self.mix_weights
    }

    /// Sets the max number of iterations for the EM algorithm.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::gmm::GaussianMixtureModel;
    ///
    /// let mut gmm = GaussianMixtureModel::new(2);
    /// gmm.set_max_iters(5);
    /// ```
    pub fn set_max_iters(&mut self, iters: usize) {
        self.max_iters = iters;
    }

    fn membership_weights(&self, inputs: &Matrix<f64>) -> (Matrix<f64>, f64) {
        let n = inputs.rows();

        let mut member_weights_data = Vec::with_capacity(n * self.comp_count);

        // We compute the determinants and inverses now
        let mut cov_sqrt_dets = Vec::with_capacity(self.comp_count);
        let mut cov_invs = Vec::with_capacity(self.comp_count);

        if let Some(ref covars) = self.model_covars {
            for cov in covars {
                // TODO: combine these. We compute det to get the inverse.
                let covar_det = cov.det();
                let covar_inv = cov.inverse().expect("Could not compute inverse of covariance.");

                cov_sqrt_dets.push(covar_det.sqrt());
                cov_invs.push(covar_inv);
            }
        }

        let mut log_lik = 0f64;

        // Now we compute the membership weights
        if let Some(ref means) = self.model_means {
            for i in 0..n {
                let mut pdfs = Vec::with_capacity(self.comp_count);
                let x_i = MatrixSlice::from_matrix(inputs, [i, 0], 1, inputs.cols());

                for j in 0..self.comp_count {
                    let mu_j = MatrixSlice::from_matrix(means, [j, 0], 1, means.cols());
                    let diff = x_i - mu_j;

                    let pdf = (&diff * &cov_invs[j] * diff.transpose() * -0.5).into_vec()[0]
                        .exp() / cov_sqrt_dets[j];
                    pdfs.push(pdf);
                }

                let weighted_pdf_sum = utils::dot(&pdfs, self.mix_weights.data());

                for (idx, pdf) in pdfs.iter().enumerate() {
                    member_weights_data.push(self.mix_weights[idx] * pdf / (weighted_pdf_sum));
                }

                log_lik += weighted_pdf_sum.ln();
            }
        }

        (Matrix::new(n, self.comp_count, member_weights_data), log_lik)
    }

    fn update_params(&mut self, inputs: &Matrix<f64>, membership_weights: Matrix<f64>) {
        let n = membership_weights.rows();
        let d = inputs.cols();

        let sum_weights = membership_weights.sum_rows();

        self.mix_weights = &sum_weights / (n as f64);

        let mut new_means = membership_weights.transpose() * inputs;

        for (mean, w) in new_means.iter_rows_mut().zip(sum_weights.data().iter()) {
            for m in mean.iter_mut() {
                *m /= *w;
            }
        }

        let mut new_covs = Vec::with_capacity(self.comp_count);

        for k in 0..self.comp_count {
            let mut cov_mat = Matrix::zeros(d, d);
            let new_means_k = MatrixSlice::from_matrix(&new_means, [k, 0], 1, d);

            for i in 0..n {
                let inputs_i = MatrixSlice::from_matrix(inputs, [i, 0], 1, d);
                let diff = inputs_i - new_means_k;
                cov_mat += self.compute_cov(diff, membership_weights[[i, k]]);
            }
            new_covs.push(cov_mat / sum_weights[k]);

        }

        self.model_means = Some(new_means);
        self.model_covars = Some(new_covs);
    }

    fn compute_cov(&self, diff: Matrix<f64>, weight: f64) -> Matrix<f64> {
        match self.cov_option {
            CovOption::Full => (diff.transpose() * diff) * weight,
            CovOption::Regularized(eps) => (diff.transpose() * diff) * weight + eps,
            CovOption::Diagonal => Matrix::from_diag(&diff.elemul(&diff).into_vec()) * weight,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::GaussianMixtureModel;
    use linalg::Vector;

    #[test]
    fn test_means_none() {
        let model = GaussianMixtureModel::new(5);

        assert_eq!(model.means(), None);
    }

    #[test]
    fn test_covars_none() {
        let model = GaussianMixtureModel::new(5);

        assert_eq!(model.covariances(), None);
    }

    #[test]
    fn test_negative_mixtures() {
        let mix_weights = Vector::new(vec![-0.25, 0.75, 0.5]);
        let gmm_res = GaussianMixtureModel::with_weights(3, mix_weights);
        assert!(gmm_res.is_err());
    }

    #[test]
    fn test_wrong_length_mixtures() {
        let mix_weights = Vector::new(vec![0.1, 0.25, 0.75, 0.5]);
        let gmm_res = GaussianMixtureModel::with_weights(3, mix_weights);
        assert!(gmm_res.is_err());
    }
}
<commit_msg>`LearningResult` as return type of `membership_weights` in GMM (#149)<commit_after>//! Gaussian Mixture Models
//!
//! Provides implementation of GMMs using the EM algorithm.
//!
//! # Usage
//!
//! ```
//! use rusty_machine::linalg::Matrix;
//! use rusty_machine::learning::gmm::{CovOption, GaussianMixtureModel};
//! use rusty_machine::learning::UnSupModel;
//!
//! let inputs = Matrix::new(4, 2, vec![1.0, 2.0, -3.0, -3.0, 0.1, 1.5, -5.0, -2.5]);
//! let test_inputs = Matrix::new(3, 2, vec![1.0, 2.0, 3.0, 2.9, -4.4, -2.5]);
//!
//! // Create gmm with k(=2) classes.
//! let mut model = GaussianMixtureModel::new(2);
//! model.set_max_iters(10);
//! model.cov_option = CovOption::Diagonal;
//!
//! // Where inputs is a Matrix with features in columns.
//! model.train(&inputs).unwrap();
//!
//! // Print the means and covariances of the GMM
//! println!("{:?}", model.means());
//! println!("{:?}", model.covariances());
//!
//! // Where test_inputs is a Matrix with features in columns.
//! let post_probs = model.predict(&test_inputs).unwrap();
//!
//! // Probabilities that each point comes from each Gaussian.
//! println!("{:?}", post_probs.data());
//! ```
use linalg::{Matrix, MatrixSlice, Vector, BaseMatrix, BaseMatrixMut, Axes};
use rulinalg::utils;

use learning::{LearningResult, UnSupModel};
use learning::toolkit::rand_utils;
use learning::error::{Error, ErrorKind};

/// Covariance options for GMMs.
///
/// - Full : The full covariance structure.
/// - Regularized : Adds a regularization constant to the covariance diagonal.
/// - Diagonal : Only the diagonal covariance structure.
#[derive(Clone, Copy, Debug)]
pub enum CovOption {
    /// The full covariance structure.
    Full,
    /// Adds a regularization constant to the covariance diagonal.
    Regularized(f64),
    /// Only the diagonal covariance structure.
    Diagonal,
}

/// A Gaussian Mixture Model
#[derive(Debug)]
pub struct GaussianMixtureModel {
    comp_count: usize,
    mix_weights: Vector<f64>,
    model_means: Option<Matrix<f64>>,
    model_covars: Option<Vec<Matrix<f64>>>,
    log_lik: f64,
    max_iters: usize,
    /// The covariance options for the GMM.
    pub cov_option: CovOption,
}

impl UnSupModel<Matrix<f64>, Matrix<f64>> for GaussianMixtureModel {
    /// Train the model using inputs.
    fn train(&mut self, inputs: &Matrix<f64>) -> LearningResult<()> {
        let reg_value = if inputs.rows() > 1 {
            1f64 / (inputs.rows() - 1) as f64
        } else {
            return Err(Error::new(ErrorKind::InvalidData, "Only one row of data provided."));
        };

        // Initialization:
        let k = self.comp_count;

        let cov_mat = match self.cov_option {
            CovOption::Diagonal => {
                let variance = try!(inputs.variance(Axes::Row));
                Matrix::from_diag(&variance.data()) * reg_value.sqrt()
            }

            CovOption::Full | CovOption::Regularized(_) => {
                let means = inputs.mean(Axes::Row);
                let mut cov_mat = Matrix::zeros(inputs.cols(), inputs.cols());
                for (j, row) in cov_mat.iter_rows_mut().enumerate() {
                    for (k, elem) in row.iter_mut().enumerate() {
                        *elem = inputs.iter_rows().map(|r| {
                            (r[j] - means[j]) * (r[k] - means[k])
                        }).sum::<f64>();
                    }
                }
                cov_mat *= reg_value;

                if let CovOption::Regularized(eps) = self.cov_option {
                    cov_mat += Matrix::<f64>::identity(cov_mat.cols()) * eps;
                }

                cov_mat
            }
        };

        self.model_covars = Some(vec![cov_mat; k]);

        let random_rows: Vec<usize> =
            rand_utils::reservoir_sample(&(0..inputs.rows()).collect::<Vec<usize>>(), k);
        self.model_means = Some(inputs.select_rows(&random_rows));

        for _ in 0..self.max_iters {
            let log_lik_0 = self.log_lik;

            let (weights, log_lik_1) = try!(self.membership_weights(inputs));

            if (log_lik_1 - log_lik_0).abs() < 1e-15 {
                break;
            }

            self.log_lik = log_lik_1;

            self.update_params(inputs, weights);
        }

        Ok(())
    }

    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> LearningResult<Matrix<f64>> {
        if let (&Some(_), &Some(_)) = (&self.model_means, &self.model_covars) {
            Ok(try!(self.membership_weights(inputs)).0)
        } else {
            Err(Error::new_untrained())
        }

    }
}

impl GaussianMixtureModel {
    /// Constructs a new Gaussian Mixture Model
    ///
    /// Defaults to 100 maximum iterations and
    /// full covariance structure.
    ///
    /// # Examples
    /// ```
    /// use rusty_machine::learning::gmm::GaussianMixtureModel;
    ///
    /// let gmm = GaussianMixtureModel::new(3);
    /// ```
    pub fn new(k: usize) -> GaussianMixtureModel {
        GaussianMixtureModel {
            comp_count: k,
            mix_weights: Vector::ones(k) / (k as f64),
            model_means: None,
            model_covars: None,
            log_lik: 0f64,
            max_iters: 100,
            cov_option: CovOption::Full,
        }
    }

    /// Constructs a new GMM with the specified prior mixture weights.
    ///
    /// The mixture weights must have the same length as the number of components.
    /// Each element of the mixture weights must be non-negative.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::gmm::GaussianMixtureModel;
    /// use rusty_machine::linalg::Vector;
    ///
    /// let mix_weights = Vector::new(vec![0.25, 0.25, 0.5]);
    ///
    /// let gmm = GaussianMixtureModel::with_weights(3, mix_weights).unwrap();
    /// ```
    ///
    /// # Failures
    ///
    /// Fails if either of the following conditions are met:
    ///
    /// - Mixture weights do not have length k.
    /// - Mixture weights have a negative entry.
    pub fn with_weights(k: usize, mixture_weights: Vector<f64>) -> LearningResult<GaussianMixtureModel> {
        if mixture_weights.size() != k {
            Err(Error::new(ErrorKind::InvalidParameters, "Mixture weights must have length k."))
        } else if mixture_weights.data().iter().any(|&x| x < 0f64) {
            Err(Error::new(ErrorKind::InvalidParameters, "Mixture weights must have only non-negative entries."))
        } else {
            let sum = mixture_weights.sum();
            let normalized_weights = mixture_weights / sum;

            Ok(GaussianMixtureModel {
                comp_count: k,
                mix_weights: normalized_weights,
                model_means: None,
                model_covars: None,
                log_lik: 0f64,
                max_iters: 100,
                cov_option: CovOption::Full,
            })
        }
    }

    /// The model means
    ///
    /// Returns an Option<&Matrix<f64>> containing
    /// the model means. Each row represents
    /// the mean of one of the Gaussians.
    pub fn means(&self) -> Option<&Matrix<f64>> {
        self.model_means.as_ref()
    }

    /// The model covariances
    ///
    /// Returns an Option<&Vec<Matrix<f64>>> containing
    /// the model covariances. Each Matrix in the vector
    /// is the covariance of one of the Gaussians.
    pub fn covariances(&self) -> Option<&Vec<Matrix<f64>>> {
        self.model_covars.as_ref()
    }

    /// The model mixture weights
    ///
    /// Returns a reference to the model mixture weights.
    /// These are the weighted contributions of each underlying
    /// Gaussian to the model distribution.
    pub fn mixture_weights(&self) -> &Vector<f64> {
        &self.mix_weights
    }

    /// Sets the max number of iterations for the EM algorithm.
    ///
    /// # Examples
    ///
    /// ```
    /// use rusty_machine::learning::gmm::GaussianMixtureModel;
    ///
    /// let mut gmm = GaussianMixtureModel::new(2);
    /// gmm.set_max_iters(5);
    /// ```
    pub fn set_max_iters(&mut self, iters: usize) {
        self.max_iters = iters;
    }

    fn membership_weights(&self, inputs: &Matrix<f64>) -> LearningResult<(Matrix<f64>, f64)> {
        let n = inputs.rows();

        let mut member_weights_data = Vec::with_capacity(n * self.comp_count);

        // We compute the determinants and inverses now
        let mut cov_sqrt_dets = Vec::with_capacity(self.comp_count);
        let mut cov_invs = Vec::with_capacity(self.comp_count);

        if let Some(ref covars) = self.model_covars {
            for cov in covars {
                // TODO: combine these. We compute det to get the inverse.
                let covar_det = cov.det();
                let covar_inv = try!(cov.inverse().map_err(Error::from));

                cov_sqrt_dets.push(covar_det.sqrt());
                cov_invs.push(covar_inv);
            }
        }

        let mut log_lik = 0f64;

        // Now we compute the membership weights
        if let Some(ref means) = self.model_means {
            for i in 0..n {
                let mut pdfs = Vec::with_capacity(self.comp_count);
                let x_i = MatrixSlice::from_matrix(inputs, [i, 0], 1, inputs.cols());

                for j in 0..self.comp_count {
                    let mu_j = MatrixSlice::from_matrix(means, [j, 0], 1, means.cols());
                    let diff = x_i - mu_j;

                    let pdf = (&diff * &cov_invs[j] * diff.transpose() * -0.5).into_vec()[0]
                        .exp() / cov_sqrt_dets[j];
                    pdfs.push(pdf);
                }

                let weighted_pdf_sum = utils::dot(&pdfs, self.mix_weights.data());

                for (idx, pdf) in pdfs.iter().enumerate() {
                    member_weights_data.push(self.mix_weights[idx] * pdf / (weighted_pdf_sum));
                }

                log_lik += weighted_pdf_sum.ln();
            }
        }

        Ok((Matrix::new(n, self.comp_count, member_weights_data), log_lik))
    }

    fn update_params(&mut self, inputs: &Matrix<f64>, membership_weights: Matrix<f64>) {
        let n = membership_weights.rows();
        let d = inputs.cols();

        let sum_weights = membership_weights.sum_rows();

        self.mix_weights = &sum_weights / (n as f64);

        let mut new_means = membership_weights.transpose() * inputs;

        for (mean, w) in new_means.iter_rows_mut().zip(sum_weights.data().iter()) {
            for m in mean.iter_mut() {
                *m /= *w;
            }
        }

        let mut new_covs = Vec::with_capacity(self.comp_count);

        for k in 0..self.comp_count {
            let mut cov_mat = Matrix::zeros(d, d);
            let new_means_k = MatrixSlice::from_matrix(&new_means, [k, 0], 1, d);

            for i in 0..n {
                let inputs_i = MatrixSlice::from_matrix(inputs, [i, 0], 1, d);
                let diff = inputs_i - new_means_k;
                cov_mat += self.compute_cov(diff, membership_weights[[i, k]]);
            }
            new_covs.push(cov_mat / sum_weights[k]);

        }

        self.model_means = Some(new_means);
        self.model_covars = Some(new_covs);
    }

    fn compute_cov(&self, diff: Matrix<f64>, weight: f64) -> Matrix<f64> {
        match self.cov_option {
            CovOption::Full => (diff.transpose() * diff) * weight,
            CovOption::Regularized(eps) => (diff.transpose() * diff) * weight + eps,
            CovOption::Diagonal => Matrix::from_diag(&diff.elemul(&diff).into_vec()) * weight,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::GaussianMixtureModel;
    use linalg::Vector;

    #[test]
    fn test_means_none() {
        let model = GaussianMixtureModel::new(5);

        assert_eq!(model.means(), None);
    }

    #[test]
    fn test_covars_none() {
        let model = GaussianMixtureModel::new(5);

        assert_eq!(model.covariances(), None);
    }

    #[test]
    fn test_negative_mixtures() {
        let mix_weights = Vector::new(vec![-0.25, 0.75, 0.5]);
        let gmm_res = GaussianMixtureModel::with_weights(3, mix_weights);
        assert!(gmm_res.is_err());
    }

    #[test]
    fn test_wrong_length_mixtures() {
        let mix_weights = Vector::new(vec![0.1, 0.25, 0.75, 0.5]);
        let gmm_res = GaussianMixtureModel::with_weights(3, mix_weights);
        assert!(gmm_res.is_err());
    }
}
<|endoftext|>


<commit_before>use crate::analysis::symbols;
use once_cell::sync::Lazy;
use regex::{Captures, Regex};

const LANGUAGE_SEP_BEGIN: &str = "<!-- language=\"";
const LANGUAGE_SEP_END: &str = "\" -->";
const LANGUAGE_BLOCK_BEGIN: &str = "|[";
const LANGUAGE_BLOCK_END: &str = "\n]|";

pub fn reformat_doc(input: &str, symbols: &symbols::Info, in_type: &str) -> String {
    code_blocks_transformation(input, symbols, in_type)
}

fn try_split<'a>(src: &'a str, needle: &str) -> (&'a str, Option<&'a str>) {
    match src.find(needle) {
        Some(pos) => (&src[..pos], Some(&src[pos + needle.len()..])),
        None => (src, None),
    }
}

fn code_blocks_transformation(mut input: &str, symbols: &symbols::Info, in_type: &str) -> String {
    let mut out = String::with_capacity(input.len());

    loop {
        input = match try_split(input, LANGUAGE_BLOCK_BEGIN) {
            (before, Some(after)) => {
                out.push_str(&format(before, symbols, in_type));
                if let (before, Some(after)) =
                    try_split(get_language(after, &mut out), LANGUAGE_BLOCK_END)
                {
                    out.push_str(before);
                    out.push_str("\n```");
                    after
                } else {
                    after
                }
            }
            (before, None) => {
                out.push_str(&format(before, symbols, in_type));
                return out;
            }
        };
    }
}

fn get_language<'a>(entry: &'a str, out: &mut String) -> &'a str {
    if let (_, Some(after)) = try_split(entry, LANGUAGE_SEP_BEGIN) {
        if let (before, Some(after)) = try_split(after, LANGUAGE_SEP_END) {
            out.push_str(&format!("\n```{}", before));
            return after;
        }
    }
    out.push_str("\n```text");
    entry
}

fn format(mut input: &str, symbols: &symbols::Info, in_type: &str) -> String {
    let mut ret = String::with_capacity(input.len());
    loop {
        let (before, after) = try_split(input, "`");
        ret.push_str(&replace_c_types(before, symbols, in_type));
        if let Some(after) = after {
            ret.push('`');
            let (before, after) = try_split(after, "`");
            // don't touch anything enclosed in backticks
            ret.push_str(before);
            if let Some(after) = after {
                ret.push('`');
                input = after;
            } else {
                return ret;
            }
        } else {
            return ret;
        }
    }
}

static SYMBOL: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(^|[^\\])([@#%])(\w+\b)([:.]+[\w-]+\b)?").unwrap());
static FUNCTION: Lazy<Regex> = Lazy::new(|| Regex::new(r"(\b[a-z0-9_]+)\(\)").unwrap());
static GDK_GTK: Lazy<Regex> = Lazy::new(|| Regex::new(r"G[dt]k[A-Z]\w+\b").unwrap());
static TAGS: Lazy<Regex> = Lazy::new(|| Regex::new(r"<[\w/-]+>").unwrap());
static SPACES: Lazy<Regex> = Lazy::new(|| Regex::new(r"[ ]{2,}").unwrap());

fn replace_c_types(entry: &str, symbols: &symbols::Info, in_type: &str) -> String {
    let lookup = |s: &str| -> String {
        symbols
            .by_c_name(s)
            .map(symbols::Symbol::full_rust_name)
            .unwrap_or_else(|| s.into())
    };

    let out = SYMBOL.replace_all(entry, |caps: &Captures<'_>| {
        let member = caps.get(4).map(|m| m.as_str()).unwrap_or("");
        let sym = symbols.by_c_name(&caps[3]);
        match &caps[2] {
            /* References to members, enum variants or methods within the same type. */
            "@" => {
                if let Some(sym) = sym {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    if sym.owner_name() != Some(in_type) {
                        format!(
                            "{}[`crate::{}{}`] (XXX: @-reference does not belong to {}!)",
                            &caps[1],
                            sym.full_rust_name(),
                            member,
                            in_type,
                        )
                    } else {
                        format!(
                            "{}[`{n}{m}`](Self::{n}{m})",
                            &caps[1],
                            n = sym.name(),
                            m = member
                        )
                    }
                } else {
                    format!("{}`{}{}`", &caps[1], &caps[3], member)
                }
            }
            "#" | "%" => {
                format!(
                    "{}`{}{}`",
                    &caps[1],
                    sym.map(symbols::Symbol::full_rust_name)
                        .unwrap_or_else(|| caps[3].into()),
                    member
                )
            }
            u => panic!("Unknown reference type {}", u),
        }
    });
    let out = GDK_GTK.replace_all(&out, |caps: &Captures<'_>| {
        format!("`{}`", lookup(&caps[0]))
    });
    let out = FUNCTION.replace_all(&out, |caps: &Captures<'_>| {
        format!("`{}`", lookup(&caps[1]))
    });
    let out = TAGS.replace_all(&out, "`$0`");
    SPACES.replace_all(&out, " ").into_owned()
}
<commit_msg>codegen/doc: Add `()` to function symbols<commit_after>use crate::analysis::symbols;
use once_cell::sync::Lazy;
use regex::{Captures, Regex};

const LANGUAGE_SEP_BEGIN: &str = "<!-- language=\"";
const LANGUAGE_SEP_END: &str = "\" -->";
const LANGUAGE_BLOCK_BEGIN: &str = "|[";
const LANGUAGE_BLOCK_END: &str = "\n]|";

pub fn reformat_doc(input: &str, symbols: &symbols::Info, in_type: &str) -> String {
    code_blocks_transformation(input, symbols, in_type)
}

fn try_split<'a>(src: &'a str, needle: &str) -> (&'a str, Option<&'a str>) {
    match src.find(needle) {
        Some(pos) => (&src[..pos], Some(&src[pos + needle.len()..])),
        None => (src, None),
    }
}

fn code_blocks_transformation(mut input: &str, symbols: &symbols::Info, in_type: &str) -> String {
    let mut out = String::with_capacity(input.len());

    loop {
        input = match try_split(input, LANGUAGE_BLOCK_BEGIN) {
            (before, Some(after)) => {
                out.push_str(&format(before, symbols, in_type));
                if let (before, Some(after)) =
                    try_split(get_language(after, &mut out), LANGUAGE_BLOCK_END)
                {
                    out.push_str(before);
                    out.push_str("\n```");
                    after
                } else {
                    after
                }
            }
            (before, None) => {
                out.push_str(&format(before, symbols, in_type));
                return out;
            }
        };
    }
}

fn get_language<'a>(entry: &'a str, out: &mut String) -> &'a str {
    if let (_, Some(after)) = try_split(entry, LANGUAGE_SEP_BEGIN) {
        if let (before, Some(after)) = try_split(after, LANGUAGE_SEP_END) {
            out.push_str(&format!("\n```{}", before));
            return after;
        }
    }
    out.push_str("\n```text");
    entry
}

fn format(mut input: &str, symbols: &symbols::Info, in_type: &str) -> String {
    let mut ret = String::with_capacity(input.len());
    loop {
        let (before, after) = try_split(input, "`");
        ret.push_str(&replace_c_types(before, symbols, in_type));
        if let Some(after) = after {
            ret.push('`');
            let (before, after) = try_split(after, "`");
            // don't touch anything enclosed in backticks
            ret.push_str(before);
            if let Some(after) = after {
                ret.push('`');
                input = after;
            } else {
                return ret;
            }
        } else {
            return ret;
        }
    }
}

static SYMBOL: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(^|[^\\])([@#%])(\w+\b)([:.]+[\w-]+\b)?").unwrap());
static FUNCTION: Lazy<Regex> = Lazy::new(|| Regex::new(r"(\b[a-z0-9_]+)\(\)").unwrap());
static GDK_GTK: Lazy<Regex> = Lazy::new(|| Regex::new(r"G[dt]k[A-Z]\w+\b").unwrap());
static TAGS: Lazy<Regex> = Lazy::new(|| Regex::new(r"<[\w/-]+>").unwrap());
static SPACES: Lazy<Regex> = Lazy::new(|| Regex::new(r"[ ]{2,}").unwrap());

fn replace_c_types(entry: &str, symbols: &symbols::Info, in_type: &str) -> String {
    let lookup = |s: &str| -> String {
        symbols
            .by_c_name(s)
            .map(symbols::Symbol::full_rust_name)
            .unwrap_or_else(|| s.into())
    };

    let out = SYMBOL.replace_all(entry, |caps: &Captures<'_>| {
        let member = caps.get(4).map(|m| m.as_str()).unwrap_or("");
        let sym = symbols.by_c_name(&caps[3]);
        match &caps[2] {
            /* References to members, enum variants or methods within the same type. */
            "@" => {
                if let Some(sym) = sym {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    if sym.owner_name() != Some(in_type) {
                        format!(
                            "{}[`crate::{}{}`] (XXX: @-reference does not belong to {}!)",
                            &caps[1],
                            sym.full_rust_name(),
                            member,
                            in_type,
                        )
                    } else {
                        format!(
                            "{}[`{n}{m}`](Self::{n}{m})",
                            &caps[1],
                            n = sym.name(),
                            m = member
                        )
                    }
                } else {
                    format!("{}`{}{}`", &caps[1], &caps[3], member)
                }
            }
            "#" | "%" => {
                format!(
                    "{}`{}{}`",
                    &caps[1],
                    sym.map(symbols::Symbol::full_rust_name)
                        .unwrap_or_else(|| caps[3].into()),
                    member
                )
            }
            u => panic!("Unknown reference type {}", u),
        }
    });
    let out = GDK_GTK.replace_all(&out, |caps: &Captures<'_>| {
        format!("`{}`", lookup(&caps[0]))
    });
    let out = FUNCTION.replace_all(&out, |caps: &Captures<'_>| {
        format!("`{}()`", lookup(&caps[1]))
    });
    let out = TAGS.replace_all(&out, "`$0`");
    SPACES.replace_all(&out, " ").into_owned()
}
<|endoftext|>


<commit_before>import libc = posix;

native mod libc = "libc.dylib" {

    fn open(sbuf s, int flags, uint mode) -> int;
    fn read(int fd, vbuf buf, uint count) -> int;
    fn write(int fd, vbuf buf, uint count) -> int;
    fn close(int fd) -> int;

    type FILE;
    fn fopen(sbuf path, sbuf mode) -> FILE;
    fn fdopen(int fd, sbuf mode) -> FILE;
    fn fclose(FILE f);
    fn fgetc(FILE f) -> int;
    fn ungetc(int c, FILE f);
    fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fseek(FILE f, int offset, int whence) -> int;

    type dir;
    fn opendir(sbuf d) -> dir;
    fn closedir(dir d) -> int;
    type dirent;
    fn readdir(dir d) -> dirent;

    fn getenv(sbuf n) -> sbuf;
    fn setenv(sbuf n, sbuf v, int overwrite) -> int;
    fn unsetenv(sbuf n) -> int;

    fn pipe(vbuf buf) -> int;
    fn waitpid(int pid, vbuf status, int options) -> int;
}

mod libc_constants {
    fn O_RDONLY() -> int { ret 0x0000; }
    fn O_WRONLY() -> int { ret 0x0001; }
    fn O_RDWR()   -> int { ret 0x0002; }
    fn O_APPEND() -> int { ret 0x0008; }
    fn O_CREAT()  -> int { ret 0x0200; }
    fn O_EXCL()   -> int { ret 0x0800; }
    fn O_TRUNC()  -> int { ret 0x0400; }
    fn O_TEXT()   -> int { ret 0x0000; } // nonexistent in darwin libc
    fn O_BINARY() -> int { ret 0x0000; } // nonexistent in darwin libc

    fn S_IRUSR() -> uint { ret 0x0400u; }
    fn S_IWUSR() -> uint { ret 0x0200u; }
}

fn exec_suffix() -> str {
    ret "";
}

fn target_os() -> str {
    ret "macos";
}

fn pipe() -> tup(int, int) {
    let vec[mutable int] fds = vec(mutable 0, 0);
    check(os.libc.pipe(_vec.buf[mutable int](fds)) == 0);
    ret tup(fds.(0), fds.(1));
}

fn fd_FILE(int fd) -> libc.FILE {
    ret libc.fdopen(fd, _str.buf("r"));
}

fn waitpid(int pid) -> int {
    let vec[mutable int] status = vec(mutable 0);
    check(os.libc.waitpid(pid, _vec.buf[mutable int](status), 0) != -1);
    ret status.(0);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Put out darwin fire.<commit_after>import _str.sbuf;
import _vec.vbuf;

native mod libc = "libc.dylib" {

    fn open(sbuf s, int flags, uint mode) -> int;
    fn read(int fd, vbuf buf, uint count) -> int;
    fn write(int fd, vbuf buf, uint count) -> int;
    fn close(int fd) -> int;

    type FILE;
    fn fopen(sbuf path, sbuf mode) -> FILE;
    fn fdopen(int fd, sbuf mode) -> FILE;
    fn fclose(FILE f);
    fn fgetc(FILE f) -> int;
    fn ungetc(int c, FILE f);
    fn fread(vbuf buf, uint size, uint n, FILE f) -> uint;
    fn fseek(FILE f, int offset, int whence) -> int;

    type dir;
    fn opendir(sbuf d) -> dir;
    fn closedir(dir d) -> int;
    type dirent;
    fn readdir(dir d) -> dirent;

    fn getenv(sbuf n) -> sbuf;
    fn setenv(sbuf n, sbuf v, int overwrite) -> int;
    fn unsetenv(sbuf n) -> int;

    fn pipe(vbuf buf) -> int;
    fn waitpid(int pid, vbuf status, int options) -> int;
}

mod libc_constants {
    fn O_RDONLY() -> int { ret 0x0000; }
    fn O_WRONLY() -> int { ret 0x0001; }
    fn O_RDWR()   -> int { ret 0x0002; }
    fn O_APPEND() -> int { ret 0x0008; }
    fn O_CREAT()  -> int { ret 0x0200; }
    fn O_EXCL()   -> int { ret 0x0800; }
    fn O_TRUNC()  -> int { ret 0x0400; }
    fn O_TEXT()   -> int { ret 0x0000; } // nonexistent in darwin libc
    fn O_BINARY() -> int { ret 0x0000; } // nonexistent in darwin libc

    fn S_IRUSR() -> uint { ret 0x0400u; }
    fn S_IWUSR() -> uint { ret 0x0200u; }
}

fn exec_suffix() -> str {
    ret "";
}

fn target_os() -> str {
    ret "macos";
}

fn pipe() -> tup(int, int) {
    let vec[mutable int] fds = vec(mutable 0, 0);
    check(os.libc.pipe(_vec.buf[mutable int](fds)) == 0);
    ret tup(fds.(0), fds.(1));
}

fn fd_FILE(int fd) -> libc.FILE {
    ret libc.fdopen(fd, _str.buf("r"));
}

fn waitpid(int pid) -> int {
    let vec[mutable int] status = vec(mutable 0);
    check(os.libc.waitpid(pid, _vec.buf[mutable int](status), 0) != -1);
    ret status.(0);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>use std::vec;
use std::slice;
use std::default::Default;
use std::fmt;

use clear::Clear;

pub struct RepeatedField<T> {
    vec: Vec<T>,
    len: uint,
}

impl<T> RepeatedField<T> {
    #[inline]
    fn len(&self) -> uint {
        self.len
    }

    #[inline]
    pub fn clear(&mut self) {
        self.len = 0;
    }
}

impl<T> Clear for RepeatedField<T> {
    #[inline]
    fn clear(&mut self) {
        self.len = 0;
    }
}

impl<T> Default for RepeatedField<T> {
    #[inline]
    fn default() -> RepeatedField<T> {
        RepeatedField {
            vec: Vec::new(),
            len: 0,
        }
    }
}

impl<T> RepeatedField<T> {
    #[inline]
    pub fn new() -> RepeatedField<T> {
        Default::default()
    }

    #[inline]
    pub fn from_vec(vec: Vec<T>) -> RepeatedField<T> {
        let len = vec.len();
        RepeatedField {
            vec: vec,
            len: len,
        }
    }

    #[inline]
    pub fn into_vec(self) -> Vec<T> {
        let mut vec = self.vec;
        vec.truncate(self.len);
        vec
    }

    #[inline]
    pub fn capacity(&self) -> uint {
        self.vec.capacity()
    }

    #[inline]
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        self.vec.as_mut_slice()
    }

    #[inline]
    pub fn slice<'a>(&'a self, start: uint, end: uint) -> &'a [T] {
        self.as_slice().slice(start, end)
    }

    #[inline]
    pub fn slice_mut<'a>(&'a mut self, start: uint, end: uint) -> &'a mut [T] {
        self.as_mut_slice().slice_mut(start, end)
    }

    #[inline]
    pub fn slice_from<'a>(&'a self, start: uint) -> &'a [T] {
        self.as_slice().slice_from(start)
    }

    #[inline]
    pub fn slice_from_mut<'a>(&'a mut self, start: uint) -> &'a mut [T] {
        self.as_mut_slice().slice_from_mut(start)
    }

    #[inline]
    pub fn slice_to<'a>(&'a self, end: uint) -> &'a [T] {
        self.as_slice().slice_to(end)
    }

    #[inline]
    pub fn slice_to_mut<'a>(&'a mut self, end: uint) -> &'a mut [T] {
        self.as_mut_slice().slice_to_mut(end)
    }

    #[inline]
    pub fn split_at<'a>(&'a self, mid: uint) -> (&'a [T], &'a [T]) {
        self.as_slice().split_at(mid)
    }

    #[inline]
    pub fn split_at_mut<'a>(&'a mut self, mid: uint) -> (&'a mut [T], &'a mut [T]) {
        self.as_mut_slice().split_at_mut(mid)
    }

    #[inline]
    pub fn tail<'a>(&'a self) -> &'a [T] {
        self.as_slice().tail()
    }

    #[inline]
    pub fn last<'a>(&'a self) -> Option<&'a T> {
        self.as_slice().last()
    }

    #[inline]
    pub fn last_mut<'a>(&'a mut self) -> Option<&'a mut T> {
        self.as_mut_slice().last_mut()
    }

    #[inline]
    pub fn init<'a>(&'a self) -> &'a [T] {
        self.as_slice().init()
    }

    #[inline]
    pub fn push(&mut self, value: T) {
        if self.len == self.vec.len() {
            self.vec.push(value);
        } else {
            *self.vec.get_mut(self.len) = value;
        }
        self.len += 1;
    }

    #[inline]
    pub fn pop(&mut self) -> Option<T> {
        if self.len == 0 {
            None
        } else {
            self.vec.truncate(self.len);
            self.len -= 1;
            self.vec.pop()
        }
    }

    #[inline]
    pub fn insert(&mut self, index: uint, value: T) {
        assert!(index <= self.len);
        self.vec.insert(index, value);
        self.len += 1;
    }

    #[inline]
    pub fn remove(&mut self, index: uint) -> Option<T> {
        if index < self.len {
            self.len -= 1;
            self.vec.remove(index)
        } else {
            None
        }
    }

    #[inline]
    pub fn truncate(&mut self, len: uint) {
        if self.len > len {
            self.len = len;
        }
    }

    #[inline]
    pub fn reverse(&mut self) {
        self.as_mut_slice().reverse()
    }

    #[inline]
    pub fn into_iter(mut self) -> vec::MoveItems<T> {
        self.vec.truncate(self.len);
        self.vec.into_iter()
    }

    #[inline]
    pub fn get<'a>(&'a self, index: uint) -> &'a T {
        &self.as_slice()[index]
    }

    #[inline]
    pub fn get_mut<'a>(&'a mut self, index: uint) -> &'a mut T {
        &mut self.as_mut_slice()[index]
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> slice::Items<'a, T> {
        self.as_slice().iter()
    }

    #[inline]
    pub fn iter_mut<'a>(&'a mut self) -> slice::MutItems<'a, T> {
        self.as_mut_slice().iter_mut()
    }

    #[inline]
    pub fn sort_by(&mut self, compare: |&T, &T| -> Ordering) {
        self.as_mut_slice().sort_by(compare)
    }

    #[inline]
    pub fn as_ptr(&self) -> *const T {
        self.vec.as_ptr()
    }

    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut T {
        self.vec.as_mut_ptr()
    }
}

impl<T : Default+Clear> RepeatedField<T> {
    pub fn push_default<'a>(&'a mut self) -> &'a mut T {
        if self.len == self.vec.len() {
            self.vec.push(Default::default());
        } else {
            self.vec.get_mut(self.len).clear();
        }
        self.len += 1;
        self.last_mut().unwrap()
    }
}

impl<T : Clone> RepeatedField<T> {
    // TODO: implement to_vec()
    #[inline]
    pub fn from_slice(values: &[T]) -> RepeatedField<T> {
        RepeatedField::from_vec(values.to_vec())
    }
}

impl<T : Clone> Clone for RepeatedField<T> {
    #[inline]
    fn clone(&self) -> RepeatedField<T> {
        RepeatedField {
            vec: self.as_slice().to_vec(),
            len: self.len(),
        }
    }
}

impl<T> FromIterator<T> for RepeatedField<T> {
    #[inline]
    fn from_iter<I : Iterator<T>>(iter: I) -> RepeatedField<T> {
        RepeatedField::from_vec(FromIterator::from_iter(iter))
    }
}

impl<T : PartialEq> PartialEq for RepeatedField<T> {
    #[inline]
    fn eq(&self, other: &RepeatedField<T>) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl<T : Eq> Eq for RepeatedField<T> {}

impl<T : PartialEq> RepeatedField<T> {
    #[inline]
    pub fn contains(&self, value: &T) -> bool {
        self.as_slice().contains(value)
    }
}

impl<T> AsSlice<T> for RepeatedField<T> {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a [T] {
        self.vec.slice_to(self.len)
    }
}

impl<T : fmt::Show> fmt::Show for RepeatedField<T> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}
<commit_msg>deprecate Repeated.get{,_mut} for Repeated.index{,_mut}<commit_after>use std::vec;
use std::slice;
use std::default::Default;
use std::fmt;

use clear::Clear;

pub struct RepeatedField<T> {
    vec: Vec<T>,
    len: uint,
}

impl<T> RepeatedField<T> {
    #[inline]
    fn len(&self) -> uint {
        self.len
    }

    #[inline]
    pub fn clear(&mut self) {
        self.len = 0;
    }
}

impl<T> Clear for RepeatedField<T> {
    #[inline]
    fn clear(&mut self) {
        self.len = 0;
    }
}

impl<T> Default for RepeatedField<T> {
    #[inline]
    fn default() -> RepeatedField<T> {
        RepeatedField {
            vec: Vec::new(),
            len: 0,
        }
    }
}

impl<T> RepeatedField<T> {
    #[inline]
    pub fn new() -> RepeatedField<T> {
        Default::default()
    }

    #[inline]
    pub fn from_vec(vec: Vec<T>) -> RepeatedField<T> {
        let len = vec.len();
        RepeatedField {
            vec: vec,
            len: len,
        }
    }

    #[inline]
    pub fn into_vec(self) -> Vec<T> {
        let mut vec = self.vec;
        vec.truncate(self.len);
        vec
    }

    #[inline]
    pub fn capacity(&self) -> uint {
        self.vec.capacity()
    }

    #[inline]
    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
        self.vec.as_mut_slice()
    }

    #[inline]
    pub fn slice<'a>(&'a self, start: uint, end: uint) -> &'a [T] {
        self.as_slice().slice(start, end)
    }

    #[inline]
    pub fn slice_mut<'a>(&'a mut self, start: uint, end: uint) -> &'a mut [T] {
        self.as_mut_slice().slice_mut(start, end)
    }

    #[inline]
    pub fn slice_from<'a>(&'a self, start: uint) -> &'a [T] {
        self.as_slice().slice_from(start)
    }

    #[inline]
    pub fn slice_from_mut<'a>(&'a mut self, start: uint) -> &'a mut [T] {
        self.as_mut_slice().slice_from_mut(start)
    }

    #[inline]
    pub fn slice_to<'a>(&'a self, end: uint) -> &'a [T] {
        self.as_slice().slice_to(end)
    }

    #[inline]
    pub fn slice_to_mut<'a>(&'a mut self, end: uint) -> &'a mut [T] {
        self.as_mut_slice().slice_to_mut(end)
    }

    #[inline]
    pub fn split_at<'a>(&'a self, mid: uint) -> (&'a [T], &'a [T]) {
        self.as_slice().split_at(mid)
    }

    #[inline]
    pub fn split_at_mut<'a>(&'a mut self, mid: uint) -> (&'a mut [T], &'a mut [T]) {
        self.as_mut_slice().split_at_mut(mid)
    }

    #[inline]
    pub fn tail<'a>(&'a self) -> &'a [T] {
        self.as_slice().tail()
    }

    #[inline]
    pub fn last<'a>(&'a self) -> Option<&'a T> {
        self.as_slice().last()
    }

    #[inline]
    pub fn last_mut<'a>(&'a mut self) -> Option<&'a mut T> {
        self.as_mut_slice().last_mut()
    }

    #[inline]
    pub fn init<'a>(&'a self) -> &'a [T] {
        self.as_slice().init()
    }

    #[inline]
    pub fn push(&mut self, value: T) {
        if self.len == self.vec.len() {
            self.vec.push(value);
        } else {
            *self.vec.get_mut(self.len) = value;
        }
        self.len += 1;
    }

    #[inline]
    pub fn pop(&mut self) -> Option<T> {
        if self.len == 0 {
            None
        } else {
            self.vec.truncate(self.len);
            self.len -= 1;
            self.vec.pop()
        }
    }

    #[inline]
    pub fn insert(&mut self, index: uint, value: T) {
        assert!(index <= self.len);
        self.vec.insert(index, value);
        self.len += 1;
    }

    #[inline]
    pub fn remove(&mut self, index: uint) -> Option<T> {
        if index < self.len {
            self.len -= 1;
            self.vec.remove(index)
        } else {
            None
        }
    }

    #[inline]
    pub fn truncate(&mut self, len: uint) {
        if self.len > len {
            self.len = len;
        }
    }

    #[inline]
    pub fn reverse(&mut self) {
        self.as_mut_slice().reverse()
    }

    #[inline]
    pub fn into_iter(mut self) -> vec::MoveItems<T> {
        self.vec.truncate(self.len);
        self.vec.into_iter()
    }

    #[deprecated = "use `foo[index]` instead"]
    #[inline]
    pub fn get<'a>(&'a self, index: uint) -> &'a T {
        &self.as_slice()[index]
    }

    #[deprecated = "use `foo[index] = bar` instead"]
    #[inline]
    pub fn get_mut<'a>(&'a mut self, index: uint) -> &'a mut T {
        &mut self.as_mut_slice()[index]
    }

    #[inline]
    pub fn iter<'a>(&'a self) -> slice::Items<'a, T> {
        self.as_slice().iter()
    }

    #[inline]
    pub fn iter_mut<'a>(&'a mut self) -> slice::MutItems<'a, T> {
        self.as_mut_slice().iter_mut()
    }

    #[inline]
    pub fn sort_by(&mut self, compare: |&T, &T| -> Ordering) {
        self.as_mut_slice().sort_by(compare)
    }

    #[inline]
    pub fn as_ptr(&self) -> *const T {
        self.vec.as_ptr()
    }

    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut T {
        self.vec.as_mut_ptr()
    }
}

impl<T : Default+Clear> RepeatedField<T> {
    pub fn push_default<'a>(&'a mut self) -> &'a mut T {
        if self.len == self.vec.len() {
            self.vec.push(Default::default());
        } else {
            self.vec.get_mut(self.len).clear();
        }
        self.len += 1;
        self.last_mut().unwrap()
    }
}

impl<T : Clone> RepeatedField<T> {
    // TODO: implement to_vec()
    #[inline]
    pub fn from_slice(values: &[T]) -> RepeatedField<T> {
        RepeatedField::from_vec(values.to_vec())
    }
}

impl<T : Clone> Clone for RepeatedField<T> {
    #[inline]
    fn clone(&self) -> RepeatedField<T> {
        RepeatedField {
            vec: self.as_slice().to_vec(),
            len: self.len(),
        }
    }
}

impl<T> FromIterator<T> for RepeatedField<T> {
    #[inline]
    fn from_iter<I : Iterator<T>>(iter: I) -> RepeatedField<T> {
        RepeatedField::from_vec(FromIterator::from_iter(iter))
    }
}

impl<T : PartialEq> PartialEq for RepeatedField<T> {
    #[inline]
    fn eq(&self, other: &RepeatedField<T>) -> bool {
        self.as_slice() == other.as_slice()
    }
}

impl<T : Eq> Eq for RepeatedField<T> {}

impl<T : PartialEq> RepeatedField<T> {
    #[inline]
    pub fn contains(&self, value: &T) -> bool {
        self.as_slice().contains(value)
    }
}

impl<T> AsSlice<T> for RepeatedField<T> {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a [T] {
        self.vec.slice_to(self.len)
    }
}

impl<T> Index<uint, T> for RepeatedField<T> {
    #[inline]
    fn index<'a>(&'a self, index: &uint) -> &'a T {
        &self.as_slice()[*index]
    }
}

impl<T> IndexMut<uint, T> for RepeatedField<T> {
    #[inline]
    fn index_mut<'a>(&'a mut self, index: &uint) -> &'a mut T {
        &mut self.as_mut_slice()[*index]
    }
}

impl<T : fmt::Show> fmt::Show for RepeatedField<T> {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.as_slice().fmt(f)
    }
}
<|endoftext|>


<commit_before>use anyhow::Error;

use crate::util::errors::{CargoResult, HttpNot200};
use crate::util::Config;

pub struct Retry<'a> {
    config: &'a Config,
    remaining: u32,
}

impl<'a> Retry<'a> {
    pub fn new(config: &'a Config) -> CargoResult<Retry<'a>> {
        Ok(Retry {
            config,
            remaining: config.net_config()?.retry.unwrap_or(2),
        })
    }

    pub fn r#try<T>(&mut self, f: impl FnOnce() -> CargoResult<T>) -> CargoResult<Option<T>> {
        match f() {
            Err(ref e) if maybe_spurious(e) && self.remaining > 0 => {
                let msg = format!(
                    "spurious network error ({} tries remaining): {}",
                    self.remaining,
                    e.root_cause(),
                );
                self.config.shell().warn(msg)?;
                self.remaining -= 1;
                Ok(None)
            }
            other => other.map(Some),
        }
    }
}

fn maybe_spurious(err: &Error) -> bool {
    if let Some(git_err) = err.downcast_ref::<git2::Error>() {
        match git_err.class() {
            git2::ErrorClass::Net | git2::ErrorClass::Os => return true,
            _ => (),
        }
    }
    if let Some(curl_err) = err.downcast_ref::<curl::Error>() {
        if curl_err.is_couldnt_connect()
            || curl_err.is_couldnt_resolve_proxy()
            || curl_err.is_couldnt_resolve_host()
            || curl_err.is_operation_timedout()
            || curl_err.is_recv_error()
            || curl_err.is_http2_error()
            || curl_err.is_http2_stream_error()
            || curl_err.is_ssl_connect_error()
            || curl_err.is_partial_file()
        {
            return true;
        }
    }
    if let Some(not_200) = err.downcast_ref::<HttpNot200>() {
        if 500 <= not_200.code && not_200.code < 600 {
            return true;
        }
    }
    false
}

/// Wrapper method for network call retry logic.
///
/// Retry counts provided by Config object `net.retry`. Config shell outputs
/// a warning on per retry.
///
/// Closure must return a `CargoResult`.
///
/// # Examples
///
/// ```
/// # use crate::cargo::util::{CargoResult, Config};
/// # let download_something = || return Ok(());
/// # let config = Config::default().unwrap();
/// use cargo::util::network;
/// let cargo_result = network::with_retry(&config, || download_something());
/// ```
pub fn with_retry<T, F>(config: &Config, mut callback: F) -> CargoResult<T>
where
    F: FnMut() -> CargoResult<T>,
{
    let mut retry = Retry::new(config)?;
    loop {
        if let Some(ret) = retry.r#try(&mut callback)? {
            return Ok(ret);
        }
    }
}

#[test]
fn with_retry_repeats_the_call_then_works() {
    use crate::core::Shell;

    //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
    let error1 = HttpNot200 {
        code: 501,
        url: "Uri".to_string(),
    }
    .into();
    let error2 = HttpNot200 {
        code: 502,
        url: "Uri".to_string(),
    }
    .into();
    let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
    let config = Config::default().unwrap();
    *config.shell() = Shell::from_write(Box::new(Vec::new()));
    let result = with_retry(&config, || results.pop().unwrap());
    assert!(result.is_ok())
}

#[test]
fn with_retry_finds_nested_spurious_errors() {
    use crate::core::Shell;

    //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
    //String error messages are not considered spurious
    let error1 = anyhow::Error::from(HttpNot200 {
        code: 501,
        url: "Uri".to_string(),
    });
    let error1 = anyhow::Error::from(error1.context("A non-spurious wrapping err"));
    let error2 = anyhow::Error::from(HttpNot200 {
        code: 502,
        url: "Uri".to_string(),
    });
    let error2 = anyhow::Error::from(error2.context("A second chained error"));
    let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
    let config = Config::default().unwrap();
    *config.shell() = Shell::from_write(Box::new(Vec::new()));
    let result = with_retry(&config, || results.pop().unwrap());
    assert!(result.is_ok())
}

#[test]
fn curle_http2_stream_is_spurious() {
    let code = curl_sys::CURLE_HTTP2_STREAM;
    let err = curl::Error::new(code);
    assert!(maybe_spurious(&err.into()));
}
<commit_msg>Flag git zlib errors as spurious errors<commit_after>use anyhow::Error;

use crate::util::errors::{CargoResult, HttpNot200};
use crate::util::Config;

pub struct Retry<'a> {
    config: &'a Config,
    remaining: u32,
}

impl<'a> Retry<'a> {
    pub fn new(config: &'a Config) -> CargoResult<Retry<'a>> {
        Ok(Retry {
            config,
            remaining: config.net_config()?.retry.unwrap_or(2),
        })
    }

    pub fn r#try<T>(&mut self, f: impl FnOnce() -> CargoResult<T>) -> CargoResult<Option<T>> {
        match f() {
            Err(ref e) if maybe_spurious(e) && self.remaining > 0 => {
                let msg = format!(
                    "spurious network error ({} tries remaining): {}",
                    self.remaining,
                    e.root_cause(),
                );
                self.config.shell().warn(msg)?;
                self.remaining -= 1;
                Ok(None)
            }
            other => other.map(Some),
        }
    }
}

fn maybe_spurious(err: &Error) -> bool {
    if let Some(git_err) = err.downcast_ref::<git2::Error>() {
        match git_err.class() {
            git2::ErrorClass::Net | git2::ErrorClass::Os | git2::ErrorClass::Zlib => return true,
            _ => (),
        }
    }
    if let Some(curl_err) = err.downcast_ref::<curl::Error>() {
        if curl_err.is_couldnt_connect()
            || curl_err.is_couldnt_resolve_proxy()
            || curl_err.is_couldnt_resolve_host()
            || curl_err.is_operation_timedout()
            || curl_err.is_recv_error()
            || curl_err.is_http2_error()
            || curl_err.is_http2_stream_error()
            || curl_err.is_ssl_connect_error()
            || curl_err.is_partial_file()
        {
            return true;
        }
    }
    if let Some(not_200) = err.downcast_ref::<HttpNot200>() {
        if 500 <= not_200.code && not_200.code < 600 {
            return true;
        }
    }
    false
}

/// Wrapper method for network call retry logic.
///
/// Retry counts provided by Config object `net.retry`. Config shell outputs
/// a warning on per retry.
///
/// Closure must return a `CargoResult`.
///
/// # Examples
///
/// ```
/// # use crate::cargo::util::{CargoResult, Config};
/// # let download_something = || return Ok(());
/// # let config = Config::default().unwrap();
/// use cargo::util::network;
/// let cargo_result = network::with_retry(&config, || download_something());
/// ```
pub fn with_retry<T, F>(config: &Config, mut callback: F) -> CargoResult<T>
where
    F: FnMut() -> CargoResult<T>,
{
    let mut retry = Retry::new(config)?;
    loop {
        if let Some(ret) = retry.r#try(&mut callback)? {
            return Ok(ret);
        }
    }
}

#[test]
fn with_retry_repeats_the_call_then_works() {
    use crate::core::Shell;

    //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
    let error1 = HttpNot200 {
        code: 501,
        url: "Uri".to_string(),
    }
    .into();
    let error2 = HttpNot200 {
        code: 502,
        url: "Uri".to_string(),
    }
    .into();
    let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
    let config = Config::default().unwrap();
    *config.shell() = Shell::from_write(Box::new(Vec::new()));
    let result = with_retry(&config, || results.pop().unwrap());
    assert!(result.is_ok())
}

#[test]
fn with_retry_finds_nested_spurious_errors() {
    use crate::core::Shell;

    //Error HTTP codes (5xx) are considered maybe_spurious and will prompt retry
    //String error messages are not considered spurious
    let error1 = anyhow::Error::from(HttpNot200 {
        code: 501,
        url: "Uri".to_string(),
    });
    let error1 = anyhow::Error::from(error1.context("A non-spurious wrapping err"));
    let error2 = anyhow::Error::from(HttpNot200 {
        code: 502,
        url: "Uri".to_string(),
    });
    let error2 = anyhow::Error::from(error2.context("A second chained error"));
    let mut results: Vec<CargoResult<()>> = vec![Ok(()), Err(error1), Err(error2)];
    let config = Config::default().unwrap();
    *config.shell() = Shell::from_write(Box::new(Vec::new()));
    let result = with_retry(&config, || results.pop().unwrap());
    assert!(result.is_ok())
}

#[test]
fn curle_http2_stream_is_spurious() {
    let code = curl_sys::CURLE_HTTP2_STREAM;
    let err = curl::Error::new(code);
    assert!(maybe_spurious(&err.into()));
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::config::SafetyRulesConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ConsensusConfig {
    pub max_block_txns: u64,
    pub max_block_bytes: u64,
    pub max_pruned_blocks_in_mem: usize,
    // Timeout for consensus to get an ack from mempool for executed transactions (in milliseconds)
    pub mempool_executed_txn_timeout_ms: u64,
    // Timeout for consensus to pull transactions from mempool and get a response (in milliseconds)
    pub mempool_txn_pull_timeout_ms: u64,
    pub round_initial_timeout_ms: u64,
    pub round_timeout_backoff_exponent_base: f64,
    pub round_timeout_backoff_max_exponent: usize,
    pub safety_rules: SafetyRulesConfig,
    // Only sync committed transactions but not vote for any pending blocks. This is useful when
    // validators coordinate on the latest version to apply a manual transaction.
    pub sync_only: bool,
    pub channel_size: usize,
    // When false, use the Direct Mempool Quorum Store
    pub use_quorum_store: bool,
    pub quorum_store_pull_timeout_ms: u64,
    // Decides how long the leader waits before proposing empty block if there's no txns in mempool
    // the period = (poll_count - 1) * 30ms
    pub quorum_store_poll_count: u64,
    pub intra_consensus_channel_buffer_size: usize,
}

impl Default for ConsensusConfig {
    fn default() -> ConsensusConfig {
        ConsensusConfig {
            max_block_txns: 6000,
            max_block_bytes: 5 * 1024 * 1024, // 5MB
            max_pruned_blocks_in_mem: 100,
            mempool_executed_txn_timeout_ms: 1000,
            mempool_txn_pull_timeout_ms: 1000,
            round_initial_timeout_ms: 1500,
            // 1.2^6 ~= 3
            // Timeout goes from initial_timeout to initial_timeout*3 in 6 steps
            round_timeout_backoff_exponent_base: 1.2,
            round_timeout_backoff_max_exponent: 6,
            safety_rules: SafetyRulesConfig::default(),
            sync_only: false,
            channel_size: 30, // hard-coded
            use_quorum_store: false,

            quorum_store_pull_timeout_ms: 1000,
            quorum_store_poll_count: 5,
            intra_consensus_channel_buffer_size: 10,
        }
    }
}

impl ConsensusConfig {
    pub fn set_data_dir(&mut self, data_dir: PathBuf) {
        self.safety_rules.set_data_dir(data_dir);
    }
}

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

    #[test]
    fn test_config_serialization() {
        let config = ConsensusConfig::default();
        let s = serde_yaml::to_string(&config).unwrap();

        serde_yaml::from_str::<ConsensusConfig>(&s).unwrap();
    }
}
<commit_msg>[Consensus] Tune max block size from 6k -> 3.5k (#4151)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use crate::config::SafetyRulesConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct ConsensusConfig {
    pub max_block_txns: u64,
    pub max_block_bytes: u64,
    pub max_pruned_blocks_in_mem: usize,
    // Timeout for consensus to get an ack from mempool for executed transactions (in milliseconds)
    pub mempool_executed_txn_timeout_ms: u64,
    // Timeout for consensus to pull transactions from mempool and get a response (in milliseconds)
    pub mempool_txn_pull_timeout_ms: u64,
    pub round_initial_timeout_ms: u64,
    pub round_timeout_backoff_exponent_base: f64,
    pub round_timeout_backoff_max_exponent: usize,
    pub safety_rules: SafetyRulesConfig,
    // Only sync committed transactions but not vote for any pending blocks. This is useful when
    // validators coordinate on the latest version to apply a manual transaction.
    pub sync_only: bool,
    pub channel_size: usize,
    // When false, use the Direct Mempool Quorum Store
    pub use_quorum_store: bool,
    pub quorum_store_pull_timeout_ms: u64,
    // Decides how long the leader waits before proposing empty block if there's no txns in mempool
    // the period = (poll_count - 1) * 30ms
    pub quorum_store_poll_count: u64,
    pub intra_consensus_channel_buffer_size: usize,
}

impl Default for ConsensusConfig {
    fn default() -> ConsensusConfig {
        ConsensusConfig {
            max_block_txns: 3500,
            max_block_bytes: 5 * 1024 * 1024, // 5MB
            max_pruned_blocks_in_mem: 100,
            mempool_executed_txn_timeout_ms: 1000,
            mempool_txn_pull_timeout_ms: 1000,
            round_initial_timeout_ms: 1500,
            // 1.2^6 ~= 3
            // Timeout goes from initial_timeout to initial_timeout*3 in 6 steps
            round_timeout_backoff_exponent_base: 1.2,
            round_timeout_backoff_max_exponent: 6,
            safety_rules: SafetyRulesConfig::default(),
            sync_only: false,
            channel_size: 30, // hard-coded
            use_quorum_store: false,

            quorum_store_pull_timeout_ms: 1000,
            quorum_store_poll_count: 5,
            intra_consensus_channel_buffer_size: 10,
        }
    }
}

impl ConsensusConfig {
    pub fn set_data_dir(&mut self, data_dir: PathBuf) {
        self.safety_rules.set_data_dir(data_dir);
    }
}

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

    #[test]
    fn test_config_serialization() {
        let config = ConsensusConfig::default();
        let s = serde_yaml::to_string(&config).unwrap();

        serde_yaml::from_str::<ConsensusConfig>(&s).unwrap();
    }
}
<|endoftext|>


<commit_before>/// unit creates a type representing a single unit.
///
/// # Examples
///
/// ```
/// #[macro_use(unit)]
/// extern crate fiz_math;
/// use std::fmt::Debug;
///
/// // GoldCoins are golden!
/// unit!(GoldCoins);
///
/// // SilverCoins are like gold coins, only worse!
/// unit!(SilverCoins);
///
/// fn collect<T: Debug>(coins: GoldCoins<T>) {
///     println!("We've collected {:?} golden coins!", coins.0);
/// }
///
/// fn main() {
///     let x = GoldCoins(5);
///     collect(x);
///
///     let y = SilverCoins(6);
///
///     // Try uncommenting the line below and see:
///     //
///     // error: mismatched types: expected `GoldCoins<_>`, found `SilverCoins<_>`"
///     //
///     //collect(y);
///
///     // add, subtract, multiply, divide:
///     assert_eq!(y + SilverCoins(4), SilverCoins(10));
///     assert_eq!(y - SilverCoins(3), SilverCoins(3));
///     assert_eq!(y * SilverCoins(3), SilverCoins(18));
///     assert_eq!(y / SilverCoins(2), SilverCoins(3));
///
///     // ordering and equality:
///     assert!(y < SilverCoins(7));
///     assert!(y > SilverCoins(5));
///     assert!(y <= SilverCoins(6));
///     assert!(y >= SilverCoins(6));
///     assert!(y == SilverCoins(6));
/// }
/// ```
///
#[macro_export]
macro_rules! unit {
    ( $ident:ident ) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $ident<T>(pub T);

        unit!(impl_std_ops, $ident);
        unit!(impl_std_cmp, $ident);
        unit!(impl_num_traits, $ident);
    };

    (impl_std_ops, $ident:ident ) => {
        // addition
        impl<T: ::std::ops::Add<Output = T>> ::std::ops::Add for $ident<T> {
            type Output = Self;

            fn add(self, _rhs: Self) -> Self {
                $ident(self.0 + _rhs.0)
            }
        }

        // subtraction
        impl<T: ::std::ops::Sub<Output = T>> ::std::ops::Sub for $ident<T> {
            type Output = Self;

            fn sub(self, _rhs: Self) -> Self {
                $ident(self.0 - _rhs.0)
            }
        }

        // multiplication
        impl<T: ::std::ops::Mul<Output = T>> ::std::ops::Mul for $ident<T> {
            type Output = Self;

            fn mul(self, _rhs: Self) -> Self {
                $ident(self.0 * _rhs.0)
            }
        }

        // division
        impl<T: ::std::ops::Div<Output = T>> ::std::ops::Div for $ident<T> {
            type Output = Self;

            fn div(self, _rhs: Self) -> Self {
                $ident(self.0 / _rhs.0)
            }
        }

        // remainder
        impl<T: ::std::ops::Rem<Output = T>> ::std::ops::Rem for $ident<T> {
            type Output = Self;

            fn rem(self, rhs: Self) -> Self { $ident(self.0 % rhs.0) }
        }

        // negation
        impl<T: ::std::ops::Neg<Output = T>> ::std::ops::Neg for $ident<T> {
            type Output = Self;

            fn neg(self) -> Self::Output { $ident(-self.0) }
        }

        // not
        impl<T: ::std::ops::Not<Output = T>> ::std::ops::Not for $ident<T> {
            type Output = Self;

            fn not(self) -> Self::Output { $ident(!self.0) }
        }

        // bitwise and
        impl<T: ::std::ops::BitAnd<Output = T>> ::std::ops::BitAnd for $ident<T> {
            type Output = Self;

            fn bitand(self, rhs: Self) -> Self::Output { $ident(self.0 & rhs.0) }
        }

        // bitwise or
        impl<T: ::std::ops::BitOr<Output = T>> ::std::ops::BitOr for $ident<T> {
            type Output = Self;

            fn bitor(self, rhs: Self) -> Self::Output { $ident(self.0 | rhs.0) }
        }

        // bitwise xor
        impl<T: ::std::ops::BitXor<Output = T>> ::std::ops::BitXor for $ident<T> {
            type Output = Self;

            fn bitxor(self, rhs: Self) -> Self::Output { $ident(self.0 ^ rhs.0) }
        }

        // shift left
        impl<T: ::std::ops::Shl<usize>> ::std::ops::Shl<usize> for $ident<T> {
            type Output = $ident<T::Output>;

            fn shl(self, rhs: usize) -> Self::Output { $ident(self.0 << rhs) }
        }

        // shift right
        impl<T: ::std::ops::Shr<usize>> ::std::ops::Shr<usize> for $ident<T> {
            type Output = $ident<T::Output>;

            fn shr(self, rhs: usize) -> Self::Output { $ident(self.0 >> rhs) }
        }
    };

    (impl_std_cmp, $ident:ident ) => {
        // partial equality
        impl<T: ::std::cmp::PartialEq> ::std::cmp::PartialEq for $ident<T> {
            fn eq(&self, _rhs: &Self) -> bool {
                self.0 == _rhs.0
            }
        }

        // equality
        impl<T: ::std::cmp::Eq> ::std::cmp::Eq for $ident<T> {}

        // partial ordering
        impl<T: ::std::cmp::PartialOrd> ::std::cmp::PartialOrd for $ident<T> {
            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
                if self.0 < other.0 {
                    Some(::std::cmp::Ordering::Less)
                } else if self.0 > other.0 {
                    Some(::std::cmp::Ordering::Greater)
                } else if self == other {
                    Some(::std::cmp::Ordering::Equal)
                } else {
                    None
                }
            }
        }

        // total ordering
        impl<T: ::std::cmp::Ord> ::std::cmp::Ord for $ident<T> {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                if self.0 < other.0 {
                    ::std::cmp::Ordering::Less
                } else if self.0 > other.0 {
                    ::std::cmp::Ordering::Greater
                } else {
                    ::std::cmp::Ordering::Equal
                }
            }
        }
    };

    (impl_num_traits, $ident:ident ) => {
        impl<T: $crate::num_export::traits::Zero> $crate::num_export::traits::Zero for $ident<T> {
            fn zero() -> Self { $ident(T::zero()) }
            fn is_zero(&self) -> bool { self.0.is_zero() }
        }

        impl<T: $crate::num_export::traits::One> $crate::num_export::traits::One for $ident<T> {
            fn one() -> Self { $ident(T::one()) }
        }

        impl<T: $crate::num_export::traits::Num> $crate::num_export::traits::Num for $ident<T> {
            type FromStrRadixErr = T::FromStrRadixErr;
            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
                match T::from_str_radix(str, radix) {
                    Ok(x) => { Ok($ident(x)) }
                    Err(e) => { Err(e) }
                }
            }
        }

        impl<T: $crate::num_export::traits::ToPrimitive> $crate::num_export::traits::ToPrimitive for $ident<T> {
            fn to_i64(&self) -> Option<i64> { self.0.to_i64() }
            fn to_u64(&self) -> Option<u64> { self.0.to_u64() }
            fn to_isize(&self) -> Option<isize> { self.0.to_isize() }
            fn to_i8(&self) -> Option<i8> { self.0.to_i8() }
            fn to_i16(&self) -> Option<i16> { self.0.to_i16() }
            fn to_i32(&self) -> Option<i32> { self.0.to_i32() }
            fn to_usize(&self) -> Option<usize> { self.0.to_usize() }
            fn to_u8(&self) -> Option<u8> { self.0.to_u8() }
            fn to_u16(&self) -> Option<u16> { self.0.to_u16() }
            fn to_u32(&self) -> Option<u32> { self.0.to_u32() }
            fn to_f32(&self) -> Option<f32> { self.0.to_f32() }
            fn to_f64(&self) -> Option<f64> { self.0.to_f64() }
        }

        impl<T: $crate::num_export::traits::NumCast> $crate::num_export::traits::NumCast for $ident<T> {
            fn from<X: $crate::num_export::traits::ToPrimitive>(n: X) -> Option<Self> {
                match T::from(n) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        impl<T: $crate::num_export::traits::Bounded> $crate::num_export::traits::Bounded for $ident<T> {
            fn min_value() -> Self { $ident(T::min_value()) }
            fn max_value() -> Self { $ident(T::max_value()) }
        }
    };
}
<commit_msg>unit! impl num::traits::CheckedAdd<commit_after>/// unit creates a type representing a single unit.
///
/// # Examples
///
/// ```
/// #[macro_use(unit)]
/// extern crate fiz_math;
/// use std::fmt::Debug;
///
/// // GoldCoins are golden!
/// unit!(GoldCoins);
///
/// // SilverCoins are like gold coins, only worse!
/// unit!(SilverCoins);
///
/// fn collect<T: Debug>(coins: GoldCoins<T>) {
///     println!("We've collected {:?} golden coins!", coins.0);
/// }
///
/// fn main() {
///     let x = GoldCoins(5);
///     collect(x);
///
///     let y = SilverCoins(6);
///
///     // Try uncommenting the line below and see:
///     //
///     // error: mismatched types: expected `GoldCoins<_>`, found `SilverCoins<_>`"
///     //
///     //collect(y);
///
///     // add, subtract, multiply, divide:
///     assert_eq!(y + SilverCoins(4), SilverCoins(10));
///     assert_eq!(y - SilverCoins(3), SilverCoins(3));
///     assert_eq!(y * SilverCoins(3), SilverCoins(18));
///     assert_eq!(y / SilverCoins(2), SilverCoins(3));
///
///     // ordering and equality:
///     assert!(y < SilverCoins(7));
///     assert!(y > SilverCoins(5));
///     assert!(y <= SilverCoins(6));
///     assert!(y >= SilverCoins(6));
///     assert!(y == SilverCoins(6));
/// }
/// ```
///
#[macro_export]
macro_rules! unit {
    ( $ident:ident ) => {
        #[derive(Copy, Clone, Debug)]
        pub struct $ident<T>(pub T);

        unit!(impl_std_ops, $ident);
        unit!(impl_std_cmp, $ident);
        unit!(impl_num_traits, $ident);
    };

    (impl_std_ops, $ident:ident ) => {
        // addition
        impl<T: ::std::ops::Add<Output = T>> ::std::ops::Add for $ident<T> {
            type Output = Self;

            fn add(self, _rhs: Self) -> Self {
                $ident(self.0 + _rhs.0)
            }
        }

        // subtraction
        impl<T: ::std::ops::Sub<Output = T>> ::std::ops::Sub for $ident<T> {
            type Output = Self;

            fn sub(self, _rhs: Self) -> Self {
                $ident(self.0 - _rhs.0)
            }
        }

        // multiplication
        impl<T: ::std::ops::Mul<Output = T>> ::std::ops::Mul for $ident<T> {
            type Output = Self;

            fn mul(self, _rhs: Self) -> Self {
                $ident(self.0 * _rhs.0)
            }
        }

        // division
        impl<T: ::std::ops::Div<Output = T>> ::std::ops::Div for $ident<T> {
            type Output = Self;

            fn div(self, _rhs: Self) -> Self {
                $ident(self.0 / _rhs.0)
            }
        }

        // remainder
        impl<T: ::std::ops::Rem<Output = T>> ::std::ops::Rem for $ident<T> {
            type Output = Self;

            fn rem(self, rhs: Self) -> Self { $ident(self.0 % rhs.0) }
        }

        // negation
        impl<T: ::std::ops::Neg<Output = T>> ::std::ops::Neg for $ident<T> {
            type Output = Self;

            fn neg(self) -> Self::Output { $ident(-self.0) }
        }

        // not
        impl<T: ::std::ops::Not<Output = T>> ::std::ops::Not for $ident<T> {
            type Output = Self;

            fn not(self) -> Self::Output { $ident(!self.0) }
        }

        // bitwise and
        impl<T: ::std::ops::BitAnd<Output = T>> ::std::ops::BitAnd for $ident<T> {
            type Output = Self;

            fn bitand(self, rhs: Self) -> Self::Output { $ident(self.0 & rhs.0) }
        }

        // bitwise or
        impl<T: ::std::ops::BitOr<Output = T>> ::std::ops::BitOr for $ident<T> {
            type Output = Self;

            fn bitor(self, rhs: Self) -> Self::Output { $ident(self.0 | rhs.0) }
        }

        // bitwise xor
        impl<T: ::std::ops::BitXor<Output = T>> ::std::ops::BitXor for $ident<T> {
            type Output = Self;

            fn bitxor(self, rhs: Self) -> Self::Output { $ident(self.0 ^ rhs.0) }
        }

        // shift left
        impl<T: ::std::ops::Shl<usize>> ::std::ops::Shl<usize> for $ident<T> {
            type Output = $ident<T::Output>;

            fn shl(self, rhs: usize) -> Self::Output { $ident(self.0 << rhs) }
        }

        // shift right
        impl<T: ::std::ops::Shr<usize>> ::std::ops::Shr<usize> for $ident<T> {
            type Output = $ident<T::Output>;

            fn shr(self, rhs: usize) -> Self::Output { $ident(self.0 >> rhs) }
        }
    };

    (impl_std_cmp, $ident:ident ) => {
        // partial equality
        impl<T: ::std::cmp::PartialEq> ::std::cmp::PartialEq for $ident<T> {
            fn eq(&self, _rhs: &Self) -> bool {
                self.0 == _rhs.0
            }
        }

        // equality
        impl<T: ::std::cmp::Eq> ::std::cmp::Eq for $ident<T> {}

        // partial ordering
        impl<T: ::std::cmp::PartialOrd> ::std::cmp::PartialOrd for $ident<T> {
            fn partial_cmp(&self, other: &Self) -> Option<::std::cmp::Ordering> {
                if self.0 < other.0 {
                    Some(::std::cmp::Ordering::Less)
                } else if self.0 > other.0 {
                    Some(::std::cmp::Ordering::Greater)
                } else if self == other {
                    Some(::std::cmp::Ordering::Equal)
                } else {
                    None
                }
            }
        }

        // total ordering
        impl<T: ::std::cmp::Ord> ::std::cmp::Ord for $ident<T> {
            fn cmp(&self, other: &Self) -> ::std::cmp::Ordering {
                if self.0 < other.0 {
                    ::std::cmp::Ordering::Less
                } else if self.0 > other.0 {
                    ::std::cmp::Ordering::Greater
                } else {
                    ::std::cmp::Ordering::Equal
                }
            }
        }
    };

    (impl_num_traits, $ident:ident ) => {
        impl<T: $crate::num_export::traits::Zero> $crate::num_export::traits::Zero for $ident<T> {
            fn zero() -> Self { $ident(T::zero()) }
            fn is_zero(&self) -> bool { self.0.is_zero() }
        }

        impl<T: $crate::num_export::traits::One> $crate::num_export::traits::One for $ident<T> {
            fn one() -> Self { $ident(T::one()) }
        }

        impl<T: $crate::num_export::traits::Num> $crate::num_export::traits::Num for $ident<T> {
            type FromStrRadixErr = T::FromStrRadixErr;
            fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr> {
                match T::from_str_radix(str, radix) {
                    Ok(x) => { Ok($ident(x)) }
                    Err(e) => { Err(e) }
                }
            }
        }

        impl<T: $crate::num_export::traits::ToPrimitive> $crate::num_export::traits::ToPrimitive for $ident<T> {
            fn to_i64(&self) -> Option<i64> { self.0.to_i64() }
            fn to_u64(&self) -> Option<u64> { self.0.to_u64() }
            fn to_isize(&self) -> Option<isize> { self.0.to_isize() }
            fn to_i8(&self) -> Option<i8> { self.0.to_i8() }
            fn to_i16(&self) -> Option<i16> { self.0.to_i16() }
            fn to_i32(&self) -> Option<i32> { self.0.to_i32() }
            fn to_usize(&self) -> Option<usize> { self.0.to_usize() }
            fn to_u8(&self) -> Option<u8> { self.0.to_u8() }
            fn to_u16(&self) -> Option<u16> { self.0.to_u16() }
            fn to_u32(&self) -> Option<u32> { self.0.to_u32() }
            fn to_f32(&self) -> Option<f32> { self.0.to_f32() }
            fn to_f64(&self) -> Option<f64> { self.0.to_f64() }
        }

        impl<T: $crate::num_export::traits::NumCast> $crate::num_export::traits::NumCast for $ident<T> {
            fn from<X: $crate::num_export::traits::ToPrimitive>(n: X) -> Option<Self> {
                match T::from(n) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }

        impl<T: $crate::num_export::traits::Bounded> $crate::num_export::traits::Bounded for $ident<T> {
            fn min_value() -> Self { $ident(T::min_value()) }
            fn max_value() -> Self { $ident(T::max_value()) }
        }

        // checked addition
        impl<T: $crate::num_export::traits::CheckedAdd<Output = T>> $crate::num_export::traits::CheckedAdd for $ident<T> {
            fn checked_add(&self, _rhs: &Self) -> Option<Self> {
                match self.0.checked_add(&_rhs.0) {
                    Some(x) => { Some($ident(x)) }
                    None => { None }
                }
            }
        }
    };
}
<|endoftext|>


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

//use std;
use std::{fmt, error};

pub mod ctl_op {
    /// Register the target file descriptor fd on the epoll instance
    /// referred to by the file descriptor epfd and associate the
    /// event with the internal file linked to fd.
    pub const ADD: u32 = 1;
    /// Change the event event associated with the target file descriptor fd.
    pub const MOD: u32 = 2;
    /// Remove (deregister) the target file descriptor fd from the epoll
    /// instance referred to by epfd. The event is ignored and can be NULL.
    pub const DEL: u32 = 3;
}

pub mod event_type {
    /// The associated file is available for read(2) operations.
    pub const EPOLLIN:          u32 = 0x001;
    /// The associated file is available for write(2) operations.
    pub const EPOLLOUT:         u32 = 0x004;
    /// Stream socket peer closed connection, or shut down writing
    /// half of connection.
    pub const EPOLLRDHUP:       u32 = 0x2000;
    /// There is urgent data available for read(2) operations.
    pub const EPOLLPRI:         u32 = 0x002;
    /// Error condition happened on the associated file descriptor.
    /// epoll_wait(2) will always wait for this event; it is not
    /// necessary to set it in events.
    pub const EPOLLERR:         u32 = 0x008;
    /// Hang up happened on the associated file descriptor. epoll_wait(2)
    /// will always wait for this event; it is not necessary to set it
    /// in events.
    pub const EPOLLHUP:         u32 = 0x010;
    /// Sets the Edge Triggered behavior for the associated file descriptor.
    /// The default behavior for epoll is Level Triggered.
    pub const EPOLLET:          u32 = (1 << 31);
    /// Sets the one-shot behavior for the associated file descriptor.
    /// This means that after an event is pulled out with epoll_wait(2)
    /// the associated file descriptor is internally disabled and no other
    /// events will be reported by the epoll interface. The user must call
    /// epoll_ctl() with EPOLL_CTL_MOD to rearm the file descriptor with a
    /// new event mask.
    pub const EPOLLONESHOT:     u32 = (1 << 30);
}

#[derive(Debug, Clone)]
pub enum CreateError {
    /// Invalid value specified in flags.
    EINVAL,
    /// The per-user limit on the number of epoll instances
    /// imposed by /proc/sys/fs/epoll/max_user_instances was encountered.
    EMFILE,
    /// The system limit on the total number of open files has been reached.
    ENFILE,
    /// There was insufficient memory to create the kernel object.
    ENOMEM
}

#[derive(Debug, Clone)]
pub enum CtlError {
    /// fd is not a valid file descriptor.
    EBADF,
    /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already
    /// registered with this epoll instance.
    EEXIST,
    /// epfd is not an epoll file descriptor, or fd is the same as epfd,
    /// or the requested operation op is not supported by this interface.
    EINVAL,
    /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered
    /// with this epoll instance.
    ENOENT,
    /// There was insufficient memory to handle the requested op control
    /// operation.
    ENOSPC,
    /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was
    /// encountered while trying to register (EPOLL_CTL_ADD) a new
    /// file descriptor on an epoll instance.
    EPERM
}

#[derive(Debug, Clone)]
pub enum WaitError {
    /// epfd is not a valid file descriptor.
    EBADF,
    /// The memory area pointed to by events is not accessible
    /// with write permissions.
    EFAULT,
    /// The call was interrupted by a signal handler before
    /// either any of the requested events occurred or the timeout expired.
    EINTR,
    /// epfd is not an epoll file descriptor, or maxevents is less than
    /// or equal to zero.
    EINVAL
}

impl error::Error for CreateError {
    fn description(&self) -> &str {
        match *self {
            CreateError::EINVAL => "Invalid flags",
            CreateError::EMFILE => "/proc/sys/fs/epoll/max_user_instances limit reached",
            CreateError::ENFILE => "NOFILE limit has been reached",
            CreateError::ENOMEM => "Insufficient memory"
        }
    }
}

impl error::Error for CtlError {
    fn description(&self) -> &str {
        match *self {
            CtlError::EBADF => "Invalid file descriptor",
            CtlError::EEXIST => "File descriptor already registered",
            CtlError::EINVAL => "epoll_fd is not an epoll file descriptor",
            CtlError::ENOENT => "File descriptor not registered",
            CtlError::ENOSPC => "Insufficient memory",
            CtlError::EPERM => "/proc/sys/fs/epoll/max_user_watches limit reached"
        }
    }
}

impl error::Error for WaitError {
    fn description(&self) -> &str {
        match *self {
            WaitError::EBADF => "Invalid file descriptor",
            WaitError::EFAULT => "Memory pointed to by events is not accessible with write permissions",
            WaitError::EINTR => "Interrupted by a signal before any requested events occurred or timeout expired",
            WaitError::EINVAL => "epoll_fd not an epoll file descriptor, or maxevents is less than or equal to zero."
        }
    }
}

impl fmt::Display for CreateError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CreateError::EINVAL => "EINVAL".fmt(f),
            CreateError::EMFILE => "EMFILE".fmt(f),
            CreateError::ENFILE => "ENFILE".fmt(f),
            CreateError::ENOMEM => "ENOMEM".fmt(f)
        }
    }
}

impl fmt::Display for CtlError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CtlError::EBADF => "EBADF".fmt(f),
            CtlError::EEXIST => "EEXIST".fmt(f),
            CtlError::EINVAL => "EINVAL".fmt(f),
            CtlError::ENOENT => "ENOENT".fmt(f),
            CtlError::ENOSPC => "ENOSPC".fmt(f),
            CtlError::EPERM => "EPERM".fmt(f)
        }
    }
}

impl fmt::Display for WaitError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            WaitError::EBADF => "EBADF".fmt(f),
            WaitError::EFAULT => "EFAULT".fmt(f),
            WaitError::EINTR => "EINTR".fmt(f),
            WaitError::EINVAL => "EINVAL".fmt(f)
        }
    }
}
<commit_msg>PartialEq and Eq added to Error types<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.

//use std;
use std::{fmt, error};

pub mod ctl_op {
    /// Register the target file descriptor fd on the epoll instance
    /// referred to by the file descriptor epfd and associate the
    /// event with the internal file linked to fd.
    pub const ADD: u32 = 1;
    /// Change the event event associated with the target file descriptor fd.
    pub const MOD: u32 = 2;
    /// Remove (deregister) the target file descriptor fd from the epoll
    /// instance referred to by epfd. The event is ignored and can be NULL.
    pub const DEL: u32 = 3;
}

pub mod event_type {
    /// The associated file is available for read(2) operations.
    pub const EPOLLIN:          u32 = 0x001;
    /// The associated file is available for write(2) operations.
    pub const EPOLLOUT:         u32 = 0x004;
    /// Stream socket peer closed connection, or shut down writing
    /// half of connection.
    pub const EPOLLRDHUP:       u32 = 0x2000;
    /// There is urgent data available for read(2) operations.
    pub const EPOLLPRI:         u32 = 0x002;
    /// Error condition happened on the associated file descriptor.
    /// epoll_wait(2) will always wait for this event; it is not
    /// necessary to set it in events.
    pub const EPOLLERR:         u32 = 0x008;
    /// Hang up happened on the associated file descriptor. epoll_wait(2)
    /// will always wait for this event; it is not necessary to set it
    /// in events.
    pub const EPOLLHUP:         u32 = 0x010;
    /// Sets the Edge Triggered behavior for the associated file descriptor.
    /// The default behavior for epoll is Level Triggered.
    pub const EPOLLET:          u32 = (1 << 31);
    /// Sets the one-shot behavior for the associated file descriptor.
    /// This means that after an event is pulled out with epoll_wait(2)
    /// the associated file descriptor is internally disabled and no other
    /// events will be reported by the epoll interface. The user must call
    /// epoll_ctl() with EPOLL_CTL_MOD to rearm the file descriptor with a
    /// new event mask.
    pub const EPOLLONESHOT:     u32 = (1 << 30);
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CreateError {
    /// Invalid value specified in flags.
    EINVAL,
    /// The per-user limit on the number of epoll instances
    /// imposed by /proc/sys/fs/epoll/max_user_instances was encountered.
    EMFILE,
    /// The system limit on the total number of open files has been reached.
    ENFILE,
    /// There was insufficient memory to create the kernel object.
    ENOMEM
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum CtlError {
    /// fd is not a valid file descriptor.
    EBADF,
    /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already
    /// registered with this epoll instance.
    EEXIST,
    /// epfd is not an epoll file descriptor, or fd is the same as epfd,
    /// or the requested operation op is not supported by this interface.
    EINVAL,
    /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered
    /// with this epoll instance.
    ENOENT,
    /// There was insufficient memory to handle the requested op control
    /// operation.
    ENOSPC,
    /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was
    /// encountered while trying to register (EPOLL_CTL_ADD) a new
    /// file descriptor on an epoll instance.
    EPERM
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum WaitError {
    /// epfd is not a valid file descriptor.
    EBADF,
    /// The memory area pointed to by events is not accessible
    /// with write permissions.
    EFAULT,
    /// The call was interrupted by a signal handler before
    /// either any of the requested events occurred or the timeout expired.
    EINTR,
    /// epfd is not an epoll file descriptor, or maxevents is less than
    /// or equal to zero.
    EINVAL
}

impl error::Error for CreateError {
    fn description(&self) -> &str {
        match *self {
            CreateError::EINVAL => "Invalid flags",
            CreateError::EMFILE => "/proc/sys/fs/epoll/max_user_instances limit reached",
            CreateError::ENFILE => "NOFILE limit has been reached",
            CreateError::ENOMEM => "Insufficient memory"
        }
    }
}

impl error::Error for CtlError {
    fn description(&self) -> &str {
        match *self {
            CtlError::EBADF => "Invalid file descriptor",
            CtlError::EEXIST => "File descriptor already registered",
            CtlError::EINVAL => "epoll_fd is not an epoll file descriptor",
            CtlError::ENOENT => "File descriptor not registered",
            CtlError::ENOSPC => "Insufficient memory",
            CtlError::EPERM => "/proc/sys/fs/epoll/max_user_watches limit reached"
        }
    }
}

impl error::Error for WaitError {
    fn description(&self) -> &str {
        match *self {
            WaitError::EBADF => "Invalid file descriptor",
            WaitError::EFAULT => "Memory pointed to by events is not accessible with write permissions",
            WaitError::EINTR => "Interrupted by a signal before any requested events occurred or timeout expired",
            WaitError::EINVAL => "epoll_fd not an epoll file descriptor, or maxevents is less than or equal to zero."
        }
    }
}

impl fmt::Display for CreateError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CreateError::EINVAL => "EINVAL".fmt(f),
            CreateError::EMFILE => "EMFILE".fmt(f),
            CreateError::ENFILE => "ENFILE".fmt(f),
            CreateError::ENOMEM => "ENOMEM".fmt(f)
        }
    }
}

impl fmt::Display for CtlError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CtlError::EBADF => "EBADF".fmt(f),
            CtlError::EEXIST => "EEXIST".fmt(f),
            CtlError::EINVAL => "EINVAL".fmt(f),
            CtlError::ENOENT => "ENOENT".fmt(f),
            CtlError::ENOSPC => "ENOSPC".fmt(f),
            CtlError::EPERM => "EPERM".fmt(f)
        }
    }
}

impl fmt::Display for WaitError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            WaitError::EBADF => "EBADF".fmt(f),
            WaitError::EFAULT => "EFAULT".fmt(f),
            WaitError::EINTR => "EINTR".fmt(f),
            WaitError::EINVAL => "EINVAL".fmt(f)
        }
    }
}
<|endoftext|>