<commit_before>//! Gaussian Mixture Models
//!
//! Provides implementation of GMMs using the EM algorithm.
//!
//! # Usage
//!
//! ```
//! use rusty_machine::linalg::matrix::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, 2.0, 4.0, 5.0, 2.5]);
//! let test_inputs = Matrix::new(3, 2, vec![1.0, 2.0, 3.0, 2.9, 2.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);
//!
//! // Where pred_data is a Matrix with features in columns.
//! let a = model.predict(&test_inputs);
//! println!("{:?}", a.data());
//! ```

use linalg::vector::Vector;
use linalg::matrix::Matrix;
use linalg::utils;

use learning::UnSupModel;
use learning::toolkit::rand_utils;

/// 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>) {
        // Initialization:
        let k = self.comp_count;

        // TODO: Compute sample covariance of the data.
        // https://en.wikipedia.org/wiki/Sample_mean_and_covariance#Sample_covariance
        let mut cov_vec = Vec::with_capacity(k);
        for _ in 0..k {
            cov_vec.push(Matrix::identity(inputs.cols()));
        }

        self.model_covars = Some(cov_vec);

        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);
        }
    }

    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> Matrix<f64> {
        if let (&Some(_), &Some(_)) = (&self.model_means, &self.model_covars) {
            self.membership_weights(inputs).0
        } else {
            panic!("Model has not been trained.");
        }

    }
}

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,
        }
    }

    /// The model means
    ///
    /// Returns a reference to the Option<Matrix<f64>>
    /// which contains the model means. Each row represents
    /// the mean of one of the Gaussians.
    pub fn means(&self) -> &Option<Matrix<f64>> {
        &self.model_means
    }

    /// The model covariances
    ///
    /// Returns a reference to the Option<Vec<Matrix<f64>>>
    /// which contains 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
    }

    /// 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();

                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 = inputs.select_rows(&[i]);

                for j in 0..self.comp_count {
                    let mu_j = means.select_rows(&[j]);
                    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 (idx, mean) in new_means.mut_data().chunks_mut(d).enumerate() {
            for m in mean {
                *m = *m / sum_weights[idx];
            }
        }

        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);

            for i in 0..n {
                let diff = inputs.select_rows(&[i]) - new_means.select_rows(&[k]);
                cov_mat = 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()),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::GaussianMixtureModel;
    #[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);
    }
}<commit_msg>Fixing diagonal cov option bug. Adding gmm constructor (#79)<commit_after>//! Gaussian Mixture Models
//!
//! Provides implementation of GMMs using the EM algorithm.
//!
//! # Usage
//!
//! ```
//! use rusty_machine::linalg::matrix::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);
//!
//! // 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);
//!
//! // Probabilities that each point comes from each Gaussian.
//! println!("{:?}", post_probs.data());
//! ```

use linalg::vector::Vector;
use linalg::matrix::Matrix;
use linalg::utils;

use learning::UnSupModel;
use learning::toolkit::rand_utils;

/// 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>) {
        // Initialization:
        let k = self.comp_count;

        // TODO: Compute sample covariance of the data.
        // https://en.wikipedia.org/wiki/Sample_mean_and_covariance#Sample_covariance
        let mut cov_vec = Vec::with_capacity(k);
        for _ in 0..k {
            cov_vec.push(Matrix::identity(inputs.cols()));
        }

        self.model_covars = Some(cov_vec);

        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);
        }
    }

    /// Predict output from inputs.
    fn predict(&self, inputs: &Matrix<f64>) -> Matrix<f64> {
        if let (&Some(_), &Some(_)) = (&self.model_means, &self.model_covars) {
            self.membership_weights(inputs).0
        } else {
            panic!("Model has not been trained.");
        }

    }
}

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::Vector;
    ///
    /// let mix_weights = Vector::new(vec![0.25, 0.25, 0.5]);
    ///
    /// let _ = GaussianMixtureModel::with_weights(3, mix_weights);
    /// ```
    ///
    /// # Panics
    ///
    /// Panics 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>) -> GaussianMixtureModel {
        assert!(mixture_weights.size() == k,
                "Mixture weights must have length k.");
        assert!(!mixture_weights.data().iter().any(|&x| x < 0f64),
                "Mixture weights must have only non-negative entries.");

        let sum = mixture_weights.sum();
        let normalized_weights = mixture_weights / sum;

        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 a reference to the Option<Matrix<f64>>
    /// which contains the model means. Each row represents
    /// the mean of one of the Gaussians.
    pub fn means(&self) -> &Option<Matrix<f64>> {
        &self.model_means
    }

    /// The model covariances
    ///
    /// Returns a reference to the Option<Vec<Matrix<f64>>>
    /// which contains 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
    }

    /// 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();

                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 = inputs.select_rows(&[i]);

                for j in 0..self.comp_count {
                    let mu_j = means.select_rows(&[j]);
                    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 (idx, mean) in new_means.mut_data().chunks_mut(d).enumerate() {
            for m in mean {
                *m = *m / sum_weights[idx];
            }
        }

        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);

            for i in 0..n {
                let diff = inputs.select_rows(&[i]) - new_means.select_rows(&[k]);
                cov_mat = 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;
    #[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]
    #[should_panic]
    fn test_negative_mixtures() {
        use linalg::vector::Vector;

        let mix_weights = Vector::new(vec![-0.25, 0.75, 0.5]);
        let _ = GaussianMixtureModel::with_weights(3, mix_weights);
    }

    #[test]
    #[should_panic]
    fn test_wrong_length_mixtures() {
        use linalg::vector::Vector;

        let mix_weights = Vector::new(vec![0.1, 0.25, 0.75, 0.5]);
        let _ = GaussianMixtureModel::with_weights(3, mix_weights);
    }
}
<|endoftext|>


<commit_before>//! Patterns telling us certain facts about current syntax element, they are used in completion context

use syntax::{
    algo::non_trivia_sibling,
    ast::{self, LoopBodyOwner},
    match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
    SyntaxKind::*,
    SyntaxNode, SyntaxToken,
};

#[cfg(test)]
use crate::completion::test_utils::check_pattern_is_applicable;

pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element)
        .filter(|it| it.kind() == ASSOC_ITEM_LIST)
        .and_then(|it| it.parent())
        .filter(|it| it.kind() == TRAIT)
        .is_some()
}
#[test]
fn test_has_trait_parent() {
    check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent);
}

pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element)
        .filter(|it| it.kind() == ASSOC_ITEM_LIST)
        .and_then(|it| it.parent())
        .filter(|it| it.kind() == IMPL)
        .is_some()
}
#[test]
fn test_has_impl_parent() {
    check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
}
pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element).filter(|it| it.kind() == RECORD_FIELD_LIST).is_some()
}
#[test]
fn test_has_field_list_parent() {
    check_pattern_is_applicable(r"struct Foo { f<|> }", has_field_list_parent);
    check_pattern_is_applicable(r"struct Foo { f<|> pub f: i32}", has_field_list_parent);
}

pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
}
#[test]
fn test_has_block_expr_parent() {
    check_pattern_is_applicable(r"fn my_fn() { let a = 2; f<|> }", has_block_expr_parent);
}

pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
    element.ancestors().find(|it| it.kind() == IDENT_PAT).is_some()
}
#[test]
fn test_has_bind_pat_parent() {
    check_pattern_is_applicable(r"fn my_fn(m<|>) {}", has_bind_pat_parent);
    check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent);
}

pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element)
        .filter(|it| it.kind() == REF_PAT || it.kind() == REF_EXPR)
        .is_some()
}
#[test]
fn test_has_ref_parent() {
    check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent);
    check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent);
}

pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
    let ancestor = not_same_range_ancestor(element);
    if !ancestor.is_some() {
        return true;
    }
    ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some()
}
#[test]
fn test_has_item_list_or_source_file_parent() {
    check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent);
    check_pattern_is_applicable(r"mod foo { f<|> }", has_item_list_or_source_file_parent);
}

pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some()
        && previous_sibling_or_ancestor_sibling(element)
            .and_then(|it| it.into_token())
            .filter(|it| it.kind() == FAT_ARROW)
            .is_some()
}
#[test]
fn test_is_match_arm() {
    check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm);
}

pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
    element
        .into_token()
        .and_then(|it| previous_non_trivia_token(it))
        .filter(|it| it.kind() == UNSAFE_KW)
        .is_some()
}
#[test]
fn test_unsafe_is_prev() {
    check_pattern_is_applicable(r"unsafe i<|>", unsafe_is_prev);
}

pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
    element
        .into_token()
        .and_then(|it| previous_non_trivia_token(it))
        .filter(|it| it.kind() == IF_KW)
        .is_some()
}

pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool {
    element
        .into_token()
        .and_then(|it| previous_non_trivia_token(it))
        .filter(|it| it.kind() == FN_KW)
        .is_some()
}

/// Check if the token previous to the previous one is `for`.
/// For example, `for _ i<|>` => true.
pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool {
    element
        .into_token()
        .and_then(|it| previous_non_trivia_token(it))
        .and_then(|it| previous_non_trivia_token(it))
        .filter(|it| it.kind() == FOR_KW)
        .is_some()
}

#[test]
fn test_if_is_prev() {
    check_pattern_is_applicable(r"if l<|>", if_is_prev);
}

pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
    previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some()
}
#[test]
fn test_has_trait_as_prev_sibling() {
    check_pattern_is_applicable(r"trait A w<|> {}", has_trait_as_prev_sibling);
}

pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
    previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL).is_some()
}
#[test]
fn test_has_impl_as_prev_sibling() {
    check_pattern_is_applicable(r"impl A w<|> {}", has_impl_as_prev_sibling);
}

pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
    let leaf = match element {
        NodeOrToken::Node(node) => node,
        NodeOrToken::Token(token) => token.parent(),
    };
    for node in leaf.ancestors() {
        if node.kind() == FN || node.kind() == CLOSURE_EXPR {
            break;
        }
        let loop_body = match_ast! {
            match node {
                ast::ForExpr(it) => it.loop_body(),
                ast::WhileExpr(it) => it.loop_body(),
                ast::LoopExpr(it) => it.loop_body(),
                _ => None,
            }
        };
        if let Some(body) = loop_body {
            if body.syntax().text_range().contains_range(leaf.text_range()) {
                return true;
            }
        }
    }
    false
}

fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {
    element
        .ancestors()
        .take_while(|it| it.text_range() == element.text_range())
        .last()
        .and_then(|it| it.parent())
}

fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
    let mut token = token.prev_token();
    while let Some(inner) = token.clone() {
        if !inner.kind().is_trivia() {
            return Some(inner);
        } else {
            token = inner.prev_token();
        }
    }
    None
}

fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<SyntaxElement> {
    let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev);
    if let Some(sibling) = token_sibling {
        Some(sibling)
    } else {
        // if not trying to find first ancestor which has such a sibling
        let node = match element {
            NodeOrToken::Node(node) => node,
            NodeOrToken::Token(token) => token.parent(),
        };
        let range = node.text_range();
        let top_node = node.ancestors().take_while(|it| it.text_range() == range).last()?;
        let prev_sibling_node = top_node.ancestors().find(|it| {
            non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some()
        })?;
        non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
    }
}
<commit_msg>Add test for new pattern functions<commit_after>//! Patterns telling us certain facts about current syntax element, they are used in completion context

use syntax::{
    algo::non_trivia_sibling,
    ast::{self, LoopBodyOwner},
    match_ast, AstNode, Direction, NodeOrToken, SyntaxElement,
    SyntaxKind::*,
    SyntaxNode, SyntaxToken,
};

#[cfg(test)]
use crate::completion::test_utils::check_pattern_is_applicable;

pub(crate) fn has_trait_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element)
        .filter(|it| it.kind() == ASSOC_ITEM_LIST)
        .and_then(|it| it.parent())
        .filter(|it| it.kind() == TRAIT)
        .is_some()
}
#[test]
fn test_has_trait_parent() {
    check_pattern_is_applicable(r"trait A { f<|> }", has_trait_parent);
}

pub(crate) fn has_impl_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element)
        .filter(|it| it.kind() == ASSOC_ITEM_LIST)
        .and_then(|it| it.parent())
        .filter(|it| it.kind() == IMPL)
        .is_some()
}
#[test]
fn test_has_impl_parent() {
    check_pattern_is_applicable(r"impl A { f<|> }", has_impl_parent);
}
pub(crate) fn has_field_list_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element).filter(|it| it.kind() == RECORD_FIELD_LIST).is_some()
}
#[test]
fn test_has_field_list_parent() {
    check_pattern_is_applicable(r"struct Foo { f<|> }", has_field_list_parent);
    check_pattern_is_applicable(r"struct Foo { f<|> pub f: i32}", has_field_list_parent);
}

pub(crate) fn has_block_expr_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element).filter(|it| it.kind() == BLOCK_EXPR).is_some()
}
#[test]
fn test_has_block_expr_parent() {
    check_pattern_is_applicable(r"fn my_fn() { let a = 2; f<|> }", has_block_expr_parent);
}

pub(crate) fn has_bind_pat_parent(element: SyntaxElement) -> bool {
    element.ancestors().find(|it| it.kind() == IDENT_PAT).is_some()
}
#[test]
fn test_has_bind_pat_parent() {
    check_pattern_is_applicable(r"fn my_fn(m<|>) {}", has_bind_pat_parent);
    check_pattern_is_applicable(r"fn my_fn() { let m<|> }", has_bind_pat_parent);
}

pub(crate) fn has_ref_parent(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element)
        .filter(|it| it.kind() == REF_PAT || it.kind() == REF_EXPR)
        .is_some()
}
#[test]
fn test_has_ref_parent() {
    check_pattern_is_applicable(r"fn my_fn(&m<|>) {}", has_ref_parent);
    check_pattern_is_applicable(r"fn my() { let &m<|> }", has_ref_parent);
}

pub(crate) fn has_item_list_or_source_file_parent(element: SyntaxElement) -> bool {
    let ancestor = not_same_range_ancestor(element);
    if !ancestor.is_some() {
        return true;
    }
    ancestor.filter(|it| it.kind() == SOURCE_FILE || it.kind() == ITEM_LIST).is_some()
}
#[test]
fn test_has_item_list_or_source_file_parent() {
    check_pattern_is_applicable(r"i<|>", has_item_list_or_source_file_parent);
    check_pattern_is_applicable(r"mod foo { f<|> }", has_item_list_or_source_file_parent);
}

pub(crate) fn is_match_arm(element: SyntaxElement) -> bool {
    not_same_range_ancestor(element.clone()).filter(|it| it.kind() == MATCH_ARM).is_some()
        && previous_sibling_or_ancestor_sibling(element)
            .and_then(|it| it.into_token())
            .filter(|it| it.kind() == FAT_ARROW)
            .is_some()
}
#[test]
fn test_is_match_arm() {
    check_pattern_is_applicable(r"fn my_fn() { match () { () => m<|> } }", is_match_arm);
}

pub(crate) fn unsafe_is_prev(element: SyntaxElement) -> bool {
    element
        .into_token()
        .and_then(|it| previous_non_trivia_token(it))
        .filter(|it| it.kind() == UNSAFE_KW)
        .is_some()
}
#[test]
fn test_unsafe_is_prev() {
    check_pattern_is_applicable(r"unsafe i<|>", unsafe_is_prev);
}

pub(crate) fn if_is_prev(element: SyntaxElement) -> bool {
    element
        .into_token()
        .and_then(|it| previous_non_trivia_token(it))
        .filter(|it| it.kind() == IF_KW)
        .is_some()
}

pub(crate) fn fn_is_prev(element: SyntaxElement) -> bool {
    element
        .into_token()
        .and_then(|it| previous_non_trivia_token(it))
        .filter(|it| it.kind() == FN_KW)
        .is_some()
}
#[test]
fn test_fn_is_prev() {
    check_pattern_is_applicable(r"fn l<|>", fn_is_prev);
}

/// Check if the token previous to the previous one is `for`.
/// For example, `for _ i<|>` => true.
pub(crate) fn for_is_prev2(element: SyntaxElement) -> bool {
    element
        .into_token()
        .and_then(|it| previous_non_trivia_token(it))
        .and_then(|it| previous_non_trivia_token(it))
        .filter(|it| it.kind() == FOR_KW)
        .is_some()
}
#[test]
fn test_for_is_prev2() {
    check_pattern_is_applicable(r"for i i<|>", for_is_prev2);
}

#[test]
fn test_if_is_prev() {
    check_pattern_is_applicable(r"if l<|>", if_is_prev);
}

pub(crate) fn has_trait_as_prev_sibling(element: SyntaxElement) -> bool {
    previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == TRAIT).is_some()
}
#[test]
fn test_has_trait_as_prev_sibling() {
    check_pattern_is_applicable(r"trait A w<|> {}", has_trait_as_prev_sibling);
}

pub(crate) fn has_impl_as_prev_sibling(element: SyntaxElement) -> bool {
    previous_sibling_or_ancestor_sibling(element).filter(|it| it.kind() == IMPL).is_some()
}
#[test]
fn test_has_impl_as_prev_sibling() {
    check_pattern_is_applicable(r"impl A w<|> {}", has_impl_as_prev_sibling);
}

pub(crate) fn is_in_loop_body(element: SyntaxElement) -> bool {
    let leaf = match element {
        NodeOrToken::Node(node) => node,
        NodeOrToken::Token(token) => token.parent(),
    };
    for node in leaf.ancestors() {
        if node.kind() == FN || node.kind() == CLOSURE_EXPR {
            break;
        }
        let loop_body = match_ast! {
            match node {
                ast::ForExpr(it) => it.loop_body(),
                ast::WhileExpr(it) => it.loop_body(),
                ast::LoopExpr(it) => it.loop_body(),
                _ => None,
            }
        };
        if let Some(body) = loop_body {
            if body.syntax().text_range().contains_range(leaf.text_range()) {
                return true;
            }
        }
    }
    false
}

fn not_same_range_ancestor(element: SyntaxElement) -> Option<SyntaxNode> {
    element
        .ancestors()
        .take_while(|it| it.text_range() == element.text_range())
        .last()
        .and_then(|it| it.parent())
}

fn previous_non_trivia_token(token: SyntaxToken) -> Option<SyntaxToken> {
    let mut token = token.prev_token();
    while let Some(inner) = token.clone() {
        if !inner.kind().is_trivia() {
            return Some(inner);
        } else {
            token = inner.prev_token();
        }
    }
    None
}

fn previous_sibling_or_ancestor_sibling(element: SyntaxElement) -> Option<SyntaxElement> {
    let token_sibling = non_trivia_sibling(element.clone(), Direction::Prev);
    if let Some(sibling) = token_sibling {
        Some(sibling)
    } else {
        // if not trying to find first ancestor which has such a sibling
        let node = match element {
            NodeOrToken::Node(node) => node,
            NodeOrToken::Token(token) => token.parent(),
        };
        let range = node.text_range();
        let top_node = node.ancestors().take_while(|it| it.text_range() == range).last()?;
        let prev_sibling_node = top_node.ancestors().find(|it| {
            non_trivia_sibling(NodeOrToken::Node(it.to_owned()), Direction::Prev).is_some()
        })?;
        non_trivia_sibling(NodeOrToken::Node(prev_sibling_node), Direction::Prev)
    }
}
<|endoftext|>


<commit_before>//! Caches run-time feature detection so that it only needs to be computed
//! once.

#![allow(dead_code)] // not used on all platforms

use core::sync::atomic::Ordering;

#[cfg(target_pointer_width = "64")]
use core::sync::atomic::AtomicU64;

#[cfg(target_pointer_width = "32")]
use core::sync::atomic::AtomicU32;

/// Sets the `bit` of `x`.
#[inline]
const fn set_bit(x: u64, bit: u32) -> u64 {
    x | 1 << bit
}

/// Tests the `bit` of `x`.
#[inline]
const fn test_bit(x: u64, bit: u32) -> bool {
    x & (1 << bit) != 0
}

/// Maximum number of features that can be cached.
const CACHE_CAPACITY: u32 = 63;

/// This type is used to initialize the cache
#[derive(Copy, Clone)]
pub(crate) struct Initializer(u64);

#[cfg_attr(feature = "cargo-clippy", allow(clippy::use_self))]
impl Default for Initializer {
    fn default() -> Self {
        Initializer(0)
    }
}

impl Initializer {
    /// Tests the `bit` of the cache.
    #[allow(dead_code)]
    #[inline]
    pub(crate) fn test(self, bit: u32) -> bool {
        // FIXME: this way of making sure that the cache is large enough is
        // brittle.
        debug_assert!(
            bit < CACHE_CAPACITY,
            "too many features, time to increase the cache size!"
        );
        test_bit(self.0, bit)
    }

    /// Sets the `bit` of the cache.
    #[inline]
    pub(crate) fn set(&mut self, bit: u32) {
        // FIXME: this way of making sure that the cache is large enough is
        // brittle.
        debug_assert!(
            bit < CACHE_CAPACITY,
            "too many features, time to increase the cache size!"
        );
        let v = self.0;
        self.0 = set_bit(v, bit);
    }
}

/// This global variable is a cache of the features supported by the CPU.
static CACHE: Cache = Cache::uninitialized();

/// Feature cache with capacity for `CACHE_CAPACITY` features.
///
/// Note: the last feature bit is used to represent an
/// uninitialized cache.
#[cfg(target_pointer_width = "64")]
struct Cache(AtomicU64);

#[cfg(target_pointer_width = "64")]
#[cfg_attr(feature = "cargo-clippy", allow(clippy::use_self))]
impl Cache {
    /// Creates an uninitialized cache.
    #[cfg_attr(
        feature = "cargo-clippy",
        allow(clippy::declare_interior_mutable_const)
    )]
    const fn uninitialized() -> Self {
        const X: AtomicU64 = AtomicU64::new(u64::max_value());
        Cache(X)
    }
    /// Is the cache uninitialized?
    #[inline]
    pub(crate) fn is_uninitialized(&self) -> bool {
        self.0.load(Ordering::Relaxed) == u64::max_value()
    }

    /// Is the `bit` in the cache set?
    #[inline]
    pub(crate) fn test(&self, bit: u32) -> bool {
        test_bit(CACHE.0.load(Ordering::Relaxed), bit)
    }

    /// Initializes the cache.
    #[inline]
    pub(crate) fn initialize(&self, value: Initializer) {
        self.0.store(value.0, Ordering::Relaxed);
    }
}

/// Feature cache with capacity for `CACHE_CAPACITY` features.
///
/// Note: the last feature bit is used to represent an
/// uninitialized cache.
#[cfg(target_pointer_width = "32")]
struct Cache(AtomicU32, AtomicU32);

#[cfg(target_pointer_width = "32")]
impl Cache {
    /// Creates an uninitialized cache.
    const fn uninitialized() -> Self {
        Cache(
            AtomicU32::new(u32::max_value()),
            AtomicU32::new(u32::max_value()),
        )
    }
    /// Is the cache uninitialized?
    #[inline]
    pub(crate) fn is_uninitialized(&self) -> bool {
        self.1.load(Ordering::Relaxed) == u32::max_value()
    }

    /// Is the `bit` in the cache set?
    #[inline]
    pub(crate) fn test(&self, bit: u32) -> bool {
        if bit < 32 {
            test_bit(CACHE.0.load(Ordering::Relaxed) as u64, bit)
        } else {
            test_bit(CACHE.1.load(Ordering::Relaxed) as u64, bit - 32)
        }
    }

    /// Initializes the cache.
    #[inline]
    pub(crate) fn initialize(&self, value: Initializer) {
        let lo: u32 = value.0 as u32;
        let hi: u32 = (value.0 >> 32) as u32;
        self.0.store(lo, Ordering::Relaxed);
        self.1.store(hi, Ordering::Relaxed);
    }
}

/// Test the `bit` of the storage. If the storage has not been initialized,
/// initializes it with the result of `f()`.
///
/// On its first invocation, it detects the CPU features and caches them in the
/// `CACHE` global variable as an `AtomicU64`.
///
/// It uses the `Feature` variant to index into this variable as a bitset. If
/// the bit is set, the feature is enabled, and otherwise it is disabled.
#[inline]
pub(crate) fn test<F>(bit: u32, f: F) -> bool
where
    F: FnOnce() -> Initializer,
{
    if CACHE.is_uninitialized() {
        CACHE.initialize(f());
    }
    CACHE.test(bit)
}
<commit_msg>Remove const workaround in std_detect cache<commit_after>//! Caches run-time feature detection so that it only needs to be computed
//! once.

#![allow(dead_code)] // not used on all platforms

use core::sync::atomic::Ordering;

#[cfg(target_pointer_width = "64")]
use core::sync::atomic::AtomicU64;

#[cfg(target_pointer_width = "32")]
use core::sync::atomic::AtomicU32;

/// Sets the `bit` of `x`.
#[inline]
const fn set_bit(x: u64, bit: u32) -> u64 {
    x | 1 << bit
}

/// Tests the `bit` of `x`.
#[inline]
const fn test_bit(x: u64, bit: u32) -> bool {
    x & (1 << bit) != 0
}

/// Maximum number of features that can be cached.
const CACHE_CAPACITY: u32 = 63;

/// This type is used to initialize the cache
#[derive(Copy, Clone)]
pub(crate) struct Initializer(u64);

#[cfg_attr(feature = "cargo-clippy", allow(clippy::use_self))]
impl Default for Initializer {
    fn default() -> Self {
        Initializer(0)
    }
}

impl Initializer {
    /// Tests the `bit` of the cache.
    #[allow(dead_code)]
    #[inline]
    pub(crate) fn test(self, bit: u32) -> bool {
        // FIXME: this way of making sure that the cache is large enough is
        // brittle.
        debug_assert!(
            bit < CACHE_CAPACITY,
            "too many features, time to increase the cache size!"
        );
        test_bit(self.0, bit)
    }

    /// Sets the `bit` of the cache.
    #[inline]
    pub(crate) fn set(&mut self, bit: u32) {
        // FIXME: this way of making sure that the cache is large enough is
        // brittle.
        debug_assert!(
            bit < CACHE_CAPACITY,
            "too many features, time to increase the cache size!"
        );
        let v = self.0;
        self.0 = set_bit(v, bit);
    }
}

/// This global variable is a cache of the features supported by the CPU.
static CACHE: Cache = Cache::uninitialized();

/// Feature cache with capacity for `CACHE_CAPACITY` features.
///
/// Note: the last feature bit is used to represent an
/// uninitialized cache.
#[cfg(target_pointer_width = "64")]
struct Cache(AtomicU64);

#[cfg(target_pointer_width = "64")]
#[cfg_attr(feature = "cargo-clippy", allow(clippy::use_self))]
impl Cache {
    /// Creates an uninitialized cache.
    #[cfg_attr(
        feature = "cargo-clippy",
        allow(clippy::declare_interior_mutable_const)
    )]
    const fn uninitialized() -> Self {
        Cache(AtomicU64::new(u64::max_value()))
    }
    /// Is the cache uninitialized?
    #[inline]
    pub(crate) fn is_uninitialized(&self) -> bool {
        self.0.load(Ordering::Relaxed) == u64::max_value()
    }

    /// Is the `bit` in the cache set?
    #[inline]
    pub(crate) fn test(&self, bit: u32) -> bool {
        test_bit(CACHE.0.load(Ordering::Relaxed), bit)
    }

    /// Initializes the cache.
    #[inline]
    pub(crate) fn initialize(&self, value: Initializer) {
        self.0.store(value.0, Ordering::Relaxed);
    }
}

/// Feature cache with capacity for `CACHE_CAPACITY` features.
///
/// Note: the last feature bit is used to represent an
/// uninitialized cache.
#[cfg(target_pointer_width = "32")]
struct Cache(AtomicU32, AtomicU32);

#[cfg(target_pointer_width = "32")]
impl Cache {
    /// Creates an uninitialized cache.
    const fn uninitialized() -> Self {
        Cache(
            AtomicU32::new(u32::max_value()),
            AtomicU32::new(u32::max_value()),
        )
    }
    /// Is the cache uninitialized?
    #[inline]
    pub(crate) fn is_uninitialized(&self) -> bool {
        self.1.load(Ordering::Relaxed) == u32::max_value()
    }

    /// Is the `bit` in the cache set?
    #[inline]
    pub(crate) fn test(&self, bit: u32) -> bool {
        if bit < 32 {
            test_bit(CACHE.0.load(Ordering::Relaxed) as u64, bit)
        } else {
            test_bit(CACHE.1.load(Ordering::Relaxed) as u64, bit - 32)
        }
    }

    /// Initializes the cache.
    #[inline]
    pub(crate) fn initialize(&self, value: Initializer) {
        let lo: u32 = value.0 as u32;
        let hi: u32 = (value.0 >> 32) as u32;
        self.0.store(lo, Ordering::Relaxed);
        self.1.store(hi, Ordering::Relaxed);
    }
}

/// Test the `bit` of the storage. If the storage has not been initialized,
/// initializes it with the result of `f()`.
///
/// On its first invocation, it detects the CPU features and caches them in the
/// `CACHE` global variable as an `AtomicU64`.
///
/// It uses the `Feature` variant to index into this variable as a bitset. If
/// the bit is set, the feature is enabled, and otherwise it is disabled.
#[inline]
pub(crate) fn test<F>(bit: u32, f: F) -> bool
where
    F: FnOnce() -> Initializer,
{
    if CACHE.is_uninitialized() {
        CACHE.initialize(f());
    }
    CACHE.test(bit)
}
<|endoftext|>


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

use dom::bindings::utils::{Reflectable, DOMString, ErrorResult};
use dom::element::HTMLFormElementTypeId;
use dom::htmlcollection::HTMLCollection;
use dom::htmlelement::HTMLElement;
use dom::node::{AbstractNode, ElementNodeTypeId, Node, ScriptView};

use js::jsapi::{JSObject, JSContext};

pub struct HTMLFormElement {
    htmlelement: HTMLElement
}

impl HTMLFormElement {
    fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
        let doc = self.htmlelement.element.node.owner_doc.unwrap();
        let win = doc.with_base(|doc| doc.window.unwrap());
        let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
        let scope = win.reflector().get_jsobject();
        (scope, cx)
    }

    pub fn AcceptCharset(&self) -> DOMString {
        None
    }

    pub fn SetAcceptCharset(&mut self, _accept_charset: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Action(&self) -> DOMString {
        None
    }

    pub fn SetAction(&mut self, _action: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Autocomplete(&self) -> DOMString {
        None
    }

    pub fn SetAutocomplete(&mut self, _autocomplete: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Enctype(&self) -> DOMString {
        None
    }

    pub fn SetEnctype(&mut self, _enctype: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Encoding(&self) -> DOMString {
        None
    }

    pub fn SetEncoding(&mut self, _encoding: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Method(&self) -> DOMString {
        None
    }

    pub fn SetMethod(&mut self, _method: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Name(&self) -> DOMString {
        None
    }

    pub fn SetName(&mut self, _name: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn NoValidate(&self) -> bool {
        false
    }

    pub fn SetNoValidate(&mut self, _no_validate: bool) -> ErrorResult {
        Ok(())
    }

    pub fn Target(&self) -> DOMString {
        None
    }

    pub fn SetTarget(&mut self, _target: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Elements(&self) -> @mut HTMLCollection {
        let (scope, cx) = self.get_scope_and_cx();
        HTMLCollection::new(~[], cx, scope)
    }

    pub fn Length(&self) -> i32 {
        0
    }

    pub fn Submit(&self) -> ErrorResult {
        Ok(())
    }

    pub fn Reset(&self) {
    }

    pub fn CheckValidity(&self) -> bool {
        false
    }

    pub fn IndexedGetter(&self, _index: u32, _found: &mut bool) -> AbstractNode<ScriptView> {
        fail!("Not implemented.")
    }
}
<commit_msg>auto merge of #1031 : luisbg/servo/master, r=kmcallister<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::utils::{Reflectable, DOMString, ErrorResult};
use dom::htmlcollection::HTMLCollection;
use dom::htmlelement::HTMLElement;
use dom::node::{AbstractNode, ScriptView};

use js::jsapi::{JSObject, JSContext};

pub struct HTMLFormElement {
    htmlelement: HTMLElement
}

impl HTMLFormElement {
    fn get_scope_and_cx(&self) -> (*JSObject, *JSContext) {
        let doc = self.htmlelement.element.node.owner_doc.unwrap();
        let win = doc.with_base(|doc| doc.window.unwrap());
        let cx = win.page.js_info.get_ref().js_compartment.cx.ptr;
        let scope = win.reflector().get_jsobject();
        (scope, cx)
    }

    pub fn AcceptCharset(&self) -> DOMString {
        None
    }

    pub fn SetAcceptCharset(&mut self, _accept_charset: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Action(&self) -> DOMString {
        None
    }

    pub fn SetAction(&mut self, _action: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Autocomplete(&self) -> DOMString {
        None
    }

    pub fn SetAutocomplete(&mut self, _autocomplete: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Enctype(&self) -> DOMString {
        None
    }

    pub fn SetEnctype(&mut self, _enctype: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Encoding(&self) -> DOMString {
        None
    }

    pub fn SetEncoding(&mut self, _encoding: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Method(&self) -> DOMString {
        None
    }

    pub fn SetMethod(&mut self, _method: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Name(&self) -> DOMString {
        None
    }

    pub fn SetName(&mut self, _name: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn NoValidate(&self) -> bool {
        false
    }

    pub fn SetNoValidate(&mut self, _no_validate: bool) -> ErrorResult {
        Ok(())
    }

    pub fn Target(&self) -> DOMString {
        None
    }

    pub fn SetTarget(&mut self, _target: &DOMString) -> ErrorResult {
        Ok(())
    }

    pub fn Elements(&self) -> @mut HTMLCollection {
        let (scope, cx) = self.get_scope_and_cx();
        HTMLCollection::new(~[], cx, scope)
    }

    pub fn Length(&self) -> i32 {
        0
    }

    pub fn Submit(&self) -> ErrorResult {
        Ok(())
    }

    pub fn Reset(&self) {
    }

    pub fn CheckValidity(&self) -> bool {
        false
    }

    pub fn IndexedGetter(&self, _index: u32, _found: &mut bool) -> AbstractNode<ScriptView> {
        fail!("Not implemented.")
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use self::Color::*;
use self::Rank::*;
use std::slice::Iter;
use std::fmt;

extern crate rand;
use self::rand::{thread_rng, Rng};

#[derive(Copy, Clone)]
enum Color
{
    Spades,   // ♠,
    Hearts,   // ♥,
    Diamonds, // ♦,
    Clubs,    // ♣
}

#[derive(Copy, Clone)]
enum Rank
{
    A     = 1,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    J,
    Q,
    K
}

impl Color
{
    // https://stackoverflow.com/a/21376984
    fn iterator () -> Iter<'static, Color>
    {
        static COLORS: [Color; 4] = [Spades, Hearts, Diamonds, Clubs];
        COLORS.into_iter()
    }
}

impl fmt::Display for Color
{
    // https://stackoverflow.com/a/45893535
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            Spades => write!(f, "♠"),
            Hearts => write!(f, "♥"),
            Diamonds => write!(f, "♦"),
            Clubs => write!(f, "♣"),
        }
    }
}

impl Rank
{
    fn iterator () -> Iter<'static, Rank>
    {
        static RANKS: [Rank; 12] =
            [ A, Two, Three, Four, Five, Six, Seven, Eight, Nine, J, Q, K ] ;
        RANKS.into_iter()
    }
}

impl fmt::Display for Rank
{
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            A     => write!(f, "A"),
            Two   => write!(f, "2"),
            Three => write!(f, "3"),
            Four  => write!(f, "4"),
            Five  => write!(f, "5"),
            Six   => write!(f, "6"),
            Seven => write!(f, "7"),
            Eight => write!(f, "8"),
            Nine  => write!(f, "9"),
            J     => write!(f, "J"),
            Q     => write!(f, "Q"),
            K     => write!(f, "K"),
        }
    }
}

struct Card
{
    color:     Color,
    rank:      Rank,
    id:        u8,
    facing_up: bool
}

fn main ()
{
    let mut all_cards: Vec<Card> = Vec::new();

    let ids_available: Vec<u8> = (0..51).collect();

    for color in Color::iterator()
    {
        for rank in Rank::iterator()
        {
            let curr_id: u8;

            curr_id = 0;

            let card = Card
            {
                color:     *color,
                rank:      *rank,
                id:        curr_id,
                facing_up: false
            };

            all_cards.push(card);
        }
    }

    for card in all_cards.iter()
    {
        println!("{}{} {} {}",
                 card.color, card.rank, card.id, card.facing_up);
    }
}
<commit_msg>Totally forgot that the value 10 exists on cards. Realized something was up when the total number of cards was 48 and not 52.<commit_after>/*
 * Copyright (c) 2017 Erik Nordstrøm <erik@nordstroem.no>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

use self::Color::*;
use self::Rank::*;
use std::slice::Iter;
use std::fmt;

extern crate rand;
use self::rand::{thread_rng, Rng};

#[derive(Copy, Clone)]
enum Color
{
    Spades,   // ♠,
    Hearts,   // ♥,
    Diamonds, // ♦,
    Clubs,    // ♣
}

#[derive(Copy, Clone)]
enum Rank
{
    A     = 1,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    J,
    Q,
    K
}

impl Color
{
    // https://stackoverflow.com/a/21376984
    fn iterator () -> Iter<'static, Color>
    {
        static COLORS: [Color; 4] = [Spades, Hearts, Diamonds, Clubs];
        COLORS.into_iter()
    }
}

impl fmt::Display for Color
{
    // https://stackoverflow.com/a/45893535
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            Spades => write!(f, "♠"),
            Hearts => write!(f, "♥"),
            Diamonds => write!(f, "♦"),
            Clubs => write!(f, "♣"),
        }
    }
}

impl Rank
{
    fn iterator () -> Iter<'static, Rank>
    {
        static RANKS: [Rank; 13] =
            [ A, Two, Three, Four, Five, Six, Seven,
              Eight, Nine, Ten, J, Q, K ] ;
        RANKS.into_iter()
    }
}

impl fmt::Display for Rank
{
    fn fmt (&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        match *self
        {
            A     => write!(f, "A"),
            Two   => write!(f, "2"),
            Three => write!(f, "3"),
            Four  => write!(f, "4"),
            Five  => write!(f, "5"),
            Six   => write!(f, "6"),
            Seven => write!(f, "7"),
            Eight => write!(f, "8"),
            Nine  => write!(f, "9"),
            Ten   => write!(f, "10"),
            J     => write!(f, "J"),
            Q     => write!(f, "Q"),
            K     => write!(f, "K"),
        }
    }
}

struct Card
{
    color:     Color,
    rank:      Rank,
    id:        u8,
    facing_up: bool
}

fn main ()
{
    let mut all_cards: Vec<Card> = Vec::new();

    let ids_available: Vec<u8> = (0..51).collect();

    for color in Color::iterator()
    {
        for rank in Rank::iterator()
        {
            let curr_id: u8;

            curr_id = 0;

            let card = Card
            {
                color:     *color,
                rank:      *rank,
                id:        curr_id,
                facing_up: false
            };

            all_cards.push(card);
        }
    }

    for card in all_cards.iter()
    {
        println!("{}{} {} {}",
                 card.color, card.rank, card.id, card.facing_up);
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize;
#[macro_use]
extern crate nickel;
extern crate redis;
extern crate r2d2;
extern crate r2d2_redis;
extern crate plugin;
extern crate typemap;

extern crate core;

use std::env;
use std::collections::HashMap;
use r2d2::NopErrorHandler;
use nickel::{Nickel, HttpRouter, JsonBody, MediaType, QueryString};
use nickel::status::StatusCode;
use core::ops::Deref;
use redis::{Commands, Connection};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;

use redis_middleware::{RedisMiddleware, RedisRequestExtensions};
mod redis_middleware;

#[derive(RustcDecodable, RustcEncodable)]
struct RatingSubmission {
    uuid: String,
    mod_str: String,
    rating: Rating,
}

#[derive(Clone, Copy, Debug)]
enum Rating {
    Poor = 0,
    BelowAverage,
    Average,
    AboveAverage,
    Excellent,
}

#[derive(RustcEncodable)]
struct RatingResults {
    average: HashMap<String, Rating>,
    own: Option<HashMap<String, Rating>>,
}

impl From<u8> for Rating {
    fn from(rating: u8) -> Self {
        match rating {
            0 => Rating::Poor,
            1 => Rating::BelowAverage,
            2 => Rating::Average,
            3 => Rating::AboveAverage,
            _ => Rating::Excellent,
        }
    }
}

impl Decodable for Rating {
    fn decode<D: Decoder>(d: &mut D) -> Result<Rating, D::Error> {
        let r = try!(d.read_u8());
        Ok(Rating::from(r))
    }
}

impl Encodable for Rating {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let as_u8 = *self as u8;
        s.emit_u8(as_u8)
    }
}

fn incr_requests(conn: &Connection) {
    if let Err(_) = conn.incr::<_, _, u64>("requests", 1) {
        println!("failed to incr request counter.")
    }
}

const OK_RESP: (StatusCode, &'static str) = (StatusCode::Ok, "ok");

fn main() {
    let mut webserver = Nickel::new();

    let redis_url = env::var("DATABASE_URL").unwrap_or("redis://localhost/3".to_owned());
    println!("connecting to redis @ {}", redis_url);

    let redispool = RedisMiddleware::new(&*redis_url, 3, Box::new(NopErrorHandler)).unwrap();
    webserver.utilize(redispool);

    webserver.post("/submit",
                   middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let sbm = try_with!(response, {
            request.json_as::<RatingSubmission>().map_err(|e| (StatusCode::BadRequest, e))
        });
        println!("{} rates {} as {:?}", sbm.uuid, sbm.mod_str, sbm.rating);
        let _: bool = try_with!(response, {
            redis_conn.hset("mods", &*sbm.mod_str, true).map_err(|e| (StatusCode::BadRequest, e))
        });
        let _: u8 = try_with!(response, {
            redis_conn.hset(sbm.mod_str, sbm.uuid, sbm.rating as u8).map_err(|e|
                (StatusCode::BadRequest, e)
            )
        });
        OK_RESP
    });

    webserver.get("/rating/:mod",
                  middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let mod_str = request.param("mod").unwrap();
        let ratings = try_with!(response, {
            redis_conn.hvals::<_, Vec<u8>>(mod_str).map_err(|e| (StatusCode::BadRequest, e))
        });
        let length = ratings.len();
        let mut sum = 0usize;
        for rating in ratings {
            sum += rating as usize;
        }
        match length {
            0 => (StatusCode::NotFound, "{\"not_found\": true}".to_owned()),
            _ => (StatusCode::Ok, format!("{}", sum / length)),
        }
    });

    webserver.get("/ratings",
                  middleware! { |request, mut response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);

        let mods = try_with!(response, {
            redis_conn.hkeys::<_, Vec<String>>("mods").map_err(|e| (StatusCode::BadRequest, e))
        });

        let mut own_ratings = HashMap::new();
        let mut average_ratings = HashMap::new();

        for mod_str in mods {
            let mod_str = mod_str.as_str();
            let ratings = try_with!(response, {
                redis_conn.hvals::<_, Vec<u8>>(mod_str).map_err(|e| (StatusCode::BadRequest, e))
            });
            let length = ratings.len();
            let mut sum = 0usize;
            for rating in ratings {
                sum += rating as usize;
            }
            if length > 0 {
                average_ratings.insert(mod_str.to_owned(), Rating::from((sum / length) as u8));
            }
            if let Some(uuid) = request.query().get("uuid") {
                if let Ok(rating) = redis_conn.hget::<_, _, u8>(mod_str, uuid) {
                    own_ratings.insert(mod_str.to_owned(), Rating::from(rating));
                }
            }
        }

        let result = RatingResults {
            average: average_ratings,
            own: match request.query().get("uuid") {
                Some(_) => Some(own_ratings),
                None => None,
            },
        };
        response.set(MediaType::Json);
        json::encode(&result).unwrap()
    });

    webserver.listen("127.0.0.1:7998")
}
<commit_msg>refactoring<commit_after>extern crate rustc_serialize;
#[macro_use]
extern crate nickel;
extern crate redis;
extern crate r2d2;
extern crate r2d2_redis;
extern crate plugin;
extern crate typemap;

extern crate core;

use std::env;
use std::collections::HashMap;
use r2d2::NopErrorHandler;
use nickel::{Nickel, HttpRouter, JsonBody, MediaType, QueryString};
use nickel::status::StatusCode;
use core::ops::Deref;
use redis::{Commands, Connection, RedisError};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_serialize::json;

use redis_middleware::{RedisMiddleware, RedisRequestExtensions};
mod redis_middleware;

#[derive(RustcDecodable, RustcEncodable)]
struct RatingSubmission {
    uuid: String,
    mod_str: String,
    rating: Rating,
}

#[derive(Clone, Copy, Debug)]
enum Rating {
    Poor = 0,
    BelowAverage,
    Average,
    AboveAverage,
    Excellent,
}

impl From<u8> for Rating {
    fn from(rating: u8) -> Self {
        match rating {
            0 => Rating::Poor,
            1 => Rating::BelowAverage,
            2 => Rating::Average,
            3 => Rating::AboveAverage,
            _ => Rating::Excellent,
        }
    }
}

impl Decodable for Rating {
    fn decode<D: Decoder>(d: &mut D) -> Result<Rating, D::Error> {
        let r = try!(d.read_u8());
        Ok(Rating::from(r))
    }
}

impl Encodable for Rating {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        let as_u8 = *self as u8;
        s.emit_u8(as_u8)
    }
}

#[derive(RustcEncodable)]
struct RatingResults {
    average: HashMap<String, Rating>,
    own: Option<HashMap<String, Rating>>,
}

fn incr_requests(conn: &Connection) {
    if let Err(_) = conn.incr::<_, _, u64>("requests", 1) {
        println!("failed to incr request counter.")
    }
}

fn get_mod_rating(conn: &Connection, mod_str: &str) -> Result<(Rating, u32), RedisError> {
    let ratings = try!(conn.hvals::<_, Vec<u8>>(mod_str));
    let length = ratings.len() as u32;
    let mut sum = 0u32;
    for rating in ratings {
        sum += rating as u32;
    }
    match length {
        0 => Ok((Rating::Poor, length)),
        _ => Ok((Rating::from((sum / length) as u8), length)),
    }
}

const OK_RESP: (StatusCode, &'static str) = (StatusCode::Ok, "ok");

fn main() {
    let mut webserver = Nickel::new();

    let redis_url = env::var("DATABASE_URL").unwrap_or("redis://localhost/3".to_owned());
    println!("connecting to redis @ {}", redis_url);

    let redispool = RedisMiddleware::new(&*redis_url, 3, Box::new(NopErrorHandler)).unwrap();
    webserver.utilize(redispool);

    webserver.post("/submit",
                   middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let sbm = try_with!(response, {
            request.json_as::<RatingSubmission>().map_err(|e| (StatusCode::BadRequest, e))
        });
        println!("{} rates {} as {:?}", sbm.uuid, sbm.mod_str, sbm.rating);
        let _: bool = try_with!(response, {
            redis_conn.hset("mods", &*sbm.mod_str, true).map_err(|e| (StatusCode::BadRequest, e))
        });
        let _: u8 = try_with!(response, {
            redis_conn.hset(sbm.mod_str, sbm.uuid, sbm.rating as u8).map_err(|e|
                (StatusCode::BadRequest, e)
            )
        });
        OK_RESP
    });

    webserver.get("/rating/:mod",
                  middleware! { |request, response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);
        let mod_str = request.param("mod").unwrap();
        let result = try_with!(response, {
            get_mod_rating(redis_conn, mod_str).map_err(|e| (StatusCode::BadRequest, e))
        });
        match result {
            (_, 0) => (StatusCode::NotFound, "Not Found!".to_owned()),
            (rating, sbm) => (StatusCode::Ok, format!("{:?}, {} submissions", rating, sbm)),
        }
    });

    webserver.get("/ratings",
                  middleware! { |request, mut response|
        let rcn_ref = request.redis_conn();
        let redis_conn = rcn_ref.deref();
        incr_requests(&redis_conn);

        let mods = try_with!(response, {
            redis_conn.hkeys::<_, Vec<String>>("mods").map_err(|e| (StatusCode::BadRequest, e))
        });

        let mut own_ratings: HashMap<String, Rating> = HashMap::new();
        let mut average_ratings: HashMap<String, Rating> = HashMap::new();

        for mod_str in mods {
            let mod_str = mod_str.as_str();
            let (rating, sbm) = try_with!(response, {
                get_mod_rating(redis_conn, mod_str).map_err(|e| (StatusCode::BadRequest, e))
            });
            if sbm == 0 {
                continue;
            }
            average_ratings.insert(mod_str.to_owned(), rating);
            if let Some(uuid) = request.query().get("uuid") {
                if let Ok(rating) = redis_conn.hget::<_, _, u8>(mod_str, uuid) {
                    own_ratings.insert(mod_str.to_owned(), Rating::from(rating));
                }
            }
        }

        let result = RatingResults {
            average: average_ratings,
            own: match request.query().get("uuid") {
                Some(_) => Some(own_ratings),
                None => None,
            },
        };
        response.set(MediaType::Json);
        json::encode(&result).unwrap()
    });

    webserver.listen("127.0.0.1:7998")
}
<|endoftext|>


<commit_before>// Based on http://www.keithschwarz.com/interesting/code/?dir=fibonacci-heap

use std::mem;
use std::ptr;
use std::cmp::Ordering;

pub struct FibonacciHeap<T: PartialOrd> {
    size: usize,
    min: Link<T>,
    tree_table: Vec<Link<T>>,
    to_visit: Vec<Link<T>>,
}

struct Entry<T: PartialOrd> {
    pub value: T,

    pub degree: usize,
    // TODO: Implement decrease_key and delete
    // pub is_marked: bool,

    pub parent: Link<T>,
    pub next: Link<T>,
    pub prev: Link<T>,
    pub child: Link<T>,
}

struct Link<T: PartialOrd> {
    entry: *mut Entry<T>
}

impl <T: PartialOrd> FibonacciHeap<T> {
    pub fn new() -> FibonacciHeap<T> {
        FibonacciHeap {
            min: Link::none(),
            size: 0,
            to_visit: Vec::new(),
            tree_table: Vec::new(),
        }
    }

    pub fn min(&self) -> Option<&T> {
        self.min.borrow()
    }

    pub fn is_empty(&self) -> bool {
        self.min.is_none()
    }

    pub fn size(&self) -> usize {
        self.size
    }

    pub fn push(&mut self, value: T) {
        let link = Link::new(value);

        let mut min = Link::none();
        mem::swap(&mut min, &mut self.min);

        self.min = FibonacciHeap::<T>::merge_entries(min, link);
        self.size += 1;
    }

    pub fn pop(&mut self) -> Option<T> {
        if self.is_empty() {
            return None;
        }

        self.size -= 1;

        let mut min = Link::none();
        mem::swap(&mut min, &mut self.min);

        if !min.get_next().are_same(&min) {
            let mut min_prev = min.get_prev();
            let mut min_next = min.get_next();
            min_prev.set_next(&min_next);
            min_next.set_prev(&min_prev);
            self.min = min_next;
        }

        let min_child = min.get_child();
        if !min_child.is_none() {
            let mut current = min_child.clone();
            while {
                current.set_parent(&Link::none());
                current = current.get_next();

                !current.are_same(&min_child)
            } {}
        }

        let mut new_min = Link::none();
        mem::swap(&mut new_min, &mut self.min);

        self.min = FibonacciHeap::<T>::merge_entries(new_min, min_child);

        if self.size == 0 {
            return min.into_value();
        }

        let mut current = self.min.clone();
        while self.to_visit.is_empty() || !self.to_visit[0].are_same(&current) {
            let next = current.get_next();
            self.to_visit.push(current);
            current = next;
        }

        for link_to_visit in &self.to_visit {
            let mut link = link_to_visit.clone();

            loop {
                let link_degree = link.get_degree();

                while link_degree >= self.tree_table.len() {
                    self.tree_table.push(Link::none());
                }

                if self.tree_table[link_degree].is_none() {
                    self.tree_table[link_degree] = link.clone();
                    break;
                }

                self.tree_table.push(Link::none());
                let other = self.tree_table.swap_remove(link_degree);

                let (mut min_link, mut max) = if link < other {
                    (link, other)
                } else {
                    (other, link)
                };

                let mut max_next = max.get_next();
                let mut max_prev = max.get_prev();
                max_next.set_prev(&max_prev);
                max_prev.set_next(&max_next);

                let max_clone = max.clone();
                max.set_prev(&max_clone);
                max.set_next(&max_clone);

                max.set_parent(&min_link);

                let min_link_child = min_link.get_child();
                min_link.set_child(&FibonacciHeap::<T>::merge_entries(min_link_child, max));
                // max.is_marked = false;

                min_link.inc_degree();

                link = min_link;
            }

            if link <= self.min {
                self.min = link;
            }
        }

        self.to_visit.clear();
        self.tree_table.clear();

        min.into_value()
    }

    pub fn merge(x: FibonacciHeap<T>, y: FibonacciHeap<T>) -> FibonacciHeap<T> {
        let mut result = FibonacciHeap::new();

        result.min = FibonacciHeap::<T>::merge_entries(x.min, y.min);
        result.size = x.size + y.size;

        result
    }

    fn merge_entries(mut x: Link<T>, mut y: Link<T>) -> Link<T> {
        if x.is_none() && y.is_none() {
            Link::none()
        } else if !x.is_none() && y.is_none() {
            x
        } else if x.is_none() && !y.is_none() {
            y
        } else {
            let mut x_next = x.get_next();
            let mut y_next = y.get_next();
            x.set_next(&y_next);
            y_next.set_prev(&x);
            y.set_next(&x_next);
            x_next.set_prev(&y);

            if x < y { x } else { y }
        }
    }
}

impl <T: PartialOrd> Entry<T> {
    pub fn new(value: T) -> Entry<T> {
        Entry {
            value: value,

            degree: 0,
            // is_marked: false,

            parent: Link::none(),
            next: Link::none(),
            prev: Link::none(),
            child: Link::none(),
        }
    }
}

impl <T: PartialOrd> Link<T> {
    #[inline]
    pub fn none() -> Link<T> {
        Link { entry: ptr::null_mut() }
    }

    #[inline]
    pub fn is_none(&self) -> bool {
        self.entry.is_null()
    }

    #[inline]
    pub fn is_some(&self) -> bool {
        !self.is_none()
    }

    pub fn new(value: T) -> Link<T> {
        let entry_box = Box::new(Entry::new(value));
        let entry = Box::into_raw(entry_box);
        let prev = entry.clone();
        let next = entry.clone();

        unsafe {
            (*entry).prev = Link { entry: prev };
            (*entry).next = Link { entry: next };
        }

        Link { entry: entry }
    }

    pub fn get_degree(&self) -> usize {
        if self.is_none() {
            0
        } else {
            unsafe {
                (*self.entry).degree
            }
        }
    }

    pub fn inc_degree(&mut self) {
        if self.is_some() {
            unsafe {
                (*self.entry).degree += 1;
            }
        }
    }

    pub fn into_value(mut self) -> Option<T> {
        if self.is_none() {
            None
        } else {
            let mut raw_entry: *mut Entry<T> = ptr::null_mut();
            mem::swap(&mut raw_entry, &mut self.entry);

            let mut entry: Entry<T>;

            unsafe {
                entry = *Box::from_raw(raw_entry);
            }

            entry.next = Link::none();
            entry.prev = Link::none();

            Some(entry.value)
        }
    }

    pub fn borrow(&self) -> Option<&T> {
        if self.is_none() {
            None
        } else {
            unsafe {
                Some(&(*self.entry).value)
            }
        }
    }

    pub fn are_same(&self, other: &Link<T>) -> bool {
        self.entry == other.entry
    }

    #[inline]
    pub fn get_child(&self) -> Link<T> {
        if self.is_none() {
            Link::<T>::none()
        } else {
            unsafe {
                (*self.entry).child.clone()
            }
        }
    }

    #[inline]
    pub fn get_next(&self) -> Link<T> {
        if self.is_none() {
            Link::<T>::none()
        } else {
            unsafe {
                (*self.entry).next.clone()
            }
        }
    }

    #[inline]
    pub fn get_prev(&self) -> Link<T> {
        if self.is_none() {
            Link::<T>::none()
        } else {
            unsafe {
                (*self.entry).prev.clone()
            }
        }
    }

    #[inline]
    pub fn set_child(&mut self, child: &Link<T>) {
        if self.is_some() {
            unsafe {
                (*self.entry).child = child.clone();
            }
        }
    }

    #[inline]
    pub fn set_parent(&mut self, parent: &Link<T>) {
        if self.is_some() {
            unsafe {
                (*self.entry).parent = parent.clone();
            }
        }
    }

    #[inline]
    pub fn set_next(&mut self, next: &Link<T>) {
        if self.is_some() {
            unsafe {
                (*self.entry).next = next.clone();
            }
        }
    }

    #[inline]
    pub fn set_prev(&mut self, prev: &Link<T>) {
        if self.is_some() {
            unsafe {
                (*self.entry).prev = prev.clone();
            }
        }
    }
}

impl <T: PartialOrd> Clone for Link<T> {
    #[inline]
    fn clone(&self) -> Self {
        Link { entry: self.entry.clone() }
    }
}

impl <T: PartialOrd> PartialEq for Link<T> {
    #[inline]
    fn eq(&self, other: &Link<T>) -> bool {
        if self.is_none() || other.is_none() {
            false
        } else {
            unsafe {
                (*self.entry).value.eq(&(*other.entry).value)
            }
        }
    }
}

impl <T: PartialOrd> PartialOrd for Link<T> {
    #[inline]
    fn partial_cmp(&self, other: &Link<T>) -> Option<Ordering> {
        if self.is_none() || other.is_none() {
            None
        } else {
            unsafe {
                (*self.entry).value.partial_cmp(&(*other.entry).value)
            }
        }
    }
}

#[test]
fn test_size() {
    let mut heap = FibonacciHeap::new();

    heap.push(1);

    assert_eq!(1, heap.size);
}

#[test]
fn test_min() {
    let mut heap = FibonacciHeap::new();

    heap.push(1);

    assert_eq!(1, *heap.min().unwrap());
}

#[test]
fn test_pop() {
    let mut heap = FibonacciHeap::new();

    heap.push(1);

    assert_eq!(1, heap.pop().unwrap());
}

#[test]
fn test_order() {
    let mut heap = FibonacciHeap::new();

    heap.push(7);
    heap.push(1);
    heap.push(8);
    heap.push(4);
    heap.push(5);
    heap.push(2);
    heap.push(3);
    heap.push(6);

    assert_eq!(1, heap.pop().unwrap());
    assert_eq!(2, heap.pop().unwrap());
    assert_eq!(3, heap.pop().unwrap());
    assert_eq!(4, heap.pop().unwrap());
    assert_eq!(5, heap.pop().unwrap());
    assert_eq!(6, heap.pop().unwrap());
    assert_eq!(7, heap.pop().unwrap());
    assert_eq!(8, heap.pop().unwrap());
}

#[bench]
fn bench_push_pop(b: &mut ::test::Bencher) {
    b.iter(|| {
        // TODO: Optimize heap
        let mut heap = FibonacciHeap::new();

        for i in 1..10001 {
            heap.push(10001 - i);
        }

        for _ in 1..10001 {
            heap.pop();
        }
    })
}
<commit_msg>updated unsafe version<commit_after>// Based on http://www.keithschwarz.com/interesting/code/?dir=fibonacci-heap

use std::mem;
use std::ptr;
use std::cmp::Ordering;

pub struct FibonacciHeap<T: PartialOrd> {
    size: usize,
    min: Link<T>,
    tree_table: Vec<Link<T>>,
    to_visit: Vec<Link<T>>,
}

struct Entry<T: PartialOrd> {
    pub value: T,

    pub degree: usize,
    // TODO: Implement decrease_key and delete
    // pub is_marked: bool,

    pub parent: Link<T>,
    pub next: Link<T>,
    pub prev: Link<T>,
    pub child: Link<T>,
}

struct Link<T: PartialOrd> {
    entry: *mut Entry<T>
}

impl <T: PartialOrd> FibonacciHeap<T> {
    pub fn new() -> FibonacciHeap<T> {
        FibonacciHeap {
            min: Link::none(),
            size: 0,
            to_visit: Vec::new(),
            tree_table: Vec::new(),
        }
    }

    pub fn min(&self) -> Option<&T> {
        self.min.borrow()
    }

    pub fn is_empty(&self) -> bool {
        self.min.is_none()
    }

    pub fn size(&self) -> usize {
        self.size
    }

    pub fn push(&mut self, value: T) {
        let link = Link::new(value);

        let mut min = Link::none();
        mem::swap(&mut min, &mut self.min);

        self.min = FibonacciHeap::<T>::merge_entries(min, link);
        self.size += 1;
    }

    pub fn pop(&mut self) -> Option<T> {
        if self.is_empty() {
            return None;
        }

        self.size -= 1;

        let mut min = Link::none();
        mem::swap(&mut min, &mut self.min);

        if !min.get_next().are_same(&min) {
            let mut min_prev = min.get_prev();
            let mut min_next = min.get_next();
            min_prev.set_next(&min_next);
            min_next.set_prev(&min_prev);
            self.min = min_next;
        }

        let min_child = min.get_child();
        if !min_child.is_none() {
            let mut current = min_child.clone();
            while {
                current.set_parent(&Link::none());
                current = current.get_next();

                !current.are_same(&min_child)
            } {}
        }

        let mut new_min = Link::none();
        mem::swap(&mut new_min, &mut self.min);

        self.min = FibonacciHeap::<T>::merge_entries(new_min, min_child);

        if self.size == 0 {
            return min.into_value();
        }

        let mut current = self.min.clone();
        while self.to_visit.is_empty() || !self.to_visit[0].are_same(&current) {
            let next = current.get_next();
            self.to_visit.push(current);
            current = next;
        }

        for link_to_visit in &self.to_visit {
            let mut link = link_to_visit.clone();

            loop {
                let link_degree = link.get_degree();

                while link_degree >= self.tree_table.len() {
                    self.tree_table.push(Link::none());
                }

                if self.tree_table[link_degree].is_none() {
                    self.tree_table[link_degree] = link.clone();
                    break;
                }

                self.tree_table.push(Link::none());
                let other = self.tree_table.swap_remove(link_degree);

                let (mut min_link, mut max) = if link < other {
                    (link, other)
                } else {
                    (other, link)
                };

                let mut max_next = max.get_next();
                let mut max_prev = max.get_prev();
                max_next.set_prev(&max_prev);
                max_prev.set_next(&max_next);

                let max_clone = max.clone();
                max.set_prev(&max_clone);
                max.set_next(&max_clone);

                max.set_parent(&min_link);

                let min_link_child = min_link.get_child();
                min_link.set_child(&FibonacciHeap::<T>::merge_entries(min_link_child, max));
                // max.is_marked = false;

                min_link.inc_degree();

                link = min_link;
            }

            if link <= self.min {
                self.min = link;
            }
        }

        self.to_visit.clear();
        self.tree_table.clear();

        min.into_value()
    }

    pub fn merge(x: FibonacciHeap<T>, y: FibonacciHeap<T>) -> FibonacciHeap<T> {
        let mut result = FibonacciHeap::new();

        result.min = FibonacciHeap::<T>::merge_entries(x.min, y.min);
        result.size = x.size + y.size;

        result
    }

    fn merge_entries(mut x: Link<T>, mut y: Link<T>) -> Link<T> {
        if x.is_none() && y.is_none() {
            Link::none()
        } else if !x.is_none() && y.is_none() {
            x
        } else if x.is_none() && !y.is_none() {
            y
        } else {
            let mut x_next = x.get_next();
            let mut y_next = y.get_next();
            x.set_next(&y_next);
            y_next.set_prev(&x);
            y.set_next(&x_next);
            x_next.set_prev(&y);

            if x < y { x } else { y }
        }
    }
}

impl <T: PartialOrd> Entry<T> {
    pub fn new(value: T) -> Entry<T> {
        Entry {
            value: value,

            degree: 0,
            // is_marked: false,

            parent: Link::none(),
            next: Link::none(),
            prev: Link::none(),
            child: Link::none(),
        }
    }
}

impl <T: PartialOrd> Link<T> {
    #[inline]
    pub fn none() -> Link<T> {
        Link { entry: ptr::null_mut() }
    }

    #[inline]
    pub fn is_none(&self) -> bool {
        self.entry.is_null()
    }

    #[inline]
    pub fn is_some(&self) -> bool {
        !self.is_none()
    }

    pub fn new(value: T) -> Link<T> {
        let entry_box = Box::new(Entry::new(value));
        let entry = Box::into_raw(entry_box);
        let prev = entry.clone();
        let next = entry.clone();

        unsafe {
            (*entry).prev = Link { entry: prev };
            (*entry).next = Link { entry: next };
        }

        Link { entry: entry }
    }

    #[inline]
    pub fn get_degree(&self) -> usize {
        if self.is_none() {
            0
        } else {
            unsafe {
                (*self.entry).degree
            }
        }
    }

    #[inline]
    pub fn inc_degree(&mut self) {
        if self.is_some() {
            unsafe {
                (*self.entry).degree += 1;
            }
        }
    }

    pub fn into_value(mut self) -> Option<T> {
        if self.is_none() {
            None
        } else {
            let mut raw_entry: *mut Entry<T> = ptr::null_mut();
            mem::swap(&mut raw_entry, &mut self.entry);

            let entry: Entry<T>;
            unsafe {
                entry = *Box::from_raw(raw_entry);
            }

            Some(entry.value)
        }
    }

    #[inline]
    pub fn borrow(&self) -> Option<&T> {
        if self.is_none() {
            None
        } else {
            unsafe {
                Some(&(*self.entry).value)
            }
        }
    }

    #[inline]
    pub fn are_same(&self, other: &Link<T>) -> bool {
        self.entry == other.entry
    }

    #[inline]
    pub fn get_child(&self) -> Link<T> {
        if self.is_none() {
            Link::<T>::none()
        } else {
            unsafe {
                (*self.entry).child.clone()
            }
        }
    }

    #[inline]
    pub fn get_next(&self) -> Link<T> {
        if self.is_none() {
            Link::<T>::none()
        } else {
            unsafe {
                (*self.entry).next.clone()
            }
        }
    }

    #[inline]
    pub fn get_prev(&self) -> Link<T> {
        if self.is_none() {
            Link::<T>::none()
        } else {
            unsafe {
                (*self.entry).prev.clone()
            }
        }
    }

    #[inline]
    pub fn set_child(&mut self, child: &Link<T>) {
        if self.is_some() {
            unsafe {
                (*self.entry).child = child.clone();
            }
        }
    }

    #[inline]
    pub fn set_parent(&mut self, parent: &Link<T>) {
        if self.is_some() {
            unsafe {
                (*self.entry).parent = parent.clone();
            }
        }
    }

    #[inline]
    pub fn set_next(&mut self, next: &Link<T>) {
        if self.is_some() {
            unsafe {
                (*self.entry).next = next.clone();
            }
        }
    }

    #[inline]
    pub fn set_prev(&mut self, prev: &Link<T>) {
        if self.is_some() {
            unsafe {
                (*self.entry).prev = prev.clone();
            }
        }
    }
}

impl <T: PartialOrd> Clone for Link<T> {
    #[inline]
    fn clone(&self) -> Self {
        Link { entry: self.entry.clone() }
    }
}

impl <T: PartialOrd> PartialEq for Link<T> {
    #[inline]
    fn eq(&self, other: &Link<T>) -> bool {
        if self.is_none() || other.is_none() {
            false
        } else {
            unsafe {
                (*self.entry).value.eq(&(*other.entry).value)
            }
        }
    }
}

impl <T: PartialOrd> PartialOrd for Link<T> {
    #[inline]
    fn partial_cmp(&self, other: &Link<T>) -> Option<Ordering> {
        if self.is_none() || other.is_none() {
            None
        } else {
            unsafe {
                (*self.entry).value.partial_cmp(&(*other.entry).value)
            }
        }
    }
}

#[test]
fn test_size() {
    let mut heap = FibonacciHeap::new();

    heap.push(1);

    assert_eq!(1, heap.size);
}

#[test]
fn test_min() {
    let mut heap = FibonacciHeap::new();

    heap.push(1);

    assert_eq!(1, *heap.min().unwrap());
}

#[test]
fn test_pop() {
    let mut heap = FibonacciHeap::new();

    heap.push(1);

    assert_eq!(1, heap.pop().unwrap());
}

#[test]
fn test_order() {
    let mut heap = FibonacciHeap::new();

    heap.push(7);
    heap.push(1);
    heap.push(8);
    heap.push(4);
    heap.push(5);
    heap.push(2);
    heap.push(3);
    heap.push(6);

    assert_eq!(1, heap.pop().unwrap());
    assert_eq!(2, heap.pop().unwrap());
    assert_eq!(3, heap.pop().unwrap());
    assert_eq!(4, heap.pop().unwrap());
    assert_eq!(5, heap.pop().unwrap());
    assert_eq!(6, heap.pop().unwrap());
    assert_eq!(7, heap.pop().unwrap());
    assert_eq!(8, heap.pop().unwrap());
}

#[bench]
fn bench_push_pop(b: &mut ::test::Bencher) {
    b.iter(|| {
        // TODO: Optimize heap
        let mut heap = FibonacciHeap::new();

        for i in 1..10001 {
            heap.push(10001 - i);
        }

        for _ in 1..10001 {
            heap.pop();
        }
    })
}
<|endoftext|>