<commit_before>use regex::Regex;
use reqwest;
use serde_json;

use web::data::{SolrTermSummary, SolrReferenceSummary};
use web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    terms_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let mut prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    clean_words_for_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^10", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

}
<commit_msg>Boost publication_year even more<commit_after>use regex::Regex;
use reqwest;
use serde_json;

use web::data::{SolrTermSummary, SolrReferenceSummary};
use web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    terms_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let mut prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    clean_words_for_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^20", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

}
<|endoftext|>


<commit_before>use std::sync::Arc;

use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
use ra_db::{SourceDatabase, salsa};

use crate::{
    MacroCallId, HirFileId,
    SourceFileItems, SourceItemId, Crate, Module, HirInterner,
    query_definitions,
    Function, FnSignature, ExprScopes,
    Struct, Enum, StructField,
    macros::MacroExpansion,
    module_tree::ModuleTree,
    nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
    ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
    adt::{StructData, EnumData},
    impl_block::{ModuleImplBlocks, ImplSourceMap},
    generics::{GenericParams, GenericDef},
    ids::SourceFileItemId,
};

#[salsa::query_group(HirDatabaseStorage)]
pub trait HirDatabase: SourceDatabase + AsRef<HirInterner> {
    #[salsa::invoke(HirFileId::hir_parse)]
    fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;

    #[salsa::invoke(crate::macros::expand_macro_invocation)]
    fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;

    #[salsa::invoke(ExprScopes::expr_scopes_query)]
    fn expr_scopes(&self, func: Function) -> Arc<ExprScopes>;

    #[salsa::invoke(crate::adt::StructData::struct_data_query)]
    fn struct_data(&self, s: Struct) -> Arc<StructData>;

    #[salsa::invoke(crate::adt::EnumData::enum_data_query)]
    fn enum_data(&self, e: Enum) -> Arc<EnumData>;

    #[salsa::invoke(crate::ty::infer)]
    fn infer(&self, func: Function) -> Arc<InferenceResult>;

    #[salsa::invoke(crate::ty::type_for_def)]
    fn type_for_def(&self, def: TypableDef) -> Ty;

    #[salsa::invoke(crate::ty::type_for_field)]
    fn type_for_field(&self, field: StructField) -> Ty;

    #[salsa::invoke(query_definitions::file_items)]
    fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>;

    #[salsa::invoke(query_definitions::file_item)]
    fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>;

    #[salsa::invoke(crate::module_tree::Submodule::submodules_query)]
    fn submodules(
        &self,
        file_id: HirFileId,
        delc_id: Option<SourceFileItemId>,
    ) -> Arc<Vec<crate::module_tree::Submodule>>;

    #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)]
    fn lower_module(&self, module: Module) -> (Arc<LoweredModule>, Arc<ImportSourceMap>);

    #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_module_query)]
    fn lower_module_module(&self, module: Module) -> Arc<LoweredModule>;

    #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_source_map_query)]
    fn lower_module_source_map(&self, module: Module) -> Arc<ImportSourceMap>;

    #[salsa::invoke(crate::nameres::ItemMap::item_map_query)]
    fn item_map(&self, krate: Crate) -> Arc<ItemMap>;

    #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)]
    fn module_tree(&self, krate: Crate) -> Arc<ModuleTree>;

    #[salsa::invoke(crate::impl_block::impls_in_module_with_source_map_query)]
    fn impls_in_module_with_source_map(
        &self,
        module: Module,
    ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>);

    #[salsa::invoke(crate::impl_block::impls_in_module)]
    fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>;

    #[salsa::invoke(crate::impl_block::impls_in_module_source_map_query)]
    fn impls_in_module_source_map(&self, module: Module) -> Arc<ImplSourceMap>;

    #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
    fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;

    #[salsa::invoke(crate::expr::body_hir)]
    fn body_hir(&self, func: Function) -> Arc<crate::expr::Body>;

    #[salsa::invoke(crate::expr::body_syntax_mapping)]
    fn body_syntax_mapping(&self, func: Function) -> Arc<crate::expr::BodySyntaxMapping>;

    #[salsa::invoke(crate::generics::GenericParams::generic_params_query)]
    fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>;

    #[salsa::invoke(crate::FnSignature::fn_signature_query)]
    fn fn_signature(&self, func: Function) -> Arc<FnSignature>;
}
<commit_msg>split hirdatabase<commit_after>use std::sync::Arc;

use ra_syntax::{SyntaxNode, TreeArc, SourceFile};
use ra_db::{SourceDatabase, salsa};

use crate::{
    MacroCallId, HirFileId,
    SourceFileItems, SourceItemId, Crate, Module, HirInterner,
    query_definitions,
    Function, FnSignature, ExprScopes,
    Struct, Enum, StructField,
    macros::MacroExpansion,
    module_tree::ModuleTree,
    nameres::{ItemMap, lower::{LoweredModule, ImportSourceMap}},
    ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef},
    adt::{StructData, EnumData},
    impl_block::{ModuleImplBlocks, ImplSourceMap},
    generics::{GenericParams, GenericDef},
    ids::SourceFileItemId,
};

#[salsa::query_group(PersistentHirDatabaseStorage)]
pub trait PersistentHirDatabase: SourceDatabase + AsRef<HirInterner> {
    #[salsa::invoke(HirFileId::hir_parse)]
    fn hir_parse(&self, file_id: HirFileId) -> TreeArc<SourceFile>;

    #[salsa::invoke(crate::macros::expand_macro_invocation)]
    fn expand_macro_invocation(&self, invoc: MacroCallId) -> Option<Arc<MacroExpansion>>;

    #[salsa::invoke(ExprScopes::expr_scopes_query)]
    fn expr_scopes(&self, func: Function) -> Arc<ExprScopes>;

    #[salsa::invoke(crate::adt::StructData::struct_data_query)]
    fn struct_data(&self, s: Struct) -> Arc<StructData>;

    #[salsa::invoke(crate::adt::EnumData::enum_data_query)]
    fn enum_data(&self, e: Enum) -> Arc<EnumData>;

    #[salsa::invoke(query_definitions::file_items)]
    fn file_items(&self, file_id: HirFileId) -> Arc<SourceFileItems>;

    #[salsa::invoke(crate::module_tree::Submodule::submodules_query)]
    fn submodules(
        &self,
        file_id: HirFileId,
        delc_id: Option<SourceFileItemId>,
    ) -> Arc<Vec<crate::module_tree::Submodule>>;

    #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_query)]
    fn lower_module(&self, module: Module) -> (Arc<LoweredModule>, Arc<ImportSourceMap>);

    #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_module_query)]
    fn lower_module_module(&self, module: Module) -> Arc<LoweredModule>;

    #[salsa::invoke(crate::nameres::lower::LoweredModule::lower_module_source_map_query)]
    fn lower_module_source_map(&self, module: Module) -> Arc<ImportSourceMap>;

    #[salsa::invoke(crate::nameres::ItemMap::item_map_query)]
    fn item_map(&self, krate: Crate) -> Arc<ItemMap>;

    #[salsa::invoke(crate::module_tree::ModuleTree::module_tree_query)]
    fn module_tree(&self, krate: Crate) -> Arc<ModuleTree>;

    #[salsa::invoke(crate::impl_block::impls_in_module_with_source_map_query)]
    fn impls_in_module_with_source_map(
        &self,
        module: Module,
    ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>);

    #[salsa::invoke(crate::impl_block::impls_in_module)]
    fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>;

    #[salsa::invoke(crate::impl_block::impls_in_module_source_map_query)]
    fn impls_in_module_source_map(&self, module: Module) -> Arc<ImplSourceMap>;

    #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
    fn impls_in_crate(&self, krate: Crate) -> Arc<CrateImplBlocks>;

    #[salsa::invoke(crate::generics::GenericParams::generic_params_query)]
    fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>;

    #[salsa::invoke(crate::FnSignature::fn_signature_query)]
    fn fn_signature(&self, func: Function) -> Arc<FnSignature>;
}

#[salsa::query_group(HirDatabaseStorage)]
pub trait HirDatabase: PersistentHirDatabase {
    #[salsa::invoke(query_definitions::fn_scopes)]
    fn fn_scopes(&self, func: Function) -> Arc<FnScopes>;

    #[salsa::invoke(query_definitions::file_item)]
    fn file_item(&self, source_item_id: SourceItemId) -> TreeArc<SyntaxNode>;

    #[salsa::invoke(crate::ty::infer)]
    fn infer(&self, func: Function) -> Arc<InferenceResult>;

    #[salsa::invoke(crate::ty::type_for_def)]
    fn type_for_def(&self, def: TypableDef) -> Ty;

    #[salsa::invoke(crate::ty::type_for_field)]
    fn type_for_field(&self, field: StructField) -> Ty;

    #[salsa::invoke(crate::expr::body_hir)]
    fn body_hir(&self, func: Function) -> Arc<crate::expr::Body>;

    #[salsa::invoke(crate::expr::body_syntax_mapping)]
    fn body_syntax_mapping(&self, func: Function) -> Arc<crate::expr::BodySyntaxMapping>;
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate askama;

use askama::Template;

#[derive(Template)]
#[template(path = "simple.html")]
struct VariablesTemplate<'a> {
    strvar: &'a str,
    num: i64,
    i18n: String,
}

#[test]
fn test_variables() {
    let s = VariablesTemplate {
        strvar: "foo",
        num: 42,
        i18n: "Iñtërnâtiônàlizætiøn".to_string(),
    };
    assert_eq!(s.render(), "\nhello world, foo\n\
                            with number: 42\n\
                            Iñtërnâtiônàlizætiøn is important\n\
                            in vars too: Iñtërnâtiônàlizætiøn");
}

#[derive(Template)]
#[template(path = "if.html")]
struct IfTemplate {
    cond: bool,
}

#[test]
fn test_if() {
    let s = IfTemplate { cond: true };
    assert_eq!(s.render(), "true");
}

#[derive(Template)]
#[template(path = "else.html")]
struct ElseTemplate {
    cond: bool,
}

#[test]
fn test_else() {
    let s = ElseTemplate { cond: false };
    assert_eq!(s.render(), "false");
}

#[derive(Template)]
#[template(path = "else-if.html")]
struct ElseIfTemplate {
    cond: bool,
    check: bool,
}

#[test]
fn test_else_if() {
    let s = ElseIfTemplate { cond: false, check: true };
    assert_eq!(s.render(), "checked");
}

#[derive(Template)]
#[template(path = "literals.html")]
struct LiteralsTemplate {}

#[test]
fn test_literals() {
    let s = LiteralsTemplate {};
    assert_eq!(s.render(), "a");
}

struct Holder {
    a: usize,
}

#[derive(Template)]
#[template(path = "attr.html")]
struct AttrTemplate {
    inner: Holder,
}

#[test]
fn test_attr() {
    let t = AttrTemplate { inner: Holder { a: 5 } };
    assert_eq!(t.render(), "5");
}

#[derive(Template)]
#[template(path = "option.html")]
struct OptionTemplate<'a> {
    var: Option<&'a str>,
}

#[test]
fn test_option() {
    let some = OptionTemplate { var: Some("foo") };
    assert_eq!(some.render(), "some: foo");
    let none = OptionTemplate { var: None };
    assert_eq!(none.render(), "none");
}
<commit_msg>Add test for type parameters and where clauses (see #9)<commit_after>#[macro_use]
extern crate askama;

use askama::Template;

#[derive(Template)]
#[template(path = "simple.html")]
struct VariablesTemplate<'a> {
    strvar: &'a str,
    num: i64,
    i18n: String,
}

#[test]
fn test_variables() {
    let s = VariablesTemplate {
        strvar: "foo",
        num: 42,
        i18n: "Iñtërnâtiônàlizætiøn".to_string(),
    };
    assert_eq!(s.render(), "\nhello world, foo\n\
                            with number: 42\n\
                            Iñtërnâtiônàlizætiøn is important\n\
                            in vars too: Iñtërnâtiônàlizætiøn");
}

#[derive(Template)]
#[template(path = "if.html")]
struct IfTemplate {
    cond: bool,
}

#[test]
fn test_if() {
    let s = IfTemplate { cond: true };
    assert_eq!(s.render(), "true");
}

#[derive(Template)]
#[template(path = "else.html")]
struct ElseTemplate {
    cond: bool,
}

#[test]
fn test_else() {
    let s = ElseTemplate { cond: false };
    assert_eq!(s.render(), "false");
}

#[derive(Template)]
#[template(path = "else-if.html")]
struct ElseIfTemplate {
    cond: bool,
    check: bool,
}

#[test]
fn test_else_if() {
    let s = ElseIfTemplate { cond: false, check: true };
    assert_eq!(s.render(), "checked");
}

#[derive(Template)]
#[template(path = "literals.html")]
struct LiteralsTemplate {}

#[test]
fn test_literals() {
    let s = LiteralsTemplate {};
    assert_eq!(s.render(), "a");
}

struct Holder {
    a: usize,
}

#[derive(Template)]
#[template(path = "attr.html")]
struct AttrTemplate {
    inner: Holder,
}

#[test]
fn test_attr() {
    let t = AttrTemplate { inner: Holder { a: 5 } };
    assert_eq!(t.render(), "5");
}

#[derive(Template)]
#[template(path = "option.html")]
struct OptionTemplate<'a> {
    var: Option<&'a str>,
}

#[test]
fn test_option() {
    let some = OptionTemplate { var: Some("foo") };
    assert_eq!(some.render(), "some: foo");
    let none = OptionTemplate { var: None };
    assert_eq!(none.render(), "none");
}

#[derive(Template)]
#[template(path = "generics.html")]
struct GenericsTemplate<T: std::fmt::Display, U> where U: std::fmt::Display {
    t: T,
    u: U,
}

#[test]
fn test_generics() {
    let t = GenericsTemplate { t: "a", u: 42 };
    assert_eq!(t.render(), "a42");
}
<|endoftext|>


<commit_before>extern crate regex;

use self::regex::{Error as RegexError, Regex};

use constant::ME;
use error::{CannotHappenError, CliError, CronError, CronErrorKind};
use lib::io::*;
use std::io::Write;
use std::process::{self, Stdio};
use std::str;

#[derive(Debug)]
pub struct Cron {
    contents: String,
}

impl Cron {
    fn base_mark(keyword: &str) -> String {
        format!(
            r#"###################################
# "{}" uses the lines {}.
# Please don't touch them and me!
###################################
"#,
            ME,
            keyword,
        )
    }
    fn start_mark() -> String {
        Cron::base_mark("from this")
    }
    fn end_mark() -> String {
        Cron::base_mark("up to here")
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, "Read cron");

        let result = process::Command::new("crontab")
            .arg("-l")
            .output();
        let output = try!(result);

        let contents = if output.status.success() {
            try!(str::from_utf8(&output.stdout).map_err(|_| CronError::new(CronErrorKind::IncludingInvalidCharacters)))
        } else {
            ""
        };

        Ok(Cron { contents: contents.to_string() })
    }

    pub fn update(mut self) -> Result<Self, RegexError> {
        let start_mark  = Cron::start_mark();
        let end_mark    = Cron::end_mark();
        let my_area     = format!("{}.*{}"    , &start_mark, &end_mark);
        let my_new_area = format!("{}# blur{}", &start_mark, &end_mark);

        let re           = try!(Regex::new(&my_area));
        let new_contents = if re.is_match(&self.contents) {
            let my_new_area: &str = my_new_area.as_ref();
            re.replace(self.contents.as_ref(), my_new_area)
        } else {
            self.contents + &my_new_area
        };

        self.contents = new_contents;
        Ok(self)
    }

    pub fn set(&self) -> Result<(), CliError> {
        print_with_tag(Tag::Info, "Set new cron");

        let result = process::Command::new("crontab")
            .stdin(Stdio::piped())
            .spawn();
        let mut child = try!(result);

        match &mut child.stdin {
            &mut Some(ref mut stdin) => try!(stdin.write_all(self.contents.as_bytes())),
            &mut None                => return Err(From::from(CannotHappenError)),
        };

        let output = try!(child.wait_with_output());

        if output.status.success() {
            Ok(())
        } else {
            Err(From::from(CronError::new(CronErrorKind::FailedToWrite)))
        }
    }
}
<commit_msg>[Bug] Fix as matching with all characters including line break<commit_after>extern crate regex;

use self::regex::{Error as RegexError, Regex};

use constant::ME;
use error::{CannotHappenError, CliError, CronError, CronErrorKind};
use lib::io::*;
use std::io::Write;
use std::process::{self, Stdio};
use std::str;

#[derive(Debug)]
pub struct Cron {
    contents: String,
}

impl Cron {
    fn base_mark(keyword: &str) -> String {
        format!(
            r#"###################################
# "{}" uses the lines {}.
# Please don't touch them and me!
###################################
"#,
            ME,
            keyword,
        )
    }
    fn start_mark() -> String {
        Cron::base_mark("from this")
    }
    fn end_mark() -> String {
        Cron::base_mark("up to here")
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, "Read cron");

        let result = process::Command::new("crontab")
            .arg("-l")
            .output();
        let output = try!(result);

        let contents = if output.status.success() {
            try!(str::from_utf8(&output.stdout).map_err(|_| CronError::new(CronErrorKind::IncludingInvalidCharacters)))
        } else {
            ""
        };

        Ok(Cron { contents: contents.to_string() })
    }

    pub fn update(mut self) -> Result<Self, RegexError> {
        let start_mark  = Cron::start_mark();
        let end_mark    = Cron::end_mark();
        let my_area     = format!("{}(.|\n)*{}" , &start_mark, &end_mark);
        let my_new_area = format!("{}# blur\n{}", &start_mark, &end_mark);

        let re           = try!(Regex::new(&my_area));
        let new_contents = if re.is_match(&self.contents) {
            let my_new_area: &str = my_new_area.as_ref();
            re.replace(self.contents.as_ref(), my_new_area)
        } else {
            self.contents + &my_new_area
        };

        self.contents = new_contents;
        Ok(self)
    }

    pub fn set(&self) -> Result<(), CliError> {
        print_with_tag(Tag::Info, "Set new cron");

        let result = process::Command::new("crontab")
            .stdin(Stdio::piped())
            .spawn();
        let mut child = try!(result);

        match &mut child.stdin {
            &mut Some(ref mut stdin) => try!(stdin.write_all(self.contents.as_bytes())),
            &mut None                => return Err(From::from(CannotHappenError)),
        };

        let output = try!(child.wait_with_output());

        if output.status.success() {
            Ok(())
        } else {
            Err(From::from(CronError::new(CronErrorKind::FailedToWrite)))
        }
    }
}
<|endoftext|>


<commit_before>extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use serde_json::*;
use std::fs::File;
use std::iter::Iterator;
use std::io::prelude::*;

#[derive(Deserialize)]
struct GodotClass {
	name: String,
	base_class: String,
	api_type: String,
	singleton: bool,
	instanciable: bool,
	constants: Map<String, Value>,
	methods: Vec<GodotMethod>
}

#[derive(Deserialize)]
struct GodotMethod {
	name: String,
	return_type: String,
	arguments: Vec<GodotArgument>
}

#[derive(Deserialize)]
struct GodotArgument {
	name: String,
	#[serde(rename = "type")]
	_type: String,
	default_value: String
}

fn strip_name(s: &String) -> &str {
	if s.starts_with("_") {
		unsafe { s.slice_unchecked(1, s.len()) }
	} else {
		s.as_str()
	}
}

fn main() {
	let base_dir = "/home/karroffel/Gamedev/dlscript_cpp_example/src/include/godot_cpp/";

	let mut file = File::open("/home/karroffel/Development/api.json").unwrap();

	let mut file_contents = String::new();

	file.read_to_string(&mut file_contents);

	let json: Vec<GodotClass> = serde_json::from_str::<Vec<GodotClass>>(&file_contents).unwrap();

	let mut forward_declares = String::new();
	{
		for class in &json {
			forward_declares = forward_declares + "class " + strip_name(&class.name) + ";\n";
		}
	}

	for class in json {
		generate_class_binding(&forward_declares, (base_dir.to_string() + strip_name(&class.name) + ".h").as_str(), &class);
	}
}

fn generate_class_binding(forward_declares: &String, filename: &str, class: &GodotClass) {
	let mut file = File::create(filename).unwrap();

	file.write_all(generate_class_content(forward_declares, class).as_bytes());
}

fn generate_class_content(forward_declares: &String, class: &GodotClass) -> String {
	let mut contents = String::new();

	contents = contents + "#ifndef ";
	contents = contents + strip_name(&class.name).to_string().to_uppercase().as_str() + "_H\n";

	contents = contents + "#define ";
	contents = contents + strip_name(&class.name).to_string().to_uppercase().as_str() + "_H\n\n";

	contents = contents + "\n#include \"core/CoreTypes.h\"\n";

	contents = contents + "\n#include <godot.h>\n\n\n";

	if class.base_class != "" {
		contents = contents + "\n#include \"" + strip_name(&class.base_class) + ".h\"\n\n\n";
	}

	contents = contents + "namespace godot {\n\n";

	contents += forward_declares;

	contents = contents + "\n\n\nclass " + strip_name(&class.name);

	if class.base_class != "" {
		contents = contents + " : public " + strip_name(&class.base_class);
	}

	contents = contents + " {\n";

	if class.base_class == "" {
		contents = contents + "protected:\n\tgodot_object *__core_object;\n\n";
	}

	contents = contents + "public:\n\n";

	// default constructor

	{
		contents = contents + "\t" + strip_name(&class.name) + "() {\n";
		contents = contents + "\t\t\n";
		contents = contents + "\t}\n";
	}

	// pointer constructor
	{
		contents = contents + "\t" + strip_name(&class.name) + "(godot_object *ptr) {\n";
		contents = contents + "\t\t__core_object = ptr;\n";
		contents = contents + "\t}\n\n\n";
	}

	for (name, value) in &class.constants {
		contents = contents + "\tconst static int " + name.as_str() + " = " + value.as_i64().unwrap().to_string().as_str() + ";\n";
	}

	contents += "\n\n";

	for method in &class.methods {
		contents = contents + "\t" + strip_name(&method.return_type) + (if !is_core_type(&method.return_type) && !is_primitive(&method.return_type) { " &" } else { " " }) + method.name.as_str() + "(";

		for (i, argument) in (&method.arguments).iter().enumerate() {
			if !is_primitive(&argument._type) {
				contents = contents + "const " + argument._type.as_str() + "&";
			} else {
				contents = contents + "const " + argument._type.as_str() + "";
			}

			contents = contents + " " + escape_cpp(&argument.name);
			if i != method.arguments.len() - 1 {
				contents += ", ";
			}
		}

		contents = contents + ") {\n";

		contents = contents + "\t\tstatic godot_method_bind *mb = NULL;\n"
		                    + "\t\tif (mb == NULL) {\n"
		                    + "\t\t\tmb = godot_method_bind_get_method(\"" + class.name.as_str() + "\", \"" + method.name.as_str() + "\");\n"
		                    + "\t\t}\n";

		if method.return_type != "void" {
			// contents = contents + "\t\t" + strip_name(&method.return_type) + (if !is_core_type(&method.return_type) && !is_primitive(&method.return_type) { "*" } else { "" }) + " ret;" + "\n";
			contents = contents + "\t\t" + if !is_core_type(&method.return_type) && !is_primitive(&method.return_type) { "godot_object*" } else { strip_name(&method.return_type) } + " ret;\n";
		}

		contents = contents + "\t\tconst void *args[] = {\n";

		for argument in &method.arguments {
			contents = contents + "\t\t\t";
			if is_primitive(&argument._type) {
				contents = contents + "&" + argument.name.as_str();
			} else if is_core_type(&argument._type) {
				contents = contents + "(void *) &" + escape_cpp(&argument.name);
			} else {
				contents = contents + "(void *) &" + escape_cpp(&argument.name);
			}
			contents = contents + ",\n";
		}

		contents = contents + "\t\t};\n";

		contents = contents + "\t\tgodot_method_bind_ptrcall(mb, __core_object, args, " + if method.return_type == "void" { "NULL" } else { "&ret" } + ");\n";

		if !is_primitive(&method.return_type) && !is_core_type(&method.return_type) {
			contents = contents + "\t\treturn reinterpret_cast<" + strip_name(&method.return_type) + "&>(ret);\n";
		} else if method.return_type != "void" {
			contents = contents + "\t\treturn ret;\n";
		}

		contents = contents + "\t}\n\n";
	}

	contents = contents + "};\n\n";

	contents = contents + "}\n";

	contents = contents + "#endif\n";

	contents
}

fn is_core_type(name: &String) -> bool {
	let core_types = vec!["Array", "PoolStringArray", "Vector2", "Vector3", "String", "Variant"];
	core_types.contains(&name.as_str())
}

fn is_primitive(name: &String) -> bool {
	let core_types = vec!["int", "bool", "real", "float", "void"];
	core_types.contains(&name.as_str())
}

fn escape_cpp(name: &String) -> &str {
	match name.as_str() {
		"class" => "_class",
		"char"  => "_char",
		x       => x
	}
}<commit_msg>added proper singleton suport<commit_after>extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use serde_json::*;
use std::fs::File;
use std::iter::Iterator;
use std::io::prelude::*;

#[derive(Deserialize)]
struct GodotClass {
	name: String,
	base_class: String,
	api_type: String,
	singleton: bool,
	instanciable: bool,
	constants: Map<String, Value>,
	methods: Vec<GodotMethod>
}

#[derive(Deserialize)]
struct GodotMethod {
	name: String,
	return_type: String,
	arguments: Vec<GodotArgument>
}

#[derive(Deserialize)]
struct GodotArgument {
	name: String,
	#[serde(rename = "type")]
	_type: String,
	default_value: String
}

fn strip_name(s: &String) -> &str {
	if s.starts_with("_") {
		unsafe { s.slice_unchecked(1, s.len()) }
	} else {
		s.as_str()
	}
}

fn main() {
	let base_dir = "/home/karroffel/Gamedev/dlscript_cpp_example/src/include/godot_cpp/";

	let mut file = File::open("/home/karroffel/Development/api.json").unwrap();

	let mut file_contents = String::new();

	file.read_to_string(&mut file_contents);

	let json: Vec<GodotClass> = serde_json::from_str::<Vec<GodotClass>>(&file_contents).unwrap();

	let mut forward_declares = String::new();
	{
		for class in &json {
			forward_declares = forward_declares + "class " + strip_name(&class.name) + ";\n";
		}
	}

	for class in json {
		generate_class_binding(&forward_declares, (base_dir.to_string() + strip_name(&class.name) + ".h").as_str(), &class);
	}
}

fn generate_class_binding(forward_declares: &String, filename: &str, class: &GodotClass) {
	let mut file = File::create(filename).unwrap();

	file.write_all(generate_class_content(forward_declares, class).as_bytes());
}

fn generate_class_content(forward_declares: &String, class: &GodotClass) -> String {
	let mut contents = String::new();

	contents = contents + "#ifndef ";
	contents = contents + strip_name(&class.name).to_string().to_uppercase().as_str() + "_H\n";

	contents = contents + "#define ";
	contents = contents + strip_name(&class.name).to_string().to_uppercase().as_str() + "_H\n\n";

	contents = contents + "\n#include \"core/CoreTypes.h\"\n";

	contents = contents + "\n#include <godot.h>\n\n\n";

	if class.base_class != "" {
		contents = contents + "\n#include \"" + strip_name(&class.base_class) + ".h\"\n\n\n";
	}

	contents = contents + "namespace godot {\n\n";

	contents += forward_declares;

	let core_obj_name = {
		let mut name = String::new();
		if class.singleton {
			name = name + "___static_object_" + strip_name(&class.name);
		} else {
			name = name + "__core_object";
		};
		name
	};

	if class.singleton {
		contents = contents + "\n\nstatic godot_object *" + core_obj_name.as_str() + ";\n\n";
	}

	contents = contents + "\n\n\nclass " + strip_name(&class.name);

	if class.base_class != "" {
		contents = contents + " : public " + strip_name(&class.base_class);
	}

	contents = contents + " {\n";

	if class.base_class == "" {
		contents = contents + "protected:\n\tgodot_object *__core_object = 0;\n\n";
	}

	if class.singleton {
		contents = contents + "private:\n";
		contents = contents + "\tstatic void ___singleton_init() { "
			+ core_obj_name.as_str() + " = godot_global_get_singleton(\"" + strip_name(&class.name) + "\"); }\n\n";
	}

	contents = contents + "public:\n\n";

	// default constructor

	{
		contents = contents + "\t" + strip_name(&class.name) + "() {\n";
		contents = contents + "\t\t\n";
		contents = contents + "\t}\n\n";
	}

	// pointer constructor
	{
		contents = contents + "\t" + strip_name(&class.name) + "(godot_object *ptr) {\n";
		contents = contents + "\t\t__core_object = ptr;\n";
		contents = contents + "\t}\n\n\n";
	}

	if class.instanciable {
		contents = contents + "\tstatic " + strip_name(&class.name) + "& _new();\n";
		contents = contents + "\tvoid _destroy();\n\n";
	}

	for (name, value) in &class.constants {
		contents = contents + "\tconst static int " + name.as_str() + " = " + value.as_i64().unwrap().to_string().as_str() + ";\n";
	}

	contents += "\n\n";

	for method in &class.methods {
		contents = contents + "\t" + (if class.singleton { "static " } else { "" }) + strip_name(&method.return_type) + (if !is_core_type(&method.return_type) && !is_primitive(&method.return_type) { " &" } else { " " }) + method.name.as_str() + "(";

		for (i, argument) in (&method.arguments).iter().enumerate() {
			if !is_primitive(&argument._type) {
				contents = contents + "const " + argument._type.as_str() + "&";
			} else {
				contents = contents + "const " + argument._type.as_str() + "";
			}

			contents = contents + " " + escape_cpp(&argument.name);
			if i != method.arguments.len() - 1 {
				contents += ", ";
			}
		}

		contents = contents + ") {\n";

		if class.singleton {
			contents = contents + "\t\tif (" + core_obj_name.as_str() + " == 0) {\n";
			contents = contents + "\t\t\t___singleton_init();\n";
			contents = contents + "\t\t}\n\n";
		}

		contents = contents + "\t\tstatic godot_method_bind *mb = NULL;\n"
		                    + "\t\tif (mb == NULL) {\n"
		                    + "\t\t\tmb = godot_method_bind_get_method(\"" + class.name.as_str() + "\", \"" + method.name.as_str() + "\");\n"
		                    + "\t\t}\n";

		if method.return_type != "void" {
			// contents = contents + "\t\t" + strip_name(&method.return_type) + (if !is_core_type(&method.return_type) && !is_primitive(&method.return_type) { "*" } else { "" }) + " ret;" + "\n";
			contents = contents + "\t\t" + if !is_core_type(&method.return_type) && !is_primitive(&method.return_type) { "godot_object*" } else { strip_name(&method.return_type) } + " ret;\n";
		}

		contents = contents + "\t\tconst void *args[] = {\n";

		for argument in &method.arguments {
			contents = contents + "\t\t\t";
			if is_primitive(&argument._type) {
				contents = contents + "&" + argument.name.as_str();
			} else if is_core_type(&argument._type) {
				contents = contents + "(void *) &" + escape_cpp(&argument.name);
			} else {
				contents = contents + "(void *) &" + escape_cpp(&argument.name);
			}
			contents = contents + ",\n";
		}

		contents = contents + "\t\t};\n";

		contents = contents + "\t\tgodot_method_bind_ptrcall(mb, " + core_obj_name.as_str() + ", args, " + if method.return_type == "void" { "NULL" } else { "&ret" } + ");\n";

		if !is_primitive(&method.return_type) && !is_core_type(&method.return_type) {
			contents = contents + "\t\treturn reinterpret_cast<" + strip_name(&method.return_type) + "&>(ret);\n";
		} else if method.return_type != "void" {
			contents = contents + "\t\treturn ret;\n";
		}

		contents = contents + "\t}\n\n";
	}

	contents = contents + "};\n\n";

	contents = contents + "}\n";

	if class.instanciable {

		contents = contents + "#include \"ClassDB.h\"\n";

		contents = contents + "namespace godot {\n\n";

		contents = contents + "" + strip_name(&class.name) + "& " + strip_name(&class.name) + "::_new() {\n";
		contents = contents + "\tObject *ptr = ClassDB::instance(\"" + class.name.as_str() + "\");\n";
		contents = contents + "\treturn reinterpret_cast<" + strip_name(&class.name) + "&>(ptr);";
		contents = contents + "}\n\n";

		contents = contents + "void " + strip_name(&class.name) + "::_destroy() {\n";
		contents = contents + "\tgodot_object_destroy(__core_object);\n";
		contents = contents + "}\n\n\n";

		contents = contents + "}\n";
	}

	contents = contents + "#endif\n";

	contents
}

fn is_core_type(name: &String) -> bool {
	let core_types = vec!["Array", "PoolStringArray", "Vector2", "Vector3", "String", "Variant"];
	core_types.contains(&name.as_str())
}

fn is_primitive(name: &String) -> bool {
	let core_types = vec!["int", "bool", "real", "float", "void"];
	core_types.contains(&name.as_str())
}

fn escape_cpp(name: &String) -> &str {
	match name.as_str() {
		"class" => "_class",
		"char"  => "_char",
		x       => x
	}
}<|endoftext|>


<commit_before>//
// Copyright 2020 The Project Oak 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.
//

use std::collections::{HashMap, VecDeque};
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::{Arc, Mutex, RwLock, Weak};
use std::thread::{Thread, ThreadId};

use log::debug;
use rand::RngCore;

use oak_abi::OakStatus;

use crate::Message;

type Messages = VecDeque<Message>;

/// We use a `HashMap` keyed by `ThreadId` to prevent build up of stale `Weak<Thread>`s.
///
/// That is: If a thread waiting/blocked on a channel is woken by a different channel, its
/// `Weak<Thread>` will remain in the first channel's waiting_thread member. If a thread keeps
/// waiting on this first channel, and keeps being woken by other channels, it will keep re-adding
/// itself. We use a `HashMap` and insert at the current `ThreadId` so that we replace any stale
/// `Weak<Thread>`s which will have gone out of scope. (`wait_on_channels` drops the underlying arc
/// as soon as it is resumed.)
type WaitingThreads = Mutex<HashMap<ThreadId, Weak<Thread>>>;

/// The internal implementation of a channel representation backed by a `VecDeque<Message>`.
/// Readers and writers to this channel must increment the reader/writer count. This is implemented
/// for `ChannelWriter`/`ChannelReader`, which will increment/decrement readers/writers when
/// cloning/dropping.
#[derive(Debug)]
pub struct Channel {
    pub messages: RwLock<Messages>,

    pub writers: AtomicU64,
    pub readers: AtomicU64,

    /// A HashMap of `ThreadId`s to `Weak<Thread>`s. This allows threads to insert a weak reference
    /// to themselves to be woken when a new message is available. Weak references are used so that
    /// if the thread is woken by a different channel, it can deallocate the underlying `Arc`
    /// instead of removing itself from all the `Channel`s it subscribed to.
    /// Threads can be woken up spuriously without issue.
    pub waiting_threads: WaitingThreads,

    /// The Label associated with this channel.
    ///
    /// This is set at channel creation time and does not change after that.
    ///
    /// See https://github.com/project-oak/oak/blob/master/docs/concepts.md#labels
    label: oak_abi::label::Label,
}

/// A reference to a [`Channel`]. Each [`Handle`] has an implicit direction such that it is only
/// possible to read or write to a [`Handle`] (exclusive or).
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub struct Handle(oak_abi::Handle);

/// The direction of a [`Handle`] can be discovered by querying the associated
/// [`oak_runtime::Runtime`] [`oak_runtime::Runtime::channel_get_direction`].
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum HandleDirection {
    Read,
    Write,
}

/// An internal identifier to track a [`Channel`]. This is implementation specific and should not
/// be visible outside the internals of [`Runtime`].
type ChannelId = u64;

/// Ownership and mapping of [`Channel`]s to [`Handle`]s.
#[derive(Debug)]
pub struct ChannelMapping {
    pub channels: RwLock<HashMap<ChannelId, Channel>>,

    pub next_channel_id: AtomicU64,

    pub readers: RwLock<HashMap<Handle, ChannelId>>,
    pub writers: RwLock<HashMap<Handle, ChannelId>>,
}

impl Channel {
    /// Create a new channel with the assumption there is currently one active reader and one active
    /// writer references.
    pub fn new(label: &oak_abi::label::Label) -> Channel {
        Channel {
            messages: RwLock::new(Messages::new()),
            writers: AtomicU64::new(1),
            readers: AtomicU64::new(1),
            waiting_threads: Mutex::new(HashMap::new()),
            label: label.clone(),
        }
    }

    /// Thread safe method that returns true when there is no longer at least one reader and one
    /// writer.
    pub fn is_orphan(&self) -> bool {
        self.readers.load(SeqCst) == 0 || self.writers.load(SeqCst) == 0
    }

    /// Thread safe method that returns true when there is no longer at least one reader or
    /// writer.
    pub fn has_no_reference(&self) -> bool {
        self.readers.load(SeqCst) == 0 && self.writers.load(SeqCst) == 0
    }

    /// Insert the given `thread` reference into `thread_id` slot of the HashMap of waiting
    /// channels attached to an underlying channel. This allows the channel to wake up any waiting
    /// channels by calling `thread::unpark` on all the threads it knows about.
    pub fn add_waiter(&self, thread_id: ThreadId, thread: &Arc<Thread>) {
        self.waiting_threads
            .lock()
            .unwrap()
            .insert(thread_id, Arc::downgrade(thread));
    }

    /// Decrement the [`Channel`] writer counter.
    pub fn remove_writer(&self) {
        if self.writers.fetch_sub(1, SeqCst) == 0 {
            panic!("remove_reader: Writer count was already 0, something is very wrong!")
        }
    }

    /// Decrement the [`Channel`] reader counter.
    pub fn remove_reader(&self) {
        if self.readers.fetch_sub(1, SeqCst) == 0 {
            panic!("remove_reader: Reader count was already 0, something is very wrong!")
        }
    }

    /// Increment the [`Channel`] writer counter.
    pub fn add_writer(&self) -> u64 {
        self.writers.fetch_add(1, SeqCst)
    }

    /// Increment the [`Channel`] reader counter.
    pub fn add_reader(&self) -> u64 {
        self.readers.fetch_add(1, SeqCst)
    }
}

impl ChannelMapping {
    /// Create a new empty [`ChannelMapping`].
    pub fn new() -> ChannelMapping {
        ChannelMapping {
            channels: RwLock::new(HashMap::new()),

            next_channel_id: AtomicU64::new(0),

            readers: RwLock::new(HashMap::new()),
            writers: RwLock::new(HashMap::new()),
        }
    }

    /// Creates a new [`Channel`] and returns a `(writer handle, reader handle)` pair.
    pub fn new_channel(&self, label: &oak_abi::label::Label) -> (Handle, Handle) {
        let channel_id = self.next_channel_id.fetch_add(1, SeqCst);
        self.channels
            .write()
            .unwrap()
            .insert(channel_id, Channel::new(label));
        (self.new_writer(channel_id), self.new_reader(channel_id))
    }

    /// Get a new free random [`Handle`] that is not used by any readers or writers.
    fn new_reference(&self) -> Handle {
        loop {
            let handle = Handle(rand::thread_rng().next_u64());

            let exists_reader = self.readers.read().unwrap().get(&handle).is_some();
            let exists_writer = self.writers.read().unwrap().get(&handle).is_some();

            if exists_reader || exists_writer {
                continue;
            }

            return handle;
        }
    }

    /// Create a new writer reference.
    fn new_writer(&self, channel: ChannelId) -> Handle {
        let reference = self.new_reference();
        self.writers.write().unwrap().insert(reference, channel);
        reference
    }

    /// Create a new reader reference.
    fn new_reader(&self, channel: ChannelId) -> Handle {
        let reference = self.new_reference();
        self.readers.write().unwrap().insert(reference, channel);
        reference
    }

    /// Attempt to retrieve the [`ChannelId`] associated with a reader [`Handle`].
    pub fn get_reader_channel(&self, reference: Handle) -> Result<ChannelId, OakStatus> {
        self.readers
            .read()
            .unwrap()
            .get(&reference)
            .map_or(Err(OakStatus::ErrBadHandle), |id| Ok(*id))
    }

    /// Attempt to retrieve the [`ChannelId`] associated with a writer [`Handle`].
    pub fn get_writer_channel(&self, reference: Handle) -> Result<ChannelId, OakStatus> {
        self.writers
            .read()
            .unwrap()
            .get(&reference)
            .map_or(Err(OakStatus::ErrBadHandle), |id| Ok(*id))
    }

    /// Perform an operation on a [`Channel`] associated with some [`ChannelId`].
    /// The channels read lock is held while the operation is performed.
    pub fn with_channel<U, F: FnOnce(&Channel) -> Result<U, OakStatus>>(
        &self,
        channel_id: ChannelId,
        f: F,
    ) -> Result<U, OakStatus> {
        let channels = self.channels.read().unwrap();
        let channel = channels.get(&channel_id).ok_or(OakStatus::ErrBadHandle)?;
        f(channel)
    }

    /// Deallocate a [`Handle`] reference. The reference will no longer be usable in
    /// operations, and the underlying [`Channel`] may become orphaned.
    pub fn remove_reference(&self, reference: Handle) -> Result<(), OakStatus> {
        if let Ok(channel_id) = self.get_writer_channel(reference) {
            {
                let mut channels = self.channels.write().unwrap();
                let channel = channels
                    .get(&channel_id)
                    .expect("remove_reference: Handle is invalid!");
                channel.remove_writer();
                if channel.has_no_reference() {
                    channels.remove(&channel_id);
                    debug!("remove_reference: deallocating channel {:?}", channel_id);
                }
            }

            self.writers.write().unwrap().remove(&reference);
        }

        if let Ok(channel_id) = self.get_reader_channel(reference) {
            {
                let mut channels = self.channels.write().unwrap();
                let channel = channels
                    .get(&channel_id)
                    .expect("remove_reference: Handle is invalid!");
                channel.remove_reader();
                if channel.has_no_reference() {
                    channels.remove(&channel_id);
                    debug!("remove_reference: deallocating channel {:?}", channel_id);
                }
            }

            self.readers.write().unwrap().remove(&reference);
        }

        Ok(())
    }

    /// Duplicate a [`Handle`] reference. This new reference and when it is closed will be
    /// tracked separately from the first [`Handle`]. For instance this is used by the
    /// [`oak_runtime::Runtime`] to encode [`Channel`]s in messages.
    pub fn duplicate_reference(&self, reference: Handle) -> Result<Handle, OakStatus> {
        if let Ok(channel_id) = self.get_writer_channel(reference) {
            self.with_channel(channel_id, |channel| Ok(channel.add_writer()))?;

            return Ok(self.new_writer(channel_id));
        }

        if let Ok(channel_id) = self.get_reader_channel(reference) {
            self.with_channel(channel_id, |channel| Ok(channel.add_reader()))?;

            return Ok(self.new_reader(channel_id));
        }

        Err(OakStatus::ErrBadHandle)
    }
}
<commit_msg>runtime/rust: rename {add,remove}_{reader,writer} methods<commit_after>//
// Copyright 2020 The Project Oak 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.
//

use std::collections::{HashMap, VecDeque};
use std::sync::atomic::AtomicU64;
use std::sync::atomic::Ordering::SeqCst;
use std::sync::{Arc, Mutex, RwLock, Weak};
use std::thread::{Thread, ThreadId};

use log::debug;
use rand::RngCore;

use oak_abi::OakStatus;

use crate::Message;

type Messages = VecDeque<Message>;

/// We use a `HashMap` keyed by `ThreadId` to prevent build up of stale `Weak<Thread>`s.
///
/// That is: If a thread waiting/blocked on a channel is woken by a different channel, its
/// `Weak<Thread>` will remain in the first channel's waiting_thread member. If a thread keeps
/// waiting on this first channel, and keeps being woken by other channels, it will keep re-adding
/// itself. We use a `HashMap` and insert at the current `ThreadId` so that we replace any stale
/// `Weak<Thread>`s which will have gone out of scope. (`wait_on_channels` drops the underlying arc
/// as soon as it is resumed.)
type WaitingThreads = Mutex<HashMap<ThreadId, Weak<Thread>>>;

/// The internal implementation of a channel representation backed by a `VecDeque<Message>`.
/// Readers and writers to this channel must increment the reader/writer count. This is implemented
/// for `ChannelWriter`/`ChannelReader`, which will increment/decrement readers/writers when
/// cloning/dropping.
#[derive(Debug)]
pub struct Channel {
    pub messages: RwLock<Messages>,

    pub writers: AtomicU64,
    pub readers: AtomicU64,

    /// A HashMap of `ThreadId`s to `Weak<Thread>`s. This allows threads to insert a weak reference
    /// to themselves to be woken when a new message is available. Weak references are used so that
    /// if the thread is woken by a different channel, it can deallocate the underlying `Arc`
    /// instead of removing itself from all the `Channel`s it subscribed to.
    /// Threads can be woken up spuriously without issue.
    pub waiting_threads: WaitingThreads,

    /// The Label associated with this channel.
    ///
    /// This is set at channel creation time and does not change after that.
    ///
    /// See https://github.com/project-oak/oak/blob/master/docs/concepts.md#labels
    label: oak_abi::label::Label,
}

/// A reference to a [`Channel`]. Each [`Handle`] has an implicit direction such that it is only
/// possible to read or write to a [`Handle`] (exclusive or).
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub struct Handle(oak_abi::Handle);

/// The direction of a [`Handle`] can be discovered by querying the associated
/// [`oak_runtime::Runtime`] [`oak_runtime::Runtime::channel_get_direction`].
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum HandleDirection {
    Read,
    Write,
}

/// An internal identifier to track a [`Channel`]. This is implementation specific and should not
/// be visible outside the internals of [`Runtime`].
type ChannelId = u64;

/// Ownership and mapping of [`Channel`]s to [`Handle`]s.
#[derive(Debug)]
pub struct ChannelMapping {
    pub channels: RwLock<HashMap<ChannelId, Channel>>,

    pub next_channel_id: AtomicU64,

    pub readers: RwLock<HashMap<Handle, ChannelId>>,
    pub writers: RwLock<HashMap<Handle, ChannelId>>,
}

impl Channel {
    /// Create a new channel with the assumption there is currently one active reader and one active
    /// writer references.
    pub fn new(label: &oak_abi::label::Label) -> Channel {
        Channel {
            messages: RwLock::new(Messages::new()),
            writers: AtomicU64::new(1),
            readers: AtomicU64::new(1),
            waiting_threads: Mutex::new(HashMap::new()),
            label: label.clone(),
        }
    }

    /// Thread safe method that returns true when there is no longer at least one reader and one
    /// writer.
    pub fn is_orphan(&self) -> bool {
        self.readers.load(SeqCst) == 0 || self.writers.load(SeqCst) == 0
    }

    /// Thread safe method that returns true when there is no longer at least one reader or
    /// writer.
    pub fn has_no_reference(&self) -> bool {
        self.readers.load(SeqCst) == 0 && self.writers.load(SeqCst) == 0
    }

    /// Insert the given `thread` reference into `thread_id` slot of the HashMap of waiting
    /// channels attached to an underlying channel. This allows the channel to wake up any waiting
    /// channels by calling `thread::unpark` on all the threads it knows about.
    pub fn add_waiter(&self, thread_id: ThreadId, thread: &Arc<Thread>) {
        self.waiting_threads
            .lock()
            .unwrap()
            .insert(thread_id, Arc::downgrade(thread));
    }

    /// Decrement the [`Channel`] writer counter.
    pub fn dec_writer_count(&self) {
        if self.writers.fetch_sub(1, SeqCst) == 0 {
            panic!("remove_reader: Writer count was already 0, something is very wrong!")
        }
    }

    /// Decrement the [`Channel`] reader counter.
    pub fn dec_reader_count(&self) {
        if self.readers.fetch_sub(1, SeqCst) == 0 {
            panic!("remove_reader: Reader count was already 0, something is very wrong!")
        }
    }

    /// Increment the [`Channel`] writer counter.
    pub fn inc_writer_count(&self) -> u64 {
        self.writers.fetch_add(1, SeqCst)
    }

    /// Increment the [`Channel`] reader counter.
    pub fn inc_reader_count(&self) -> u64 {
        self.readers.fetch_add(1, SeqCst)
    }
}

impl ChannelMapping {
    /// Create a new empty [`ChannelMapping`].
    pub fn new() -> ChannelMapping {
        ChannelMapping {
            channels: RwLock::new(HashMap::new()),

            next_channel_id: AtomicU64::new(0),

            readers: RwLock::new(HashMap::new()),
            writers: RwLock::new(HashMap::new()),
        }
    }

    /// Creates a new [`Channel`] and returns a `(writer handle, reader handle)` pair.
    pub fn new_channel(&self, label: &oak_abi::label::Label) -> (Handle, Handle) {
        let channel_id = self.next_channel_id.fetch_add(1, SeqCst);
        self.channels
            .write()
            .unwrap()
            .insert(channel_id, Channel::new(label));
        (self.new_writer(channel_id), self.new_reader(channel_id))
    }

    /// Get a new free random [`Handle`] that is not used by any readers or writers.
    fn new_reference(&self) -> Handle {
        loop {
            let handle = Handle(rand::thread_rng().next_u64());

            let exists_reader = self.readers.read().unwrap().get(&handle).is_some();
            let exists_writer = self.writers.read().unwrap().get(&handle).is_some();

            if exists_reader || exists_writer {
                continue;
            }

            return handle;
        }
    }

    /// Create a new writer reference.
    fn new_writer(&self, channel: ChannelId) -> Handle {
        let reference = self.new_reference();
        self.writers.write().unwrap().insert(reference, channel);
        reference
    }

    /// Create a new reader reference.
    fn new_reader(&self, channel: ChannelId) -> Handle {
        let reference = self.new_reference();
        self.readers.write().unwrap().insert(reference, channel);
        reference
    }

    /// Attempt to retrieve the [`ChannelId`] associated with a reader [`Handle`].
    pub fn get_reader_channel(&self, reference: Handle) -> Result<ChannelId, OakStatus> {
        self.readers
            .read()
            .unwrap()
            .get(&reference)
            .map_or(Err(OakStatus::ErrBadHandle), |id| Ok(*id))
    }

    /// Attempt to retrieve the [`ChannelId`] associated with a writer [`Handle`].
    pub fn get_writer_channel(&self, reference: Handle) -> Result<ChannelId, OakStatus> {
        self.writers
            .read()
            .unwrap()
            .get(&reference)
            .map_or(Err(OakStatus::ErrBadHandle), |id| Ok(*id))
    }

    /// Perform an operation on a [`Channel`] associated with some [`ChannelId`].
    /// The channels read lock is held while the operation is performed.
    pub fn with_channel<U, F: FnOnce(&Channel) -> Result<U, OakStatus>>(
        &self,
        channel_id: ChannelId,
        f: F,
    ) -> Result<U, OakStatus> {
        let channels = self.channels.read().unwrap();
        let channel = channels.get(&channel_id).ok_or(OakStatus::ErrBadHandle)?;
        f(channel)
    }

    /// Deallocate a [`Handle`] reference. The reference will no longer be usable in
    /// operations, and the underlying [`Channel`] may become orphaned.
    pub fn remove_reference(&self, reference: Handle) -> Result<(), OakStatus> {
        if let Ok(channel_id) = self.get_writer_channel(reference) {
            {
                let mut channels = self.channels.write().unwrap();
                let channel = channels
                    .get(&channel_id)
                    .expect("remove_reference: Handle is invalid!");
                channel.dec_writer_count();
                if channel.has_no_reference() {
                    channels.remove(&channel_id);
                    debug!("remove_reference: deallocating channel {:?}", channel_id);
                }
            }

            self.writers.write().unwrap().remove(&reference);
        }

        if let Ok(channel_id) = self.get_reader_channel(reference) {
            {
                let mut channels = self.channels.write().unwrap();
                let channel = channels
                    .get(&channel_id)
                    .expect("remove_reference: Handle is invalid!");
                channel.dec_reader_count();
                if channel.has_no_reference() {
                    channels.remove(&channel_id);
                    debug!("remove_reference: deallocating channel {:?}", channel_id);
                }
            }

            self.readers.write().unwrap().remove(&reference);
        }

        Ok(())
    }

    /// Duplicate a [`Handle`] reference. This new reference and when it is closed will be
    /// tracked separately from the first [`Handle`]. For instance this is used by the
    /// [`oak_runtime::Runtime`] to encode [`Channel`]s in messages.
    pub fn duplicate_reference(&self, reference: Handle) -> Result<Handle, OakStatus> {
        if let Ok(channel_id) = self.get_writer_channel(reference) {
            self.with_channel(channel_id, |channel| Ok(channel.inc_writer_count()))?;

            return Ok(self.new_writer(channel_id));
        }

        if let Ok(channel_id) = self.get_reader_channel(reference) {
            self.with_channel(channel_id, |channel| Ok(channel.inc_reader_count()))?;

            return Ok(self.new_reader(channel_id));
        }

        Err(OakStatus::ErrBadHandle)
    }
}
<|endoftext|>


<commit_before>use time::get_time;
use time::Timespec;

use std::sync::Mutex;

use ewma::EWMA;

const WINDOW: [f64, ..3] = [1f64, 5f64, 15f64];

pub struct MeterSnapshot{
    count: i64,
    rates: [f64, ..3],
    rate_mean: f64
}

pub struct Meter {
    data: Mutex<MeterSnapshot>,
    ewma: [EWMA, ..3],
    start: Timespec
}

impl Meter {
    pub fn mark(&self, n: i64) {
        let mut s = self.data.lock();
        s.count += n;

        for i in range(0, WINDOW.len()) {
            self.ewma[i].update(n as uint);
        }
    }

    pub fn snapshot(&self) -> MeterSnapshot{
        let s = self.data.lock();

        MeterSnapshot {
            count: s.count,
            rates: s.rates,
            rate_mean: s.rate_mean
        }
    }

    fn update_snapshot(&self) {
        let mut s = self.data.lock();

        for i in range(0, WINDOW.len()) {
            s.rates[i] = self.ewma[i].rate();
        }

        let diff = get_time() - self.start;
        s.rate_mean = s.count as f64 / diff.num_seconds() as f64;
    }

    pub fn tick(&mut self) {
        self.data.lock();

        for i in range(0, WINDOW.len()) {
            self.ewma[i].tick();
        }

        self.update_snapshot()
    }

    pub fn new() -> Meter {
        let data = MeterSnapshot{
            count: 0i64,
            rates: [0f64, 0f64, 0f64],
            rate_mean: 0f64
        };

        let ewma: [EWMA, ..3] = [EWMA::new(1f64), EWMA::new(5f64), EWMA::new(15f64)];

        Meter {
            data: Mutex::new(data),
            ewma: ewma,
            start: get_time()
        }
    }
}

#[cfg(test)]
mod test {
    use meter::{Meter,MeterSnapshot};

    #[test]
    fn zero() {
        let m: Meter = Meter::new();
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 0);
    }

    #[test]
    fn non_zero() {
        let m: Meter = Meter::new();
        m.mark(3);
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 3);
    }

    #[test]
    fn snapshot() {
        let m: Meter = Meter::new();
        m.mark(1);
        m.mark(1);

        let s = m.snapshot();

        m.mark(1);

        assert_eq!(s.count, 2);
        assert_eq!(m.snapshot().count, 3);
    }
}<commit_msg>Fixup Meter<commit_after>use time::get_time;
use time::Timespec;

use std::sync::Mutex;

use ewma::EWMA;
use metric::Metric;

const WINDOW: [f64, ..3] = [1f64, 5f64, 15f64];

// A MeterSnapshot
pub struct MeterSnapshot {
    count: i64,
    rates: [f64, ..3],
    rate_mean: f64
}

// A StdMeter struct
pub struct StdMeter {
    data: Mutex<MeterSnapshot>,
    ewma: [EWMA, ..3],
    start: Timespec
}

// A Meter trait
pub trait Meter : Metric {
    fn snapshot(&self) -> MeterSnapshot;

    fn mark(&self, n: i64);

    fn tick(&mut self);

    fn rate(&self, rate: uint) -> f64;

    fn count(&self) -> i64;
}

impl Meter for StdMeter {
    fn snapshot(&self) -> MeterSnapshot {
        let s = self.data.lock();

        MeterSnapshot {
            count: s.count,
            rates: s.rates,
            rate_mean: s.rate_mean
        }
    }

    fn mark(&self, n: i64) {
        let mut s = self.data.lock();

        s.count += n;

        for i in range(0, WINDOW.len()) {
            self.ewma[i].update(n as uint);
        }

        self.update_snapshot(*s);
    }

    fn tick(&mut self) {
        let mut s = self.data.lock();

        for i in range(0, WINDOW.len()) {
            self.ewma[i].tick();
        }

        self.update_snapshot(*s);
    }

    fn rate(&self, rate: uint) -> f64 {
        let mut s = self.data.lock();
        s.rates[rate]
    }

    fn count(&self) -> i64 {
        let s = self.data.lock();
        s.count
    }
}

impl Metric for StdMeter {
}

impl StdMeter {
    fn update_snapshot(&self, mut s: MeterSnapshot) {
        for i in range(0, WINDOW.len()) {
            s.rates[i] = self.ewma[i].rate();
        }

        let diff = get_time() - self.start;
        s.rate_mean = s.count as f64 / diff.num_seconds() as f64;
    }

    pub fn new() -> StdMeter {
        let data = MeterSnapshot{
            count: 0i64,
            rates: [0f64, 0f64, 0f64],
            rate_mean: 0f64
        };

        let ewma: [EWMA, ..3] = [EWMA::new(1f64), EWMA::new(5f64), EWMA::new(15f64)];

        StdMeter {
            data: Mutex::new(data),
            ewma: ewma,
            start: get_time()
        }
    }

}

#[cfg(test)]
mod test {
    use meter::{Meter,MeterSnapshot,StdMeter};

    #[test]
    fn zero() {
        let m: StdMeter = StdMeter::new();
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 0);
    }

    #[test]
    fn non_zero() {
        let m: StdMeter = StdMeter::new();
        m.mark(3);
        let s: MeterSnapshot = m.snapshot();
        assert_eq!(s.count, 3);
    }

    #[test]
    fn snapshot() {
        let m: StdMeter = StdMeter::new();
        m.mark(1);
        m.mark(1);

        let s = m.snapshot();

        m.mark(1);

        assert_eq!(s.count, 2);
        assert_eq!(m.snapshot().count, 3);
    }
}<|endoftext|>


<commit_before>import syntax::ast::*;
import syntax::visit;
import syntax::ast_util;
import driver::session::session;
import std::map::hashmap;

enum deref_t { unbox(bool), field, index, }

type deref = @{mutbl: bool, kind: deref_t, outer_t: ty::t};

// Finds the root (the thing that is dereferenced) for the given expr, and a
// vec of dereferences that were used on this root. Note that, in this vec,
// the inner derefs come in front, so foo.bar[1] becomes rec(ex=foo,
// ds=[index,field])
fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
   {ex: @expr, ds: @[deref]} {
    fn maybe_auto_unbox(tcx: ty::ctxt, t: ty::t) -> {t: ty::t, ds: [deref]} {
        let ds = [], t = t;
        loop {
            alt ty::get(t).struct {
              ty::ty_box(mt) {
                ds += [@{mutbl: mt.mutbl == m_mutbl,
                         kind: unbox(false),
                         outer_t: t}];
                t = mt.ty;
              }
              ty::ty_uniq(mt) {
                ds += [@{mutbl: mt.mutbl == m_mutbl,
                         kind: unbox(false),
                         outer_t: t}];
                t = mt.ty;
              }
              ty::ty_res(_, inner, tps) {
                ds += [@{mutbl: false, kind: unbox(false), outer_t: t}];
                t = ty::substitute_type_params(tcx, tps, inner);
              }
              ty::ty_enum(did, tps) {
                let variants = ty::enum_variants(tcx, did);
                if vec::len(*variants) != 1u ||
                       vec::len(variants[0].args) != 1u {
                    break;
                }
                ds += [@{mutbl: false, kind: unbox(false), outer_t: t}];
                t = ty::substitute_type_params(tcx, tps, variants[0].args[0]);
              }
              _ { break; }
            }
        }
        ret {t: t, ds: ds};
    }
    let ds: [deref] = [], ex = ex;
    loop {
        alt copy ex.node {
          expr_field(base, ident, _) {
            let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, base));
            let is_mutbl = false;
            alt ty::get(auto_unbox.t).struct {
              ty::ty_rec(fields) {
                for fld: ty::field in fields {
                    if str::eq(ident, fld.ident) {
                        is_mutbl = fld.mt.mutbl == m_mutbl;
                        break;
                    }
                }
              }
              _ {}
            }
            ds += [@{mutbl: is_mutbl, kind: field, outer_t: auto_unbox.t}];
            ds += auto_unbox.ds;
            ex = base;
          }
          expr_index(base, _) {
            let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, base));
            alt ty::get(auto_unbox.t).struct {
              ty::ty_vec(mt) {
                ds +=
                    [@{mutbl: mt.mutbl == m_mutbl,
                       kind: index,
                       outer_t: auto_unbox.t}];
              }
              ty::ty_str {
                ds += [@{mutbl: false, kind: index, outer_t: auto_unbox.t}];
              }
              _ { break; }
            }
            ds += auto_unbox.ds;
            ex = base;
          }
          expr_unary(op, base) {
            if op == deref {
                let base_t = ty::expr_ty(tcx, base);
                let is_mutbl = false, ptr = false;
                alt ty::get(base_t).struct {
                  ty::ty_box(mt) { is_mutbl = mt.mutbl == m_mutbl; }
                  ty::ty_uniq(mt) { is_mutbl = mt.mutbl == m_mutbl; }
                  ty::ty_res(_, _, _) { }
                  ty::ty_enum(_, _) { }
                  ty::ty_ptr(mt) | ty::ty_rptr(_, mt) {
                    is_mutbl = mt.mutbl == m_mutbl;
                    ptr = true;
                  }
                  _ { tcx.sess.span_bug(base.span, "ill-typed base \
                        expression in deref"); }
                }
                ds += [@{mutbl: is_mutbl, kind: unbox(ptr && is_mutbl),
                         outer_t: base_t}];
                ex = base;
            } else { break; }
          }
          _ { break; }
        }
    }
    if autoderef {
        let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, ex));
        ds += auto_unbox.ds;
    }
    ret {ex: ex, ds: @ds};
}

// Actual mutbl-checking pass

type mutbl_map = std::map::hashmap<node_id, ()>;
type ctx = {tcx: ty::ctxt, mutbl_map: mutbl_map};

fn check_crate(tcx: ty::ctxt, crate: @crate) -> mutbl_map {
    let cx = @{tcx: tcx, mutbl_map: std::map::int_hash()};
    let v = @{visit_expr: bind visit_expr(cx, _, _, _),
              visit_decl: bind visit_decl(cx, _, _, _)
              with *visit::default_visitor()};
    visit::visit_crate(*crate, (), visit::mk_vt(v));
    ret cx.mutbl_map;
}

enum msg { msg_assign, msg_move_out, msg_mutbl_ref, }

fn mk_err(cx: @ctx, span: syntax::codemap::span, msg: msg, name: str) {
    cx.tcx.sess.span_err(span, alt msg {
      msg_assign { "assigning to " + name }
      msg_move_out { "moving out of " + name }
      msg_mutbl_ref { "passing " + name + " by mutable reference" }
    });
}

fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) {
    visit::visit_decl(d, e, v);
    alt d.node {
      decl_local(locs) {
        for loc in locs {
            alt loc.node.init {
              some(init) {
                if init.op == init_move { check_move_rhs(cx, init.expr); }
              }
              none { }
            }
        }
      }
      _ { }
    }
}

fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) {
    alt ex.node {
      expr_call(f, args, _) { check_call(cx, f, args); }
      expr_bind(f, args) { check_bind(cx, f, args); }
      expr_swap(lhs, rhs) {
        check_lval(cx, lhs, msg_assign);
        check_lval(cx, rhs, msg_assign);
      }
      expr_move(dest, src) {
        check_lval(cx, dest, msg_assign);
        check_move_rhs(cx, src);
      }
      expr_assign(dest, src) | expr_assign_op(_, dest, src) {
        check_lval(cx, dest, msg_assign);
      }
      expr_fn(_, _, _, cap) {
        for moved in cap.moves {
            let def = cx.tcx.def_map.get(moved.id);
            alt is_illegal_to_modify_def(cx, def, msg_move_out) {
              some(name) { mk_err(cx, moved.span, msg_move_out, moved.name); }
              _ { }
            }
            cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ());
        }
      }
      _ { }
    }
    visit::visit_expr(ex, e, v);
}

fn check_lval(cx: @ctx, dest: @expr, msg: msg) {
    alt dest.node {
      expr_path(p) {
        let def = cx.tcx.def_map.get(dest.id);
        alt is_illegal_to_modify_def(cx, def, msg) {
          some(name) { mk_err(cx, dest.span, msg, name); }
          _ { }
        }
        cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ());
      }
      _ {
        let root = expr_root(cx.tcx, dest, false);
        if vec::len(*root.ds) == 0u {
            if msg != msg_move_out {
                mk_err(cx, dest.span, msg, "non-lvalue");
            }
        } else if !root.ds[0].mutbl {
            let name =
                alt root.ds[0].kind {
                  mutbl::unbox(_) { "immutable box" }
                  mutbl::field { "immutable field" }
                  mutbl::index { "immutable vec content" }
                };
            mk_err(cx, dest.span, msg, name);
        }
      }
    }
}

fn check_move_rhs(cx: @ctx, src: @expr) {
    alt src.node {
      expr_path(p) {
        alt cx.tcx.def_map.get(src.id) {
          def_self(_) {
            mk_err(cx, src.span, msg_move_out, "method self");
          }
          _ { }
        }
        check_lval(cx, src, msg_move_out);
      }
      _ {
        let root = expr_root(cx.tcx, src, false);

        // Not a path and no-derefs means this is a temporary.
        if vec::len(*root.ds) != 0u &&
           root.ds[vec::len(*root.ds) - 1u].kind != unbox(true) {
            cx.tcx.sess.span_err(src.span, "moving out of a data structure");
        }
      }
    }
}

fn check_call(cx: @ctx, f: @expr, args: [@expr]) {
    let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f));
    let i = 0u;
    for arg_t: ty::arg in arg_ts {
        alt ty::resolved_mode(cx.tcx, arg_t.mode) {
          by_mutbl_ref { check_lval(cx, args[i], msg_mutbl_ref); }
          by_move { check_lval(cx, args[i], msg_move_out); }
          by_ref | by_val | by_copy { }
        }
        i += 1u;
    }
}

fn check_bind(cx: @ctx, f: @expr, args: [option<@expr>]) {
    let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f));
    let i = 0u;
    for arg in args {
        alt arg {
          some(expr) {
            let o_msg = alt ty::resolved_mode(cx.tcx, arg_ts[i].mode) {
              by_mutbl_ref { some("by mutable reference") }
              by_move { some("by move") }
              _ { none }
            };
            alt o_msg {
              some(name) {
                cx.tcx.sess.span_err(
                    expr.span, "can not bind an argument passed " + name);
              }
              none {}
            }
          }
          _ {}
        }
        i += 1u;
    }
}

// returns some if the def cannot be modified.  the kind of modification is
// indicated by `msg`.
fn is_illegal_to_modify_def(cx: @ctx, def: def, msg: msg) -> option<str> {
    alt def {
      def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) |
      def_use(_) {
        some("static item")
      }
      def_arg(_, m) {
        alt ty::resolved_mode(cx.tcx, m) {
          by_ref | by_val { some("argument of enclosing function") }
          by_mutbl_ref | by_move | by_copy { none }
        }
      }
      def_self(_) { some("self argument") }
      def_upvar(_, inner, node_id) {
        let ty = ty::node_id_to_type(cx.tcx, node_id);
        let proto = ty::ty_fn_proto(ty);
        ret alt proto {
          proto_any | proto_block {
            is_illegal_to_modify_def(cx, *inner, msg)
          }
          proto_bare | proto_uniq | proto_box {
            some("upvar")
          }
        };
      }

      // Note: we should *always* allow all local variables to be assigned
      // here and then guarantee in the typestate pass that immutable local
      // variables are assigned at most once.  But this requires a new kind of
      // propagation (def. not assigned), so I didn't do that.
      def_local(_, false) if msg == msg_move_out { none }
      def_local(_, false) if cx.tcx.sess.opts.enforce_mut_vars {
        some("immutable local variable")
      }

      def_binding(_) { some("binding") }
      _ { none }
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>rustc: Fix mutability checking when dereferencing a region-annotated pointer<commit_after>import syntax::ast::*;
import syntax::visit;
import syntax::ast_util;
import driver::session::session;
import std::map::hashmap;

enum deref_t { unbox(bool), field, index, }

type deref = @{mutbl: bool, kind: deref_t, outer_t: ty::t};

// Finds the root (the thing that is dereferenced) for the given expr, and a
// vec of dereferences that were used on this root. Note that, in this vec,
// the inner derefs come in front, so foo.bar[1] becomes rec(ex=foo,
// ds=[index,field])
fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
   {ex: @expr, ds: @[deref]} {
    fn maybe_auto_unbox(tcx: ty::ctxt, t: ty::t) -> {t: ty::t, ds: [deref]} {
        let ds = [], t = t;
        loop {
            alt ty::get(t).struct {
              ty::ty_box(mt) | ty::ty_uniq(mt) | ty::ty_rptr(_, mt) {
                ds += [@{mutbl: mt.mutbl == m_mutbl,
                         kind: unbox(false),
                         outer_t: t}];
                t = mt.ty;
              }
              ty::ty_res(_, inner, tps) {
                ds += [@{mutbl: false, kind: unbox(false), outer_t: t}];
                t = ty::substitute_type_params(tcx, tps, inner);
              }
              ty::ty_enum(did, tps) {
                let variants = ty::enum_variants(tcx, did);
                if vec::len(*variants) != 1u ||
                       vec::len(variants[0].args) != 1u {
                    break;
                }
                ds += [@{mutbl: false, kind: unbox(false), outer_t: t}];
                t = ty::substitute_type_params(tcx, tps, variants[0].args[0]);
              }
              _ { break; }
            }
        }
        ret {t: t, ds: ds};
    }
    let ds: [deref] = [], ex = ex;
    loop {
        alt copy ex.node {
          expr_field(base, ident, _) {
            let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, base));
            let is_mutbl = false;
            alt ty::get(auto_unbox.t).struct {
              ty::ty_rec(fields) {
                for fld: ty::field in fields {
                    if str::eq(ident, fld.ident) {
                        is_mutbl = fld.mt.mutbl == m_mutbl;
                        break;
                    }
                }
              }
              _ {}
            }
            ds += [@{mutbl: is_mutbl, kind: field, outer_t: auto_unbox.t}];
            ds += auto_unbox.ds;
            ex = base;
          }
          expr_index(base, _) {
            let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, base));
            alt ty::get(auto_unbox.t).struct {
              ty::ty_vec(mt) {
                ds +=
                    [@{mutbl: mt.mutbl == m_mutbl,
                       kind: index,
                       outer_t: auto_unbox.t}];
              }
              ty::ty_str {
                ds += [@{mutbl: false, kind: index, outer_t: auto_unbox.t}];
              }
              _ { break; }
            }
            ds += auto_unbox.ds;
            ex = base;
          }
          expr_unary(op, base) {
            if op == deref {
                let base_t = ty::expr_ty(tcx, base);
                let is_mutbl = false, ptr = false;
                alt ty::get(base_t).struct {
                  ty::ty_box(mt) { is_mutbl = mt.mutbl == m_mutbl; }
                  ty::ty_uniq(mt) { is_mutbl = mt.mutbl == m_mutbl; }
                  ty::ty_res(_, _, _) { }
                  ty::ty_enum(_, _) { }
                  ty::ty_ptr(mt) | ty::ty_rptr(_, mt) {
                    is_mutbl = mt.mutbl == m_mutbl;
                    ptr = true;
                  }
                  _ { tcx.sess.span_bug(base.span, "ill-typed base \
                        expression in deref"); }
                }
                ds += [@{mutbl: is_mutbl, kind: unbox(ptr && is_mutbl),
                         outer_t: base_t}];
                ex = base;
            } else { break; }
          }
          _ { break; }
        }
    }
    if autoderef {
        let auto_unbox = maybe_auto_unbox(tcx, ty::expr_ty(tcx, ex));
        ds += auto_unbox.ds;
    }
    ret {ex: ex, ds: @ds};
}

// Actual mutbl-checking pass

type mutbl_map = std::map::hashmap<node_id, ()>;
type ctx = {tcx: ty::ctxt, mutbl_map: mutbl_map};

fn check_crate(tcx: ty::ctxt, crate: @crate) -> mutbl_map {
    let cx = @{tcx: tcx, mutbl_map: std::map::int_hash()};
    let v = @{visit_expr: bind visit_expr(cx, _, _, _),
              visit_decl: bind visit_decl(cx, _, _, _)
              with *visit::default_visitor()};
    visit::visit_crate(*crate, (), visit::mk_vt(v));
    ret cx.mutbl_map;
}

enum msg { msg_assign, msg_move_out, msg_mutbl_ref, }

fn mk_err(cx: @ctx, span: syntax::codemap::span, msg: msg, name: str) {
    cx.tcx.sess.span_err(span, alt msg {
      msg_assign { "assigning to " + name }
      msg_move_out { "moving out of " + name }
      msg_mutbl_ref { "passing " + name + " by mutable reference" }
    });
}

fn visit_decl(cx: @ctx, d: @decl, &&e: (), v: visit::vt<()>) {
    visit::visit_decl(d, e, v);
    alt d.node {
      decl_local(locs) {
        for loc in locs {
            alt loc.node.init {
              some(init) {
                if init.op == init_move { check_move_rhs(cx, init.expr); }
              }
              none { }
            }
        }
      }
      _ { }
    }
}

fn visit_expr(cx: @ctx, ex: @expr, &&e: (), v: visit::vt<()>) {
    alt ex.node {
      expr_call(f, args, _) { check_call(cx, f, args); }
      expr_bind(f, args) { check_bind(cx, f, args); }
      expr_swap(lhs, rhs) {
        check_lval(cx, lhs, msg_assign);
        check_lval(cx, rhs, msg_assign);
      }
      expr_move(dest, src) {
        check_lval(cx, dest, msg_assign);
        check_move_rhs(cx, src);
      }
      expr_assign(dest, src) | expr_assign_op(_, dest, src) {
        check_lval(cx, dest, msg_assign);
      }
      expr_fn(_, _, _, cap) {
        for moved in cap.moves {
            let def = cx.tcx.def_map.get(moved.id);
            alt is_illegal_to_modify_def(cx, def, msg_move_out) {
              some(name) { mk_err(cx, moved.span, msg_move_out, moved.name); }
              _ { }
            }
            cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ());
        }
      }
      _ { }
    }
    visit::visit_expr(ex, e, v);
}

fn check_lval(cx: @ctx, dest: @expr, msg: msg) {
    alt dest.node {
      expr_path(p) {
        let def = cx.tcx.def_map.get(dest.id);
        alt is_illegal_to_modify_def(cx, def, msg) {
          some(name) { mk_err(cx, dest.span, msg, name); }
          _ { }
        }
        cx.mutbl_map.insert(ast_util::def_id_of_def(def).node, ());
      }
      _ {
        let root = expr_root(cx.tcx, dest, false);
        if vec::len(*root.ds) == 0u {
            if msg != msg_move_out {
                mk_err(cx, dest.span, msg, "non-lvalue");
            }
        } else if !root.ds[0].mutbl {
            let name =
                alt root.ds[0].kind {
                  mutbl::unbox(_) { "immutable box" }
                  mutbl::field { "immutable field" }
                  mutbl::index { "immutable vec content" }
                };
            mk_err(cx, dest.span, msg, name);
        }
      }
    }
}

fn check_move_rhs(cx: @ctx, src: @expr) {
    alt src.node {
      expr_path(p) {
        alt cx.tcx.def_map.get(src.id) {
          def_self(_) {
            mk_err(cx, src.span, msg_move_out, "method self");
          }
          _ { }
        }
        check_lval(cx, src, msg_move_out);
      }
      _ {
        let root = expr_root(cx.tcx, src, false);

        // Not a path and no-derefs means this is a temporary.
        if vec::len(*root.ds) != 0u &&
           root.ds[vec::len(*root.ds) - 1u].kind != unbox(true) {
            cx.tcx.sess.span_err(src.span, "moving out of a data structure");
        }
      }
    }
}

fn check_call(cx: @ctx, f: @expr, args: [@expr]) {
    let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f));
    let i = 0u;
    for arg_t: ty::arg in arg_ts {
        alt ty::resolved_mode(cx.tcx, arg_t.mode) {
          by_mutbl_ref { check_lval(cx, args[i], msg_mutbl_ref); }
          by_move { check_lval(cx, args[i], msg_move_out); }
          by_ref | by_val | by_copy { }
        }
        i += 1u;
    }
}

fn check_bind(cx: @ctx, f: @expr, args: [option<@expr>]) {
    let arg_ts = ty::ty_fn_args(ty::expr_ty(cx.tcx, f));
    let i = 0u;
    for arg in args {
        alt arg {
          some(expr) {
            let o_msg = alt ty::resolved_mode(cx.tcx, arg_ts[i].mode) {
              by_mutbl_ref { some("by mutable reference") }
              by_move { some("by move") }
              _ { none }
            };
            alt o_msg {
              some(name) {
                cx.tcx.sess.span_err(
                    expr.span, "can not bind an argument passed " + name);
              }
              none {}
            }
          }
          _ {}
        }
        i += 1u;
    }
}

// returns some if the def cannot be modified.  the kind of modification is
// indicated by `msg`.
fn is_illegal_to_modify_def(cx: @ctx, def: def, msg: msg) -> option<str> {
    alt def {
      def_fn(_, _) | def_mod(_) | def_native_mod(_) | def_const(_) |
      def_use(_) {
        some("static item")
      }
      def_arg(_, m) {
        alt ty::resolved_mode(cx.tcx, m) {
          by_ref | by_val { some("argument of enclosing function") }
          by_mutbl_ref | by_move | by_copy { none }
        }
      }
      def_self(_) { some("self argument") }
      def_upvar(_, inner, node_id) {
        let ty = ty::node_id_to_type(cx.tcx, node_id);
        let proto = ty::ty_fn_proto(ty);
        ret alt proto {
          proto_any | proto_block {
            is_illegal_to_modify_def(cx, *inner, msg)
          }
          proto_bare | proto_uniq | proto_box {
            some("upvar")
          }
        };
      }

      // Note: we should *always* allow all local variables to be assigned
      // here and then guarantee in the typestate pass that immutable local
      // variables are assigned at most once.  But this requires a new kind of
      // propagation (def. not assigned), so I didn't do that.
      def_local(_, false) if msg == msg_move_out { none }
      def_local(_, false) if cx.tcx.sess.opts.enforce_mut_vars {
        some("immutable local variable")
      }

      def_binding(_) { some("binding") }
      _ { none }
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>