<commit_before>use std::process;
use std::fs::File;
use std::io::{Read, BufReader};

use serde_json;
use std::collections::{HashMap, HashSet};

use crate::web::data::{APIMaps, IdGeneSubsetMap, APIGeneSummary, APIAlleleDetails,
                GeneDetails, TermDetails, GenotypeDetails, ReferenceDetails,
                InteractionType, OntAnnotationMap, IdOntAnnotationDetailMap,
                TermShort, TermShortOptionMap, ChromosomeDetails,
                ReferenceShort, ReferenceShortOptionMap,
                GeneShort, GeneShortOptionMap, GeneQueryData};
use crate::web::config::{Config, TermAndName};
use crate::api::query::{SingleOrMultiAllele, QueryExpressionFilter};

use flate2::read::GzDecoder;

use crate::types::{TermId, GeneUniquename};

use pombase_rc_string::RcString;

pub struct ServerData {
    config_file_name: String,
    maps: APIMaps,
    secondary_identifiers_map: HashMap<TermId, TermId>,
    search_maps_file_name: String,
}

fn make_secondary_identifiers_map(terms: &HashMap<TermId, TermDetails>)
                                  -> HashMap<TermId, TermId>
{
    let mut ret_map = HashMap::new();

    for term_details in terms.values() {
        for secondary_identifier in &term_details.secondary_identifiers {
            ret_map.insert(secondary_identifier.clone(),
                           term_details.termid.clone());
        }
    }

    ret_map
}

fn load(config: &Config, search_maps_file_name: &str) -> APIMaps
{
    let file = match File::open(search_maps_file_name) {
        Ok(file) => file,
        Err(err) => {
            eprint!("Failed to read {}: {}\n", search_maps_file_name, err);
            process::exit(1);
        }
    };
    let reader = BufReader::new(file);

    let mut decoder = GzDecoder::new(reader);
    let mut decoded_json = String::new();
    decoder.read_to_string(&mut decoded_json).unwrap();

    let mut query_api_maps: APIMaps =
        match serde_json::from_str(&decoded_json) {
            Ok(results) => results,
            Err(err) => {
                eprint!("failed to parse {}: {}", search_maps_file_name, err);
                process::exit(1);
            },
        };

    let mut new_entries: IdGeneSubsetMap = HashMap::new();

    let prefixes_to_remove: Vec<String> =
        config.server.subsets.prefixes_to_remove
        .iter().map(|prefix| prefix.clone() + ":").collect();

    // strip prefixes and add to map
    for (subset_name, subset_details) in &query_api_maps.gene_subsets {
        for prefix in &prefixes_to_remove {
            if subset_name.starts_with(prefix) {
                let new_subset_name = &subset_name[prefix.len()..];
                new_entries.insert(RcString::from(new_subset_name), subset_details.clone());
            }
        }
    }

    query_api_maps.gene_subsets.extend(new_entries);

    query_api_maps
}

impl ServerData {
    pub fn new(config_file_name: &str, search_maps_file_name: &str)
               -> ServerData
    {
        let config = Config::read(config_file_name);

        let maps = load(&config, search_maps_file_name);

        let secondary_identifiers_map =
            make_secondary_identifiers_map(&maps.terms);

        ServerData {
            config_file_name: config_file_name.into(),
            search_maps_file_name: search_maps_file_name.into(),
            secondary_identifiers_map,
            maps
        }
    }

    pub fn gene_uniquename_of_id(&self, id: &RcString) -> Option<GeneUniquename> {
        if self.maps.gene_summaries.contains_key(id) {
            Some(id.clone())
        } else {
            if let Some(gene_uniquename) =
                self.maps.gene_name_gene_map.get(id) {
                    Some(gene_uniquename.clone())
                } else {
                    let lower_case_id = id.to_lowercase();
                    for gene_uniquename in self.maps.gene_summaries.keys() {
                        if gene_uniquename.to_lowercase() == lower_case_id {
                            return Some(gene_uniquename.clone());
                        }
                    }
                    None
                }
        }
    }

    pub fn get_gene_summary(&self, gene_uniquename: &str) -> Option<&APIGeneSummary> {
        self.maps.gene_summaries.get(gene_uniquename)
    }

    pub fn get_gene_details(&self, gene_uniquename: &str) -> Option<&GeneDetails> {
        self.maps.genes.get(gene_uniquename)
    }

    pub fn get_gene_query_data(&self, gene_uniquename: &str) -> Option<&GeneQueryData> {
        self.maps.gene_query_data_map.get(gene_uniquename)
    }

    pub fn genes_of_termid(&self, term_id: &str) -> Vec<GeneUniquename> {
        match self.maps.termid_genes.get(term_id) {
            Some(gene_uniquenames) => {
                gene_uniquenames.iter().cloned().collect::<Vec<_>>()
            },
            None => vec![],
        }
    }

    pub fn genes_of_subset(&self, search_name: &str) -> Vec<GeneUniquename> {
        if search_name.starts_with('!') || search_name.ends_with('*') {
            let mut trimmed_search_name = search_name.to_owned();
            let invert_search = search_name.starts_with('!');
            let wildcard = search_name.ends_with('*');
            if invert_search {
                trimmed_search_name.remove(0);
            }
            if wildcard {
                trimmed_search_name.pop();
            }
            let mut genes = HashSet::new();
            for (subset_name, subset_details) in &self.maps.gene_subsets {
                let name_matches =
                    wildcard && subset_name.starts_with(&trimmed_search_name) ||
                    trimmed_search_name.eq(subset_name);

                if !invert_search && name_matches || invert_search && !name_matches {
                    genes.extend(subset_details.elements.iter().cloned());
                }
            }
            genes.iter().cloned().collect::<Vec<_>>()
        } else {
            match self.maps.gene_subsets.get(search_name) {
                Some(subset_details) => {
                    subset_details.elements.iter().cloned().collect::<Vec<_>>()
                },
                None => vec![],
            }
        }
    }

    pub fn genes_of_genotypes(&self, term_id: &str,
                              single_or_multi_allele: &SingleOrMultiAllele,
                              expression_filter: &Option<QueryExpressionFilter>,
                              conditions_filter: &HashSet<TermAndName>,
                              excluded_conditions_filter: &HashSet<TermAndName>)
                              -> Vec<GeneUniquename>
    {
        if let Some(annotations) = self.maps.termid_genotype_annotation.get(term_id) {
            let mut genes: HashSet<GeneUniquename> = HashSet::new();
            for annotation in annotations {

                let mut add_single = false;
                let mut add_multi = false;

                match *single_or_multi_allele {
                    SingleOrMultiAllele::Single => add_single = true,
                    SingleOrMultiAllele::Multi => add_multi = true,
                    SingleOrMultiAllele::Both => {
                        add_single = true;
                        add_multi = true;
                    },
                }

                let expression_matches =
                    |allele_details: &APIAlleleDetails| {
                        let expression = &allele_details.expression;
                        let allele_type = &allele_details.allele_type;
                        if let Some(ref expression_filter) = *expression_filter {
                            if *expression_filter == QueryExpressionFilter::Any {
                                return true;
                            }
                            if *expression_filter == QueryExpressionFilter::Null {
                                if allele_type == "deletion" {
                                    return true;
                                }
                                if let Some(ref expression) = *expression {
                                    expression == "Null"
                                } else {
                                    false
                                }
                            } else {
                                if *expression_filter == QueryExpressionFilter::WtOverexpressed {
                                    if let Some(ref expression) = *expression {
                                        expression == "Overexpression" &&
                                            allele_type == "wild_type"
                                    } else {
                                        false
                                    }
                                } else {
                                    false
                                }
                            }
                        } else {
                            true
                        }
                    };

                let condition_matches =
                    |conditions: &HashSet<TermAndName>, test_conditions_filter: &HashSet<TermAndName>| {
                        if test_conditions_filter.len() == 0 {
                            // don't filter in this case
                            return true;
                        }

                        for filter_condition in test_conditions_filter {
                            if conditions.iter().find(
                                |cond| {
                                    filter_condition.termid == cond.termid
                                })
                                .is_some() {
                                return true
                            }
                        }

                        false
                    };

                if annotation.is_multi && add_multi ||
                    !annotation.is_multi && add_single &&
                    expression_matches(&annotation.alleles[0]) &&
                    condition_matches(&annotation.conditions, conditions_filter) &&
                    !condition_matches(&annotation.conditions, excluded_conditions_filter) {
                        for allele_details in &annotation.alleles {
                            genes.insert(allele_details.gene.clone());
                        }
                }
            }
            genes.into_iter().collect::<Vec<_>>()
        } else {
            vec![]
        }
    }

    pub fn filter_genes(&self, p: & dyn Fn(&APIGeneSummary) -> bool)
                        -> Vec<GeneUniquename>
    {
        self.maps.gene_summaries.values()
            .filter(|summ| p(summ))
            .map(|summ| summ.uniquename.clone())
            .collect()
    }

    fn detail_map_of_cv_annotations(&self, ont_annotation_map: &OntAnnotationMap)
                                    -> IdOntAnnotationDetailMap
    {
        let mut details_map = HashMap::new();

        for term_annotations in ont_annotation_map.values() {
            for term_annotation in term_annotations {
                for annotation_detail_id in &term_annotation.annotations {
                    let details =
                        &self.maps.annotation_details[annotation_detail_id];
                    details_map.insert(*annotation_detail_id, details.clone());
                }
            }
        }

        details_map
    }

    fn fill_term_map(&self, term_map: &TermShortOptionMap) -> TermShortOptionMap {
        let mut ret = term_map.clone();
        for termid in term_map.keys() {
            if let Some(term_details) = self.maps.terms.get(termid) {
                let term_short = TermShort::from_term_details(term_details);
                ret.insert(termid.clone(), Some(term_short));
            } else {
                eprint!("WARNING missing short info for: {}\n", termid);
                ret.insert(termid.clone(), None);
            }
        }
        ret
    }

    fn fill_gene_map(&self, gene_map: &GeneShortOptionMap) -> GeneShortOptionMap {
        let mut ret = gene_map.clone();
        for gene_uniquename in gene_map.keys() {
            let gene_details = &self.maps.genes[gene_uniquename];
            let gene_short = GeneShort::from_gene_details(gene_details);
            ret.insert(gene_uniquename.clone(), Some(gene_short));
        }
        ret
    }

    fn fill_reference_map(&self, reference_map: &ReferenceShortOptionMap) -> ReferenceShortOptionMap {
        let mut ret = reference_map.clone();
        for reference_uniquename in reference_map.keys() {
            let reference_details = &self.maps.references[reference_uniquename];
            let reference_short = ReferenceShort::from_reference_details(reference_details);
            ret.insert(reference_uniquename.clone(), Some(reference_short));
        }
        ret
    }

    // return a GeneDetails object with the term, genes and references maps filled in
    pub fn get_full_gene_details(&self, gene_uniquename: &str) -> Option<GeneDetails> {
        if let Some(gene_ref) = self.maps.genes.get(gene_uniquename) {
            let mut gene = gene_ref.clone();
            let details_map = self.detail_map_of_cv_annotations(&gene.cv_annotations);
            gene.annotation_details = details_map;
            gene.terms_by_termid = self.fill_term_map(&gene.terms_by_termid);
            gene.genes_by_uniquename = self.fill_gene_map(&gene.genes_by_uniquename);
            gene.references_by_uniquename =
                self.fill_reference_map(&gene.references_by_uniquename);
            Some(gene)
        } else {
            None
        }
    }

    pub fn get_genotype_details(&self, genotype_uniquename: &str) -> Option<GenotypeDetails> {
        if let Some(genotype_ref) = self.maps.genotypes.get(genotype_uniquename) {
            let mut genotype = genotype_ref.clone();
            let details_map = self.detail_map_of_cv_annotations(&genotype.cv_annotations);
            genotype.annotation_details = details_map;
            genotype.terms_by_termid = self.fill_term_map(&genotype.terms_by_termid);
            genotype.genes_by_uniquename = self.fill_gene_map(&genotype.genes_by_uniquename);
            genotype.references_by_uniquename =
                self.fill_reference_map(&genotype.references_by_uniquename);
            Some(genotype)
        } else {
            None
        }
    }

    fn term_details_helper(&self, term_ref: &TermDetails) -> Option<TermDetails> {
        let mut term = term_ref.clone();
        let details_map = self.detail_map_of_cv_annotations(&term.cv_annotations);
        term.annotation_details = details_map;
        term.terms_by_termid = self.fill_term_map(&term.terms_by_termid);
        term.genes_by_uniquename = self.fill_gene_map(&term.genes_by_uniquename);
        term.references_by_uniquename =
            self.fill_reference_map(&term.references_by_uniquename);
        Some(term)
    }

    pub fn get_term_details(&self, termid: &str) -> Option<TermDetails> {
        let termid =
            if let Some(real_termid) = self.secondary_identifiers_map.get(termid) {
                real_termid
            } else {
                termid
            };
        if let Some(term_ref) = self.maps.terms.get(termid) {
            self.term_details_helper(term_ref)
        } else {
            None
        }
    }

    pub fn get_reference_details(&self, reference_uniquename: &str) -> Option<ReferenceDetails> {
        if let Some(reference_ref) = self.maps.references.get(reference_uniquename) {
            let mut reference = reference_ref.clone();
            let details_map = self.detail_map_of_cv_annotations(&reference.cv_annotations);
            reference.annotation_details = details_map;
            reference.terms_by_termid = self.fill_term_map(&reference.terms_by_termid);
            reference.genes_by_uniquename = self.fill_gene_map(&reference.genes_by_uniquename);
            Some(reference)
        } else {
            None
        }
    }

    pub fn interactors_of_genes(&self, gene_uniquename: &GeneUniquename,
                                interaction_type: InteractionType)
                                -> Vec<GeneUniquename> {
        if let Some(interactors) = self.maps.interactors_of_genes.get(gene_uniquename) {
            interactors.iter()
                .filter(|interactor| {
                    interactor.interaction_type == interaction_type
                })
                .map(|interactor| interactor.interactor_uniquename.clone())
                .collect::<Vec<_>>()
        } else {
            vec![]
        }
    }

    pub fn get_chr_details(&self, chr_name: &str) -> Option<&ChromosomeDetails> {
        self.maps.chromosomes.get(chr_name)
    }

    pub fn reload(&mut self) {
        let config = Config::read(&self.config_file_name);
        self.maps = load(&config, &self.search_maps_file_name);
    }
}
<commit_msg>Fix broken phenotype queries<commit_after>use std::process;
use std::fs::File;
use std::io::{Read, BufReader};

use serde_json;
use std::collections::{HashMap, HashSet};

use crate::web::data::{APIMaps, IdGeneSubsetMap, APIGeneSummary, APIAlleleDetails,
                GeneDetails, TermDetails, GenotypeDetails, ReferenceDetails,
                InteractionType, OntAnnotationMap, IdOntAnnotationDetailMap,
                TermShort, TermShortOptionMap, ChromosomeDetails,
                ReferenceShort, ReferenceShortOptionMap,
                GeneShort, GeneShortOptionMap, GeneQueryData};
use crate::web::config::{Config, TermAndName};
use crate::api::query::{SingleOrMultiAllele, QueryExpressionFilter};

use flate2::read::GzDecoder;

use crate::types::{TermId, GeneUniquename};

use pombase_rc_string::RcString;

pub struct ServerData {
    config_file_name: String,
    maps: APIMaps,
    secondary_identifiers_map: HashMap<TermId, TermId>,
    search_maps_file_name: String,
}

fn make_secondary_identifiers_map(terms: &HashMap<TermId, TermDetails>)
                                  -> HashMap<TermId, TermId>
{
    let mut ret_map = HashMap::new();

    for term_details in terms.values() {
        for secondary_identifier in &term_details.secondary_identifiers {
            ret_map.insert(secondary_identifier.clone(),
                           term_details.termid.clone());
        }
    }

    ret_map
}

fn load(config: &Config, search_maps_file_name: &str) -> APIMaps
{
    let file = match File::open(search_maps_file_name) {
        Ok(file) => file,
        Err(err) => {
            eprint!("Failed to read {}: {}\n", search_maps_file_name, err);
            process::exit(1);
        }
    };
    let reader = BufReader::new(file);

    let mut decoder = GzDecoder::new(reader);
    let mut decoded_json = String::new();
    decoder.read_to_string(&mut decoded_json).unwrap();

    let mut query_api_maps: APIMaps =
        match serde_json::from_str(&decoded_json) {
            Ok(results) => results,
            Err(err) => {
                eprint!("failed to parse {}: {}", search_maps_file_name, err);
                process::exit(1);
            },
        };

    let mut new_entries: IdGeneSubsetMap = HashMap::new();

    let prefixes_to_remove: Vec<String> =
        config.server.subsets.prefixes_to_remove
        .iter().map(|prefix| prefix.clone() + ":").collect();

    // strip prefixes and add to map
    for (subset_name, subset_details) in &query_api_maps.gene_subsets {
        for prefix in &prefixes_to_remove {
            if subset_name.starts_with(prefix) {
                let new_subset_name = &subset_name[prefix.len()..];
                new_entries.insert(RcString::from(new_subset_name), subset_details.clone());
            }
        }
    }

    query_api_maps.gene_subsets.extend(new_entries);

    query_api_maps
}

impl ServerData {
    pub fn new(config_file_name: &str, search_maps_file_name: &str)
               -> ServerData
    {
        let config = Config::read(config_file_name);

        let maps = load(&config, search_maps_file_name);

        let secondary_identifiers_map =
            make_secondary_identifiers_map(&maps.terms);

        ServerData {
            config_file_name: config_file_name.into(),
            search_maps_file_name: search_maps_file_name.into(),
            secondary_identifiers_map,
            maps
        }
    }

    pub fn gene_uniquename_of_id(&self, id: &RcString) -> Option<GeneUniquename> {
        if self.maps.gene_summaries.contains_key(id) {
            Some(id.clone())
        } else {
            if let Some(gene_uniquename) =
                self.maps.gene_name_gene_map.get(id) {
                    Some(gene_uniquename.clone())
                } else {
                    let lower_case_id = id.to_lowercase();
                    for gene_uniquename in self.maps.gene_summaries.keys() {
                        if gene_uniquename.to_lowercase() == lower_case_id {
                            return Some(gene_uniquename.clone());
                        }
                    }
                    None
                }
        }
    }

    pub fn get_gene_summary(&self, gene_uniquename: &str) -> Option<&APIGeneSummary> {
        self.maps.gene_summaries.get(gene_uniquename)
    }

    pub fn get_gene_details(&self, gene_uniquename: &str) -> Option<&GeneDetails> {
        self.maps.genes.get(gene_uniquename)
    }

    pub fn get_gene_query_data(&self, gene_uniquename: &str) -> Option<&GeneQueryData> {
        self.maps.gene_query_data_map.get(gene_uniquename)
    }

    pub fn genes_of_termid(&self, term_id: &str) -> Vec<GeneUniquename> {
        match self.maps.termid_genes.get(term_id) {
            Some(gene_uniquenames) => {
                gene_uniquenames.iter().cloned().collect::<Vec<_>>()
            },
            None => vec![],
        }
    }

    pub fn genes_of_subset(&self, search_name: &str) -> Vec<GeneUniquename> {
        if search_name.starts_with('!') || search_name.ends_with('*') {
            let mut trimmed_search_name = search_name.to_owned();
            let invert_search = search_name.starts_with('!');
            let wildcard = search_name.ends_with('*');
            if invert_search {
                trimmed_search_name.remove(0);
            }
            if wildcard {
                trimmed_search_name.pop();
            }
            let mut genes = HashSet::new();
            for (subset_name, subset_details) in &self.maps.gene_subsets {
                let name_matches =
                    wildcard && subset_name.starts_with(&trimmed_search_name) ||
                    trimmed_search_name.eq(subset_name);

                if !invert_search && name_matches || invert_search && !name_matches {
                    genes.extend(subset_details.elements.iter().cloned());
                }
            }
            genes.iter().cloned().collect::<Vec<_>>()
        } else {
            match self.maps.gene_subsets.get(search_name) {
                Some(subset_details) => {
                    subset_details.elements.iter().cloned().collect::<Vec<_>>()
                },
                None => vec![],
            }
        }
    }

    pub fn genes_of_genotypes(&self, term_id: &str,
                              single_or_multi_allele: &SingleOrMultiAllele,
                              expression_filter: &Option<QueryExpressionFilter>,
                              conditions_filter: &HashSet<TermAndName>,
                              excluded_conditions_filter: &HashSet<TermAndName>)
                              -> Vec<GeneUniquename>
    {
        if let Some(annotations) = self.maps.termid_genotype_annotation.get(term_id) {
            let mut genes: HashSet<GeneUniquename> = HashSet::new();
            for annotation in annotations {

                let mut add_single = false;
                let mut add_multi = false;

                match *single_or_multi_allele {
                    SingleOrMultiAllele::Single => add_single = true,
                    SingleOrMultiAllele::Multi => add_multi = true,
                    SingleOrMultiAllele::Both => {
                        add_single = true;
                        add_multi = true;
                    },
                }

                let expression_matches =
                    |allele_details: &APIAlleleDetails| {
                        let expression = &allele_details.expression;
                        let allele_type = &allele_details.allele_type;
                        if let Some(ref expression_filter) = *expression_filter {
                            if *expression_filter == QueryExpressionFilter::Any {
                                return true;
                            }
                            if *expression_filter == QueryExpressionFilter::Null {
                                if allele_type == "deletion" {
                                    return true;
                                }
                                if let Some(ref expression) = *expression {
                                    expression == "Null"
                                } else {
                                    false
                                }
                            } else {
                                if *expression_filter == QueryExpressionFilter::WtOverexpressed {
                                    if let Some(ref expression) = *expression {
                                        expression == "Overexpression" &&
                                            allele_type == "wild_type"
                                    } else {
                                        false
                                    }
                                } else {
                                    false
                                }
                            }
                        } else {
                            true
                        }
                    };

                let condition_matches =
                    |conditions: &HashSet<TermAndName>, test_conditions_filter: &HashSet<TermAndName>| {
                        if test_conditions_filter.len() == 0 {
                            // don't filter in this case
                            return true;
                        }

                        for filter_condition in test_conditions_filter {
                            if conditions.iter().find(
                                |cond| {
                                    filter_condition.termid == cond.termid
                                })
                                .is_some() {
                                return true
                            }
                        }

                        false
                    };

                if annotation.is_multi && add_multi ||
                    !annotation.is_multi && add_single &&
                    expression_matches(&annotation.alleles[0]) &&
                    condition_matches(&annotation.conditions, conditions_filter) &&
                    (excluded_conditions_filter.len() == 0 ||
                     !condition_matches(&annotation.conditions, excluded_conditions_filter)) {
                        for allele_details in &annotation.alleles {
                            genes.insert(allele_details.gene.clone());
                        }
                }
            }
            genes.into_iter().collect::<Vec<_>>()
        } else {
            vec![]
        }
    }

    pub fn filter_genes(&self, p: & dyn Fn(&APIGeneSummary) -> bool)
                        -> Vec<GeneUniquename>
    {
        self.maps.gene_summaries.values()
            .filter(|summ| p(summ))
            .map(|summ| summ.uniquename.clone())
            .collect()
    }

    fn detail_map_of_cv_annotations(&self, ont_annotation_map: &OntAnnotationMap)
                                    -> IdOntAnnotationDetailMap
    {
        let mut details_map = HashMap::new();

        for term_annotations in ont_annotation_map.values() {
            for term_annotation in term_annotations {
                for annotation_detail_id in &term_annotation.annotations {
                    let details =
                        &self.maps.annotation_details[annotation_detail_id];
                    details_map.insert(*annotation_detail_id, details.clone());
                }
            }
        }

        details_map
    }

    fn fill_term_map(&self, term_map: &TermShortOptionMap) -> TermShortOptionMap {
        let mut ret = term_map.clone();
        for termid in term_map.keys() {
            if let Some(term_details) = self.maps.terms.get(termid) {
                let term_short = TermShort::from_term_details(term_details);
                ret.insert(termid.clone(), Some(term_short));
            } else {
                eprint!("WARNING missing short info for: {}\n", termid);
                ret.insert(termid.clone(), None);
            }
        }
        ret
    }

    fn fill_gene_map(&self, gene_map: &GeneShortOptionMap) -> GeneShortOptionMap {
        let mut ret = gene_map.clone();
        for gene_uniquename in gene_map.keys() {
            let gene_details = &self.maps.genes[gene_uniquename];
            let gene_short = GeneShort::from_gene_details(gene_details);
            ret.insert(gene_uniquename.clone(), Some(gene_short));
        }
        ret
    }

    fn fill_reference_map(&self, reference_map: &ReferenceShortOptionMap) -> ReferenceShortOptionMap {
        let mut ret = reference_map.clone();
        for reference_uniquename in reference_map.keys() {
            let reference_details = &self.maps.references[reference_uniquename];
            let reference_short = ReferenceShort::from_reference_details(reference_details);
            ret.insert(reference_uniquename.clone(), Some(reference_short));
        }
        ret
    }

    // return a GeneDetails object with the term, genes and references maps filled in
    pub fn get_full_gene_details(&self, gene_uniquename: &str) -> Option<GeneDetails> {
        if let Some(gene_ref) = self.maps.genes.get(gene_uniquename) {
            let mut gene = gene_ref.clone();
            let details_map = self.detail_map_of_cv_annotations(&gene.cv_annotations);
            gene.annotation_details = details_map;
            gene.terms_by_termid = self.fill_term_map(&gene.terms_by_termid);
            gene.genes_by_uniquename = self.fill_gene_map(&gene.genes_by_uniquename);
            gene.references_by_uniquename =
                self.fill_reference_map(&gene.references_by_uniquename);
            Some(gene)
        } else {
            None
        }
    }

    pub fn get_genotype_details(&self, genotype_uniquename: &str) -> Option<GenotypeDetails> {
        if let Some(genotype_ref) = self.maps.genotypes.get(genotype_uniquename) {
            let mut genotype = genotype_ref.clone();
            let details_map = self.detail_map_of_cv_annotations(&genotype.cv_annotations);
            genotype.annotation_details = details_map;
            genotype.terms_by_termid = self.fill_term_map(&genotype.terms_by_termid);
            genotype.genes_by_uniquename = self.fill_gene_map(&genotype.genes_by_uniquename);
            genotype.references_by_uniquename =
                self.fill_reference_map(&genotype.references_by_uniquename);
            Some(genotype)
        } else {
            None
        }
    }

    fn term_details_helper(&self, term_ref: &TermDetails) -> Option<TermDetails> {
        let mut term = term_ref.clone();
        let details_map = self.detail_map_of_cv_annotations(&term.cv_annotations);
        term.annotation_details = details_map;
        term.terms_by_termid = self.fill_term_map(&term.terms_by_termid);
        term.genes_by_uniquename = self.fill_gene_map(&term.genes_by_uniquename);
        term.references_by_uniquename =
            self.fill_reference_map(&term.references_by_uniquename);
        Some(term)
    }

    pub fn get_term_details(&self, termid: &str) -> Option<TermDetails> {
        let termid =
            if let Some(real_termid) = self.secondary_identifiers_map.get(termid) {
                real_termid
            } else {
                termid
            };
        if let Some(term_ref) = self.maps.terms.get(termid) {
            self.term_details_helper(term_ref)
        } else {
            None
        }
    }

    pub fn get_reference_details(&self, reference_uniquename: &str) -> Option<ReferenceDetails> {
        if let Some(reference_ref) = self.maps.references.get(reference_uniquename) {
            let mut reference = reference_ref.clone();
            let details_map = self.detail_map_of_cv_annotations(&reference.cv_annotations);
            reference.annotation_details = details_map;
            reference.terms_by_termid = self.fill_term_map(&reference.terms_by_termid);
            reference.genes_by_uniquename = self.fill_gene_map(&reference.genes_by_uniquename);
            Some(reference)
        } else {
            None
        }
    }

    pub fn interactors_of_genes(&self, gene_uniquename: &GeneUniquename,
                                interaction_type: InteractionType)
                                -> Vec<GeneUniquename> {
        if let Some(interactors) = self.maps.interactors_of_genes.get(gene_uniquename) {
            interactors.iter()
                .filter(|interactor| {
                    interactor.interaction_type == interaction_type
                })
                .map(|interactor| interactor.interactor_uniquename.clone())
                .collect::<Vec<_>>()
        } else {
            vec![]
        }
    }

    pub fn get_chr_details(&self, chr_name: &str) -> Option<&ChromosomeDetails> {
        self.maps.chromosomes.get(chr_name)
    }

    pub fn reload(&mut self) {
        let config = Config::read(&self.config_file_name);
        self.maps = load(&config, &self.search_maps_file_name);
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate metrics;
extern crate histogram;

use iron::prelude::*;
use iron::status;
use metrics::meter::{Meter, StdMeter};
use metrics::counter::{Counter, StdCounter};
use metrics::gauge::{Gauge, StdGauge};
use metrics::registry::{Registry, StdRegistry};
use metrics::prometheus_reporter::PrometheusReporter;
use std::sync::Arc;
use histogram::*;

fn main() {
    println!("WebServer Starting");
    extern crate hyper;
    let m = StdMeter::new();
    m.mark(100);

    let mut c: StdCounter = StdCounter::new();
    c.inc();

    let mut g: StdGauge = StdGauge { value: 0f64 };
    g.set(1.2);

    let mut hc = HistogramConfig::new();
    hc.max_value(100).precision(1);
    let mut h = Histogram::configured(hc).unwrap();

    h.record(1, 1);

    let mut r = StdRegistry::new();
    r.insert("meter1", m);
    r.insert("counter1", c);
    r.insert("gauge1", g);
    r.insert("histogram", h);

    let arc_registry = Arc::new(r);
    let reporter = PrometheusReporter::new(arc_registry.clone(),
                        "test",
                        "0.0.0.0:8080",
                        "asd.asdf");
    reporter.start();
    Iron::new(|_: &mut Request| {
        Ok(Response::with(status::NotFound))
    }).http("0.0.0.0:3000").unwrap();
    println!("WebServer Running");

}
<commit_msg>Fix examples<commit_after>extern crate iron;
extern crate metrics;
extern crate histogram;

use iron::prelude::*;
use iron::status;
use metrics::metrics::counter::*;
use metrics::metrics::gauge::*;
use metrics::metrics::meter::*;
use metrics::registry::{Registry, StdRegistry};
use metrics::reporter::prometheus::PrometheusReporter;
use std::sync::Arc;
use histogram::*;

fn main() {
    println!("WebServer Starting");
    extern crate hyper;
    let m = StdMeter::new();
    m.mark(100);

    let mut c: StdCounter = StdCounter::new();
    c.inc();

    let mut g: StdGauge = StdGauge { value: 0f64 };
    g.set(1.2);

    let mut hc = HistogramConfig::new();
    hc.max_value(100).precision(1);
    let mut h = Histogram::configured(hc).unwrap();

    h.record(1, 1);

    let mut r = StdRegistry::new();
    r.insert("meter1", m);
    r.insert("counter1", c);
    r.insert("gauge1", g);
    r.insert("histogram", h);

    let arc_registry = Arc::new(r);
    let reporter = PrometheusReporter::new(arc_registry.clone(),
                        "test",
                        "0.0.0.0:8080",
                        "asd.asdf");
    reporter.start();
    Iron::new(|_: &mut Request| {
        Ok(Response::with(status::NotFound))
    }).http("0.0.0.0:3000").unwrap();
    println!("WebServer Running");

}
<|endoftext|>


<commit_before>//! This crate helps to create a Fractalide component
//!
//! It provides the macro `component` which takes the high level view of the component, and creates the code for the scheduler.
//!
//! It also declare the Trait Agent and the shared methods needed by every component and the scheduler.

extern crate capnp;

// TODO : Add method to remove components
use ports::{IPSender, IPReceiver};
use scheduler::Signal;
use result::Result;

/// Provide the generic functions of agents
///
/// These three functions are used by the scheduler
pub trait Agent {
    /// Return true if there is at least one input port
    fn is_input_ports(&self) -> bool;
    /// Connect output port
    fn connect(&mut self, port: &str, sender: IPSender) -> Result<()>;
    /// Connect array output port
    fn connect_array(&mut self, port: &str, element: String, sender: IPSender) -> Result<()>;
    /// Add input element
    fn add_inarr_element(&mut self, port: &str, element: String, recv: IPReceiver) -> Result<()>;
    /// Run the method of the component, his personal logic
    fn run(&mut self) -> Result<Signal>;
}

/// The agent macro.
///
/// It helps to define a agent, by defining the input and output ports, if there is an option or an acc port, ...
///
/// Example :
///
/// ```rust,ignore
/// agent! {
///    inputs(input: any),
///    outputs(output: any),
///    option(generic_text),
///    fn run(&mut self) -> Result<Signal> {
///        // Receive an IP
///        let ip = try!(self.input.input.recv());
///
///        // Received an IP from the option port (a generic_text)
///        let opt = self.recv_opt();
///
///        // Get the capn'p reader
///        let reader: generic_text::Reader = try!(opt.read_schema());
///        // Print the option
///        println!("{}", try!(reader.get_text()));
///
///        // Send the received IP outside, but don't care about the success (drop on fail)
///        let _ = self.output.output.send(ip);
///
///        Ok(End)
///    }
/// }
/// ```
#[macro_export]
macro_rules! agent {
    (
       $name:ident, $( edges( $( $edge:ident ),* ) )*
        inputs($( $input_field_name:ident: $input_edge_name:ident),* ),
        inputs_array($( $input_array_name:ident: $input_edge_array:ident),* ),
        outputs($( $output_field_name:ident: $output_edge_name:ident),* ),
        outputs_array($($output_array_name:ident: $output_edge_array:ident),* ),
        option($($option_edge: ident),*),
        acc($($acc_edge: ident),*), $( portal($portal_type:ty => $portal_value:expr))*
        fn run(&mut $arg:ident) -> Result<()> $fun:block
    )
        =>
    {
        use rustfbp::agent::Agent;

        use rustfbp::result;
        use rustfbp::result::Result;
        use rustfbp::scheduler::{CompMsg, Signal};
        use std::error::Error;

        use std::sync::mpsc::{Sender};
        use std::sync::mpsc::channel;

        use rustfbp::ports::{IP, IPSender, IPReceiver, OutputSend};

        #[allow(unused_imports)]
        use std::collections::HashMap;

        use capnp::serialize;
        use capnp::message;

        use std::io::{Read, Write};

        use rustfbp::scheduler::Signal::*;

        mod edge_capnp {
                include!("edge_capnp.rs");
        }

        $( $(
            use edge_capnp::$edge;
        )* )*

        impl $name {
            pub fn recv_option(&mut self) -> IP {
                self.try_recv_option();
                if self.option_ip.is_none() {
                    self.option_ip = self.ports.recv("option").ok();
                }
                match self.option_ip {
                    Some(ref ip) => ip.clone(),
                    None => unreachable!(),
                }
            }

            pub fn try_recv_option(&mut self) -> Option<IP> {
                loop {
                    match self.ports.try_recv("option") {
                        Err(_) => { break; },
                        Ok(ip) => { self.option_ip = Some(ip); }
                    };
                }
                self.option_ip.as_ref().map(|ip|{ ip.clone() })
            }
        }

        // simple and array
        impl Agent for $name {

            fn get_ports(&mut self) -> &mut Ports {
                &mut self.ports
            }

            fn is_input_ports(&self) -> bool {
                $(
                    if true || stringify!($input_field_name) == "" { return true; }
                )*
                $(
                    if true || stringify!($input_array_name) == "" { return true; }
                )*
                false
            }

            fn run(&mut $arg) -> Result<()> $fun

        }

        /* Global agent */

        #[allow(dead_code)]
        #[allow(non_camel_case_types)]
        pub struct $name {
            name: String,
            pub ports: Ports,
            pub option_ip: Option<IP>,
            $(
            pub portal: $portal_type ,
            )*
        }

        #[allow(dead_code)]
        pub fn new(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            let (ports, senders) = try!(Ports::new(name.clone(), sched,
                                   vec!["option".into(), "acc".into(), $( stringify!($input_field_name).to_string() ),*],
                                   vec![$( stringify!($input_array_name).to_string() ),*],
                                   vec!["acc".into(), $( stringify!($output_field_name).to_string() ),*],
                                   vec![$( stringify!($output_array_name).to_string() ),*],));

            // Put it together
            let comp = $name{
                name: name,
                ports: ports,
                option_ip: None,
                $(
                    portal: $portal_value,
                )*
            };
            Ok((Box::new(comp) as Box<Agent + Send>, senders))
        }

        #[no_mangle]
        pub extern fn create_agent(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            new(name, sched)
        }

        #[no_mangle]
        pub extern fn get_schema_input(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_field_name)=> Ok(stringify!($input_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_input_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_array_name) => Ok(stringify!($input_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_field_name)=> Ok(stringify!($output_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_array_name) => Ok(stringify!($output_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }
    }
}
<commit_msg>Agent: import all the schemas<commit_after>//! This crate helps to create a Fractalide component
//!
//! It provides the macro `component` which takes the high level view of the component, and creates the code for the scheduler.
//!
//! It also declare the Trait Agent and the shared methods needed by every component and the scheduler.

extern crate capnp;

// TODO : Add method to remove components
use ports::{IPSender, IPReceiver};
use scheduler::Signal;
use result::Result;

/// Provide the generic functions of agents
///
/// These three functions are used by the scheduler
pub trait Agent {
    /// Return true if there is at least one input port
    fn is_input_ports(&self) -> bool;
    /// Connect output port
    fn connect(&mut self, port: &str, sender: IPSender) -> Result<()>;
    /// Connect array output port
    fn connect_array(&mut self, port: &str, element: String, sender: IPSender) -> Result<()>;
    /// Add input element
    fn add_inarr_element(&mut self, port: &str, element: String, recv: IPReceiver) -> Result<()>;
    /// Run the method of the component, his personal logic
    fn run(&mut self) -> Result<Signal>;
}

/// The agent macro.
///
/// It helps to define a agent, by defining the input and output ports, if there is an option or an acc port, ...
///
/// Example :
///
/// ```rust,ignore
/// agent! {
///    inputs(input: any),
///    outputs(output: any),
///    option(generic_text),
///    fn run(&mut self) -> Result<Signal> {
///        // Receive an IP
///        let ip = try!(self.input.input.recv());
///
///        // Received an IP from the option port (a generic_text)
///        let opt = self.recv_opt();
///
///        // Get the capn'p reader
///        let reader: generic_text::Reader = try!(opt.read_schema());
///        // Print the option
///        println!("{}", try!(reader.get_text()));
///
///        // Send the received IP outside, but don't care about the success (drop on fail)
///        let _ = self.output.output.send(ip);
///
///        Ok(End)
///    }
/// }
/// ```
#[macro_export]
macro_rules! agent {
    (
       $name:ident, $( edges( $( $edge:ident ),* ) )*
        inputs($( $input_field_name:ident: $input_edge_name:ident),* ),
        inputs_array($( $input_array_name:ident: $input_edge_array:ident),* ),
        outputs($( $output_field_name:ident: $output_edge_name:ident),* ),
        outputs_array($($output_array_name:ident: $output_edge_array:ident),* ),
        option($($option_edge: ident),*),
        acc($($acc_edge: ident),*), $( portal($portal_type:ty => $portal_value:expr))*
        fn run(&mut $arg:ident) -> Result<()> $fun:block
    )
        =>
    {
        use rustfbp::agent::Agent;

        use rustfbp::result;
        use rustfbp::result::Result;
        use rustfbp::scheduler::{CompMsg, Signal};
        use std::error::Error;

        use std::sync::mpsc::{Sender};
        use std::sync::mpsc::channel;

        use rustfbp::ports::{IP, IPSender, IPReceiver, OutputSend};

        #[allow(unused_imports)]
        use std::collections::HashMap;

        use capnp::serialize;
        use capnp::message;

        use std::io::{Read, Write};

        use rustfbp::scheduler::Signal::*;

        mod edge_capnp {
                include!("edge_capnp.rs");
        }

        use edge_capnp::*;

        impl $name {
            pub fn recv_option(&mut self) -> IP {
                self.try_recv_option();
                if self.option_ip.is_none() {
                    self.option_ip = self.ports.recv("option").ok();
                }
                match self.option_ip {
                    Some(ref ip) => ip.clone(),
                    None => unreachable!(),
                }
            }

            pub fn try_recv_option(&mut self) -> Option<IP> {
                loop {
                    match self.ports.try_recv("option") {
                        Err(_) => { break; },
                        Ok(ip) => { self.option_ip = Some(ip); }
                    };
                }
                self.option_ip.as_ref().map(|ip|{ ip.clone() })
            }
        }

        // simple and array
        impl Agent for $name {

            fn get_ports(&mut self) -> &mut Ports {
                &mut self.ports
            }

            fn is_input_ports(&self) -> bool {
                $(
                    if true || stringify!($input_field_name) == "" { return true; }
                )*
                $(
                    if true || stringify!($input_array_name) == "" { return true; }
                )*
                false
            }

            fn run(&mut $arg) -> Result<()> $fun

        }

        /* Global agent */

        #[allow(dead_code)]
        #[allow(non_camel_case_types)]
        pub struct $name {
            name: String,
            pub ports: Ports,
            pub option_ip: Option<IP>,
            $(
            pub portal: $portal_type ,
            )*
        }

        #[allow(dead_code)]
        pub fn new(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            let (ports, senders) = try!(Ports::new(name.clone(), sched,
                                   vec!["option".into(), "acc".into(), $( stringify!($input_field_name).to_string() ),*],
                                   vec![$( stringify!($input_array_name).to_string() ),*],
                                   vec!["acc".into(), $( stringify!($output_field_name).to_string() ),*],
                                   vec![$( stringify!($output_array_name).to_string() ),*],));

            // Put it together
            let comp = $name{
                name: name,
                ports: ports,
                option_ip: None,
                $(
                    portal: $portal_value,
                )*
            };
            Ok((Box::new(comp) as Box<Agent + Send>, senders))
        }

        #[no_mangle]
        pub extern fn create_agent(name: String, sched: Sender<CompMsg>) -> Result<(Box<Agent + Send>, HashMap<String, IPSender>)> {
            new(name, sched)
        }

        #[no_mangle]
        pub extern fn get_schema_input(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_field_name)=> Ok(stringify!($input_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_input_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($input_array_name) => Ok(stringify!($input_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_field_name)=> Ok(stringify!($output_edge_name).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }

        #[no_mangle]
        pub extern fn get_schema_output_array(port: &str) -> Result<String> {
            match port {
                $(
                    stringify!($output_array_name) => Ok(stringify!($output_edge_array).into()),
                )*
                _ => { Err(result::Error::PortNotFound("unknown".into(), port.into())) }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Computing deltas between two ropes.

use std::collections::HashMap;

use crate::compare::RopeScanner;
use crate::delta::{Delta, DeltaElement};
use crate::interval::Interval;
use crate::rope::{LinesMetric, Rope, RopeDelta, RopeInfo};
use crate::tree::{Node, NodeInfo};

use memchr::memchr;

/// A trait implemented by various diffing strategies.
pub trait Diff<N: NodeInfo> {
    fn compute_delta(base: &Node<N>, target: &Node<N>) -> Delta<N>;
}

/// The minimum length of non-whitespace characters in a line before
/// we consider it for diffing purposes.
const MIN_SIZE: usize = 32;

/// A line-oriented, hash based diff algorithm.
///
/// This works by taking a hash of each line in either document that
/// has a length, ignoring leading whitespace, above some threshold.
///
/// Lines in the target document are matched against lines in the
/// base document. When a match is found, it is extended forwards
/// and backwards as far as possible.
///
/// This runs in O(n+m) in the lengths of the two ropes, and produces
/// results on a variety of workloads that are comparable in quality
/// (measured in terms of serialized diff size) with the results from
/// using a suffix array, while being an order of magnitude faster.
pub struct LineHashDiff;

impl Diff<RopeInfo> for LineHashDiff {
    fn compute_delta(base: &Rope, target: &Rope) -> RopeDelta {
        let mut builder = DiffBuilder::default();

        // before doing anything, scan top down and bottom up for like-ness.
        let mut scanner = RopeScanner::new(base, target);
        let (start_offset, diff_end) = scanner.find_min_diff_range();
        let target_end = target.len() - diff_end;

        if start_offset > 0 {
            builder.copy(0, 0, start_offset);
        }

        // if our preliminary scan finds no differences we're done
        if start_offset == base.len() && target.len() == base.len() {
            return builder.to_delta(base, target);
        }

        // TODO: because of how `lines_raw` returns Cows, we can't easily build
        // the lookup table without allocating. The eventual solution would be
        // to have a custom iter on the rope that returns suitable chunks.
        let base_string = String::from(base);
        let line_hashes = make_line_hashes(&base_string, MIN_SIZE);

        let line_count = target.measure::<LinesMetric>() + 1;
        let mut matches = Vec::with_capacity(line_count);

        let mut targ_line_offset = 0;
        let mut prev_base = 0;

        let mut needs_subseq = false;
        for line in target.lines_raw(start_offset..target_end) {
            let non_ws = non_ws_offset(&line);
            if line.len() - non_ws >= MIN_SIZE {
                if let Some(base_off) = line_hashes.get(&line[non_ws..]) {
                    let targ_off = targ_line_offset + non_ws;
                    matches.push((start_offset + targ_off, *base_off));
                    if *base_off < prev_base {
                        needs_subseq = true;
                    }
                    prev_base = *base_off;
                }
            }
            targ_line_offset += line.len();
        }

        // we now have an ordered list of matches and their positions.
        // to ensure that our delta only copies non-decreasing base regions,
        // we take the longest increasing subsequence.
        // TODO: a possible optimization here would be to expand matches
        // to adjacent lines first? this would be at best a small win though..

        let longest_subseq =
            if needs_subseq { longest_increasing_region_set(&matches) } else { matches };

        // for each matching region, we extend it forwards and backwards.
        // we keep track of how far forward we extend it each time, to avoid
        // having a subsequent scan extend backwards over the same region.
        let mut prev_end = start_offset;

        for (targ_off, base_off) in longest_subseq {
            if targ_off <= prev_end {
                continue;
            }
            let (left_dist, mut right_dist) =
                expand_match(base, target, base_off, targ_off, prev_end);

            // don't let last match expand past target_end
            right_dist = right_dist.min(target_end - targ_off);

            let targ_start = targ_off - left_dist;
            let base_start = base_off - left_dist;
            let len = left_dist + right_dist;
            prev_end = targ_start + len;

            builder.copy(base_start, targ_start, len);
        }

        if diff_end > 0 {
            builder.copy(base.len() - diff_end, target.len() - diff_end, diff_end);
        }

        builder.to_delta(base, target)
    }
}

/// Given two ropes and the offsets of two equal bytes, finds the largest
/// identical substring shared between the two ropes which contains the offset.
///
/// The return value is a pair of offsets, each of which represents an absolute
/// distance. That is to say, the position of the start and end boundaries
/// relative to the input offset.
fn expand_match(
    base: &Rope,
    target: &Rope,
    base_off: usize,
    targ_off: usize,
    prev_match_targ_end: usize,
) -> (usize, usize) {
    let mut scanner = RopeScanner::new(base, target);
    let max_left = targ_off - prev_match_targ_end;
    let start = scanner.find_ne_char_back(base_off, targ_off, max_left);
    debug_assert!(start <= max_left, "{} <= {}", start, max_left);
    let end = scanner.find_ne_char(base_off, targ_off, None);
    (start.min(max_left), end)
}

/// Finds the longest increasing subset of copyable regions. This is essentially
/// the longest increasing subsequence problem. This implementation is adapted
/// from https://codereview.stackexchange.com/questions/187337/longest-increasing-subsequence-algorithm
fn longest_increasing_region_set(items: &[(usize, usize)]) -> Vec<(usize, usize)> {
    let mut result = vec![0];
    let mut prev_chain = vec![0; items.len()];

    for i in 1..items.len() {
        // If the next item is greater than the last item of the current longest
        // subsequence, push its index at the end of the result and continue.
        let last_idx = *result.last().unwrap();
        if items[last_idx].1 < items[i].1 {
            prev_chain[i] = last_idx;
            result.push(i);
            continue;
        }

        let next_idx = match result.binary_search_by(|&j| items[j].1.cmp(&items[i].1)) {
            Ok(_) => continue, // we ignore duplicates
            Err(idx) => idx,
        };

        if items[i].1 < items[result[next_idx]].1 {
            if next_idx > 0 {
                prev_chain[i] = result[next_idx - 1];
            }
            result[next_idx] = i;
        }
    }

    // walk backwards from the last item in result to build the final sequence
    let mut u = result.len();
    let mut v = *result.last().unwrap();
    while u != 0 {
        u -= 1;
        result[u] = v;
        v = prev_chain[v];
    }
    result.iter().map(|i| items[*i]).collect()
}

#[inline]
fn non_ws_offset(s: &str) -> usize {
    s.as_bytes().iter().take_while(|b| **b == b' ' || **b == b'\t').count()
}

/// Represents copying `len` bytes from base to target.
#[derive(Debug, Clone, Copy)]
struct DiffOp {
    target_idx: usize,
    base_idx: usize,
    len: usize,
}

/// Keeps track of copy ops during diff construction.
#[derive(Debug, Clone, Default)]
pub struct DiffBuilder {
    ops: Vec<DiffOp>,
}

impl DiffBuilder {
    fn copy(&mut self, base: usize, target: usize, len: usize) {
        if let Some(prev) = self.ops.last_mut() {
            let prev_end = prev.target_idx + prev.len;
            let base_end = prev.base_idx + prev.len;
            assert!(prev_end <= target, "{} <= {} prev {:?}", prev_end, target, prev);
            if prev_end == target && base_end == base {
                prev.len += len;
                return;
            }
        }
        self.ops.push(DiffOp { target_idx: target, base_idx: base, len })
    }

    fn to_delta(self, base: &Rope, target: &Rope) -> RopeDelta {
        let mut els = Vec::with_capacity(self.ops.len() * 2);
        let mut targ_pos = 0;
        for DiffOp { base_idx, target_idx, len } in self.ops {
            if target_idx > targ_pos {
                let iv = Interval::new(targ_pos, target_idx);
                els.push(DeltaElement::Insert(target.subseq(iv)));
            }
            els.push(DeltaElement::Copy(base_idx, base_idx + len));
            targ_pos = target_idx + len;
        }

        if targ_pos < target.len() {
            let iv = Interval::new(targ_pos, target.len());
            els.push(DeltaElement::Insert(target.subseq(iv)));
        }

        Delta { els, base_len: base.len() }
    }
}

/// Fast iterator over lines in a string, not removing newline characters.
struct LineScanner<'a> {
    inner: &'a str,
    idx: usize,
}

impl<'a> Iterator for LineScanner<'a> {
    type Item = &'a str;
    fn next(&mut self) -> Option<&'a str> {
        if self.idx >= self.inner.len() {
            return None;
        }

        match memchr(b'\n', &self.inner.as_bytes()[self.idx..]) {
            Some(idx) => {
                let next_idx = self.idx + idx + 1;
                let result = &self.inner[self.idx..next_idx];
                self.idx = next_idx;
                Some(result)
            }
            None => {
                let result = &self.inner[self.idx..];
                self.idx = self.inner.len();
                Some(result)
            }
        }
    }
}

fn make_line_hashes<'a>(base: &'a str, min_size: usize) -> HashMap<&'a str, usize> {
    let mut offset = 0;
    let mut line_hashes = HashMap::with_capacity(base.len() / 60);
    let iter = LineScanner { inner: base, idx: 0 };
    for line in iter {
        let non_ws = non_ws_offset(&line);
        if line.len() - non_ws >= min_size {
            line_hashes.insert(&line[non_ws..], offset + non_ws);
        }
        offset += line.len();
    }
    line_hashes
}

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

    static SMALL_ONE: &str = "This adds FixedSizeAdler32, that has a size set at construction, and keeps bytes in a cyclic buffer of that size to be removed when it fills up.

Current logic (and implementing Write) might be too much, since bytes will probably always be fed one by one anyway. Otherwise a faster way of removing a sequence might be needed (one by one is inefficient).";

    static SMALL_TWO: &str = "This adds some function, I guess?, that has a size set at construction, and keeps bytes in a cyclic buffer of that size to be ground up and injested when it fills up.

Currently my sense of smell (and the pain of implementing Write) might be too much, since bytes will probably always be fed one by one anyway. Otherwise crying might be needed (one by one is inefficient).";

    static INTERVAL_STR: &str = include_str!("../src/interval.rs");
    static BREAKS_STR: &str = include_str!("../src/breaks.rs");

    #[test]
    fn diff_smoke_test() {
        let one = SMALL_ONE.into();
        let two = SMALL_TWO.into();

        let delta = LineHashDiff::compute_delta(&one, &two);
        println!("delta: {:?}", &delta);

        let result = delta.apply(&one);
        assert_eq!(result, two);

        let delta = LineHashDiff::compute_delta(&one, &two);
        println!("delta: {:?}", &delta);

        let result = delta.apply(&one);
        assert_eq!(result, two);
    }

    #[test]
    fn test_larger_diff() {
        let one = INTERVAL_STR.into();
        let two = BREAKS_STR.into();

        let delta = LineHashDiff::compute_delta(&one, &two);
        let result = delta.apply(&one);
        assert_eq!(String::from(result), String::from(two));
    }
}
<commit_msg>Update improve memory efficiency of rope diffing (#1137)<commit_after>// Copyright 2018 The xi-editor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Computing deltas between two ropes.

use std::borrow::Cow;
use std::collections::HashMap;

use crate::compare::RopeScanner;
use crate::delta::{Delta, DeltaElement};
use crate::interval::Interval;
use crate::rope::{LinesMetric, Rope, RopeDelta, RopeInfo};
use crate::tree::{Node, NodeInfo};

/// A trait implemented by various diffing strategies.
pub trait Diff<N: NodeInfo> {
    fn compute_delta(base: &Node<N>, target: &Node<N>) -> Delta<N>;
}

/// The minimum length of non-whitespace characters in a line before
/// we consider it for diffing purposes.
const MIN_SIZE: usize = 32;

/// A line-oriented, hash based diff algorithm.
///
/// This works by taking a hash of each line in either document that
/// has a length, ignoring leading whitespace, above some threshold.
///
/// Lines in the target document are matched against lines in the
/// base document. When a match is found, it is extended forwards
/// and backwards as far as possible.
///
/// This runs in O(n+m) in the lengths of the two ropes, and produces
/// results on a variety of workloads that are comparable in quality
/// (measured in terms of serialized diff size) with the results from
/// using a suffix array, while being an order of magnitude faster.
pub struct LineHashDiff;

impl Diff<RopeInfo> for LineHashDiff {
    fn compute_delta(base: &Rope, target: &Rope) -> RopeDelta {
        let mut builder = DiffBuilder::default();

        // before doing anything, scan top down and bottom up for like-ness.
        let mut scanner = RopeScanner::new(base, target);
        let (start_offset, diff_end) = scanner.find_min_diff_range();
        let target_end = target.len() - diff_end;

        if start_offset > 0 {
            builder.copy(0, 0, start_offset);
        }

        // if our preliminary scan finds no differences we're done
        if start_offset == base.len() && target.len() == base.len() {
            return builder.to_delta(base, target);
        }

        let line_hashes = make_line_hashes(&base, MIN_SIZE);

        let line_count = target.measure::<LinesMetric>() + 1;
        let mut matches = Vec::with_capacity(line_count);

        let mut targ_line_offset = 0;
        let mut prev_base = 0;

        let mut needs_subseq = false;
        for line in target.lines_raw(start_offset..target_end) {
            let non_ws = non_ws_offset(&line);
            if line.len() - non_ws >= MIN_SIZE {
                if let Some(base_off) = line_hashes.get(&line[non_ws..]) {
                    let targ_off = targ_line_offset + non_ws;
                    matches.push((start_offset + targ_off, *base_off));
                    if *base_off < prev_base {
                        needs_subseq = true;
                    }
                    prev_base = *base_off;
                }
            }
            targ_line_offset += line.len();
        }

        // we now have an ordered list of matches and their positions.
        // to ensure that our delta only copies non-decreasing base regions,
        // we take the longest increasing subsequence.
        // TODO: a possible optimization here would be to expand matches
        // to adjacent lines first? this would be at best a small win though..

        let longest_subseq =
            if needs_subseq { longest_increasing_region_set(&matches) } else { matches };

        // for each matching region, we extend it forwards and backwards.
        // we keep track of how far forward we extend it each time, to avoid
        // having a subsequent scan extend backwards over the same region.
        let mut prev_end = start_offset;

        for (targ_off, base_off) in longest_subseq {
            if targ_off <= prev_end {
                continue;
            }
            let (left_dist, mut right_dist) =
                expand_match(base, target, base_off, targ_off, prev_end);

            // don't let last match expand past target_end
            right_dist = right_dist.min(target_end - targ_off);

            let targ_start = targ_off - left_dist;
            let base_start = base_off - left_dist;
            let len = left_dist + right_dist;
            prev_end = targ_start + len;

            builder.copy(base_start, targ_start, len);
        }

        if diff_end > 0 {
            builder.copy(base.len() - diff_end, target.len() - diff_end, diff_end);
        }

        builder.to_delta(base, target)
    }
}

/// Given two ropes and the offsets of two equal bytes, finds the largest
/// identical substring shared between the two ropes which contains the offset.
///
/// The return value is a pair of offsets, each of which represents an absolute
/// distance. That is to say, the position of the start and end boundaries
/// relative to the input offset.
fn expand_match(
    base: &Rope,
    target: &Rope,
    base_off: usize,
    targ_off: usize,
    prev_match_targ_end: usize,
) -> (usize, usize) {
    let mut scanner = RopeScanner::new(base, target);
    let max_left = targ_off - prev_match_targ_end;
    let start = scanner.find_ne_char_back(base_off, targ_off, max_left);
    debug_assert!(start <= max_left, "{} <= {}", start, max_left);
    let end = scanner.find_ne_char(base_off, targ_off, None);
    (start.min(max_left), end)
}

/// Finds the longest increasing subset of copyable regions. This is essentially
/// the longest increasing subsequence problem. This implementation is adapted
/// from https://codereview.stackexchange.com/questions/187337/longest-increasing-subsequence-algorithm
fn longest_increasing_region_set(items: &[(usize, usize)]) -> Vec<(usize, usize)> {
    let mut result = vec![0];
    let mut prev_chain = vec![0; items.len()];

    for i in 1..items.len() {
        // If the next item is greater than the last item of the current longest
        // subsequence, push its index at the end of the result and continue.
        let last_idx = *result.last().unwrap();
        if items[last_idx].1 < items[i].1 {
            prev_chain[i] = last_idx;
            result.push(i);
            continue;
        }

        let next_idx = match result.binary_search_by(|&j| items[j].1.cmp(&items[i].1)) {
            Ok(_) => continue, // we ignore duplicates
            Err(idx) => idx,
        };

        if items[i].1 < items[result[next_idx]].1 {
            if next_idx > 0 {
                prev_chain[i] = result[next_idx - 1];
            }
            result[next_idx] = i;
        }
    }

    // walk backwards from the last item in result to build the final sequence
    let mut u = result.len();
    let mut v = *result.last().unwrap();
    while u != 0 {
        u -= 1;
        result[u] = v;
        v = prev_chain[v];
    }
    result.iter().map(|i| items[*i]).collect()
}

#[inline]
fn non_ws_offset(s: &str) -> usize {
    s.as_bytes().iter().take_while(|b| **b == b' ' || **b == b'\t').count()
}

/// Represents copying `len` bytes from base to target.
#[derive(Debug, Clone, Copy)]
struct DiffOp {
    target_idx: usize,
    base_idx: usize,
    len: usize,
}

/// Keeps track of copy ops during diff construction.
#[derive(Debug, Clone, Default)]
pub struct DiffBuilder {
    ops: Vec<DiffOp>,
}

impl DiffBuilder {
    fn copy(&mut self, base: usize, target: usize, len: usize) {
        if let Some(prev) = self.ops.last_mut() {
            let prev_end = prev.target_idx + prev.len;
            let base_end = prev.base_idx + prev.len;
            assert!(prev_end <= target, "{} <= {} prev {:?}", prev_end, target, prev);
            if prev_end == target && base_end == base {
                prev.len += len;
                return;
            }
        }
        self.ops.push(DiffOp { target_idx: target, base_idx: base, len })
    }

    fn to_delta(self, base: &Rope, target: &Rope) -> RopeDelta {
        let mut els = Vec::with_capacity(self.ops.len() * 2);
        let mut targ_pos = 0;
        for DiffOp { base_idx, target_idx, len } in self.ops {
            if target_idx > targ_pos {
                let iv = Interval::new(targ_pos, target_idx);
                els.push(DeltaElement::Insert(target.subseq(iv)));
            }
            els.push(DeltaElement::Copy(base_idx, base_idx + len));
            targ_pos = target_idx + len;
        }

        if targ_pos < target.len() {
            let iv = Interval::new(targ_pos, target.len());
            els.push(DeltaElement::Insert(target.subseq(iv)));
        }

        Delta { els, base_len: base.len() }
    }
}

/// Creates a map of lines to offsets, ignoring trailing whitespace, and only for those lines
/// where line.len() >= min_size. Offsets refer to the first non-whitespace byte in the line.
fn make_line_hashes<'a>(base: &'a Rope, min_size: usize) -> HashMap<Cow<'a, str>, usize> {
    let mut offset = 0;
    let mut line_hashes = HashMap::with_capacity(base.len() / 60);
    for line in base.lines_raw(..) {
        let non_ws = non_ws_offset(&line);
        if line.len() - non_ws >= min_size {
            let cow = match line {
                Cow::Owned(ref s) => Cow::Owned(s[non_ws..].to_string()),
                Cow::Borrowed(s) => Cow::Borrowed(&s[non_ws..]),
            };
            line_hashes.insert(cow, offset + non_ws);
        }
        offset += line.len();
    }
    line_hashes
}

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

    static SMALL_ONE: &str = "This adds FixedSizeAdler32, that has a size set at construction, and keeps bytes in a cyclic buffer of that size to be removed when it fills up.

Current logic (and implementing Write) might be too much, since bytes will probably always be fed one by one anyway. Otherwise a faster way of removing a sequence might be needed (one by one is inefficient).";

    static SMALL_TWO: &str = "This adds some function, I guess?, that has a size set at construction, and keeps bytes in a cyclic buffer of that size to be ground up and injested when it fills up.

Currently my sense of smell (and the pain of implementing Write) might be too much, since bytes will probably always be fed one by one anyway. Otherwise crying might be needed (one by one is inefficient).";

    static INTERVAL_STR: &str = include_str!("../src/interval.rs");
    static BREAKS_STR: &str = include_str!("../src/breaks.rs");

    #[test]
    fn diff_smoke_test() {
        let one = SMALL_ONE.into();
        let two = SMALL_TWO.into();

        let delta = LineHashDiff::compute_delta(&one, &two);
        println!("delta: {:?}", &delta);

        let result = delta.apply(&one);
        assert_eq!(result, two);

        let delta = LineHashDiff::compute_delta(&one, &two);
        println!("delta: {:?}", &delta);

        let result = delta.apply(&one);
        assert_eq!(result, two);
    }

    #[test]
    fn test_larger_diff() {
        let one = INTERVAL_STR.into();
        let two = BREAKS_STR.into();

        let delta = LineHashDiff::compute_delta(&one, &two);
        let result = delta.apply(&one);
        assert_eq!(String::from(result), String::from(two));
    }
}
<|endoftext|>


<commit_before>
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum ListingOrderBy {
    Id,
    Name,
    Path,
    CreatedAt,
    UpdatedAt,
    LastActivityAt,
}

macro_attr! {
    #[derive(Debug, Clone, Serialize, Deserialize, Builder!)]
    struct ProjectListerInternal {
        /// Limit by archived status
        archived: Option<bool>,
        /// Limit by visibility.
        visibility: Option<::ListingVisibility>,
        /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
        order_by: Option<ListingOrderBy>,
        /// Return requests sorted. Default is `::ListingSort::Desc`.
        sort: Option<::ListingSort>,
        /// Return list of authorized projects matching the search criteria.
        search: String,
        /// Return only the ID, URL, name, and path of each project
        simple: Option<bool>,
    }
}
<commit_msg>Let `ListingOrderBy` members be renamed for serde<commit_after>
#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum ListingOrderBy {
    #[serde(rename = "id")]
    Id,
    #[serde(rename = "name")]
    Name,
    #[serde(rename = "path")]
    Path,
    #[serde(rename = "created_at")]
    CreatedAt,
    #[serde(rename = "updated_at")]
    UpdatedAt,
    #[serde(rename = "last_activity_at")]
    LastActivityAt,
}

macro_attr! {
    #[derive(Debug, Clone, Serialize, Deserialize, Builder!)]
    struct ProjectListerInternal {
        /// Limit by archived status
        archived: Option<bool>,
        /// Limit by visibility.
        visibility: Option<::ListingVisibility>,
        /// Return requests ordered by. Default is `ListingOrderBy::CreatedAt`.
        order_by: Option<ListingOrderBy>,
        /// Return requests sorted. Default is `::ListingSort::Desc`.
        sort: Option<::ListingSort>,
        /// Return list of authorized projects matching the search criteria.
        search: String,
        /// Return only the ID, URL, name, and path of each project
        simple: Option<bool>,
    }
}
<|endoftext|>


<commit_before>use core::cmp::{Eq, Ord};
use iter::BaseIter;

pub trait PersistentMap<K: Copy Eq Ord, V: Copy> {
  pure fn get(k: K) -> Option<V>;
  pure fn put(k: K, v: V) -> self;
  pure fn delete(k: K) -> self;
}

enum RBColor {
  Red,
  Black
}

pub enum RBMap<K: Copy Eq Ord, V: Copy> {
  //   color    left         k  value       right
  Tree(RBColor, @RBMap<K,V>, K, Option<V>, @RBMap<K,V>),
  Leaf
}

pure fn RBMap<K: Copy Eq Ord, V: Copy>(key: K, value: V) -> @RBMap<K, V> {
  @Tree(Red, @Leaf, key, Some(value), @Leaf)
}

priv impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> {
  pure fn modify(k: K, new_value: Option<V>) -> @RBMap<K, V> {
    match self {
      @Leaf => @Tree(Red, self, k, copy new_value, self),
      @Tree(color, left, key, original_value, right) => {
        if (k.lt(&key)) {
          self.balanceLeft(color, left.modify(k, new_value), key, original_value, right)
        } else if (k == key) {
          @Tree(color, left, k, copy new_value, right)
        } else {
          self.balanceRight(color, left, key, original_value, right.modify(k, new_value))
        }
      }
    }
  }

  pure fn balanceLeft(c: RBColor, l: @RBMap<K,V>, k: K, v: Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black,@Tree(Red,@Tree(Red,a,xK,xV,b),yK,yV,c),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  pure fn balanceRight(c: RBColor, l: @RBMap<K,V>, k: K, v: Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black, @Tree(Red, t1, k1, v1, t2), k0, v0, @Tree(Red, t3, k2, v2, t4)) =>
        @Tree(Red, @Tree(Black, t1, k1, v1, t2), k0, v0, @Tree(Black, t3, k2, v2, t4)),
      (c, l, k, v, @Tree(Red, t1, k1, v1, t2)) =>
        @Tree(c, @Tree(Red, l, k, v, t1), k1, v1, t2),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }
}

/**
 * A purely functional Left-Leaning Red-Black Tree.
 */
impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> : PersistentMap<K, V> {
  pure fn get(k: K) -> Option<V> {
    match self {
      @Leaf => None,
      @Tree(_, left, key, maybe_value, right) => {
        if (k.lt(&key)) {
          left.get(k)
        } else if (k.gt(&key)) {
          right.get(k)
        } else {
          copy maybe_value
        }
      }
    }
  }

  pure fn put(k: K, new_value: V) -> @RBMap<K, V> {
    self.modify(k, Some(new_value))
  }

  pure fn delete(k: K) -> @RBMap<K, V> {
    self.modify(k, None)
  }
}

impl<K: Copy Eq Ord, V: Copy> RBMap<K, V>: BaseIter<(&K, &V)> {
  pure fn size_hint(&self) -> Option<uint> {
    None
  }

  pure fn each(&self, f: fn(&(&self/K, &self/V)) -> bool) {
    match *self {
      Leaf => (),
      Tree(_, ref left, ref key, ref maybe_value, ref right) => {
        let left: &self/@RBMap<K,V> = left;
        let key: &self/K = key;
        let maybe_value: &self/Option<V> = maybe_value;
        let right: &self/@RBMap<K,V> = right;
        left.each(f);
        match *maybe_value {
            Some(ref value) => {
                let value: &self/V = value;
                f(&(key, value));
            }
            None => ()
        };
        right.each(f);
      }
    }
  }
}

#[test]
fn test_rb_tree() {
  let v1 = RBMap("stevej", 150);
  let v2 = v1.put("thatstacy", 187);

  assert(v2.get("stevej") == Some(150));
  assert(v2.get("thatstacy") == Some(187));

  let v3 = v2.delete("stevej");
  assert(v3.get("stevej") == None);
  assert(v3.get("thatstacy") == Some(187));

  let v4 = v2.put("jeremy", 16);

  let v5 = v4.put("ev", 20);
  let v6 = v5.put("zhanna", 51573);

  assert(v6.get("jeremy") == Some(16));
  assert(v6.get("stevej") == Some(150));
  assert(v6.get("thatstacy") == Some(187));
  assert(v6.get("ev") == Some(20));
  assert(v6.get("zhanna") == Some(51573));
}

#[test]
fn test_base_iter_each() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, kv: &(&int, &int)) -> bool{
    match kv {
      &(k, _) => {
        assert (*n == *k);
        *n += 1;
      }
    }
    false
  }

  v5.each(|z| t(n, z));
}
<commit_msg>a broken WIP to illustrate an issue with function calling between impls<commit_after>use core::cmp::{Eq, Ord};
use iter::BaseIter;

pub trait PersistentMap<K: Copy Eq Ord, V: Copy> {
  pure fn get(k: K) -> Option<V>;
  pure fn put(k: K, v: V) -> self;
  pure fn delete(k: K) -> self;
}

enum RBColor {
  Red,
  Black
}

pub enum RBMap<K: Copy Eq Ord, V: Copy> {
  //   color    left         k  value       right
  Tree(RBColor, @RBMap<K,V>, K, Option<V>, @RBMap<K,V>),
  Leaf
}

pure fn RBMap<K: Copy Eq Ord, V: Copy>(key: K, value: V) -> @RBMap<K, V> {
  @Tree(Red, @Leaf, key, Some(value), @Leaf)
}

impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> {
  pure fn modify(k: K, new_value: Option<V>) -> @RBMap<K, V> {
    match self {
      @Leaf => @Tree(Red, self, k, copy new_value, self),
      @Tree(color, left, key, original_value, right) => {
        if (k.lt(&key)) {
          self.balanceLeft(color, left.modify(k, new_value), key, original_value, right)
        } else if (k == key) {
          @Tree(color, left, k, copy new_value, right)
        } else {
          self.balanceRight(color, left, key, original_value, right.modify(k, new_value))
        }
      }
    }
  }

  pure fn balanceLeft(c: RBColor, l: @RBMap<K,V>, k: K, v: Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black,@Tree(Red,@Tree(Red,a,xK,xV,b),yK,yV,c),zK,zV,d) =>
        @Tree(Red,@Tree(Black,a,xK,xV,b),yK,yV,@Tree(Black,c,zK,zV,d)),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  pure fn balanceRight(c: RBColor, l: @RBMap<K,V>, k: K, v: Option<V>, r: @RBMap<K,V>) -> @RBMap<K,V> {
    match (c, l, k, v, r) {
      (Black, @Tree(Red, t1, k1, v1, t2), k0, v0, @Tree(Red, t3, k2, v2, t4)) =>
        @Tree(Red, @Tree(Black, t1, k1, v1, t2), k0, v0, @Tree(Black, t3, k2, v2, t4)),
      (c, l, k, v, @Tree(Red, t1, k1, v1, t2)) =>
        @Tree(c, @Tree(Red, l, k, v, t1), k1, v1, t2),
      (c,a,xK,xV,b) =>
        @Tree(c,a,xK,xV,b)
    }
  }

  pure fn real_each(f: fn(&(&self/K, &self/V)) -> bool, descend: bool) {
    match *self {
      Leaf => (),
      Tree(_, left, key, maybe_value, right) => ()
    }
  }
}

/**
 * A purely functional Left-Leaning Red-Black Tree.
 */
impl<K: Copy Eq Ord, V: Copy> @RBMap<K, V> : PersistentMap<K, V> {
  pure fn get(k: K) -> Option<V> {
    match self {
      @Leaf => None,
      @Tree(_, left, key, maybe_value, right) => {
        if (k.lt(&key)) {
          left.get(k)
        } else if (k.gt(&key)) {
          right.get(k)
        } else {
          copy maybe_value
        }
      }
    }
  }

  pure fn put(k: K, new_value: V) -> @RBMap<K, V> {
    self.modify(k, Some(new_value))
  }

  pure fn delete(k: K) -> @RBMap<K, V> {
    self.modify(k, None)
  }
}

impl<K: Copy Eq Ord, V: Copy> RBMap<K, V>: BaseIter<(&K, &V)> {
  pure fn size_hint(&self) -> Option<uint> {
    None
  }

  pure fn each(&self, f: fn(&(&self/K, &self/V)) -> bool) {
    match *self {
      Leaf => (),
      Tree(_, ref left, ref key, ref maybe_value, ref right) => {
        self.real_each(f, true);
        let left: &self/@RBMap<K,V> = left;
        let key: &self/K = key;
        unsafe {
          io::println(fmt!("entering for %?", *key));
        }
        let maybe_value: &self/Option<V> = maybe_value;
        let right: &self/@RBMap<K,V> = right;
        left.each(f);
        match *maybe_value {
          Some(ref value) => {
            let value: &self/V = value;
            if !f(&(key, value)) {
              unsafe {
                io::println(fmt!("exiting early on key: %?", *key));
              }
            }
          }
          None => ()
        };
        unsafe {
          io::println(fmt!("descending key %?", *key));
        }

        right.each(f);
      }
    }
  }
}

#[test]
fn test_rb_tree() {
  let v1 = RBMap("stevej", 150);
  let v2 = v1.put("thatstacy", 187);

  assert(v2.get("stevej") == Some(150));
  assert(v2.get("thatstacy") == Some(187));

  let v3 = v2.delete("stevej");
  assert(v3.get("stevej") == None);
  assert(v3.get("thatstacy") == Some(187));

  let v4 = v2.put("jeremy", 16);

  let v5 = v4.put("ev", 20);
  let v6 = v5.put("zhanna", 51573);

  assert(v6.get("jeremy") == Some(16));
  assert(v6.get("stevej") == Some(150));
  assert(v6.get("thatstacy") == Some(187));
  assert(v6.get("ev") == Some(20));
  assert(v6.get("zhanna") == Some(51573));
}

#[test]
fn test_base_iter_each() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, kv: &(&int, &int)) -> bool {
    match kv {
      &(k, _) => {
        assert (*n == *k);
        *n += 1;
      }
    }
    return true;
  }

  v5.each(|z| t(n, z));
}

#[test]
fn test_for() {
  let v1 = RBMap(1, 0);
  let v2 = v1.put(4, 0);
  let v3 = v2.put(3, 0);
  let v4 = v3.put(5, 0);
  let v5 = v4.put(2, 0);

  let n = @mut 1;

  fn t(n: @mut int, kv: &(&int, &int)) -> bool {
    match kv {
      &(k, _) => {
        if (*k == 3) {
          return false;
        } else {
          *n += 1;
        }
      }
    }
    true
  }
  v5.each(|z| t(n, z));

  assert(*n == 5);
}
<|endoftext|>


<commit_before>use std::io::{Writer};
use consts::*;

pub struct ValDisplayer {
    priv writer: @Writer,
    priv display_level: i32
}

impl ValDisplayer {
    pub fn new(writer: @Writer, level: i32) -> ValDisplayer {
        ValDisplayer { display_level: level, writer: writer}
    }

    pub fn set_file(&mut self, writer: @Writer) {
        self.writer = writer;
    }

    pub fn set_level(&mut self, level: i32) {
        self.display_level = level;
    }

    pub fn display_bytes(&self, level: i32, text: &str, bytes: &[u8]) {
        if level <= self.display_level {
            self.writer.write_line(text);

            for &byte in bytes.iter() {
                self.writer.write_str(fmt!("%02X ", byte as uint));
            }

            self.writer.write_line("");
            self.writer.write_line("");
        }
    }

    pub fn display_bits(&self, level: i32, text: &str, data: &[u8], msb_fist: bool) {
        if level <= self.display_level {
            let mut i_byte;
            let mut i_bit;

            self.writer.write_line(text);

            for (i, _) in data.iter().enumerate() {
                i_byte = i / 8;
                i_bit = i % 8;

                if msb_fist {
                    self.writer.write_str(fmt!("%d ", (((data[i_byte] << i_bit) & 0x80) != 0) as int));
                } else {
                    self.writer.write_str(fmt!("%d ", (((data[i_byte] >> i_bit) & 0x01) != 0) as int));
                }
            }

            self.writer.write_line("");
            self.writer.write_line("");
        }
    }

    pub fn display_state_as_bytes(&self, level: i32, text: &str, state: &[u8]) {
        self.display_bytes(level, text, state);
    }

    pub fn display_state_as_32bit(&self, level: i32, text: &str, state: &[u32]) {
        use std::iterator::*;

        if level <= self.display_level {
            self.writer.write_line(text);

            for i in range(0, PERM_SIZE/64) {
                self.writer.write_str(fmt!("%08X:%08X", state[2 *  i] as uint, state[2 * i + 1] as uint));

                if i % 5 == 4 {
                    self.writer.write_str("\n");
                } else {
                    self.writer.write_str(" ");
                }
            }
        }
    }

    pub fn display_state_as_64bit(&self, level: i32, text: &str, state: &[u64]) {
        use std::iterator::*;

        if level <= self.display_level {
            self.writer.write_line(text);

            for i in range(0, PERM_SIZE/64) {
                self.writer.write_str(fmt!("%16X", state[i] as uint));

                if i % 5 == 4 {
                    self.writer.write_str("\n");
                } else {
                    self.writer.write_str(" ");
                }
            }
        }
    }

    pub fn display_round_number(&self, level: i32, rn: u32) {
        if level <= self.display_level {
            self.writer.write_line("");
            self.writer.write_line(fmt!("--- Round %d ---", rn as int));
            self.writer.write_line("");
        }
    }

    pub fn display_test(&self, level: i32, text: &str) {
        if level <= self.display_level {
            self.writer.write_line(text);
            self.writer.write_line("");
        }
    }
}
<commit_msg>Removed unused module<commit_after><|endoftext|>