<commit_before>//! A crate for analyzing the contents of the [rust-rosetta] repository.
//!
//! [rust-rosetta]: https://github.com/Hoverbear/rust-rosetta

#![warn(missing_docs)]

#[doc(hidden)]
pub extern crate rand;

use std::cmp;
use std::collections::{HashSet, VecDeque};
use std::fs::File;
use std::io::prelude::*;
use std::iter::FromIterator;
use std::ops::Sub;
use std::path::{Path, PathBuf};

use anyhow::Error;
use lazy_static::lazy_static;
use regex::Regex;
use reqwest::blocking::Client;
use reqwest::Url;

use local::LocalTask;
use remote::{RemoteTask, Response};

pub mod local;
mod remote;
pub mod test_utils;

/// Crate-specific error type.
pub type Result<T> = std::result::Result<T, Error>;

lazy_static! {
    /// A Regex that matches valid Rosetta Code URLs.
    static ref TASK_URL_RE: Regex =
        Regex::new(r"^https?://rosettacode\.org/wiki/([^#]+)$").unwrap();
}

/// A representation of a Rosetta Code task. Contains information about the implementation on both
/// the local repository and the wiki.
#[derive(Debug, Clone)]
pub struct Task {
    local: Option<LocalTask>,
    remote: RemoteTask,
}

impl Task {
    /// Returns the title of the task.
    pub fn title(&self) -> String {
        self.remote.title()
    }

    /// Returns the implementation of the task in the local repository, if it exists.
    pub fn local_code(&self) -> Option<String> {
        self.local.clone().map(|task| {
            // FIXME: Too simple for the multiple source file case.
            let mut code = String::new();

            for source in &task.source {
                let mut file = File::open(source).unwrap();
                file.read_to_string(&mut code).unwrap();
            }

            code
        })
    }

    /// Returns the implementation of the task on the wiki, if it exists.
    pub fn remote_code(&self) -> Option<String> {
        self.remote.source()
    }

    /// True if and only if the task is only implemented on the Rosetta Code wiki.
    pub fn is_remote_only(&self) -> bool {
        self.local.is_none() && self.remote.source().is_some()
    }

    /// True if and only if the task is is only implemented in the repository.
    pub fn is_local_only(&self) -> bool {
        self.local.is_some() && self.remote.source().is_none()
    }

    /// True if and only if the task is neither implemented on the Rosetta Code wiki or on the
    /// repository.
    pub fn is_unimplemented(&self) -> bool {
        self.local.is_none() && self.remote.source().is_none()
    }

    /// Returns the URL of the task on the Rosetta Code wiki.
    pub fn url(&self) -> Url {
        self.remote.url()
    }

    /// Returns the relative path to the task from repository root.
    pub fn local_path(&self) -> Option<PathBuf> {
        self.local.as_ref().and_then(|l| {
            let workspace_root_dir = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap();
            pathdiff::diff_paths(l.manifest_path.parent().unwrap(), workspace_root_dir)
        })
    }
}

/// The index of all tasks implemented locally and remotely.
pub struct TaskIndex {
    all_task_titles: HashSet<String>,
    local_tasks: Vec<LocalTask>,
    client: Client,
}

impl TaskIndex {
    /// Generate the task index by parsing tasks in the repository and requesting task titles from
    /// the wiki.
    pub fn create<P: AsRef<Path>>(workspace_root: P) -> Result<TaskIndex> {
        let local_tasks = local::parse_tasks(workspace_root.as_ref().join("Cargo.toml")).unwrap();
        let local_task_titles = local_tasks.iter().map(|task| task.title.clone()).collect();

        let client = Client::new();
        let all_task_titles = TaskIndex::all_task_titles(&client, &local_task_titles)?;

        Ok(TaskIndex {
            all_task_titles,
            local_tasks,
            client,
        })
    }

    /// Retrieves data for every task on Rosetta Code.
    pub fn fetch_all_tasks(&self) -> TaskIterator {
        Self::fetch_tasks(self, &[])
    }

    /// Parses both local (implemented in this repository) and remote (implemented on the wiki)
    /// tasks, and returns the code of each.
    pub fn fetch_tasks(&self, tasks: &[String]) -> TaskIterator {
        TaskIterator::new(self, tasks)
    }

    fn all_task_titles(
        client: &Client,
        local_task_titles: &HashSet<String>,
    ) -> Result<HashSet<String>> {
        let mut all_task_titles = find_unimplemented_tasks::all_tasks()
            .into_iter()
            .map(|task| task.title)
            .collect::<HashSet<_>>();

        let all_decoded_task_titles = all_task_titles
            .iter()
            .map(|title| remote::decode_title(title))
            .collect::<HashSet<_>>();

        if !local_task_titles.is_subset(&all_decoded_task_titles) {
            // If there are tasks that can't be matched on the wiki, it's possible that they are
            // just draft tasks at the moment. Perform a query to see if we get any missing pages.
            let mut possible_draft_titles = (local_task_titles.sub(&all_decoded_task_titles))
                .into_iter()
                .collect::<Vec<_>>();
            possible_draft_titles.sort();

            // FIXME: We might have to loop here if we get too many draft tasks.
            let mut request = Url::parse("http://rosettacode.org/mw/api.php").unwrap();
            request
                .query_pairs_mut()
                .append_pair("action", "query")
                .append_pair("format", "json")
                .append_pair("prop", "info")
                .append_pair("titles", &possible_draft_titles.join("|"));

            let response: Response = client.get(request.as_str()).send()?.json()?;

            // In the response, any missing pages will have a negative ID.
            let bad_titles = response
                .query
                .pages
                .into_iter()
                .flat_map(|(id, page)| if id < 0 { Some(page.title) } else { None })
                .collect::<Vec<_>>();

            if !bad_titles.is_empty() {
                panic!(
                    "Could not match some local tasks to tasks on the wiki: {:?}",
                    bad_titles
                );
            }

            all_task_titles.extend(possible_draft_titles);
        }

        Ok(all_task_titles)
    }
}

/// An iterator over tasks. Parses information from both the rust-rosetta repository and the
/// Rosetta Code wiki.
pub struct TaskIterator<'a> {
    client: &'a Client,
    fetched_remote_tasks: VecDeque<RemoteTask>,
    requested_task_titles: VecDeque<String>,
    local_tasks: Vec<LocalTask>,
}

impl<'a> TaskIterator<'a> {
    /// Creates a new iterator over the specified tasks. If no tasks are supplied, iterates over
    /// all tasks.
    fn new(task_index: &'a TaskIndex, titles: &[String]) -> TaskIterator<'a> {
        let mut requested_task_titles: Vec<_> = if titles.is_empty() {
            task_index.all_task_titles.iter().cloned().collect()
        } else {
            task_index
                .all_task_titles
                .intersection(&HashSet::from_iter(titles.iter().cloned()))
                .cloned()
                .collect()
        };

        requested_task_titles.sort();

        TaskIterator {
            client: &task_index.client,
            fetched_remote_tasks: Default::default(),
            requested_task_titles: requested_task_titles.into_iter().collect(),
            local_tasks: task_index.local_tasks.clone(),
        }
    }

    /// Fetch the next set of remote tasks.
    fn fetch_task_batch(&mut self) -> Result<()> {
        let end = cmp::min(self.requested_task_titles.len(), 50);
        let next_batch_titles = self.requested_task_titles.drain(..end).collect::<Vec<_>>();
        let mut request = Url::parse("http://rosettacode.org/mw/api.php").unwrap();
        request
            .query_pairs_mut()
            .append_pair("action", "query")
            .append_pair("format", "json")
            .append_pair("prop", "revisions")
            .append_pair("rvprop", "content")
            .append_pair("titles", &next_batch_titles.join("|"));

        let response: Response = self.client.get(request.as_str()).send()?.json()?;

        let mut remote_tasks = remote::parse_tasks(&response);
        remote_tasks.sort_by_key(|task| task.title());
        self.fetched_remote_tasks = remote_tasks.into_iter().collect();

        Ok(())
    }
}

impl<'a> Iterator for TaskIterator<'a> {
    type Item = Result<Task>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.requested_task_titles.is_empty() && self.fetched_remote_tasks.is_empty() {
            return None;
        }

        if self.fetched_remote_tasks.is_empty() {
            if let Err(err) = self.fetch_task_batch() {
                return Some(Err(err));
            }
        }

        let remote_task = self.fetched_remote_tasks.pop_front().unwrap();
        let local_task = self
            .local_tasks
            .iter()
            .cloned()
            .find(|task| task.title == remote_task.title());

        let task = Task {
            local: local_task,
            remote: remote_task,
        };

        Some(Ok(task))
    }
}
<commit_msg>One more lint fixed in coverage<commit_after>//! A crate for analyzing the contents of the [rust-rosetta] repository.
//!
//! [rust-rosetta]: https://github.com/Hoverbear/rust-rosetta

#![warn(missing_docs)]

#[doc(hidden)]
pub extern crate rand;

use std::cmp;
use std::collections::{HashSet, VecDeque};
use std::fs::File;
use std::io::prelude::*;
use std::ops::Sub;
use std::path::{Path, PathBuf};

use anyhow::Error;
use lazy_static::lazy_static;
use regex::Regex;
use reqwest::blocking::Client;
use reqwest::Url;

use local::LocalTask;
use remote::{RemoteTask, Response};

pub mod local;
mod remote;
pub mod test_utils;

/// Crate-specific error type.
pub type Result<T> = std::result::Result<T, Error>;

lazy_static! {
    /// A Regex that matches valid Rosetta Code URLs.
    static ref TASK_URL_RE: Regex =
        Regex::new(r"^https?://rosettacode\.org/wiki/([^#]+)$").unwrap();
}

/// A representation of a Rosetta Code task. Contains information about the implementation on both
/// the local repository and the wiki.
#[derive(Debug, Clone)]
pub struct Task {
    local: Option<LocalTask>,
    remote: RemoteTask,
}

impl Task {
    /// Returns the title of the task.
    pub fn title(&self) -> String {
        self.remote.title()
    }

    /// Returns the implementation of the task in the local repository, if it exists.
    pub fn local_code(&self) -> Option<String> {
        self.local.clone().map(|task| {
            // FIXME: Too simple for the multiple source file case.
            let mut code = String::new();

            for source in &task.source {
                let mut file = File::open(source).unwrap();
                file.read_to_string(&mut code).unwrap();
            }

            code
        })
    }

    /// Returns the implementation of the task on the wiki, if it exists.
    pub fn remote_code(&self) -> Option<String> {
        self.remote.source()
    }

    /// True if and only if the task is only implemented on the Rosetta Code wiki.
    pub fn is_remote_only(&self) -> bool {
        self.local.is_none() && self.remote.source().is_some()
    }

    /// True if and only if the task is is only implemented in the repository.
    pub fn is_local_only(&self) -> bool {
        self.local.is_some() && self.remote.source().is_none()
    }

    /// True if and only if the task is neither implemented on the Rosetta Code wiki or on the
    /// repository.
    pub fn is_unimplemented(&self) -> bool {
        self.local.is_none() && self.remote.source().is_none()
    }

    /// Returns the URL of the task on the Rosetta Code wiki.
    pub fn url(&self) -> Url {
        self.remote.url()
    }

    /// Returns the relative path to the task from repository root.
    pub fn local_path(&self) -> Option<PathBuf> {
        self.local.as_ref().and_then(|l| {
            let workspace_root_dir = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap();
            pathdiff::diff_paths(l.manifest_path.parent().unwrap(), workspace_root_dir)
        })
    }
}

/// The index of all tasks implemented locally and remotely.
pub struct TaskIndex {
    all_task_titles: HashSet<String>,
    local_tasks: Vec<LocalTask>,
    client: Client,
}

impl TaskIndex {
    /// Generate the task index by parsing tasks in the repository and requesting task titles from
    /// the wiki.
    pub fn create<P: AsRef<Path>>(workspace_root: P) -> Result<TaskIndex> {
        let local_tasks = local::parse_tasks(workspace_root.as_ref().join("Cargo.toml")).unwrap();
        let local_task_titles = local_tasks.iter().map(|task| task.title.clone()).collect();

        let client = Client::new();
        let all_task_titles = TaskIndex::all_task_titles(&client, &local_task_titles)?;

        Ok(TaskIndex {
            all_task_titles,
            local_tasks,
            client,
        })
    }

    /// Retrieves data for every task on Rosetta Code.
    pub fn fetch_all_tasks(&self) -> TaskIterator {
        Self::fetch_tasks(self, &[])
    }

    /// Parses both local (implemented in this repository) and remote (implemented on the wiki)
    /// tasks, and returns the code of each.
    pub fn fetch_tasks(&self, tasks: &[String]) -> TaskIterator {
        TaskIterator::new(self, tasks)
    }

    fn all_task_titles(
        client: &Client,
        local_task_titles: &HashSet<String>,
    ) -> Result<HashSet<String>> {
        let mut all_task_titles = find_unimplemented_tasks::all_tasks()
            .into_iter()
            .map(|task| task.title)
            .collect::<HashSet<_>>();

        let all_decoded_task_titles = all_task_titles
            .iter()
            .map(|title| remote::decode_title(title))
            .collect::<HashSet<_>>();

        if !local_task_titles.is_subset(&all_decoded_task_titles) {
            // If there are tasks that can't be matched on the wiki, it's possible that they are
            // just draft tasks at the moment. Perform a query to see if we get any missing pages.
            let mut possible_draft_titles = (local_task_titles.sub(&all_decoded_task_titles))
                .into_iter()
                .collect::<Vec<_>>();
            possible_draft_titles.sort();

            // FIXME: We might have to loop here if we get too many draft tasks.
            let mut request = Url::parse("http://rosettacode.org/mw/api.php").unwrap();
            request
                .query_pairs_mut()
                .append_pair("action", "query")
                .append_pair("format", "json")
                .append_pair("prop", "info")
                .append_pair("titles", &possible_draft_titles.join("|"));

            let response: Response = client.get(request.as_str()).send()?.json()?;

            // In the response, any missing pages will have a negative ID.
            let bad_titles = response
                .query
                .pages
                .into_iter()
                .flat_map(|(id, page)| if id < 0 { Some(page.title) } else { None })
                .collect::<Vec<_>>();

            if !bad_titles.is_empty() {
                panic!(
                    "Could not match some local tasks to tasks on the wiki: {:?}",
                    bad_titles
                );
            }

            all_task_titles.extend(possible_draft_titles);
        }

        Ok(all_task_titles)
    }
}

/// An iterator over tasks. Parses information from both the rust-rosetta repository and the
/// Rosetta Code wiki.
pub struct TaskIterator<'a> {
    client: &'a Client,
    fetched_remote_tasks: VecDeque<RemoteTask>,
    requested_task_titles: VecDeque<String>,
    local_tasks: Vec<LocalTask>,
}

impl<'a> TaskIterator<'a> {
    /// Creates a new iterator over the specified tasks. If no tasks are supplied, iterates over
    /// all tasks.
    fn new(task_index: &'a TaskIndex, titles: &[String]) -> TaskIterator<'a> {
        let mut requested_task_titles: Vec<_> = if titles.is_empty() {
            task_index.all_task_titles.iter().cloned().collect()
        } else {
            task_index
                .all_task_titles
                .intersection(&titles.iter().cloned().collect::<HashSet<_>>())
                .cloned()
                .collect()
        };

        requested_task_titles.sort();

        TaskIterator {
            client: &task_index.client,
            fetched_remote_tasks: Default::default(),
            requested_task_titles: requested_task_titles.into_iter().collect(),
            local_tasks: task_index.local_tasks.clone(),
        }
    }

    /// Fetch the next set of remote tasks.
    fn fetch_task_batch(&mut self) -> Result<()> {
        let end = cmp::min(self.requested_task_titles.len(), 50);
        let next_batch_titles = self.requested_task_titles.drain(..end).collect::<Vec<_>>();
        let mut request = Url::parse("http://rosettacode.org/mw/api.php").unwrap();
        request
            .query_pairs_mut()
            .append_pair("action", "query")
            .append_pair("format", "json")
            .append_pair("prop", "revisions")
            .append_pair("rvprop", "content")
            .append_pair("titles", &next_batch_titles.join("|"));

        let response: Response = self.client.get(request.as_str()).send()?.json()?;

        let mut remote_tasks = remote::parse_tasks(&response);
        remote_tasks.sort_by_key(|task| task.title());
        self.fetched_remote_tasks = remote_tasks.into_iter().collect();

        Ok(())
    }
}

impl<'a> Iterator for TaskIterator<'a> {
    type Item = Result<Task>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.requested_task_titles.is_empty() && self.fetched_remote_tasks.is_empty() {
            return None;
        }

        if self.fetched_remote_tasks.is_empty() {
            if let Err(err) = self.fetch_task_batch() {
                return Some(Err(err));
            }
        }

        let remote_task = self.fetched_remote_tasks.pop_front().unwrap();
        let local_task = self
            .local_tasks
            .iter()
            .cloned()
            .find(|task| task.title == remote_task.title());

        let task = Task {
            local: local_task,
            remote: remote_task,
        };

        Some(Ok(task))
    }
}
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(custom_attribute)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![allow(unused_attributes)]
#![feature(libc)]
#![feature(nll)]
#![feature(quote)]
#![feature(range_contains)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![feature(optin_builtin_traits)]
#![feature(concat_idents)]
#![feature(link_args)]
#![feature(static_nobundle)]

use back::write::create_target_machine;
use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;

#[macro_use] extern crate bitflags;
extern crate flate2;
extern crate libc;
#[macro_use] extern crate rustc;
extern crate jobserver;
extern crate num_cpus;
extern crate rustc_mir;
extern crate rustc_allocator;
extern crate rustc_apfloat;
extern crate rustc_target;
#[macro_use] extern crate rustc_data_structures;
extern crate rustc_demangle;
extern crate rustc_incremental;
extern crate rustc_llvm;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_codegen_utils;
extern crate rustc_fs_util;

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;
extern crate rustc_errors as errors;
extern crate serialize;
extern crate cc; // Used to locate MSVC
extern crate tempfile;
extern crate memmap;

use back::bytecode::RLIB_BYTECODE_EXTENSION;

pub use llvm_util::target_features;
use std::any::Any;
use std::sync::mpsc;
use rustc_data_structures::sync::Lrc;

use rustc::dep_graph::DepGraph;
use rustc::hir::def_id::CrateNum;
use rustc::middle::cstore::MetadataLoader;
use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource};
use rustc::middle::lang_items::LangItem;
use rustc::session::{Session, CompileIncomplete};
use rustc::session::config::{OutputFilenames, OutputType, PrintRequest};
use rustc::ty::{self, TyCtxt};
use rustc::util::time_graph;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::util::profiling::ProfileCategory;
use rustc_mir::monomorphize;
use rustc_codegen_utils::{CompiledModule, ModuleKind};
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc_data_structures::svh::Svh;

mod diagnostics;

mod back {
    mod archive;
    pub mod bytecode;
    pub mod link;
    pub mod lto;
    pub mod write;
    mod rpath;
    pub mod wasm;
}

mod abi;
mod allocator;
mod asm;
mod attributes;
mod base;
mod builder;
mod callee;
mod common;
mod consts;
mod context;
mod debuginfo;
mod declare;
mod glue;
mod intrinsic;
pub mod llvm;
mod llvm_util;
mod metadata;
mod meth;
mod mir;
mod mono_item;
mod type_;
mod type_of;
mod value;

pub struct LlvmCodegenBackend(());

impl !Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
impl !Sync for LlvmCodegenBackend {}

impl LlvmCodegenBackend {
    pub fn new() -> Box<dyn CodegenBackend> {
        box LlvmCodegenBackend(())
    }
}

impl CodegenBackend for LlvmCodegenBackend {
    fn init(&self, sess: &Session) {
        llvm_util::init(sess); // Make sure llvm is inited
    }

    fn print(&self, req: PrintRequest, sess: &Session) {
        match req {
            PrintRequest::RelocationModels => {
                println!("Available relocation models:");
                for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
                    println!("    {}", name);
                }
                println!("");
            }
            PrintRequest::CodeModels => {
                println!("Available code models:");
                for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){
                    println!("    {}", name);
                }
                println!("");
            }
            PrintRequest::TlsModels => {
                println!("Available TLS models:");
                for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){
                    println!("    {}", name);
                }
                println!("");
            }
            req => llvm_util::print(req, sess),
        }
    }

    fn print_passes(&self) {
        llvm_util::print_passes();
    }

    fn print_version(&self) {
        llvm_util::print_version();
    }

    fn diagnostics(&self) -> &[(&'static str, &'static str)] {
        &DIAGNOSTICS
    }

    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
        target_features(sess)
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        box metadata::LlvmMetadataLoader
    }

    fn provide(&self, providers: &mut ty::query::Providers) {
        rustc_codegen_utils::symbol_export::provide(providers);
        rustc_codegen_utils::symbol_names::provide(providers);
        base::provide_both(providers);
        attributes::provide(providers);
    }

    fn provide_extern(&self, providers: &mut ty::query::Providers) {
        rustc_codegen_utils::symbol_export::provide_extern(providers);
        base::provide_both(providers);
        attributes::provide_extern(providers);
    }

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        rx: mpsc::Receiver<Box<dyn Any + Send>>
    ) -> Box<dyn Any> {
        box base::codegen_crate(tcx, rx)
    }

    fn join_codegen_and_link(
        &self,
        ongoing_codegen: Box<dyn Any>,
        sess: &Session,
        dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), CompileIncomplete>{
        use rustc::util::common::time;
        let (ongoing_codegen, work_products) =
            ongoing_codegen.downcast::<::back::write::OngoingCodegen>()
                .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
                .join(sess);
        if sess.opts.debugging_opts.incremental_info {
            back::write::dump_incremental_data(&ongoing_codegen);
        }

        time(sess,
             "serialize work products",
             move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products));

        sess.compile_status()?;

        if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
                                                   i == OutputType::Metadata) {
            return Ok(());
        }

        // Run the linker on any artifacts that resulted from the LLVM run.
        // This should produce either a finished executable or library.
        sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
        time(sess, "linking", || {
            back::link::link_binary(sess, &ongoing_codegen,
                                    outputs, &ongoing_codegen.crate_name.as_str());
        });
        sess.profiler(|p| p.end_activity(ProfileCategory::Linking));

        // Now that we won't touch anything in the incremental compilation directory
        // any more, we can finalize it (which involves renaming it)
        rustc_incremental::finalize_session_directory(sess, ongoing_codegen.crate_hash);

        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    LlvmCodegenBackend::new()
}

struct ModuleCodegen {
    /// The name of the module. When the crate may be saved between
    /// compilations, incremental compilation requires that name be
    /// unique amongst **all** crates.  Therefore, it should contain
    /// something unique to this crate (e.g., a module path) as well
    /// as the crate name and disambiguator.
    /// We currently generate these names via CodegenUnit::build_cgu_name().
    name: String,
    module_llvm: ModuleLlvm,
    kind: ModuleKind,
}

struct CachedModuleCodegen {
    name: String,
    source: WorkProduct,
}

impl ModuleCodegen {
    fn into_compiled_module(self,
                            emit_obj: bool,
                            emit_bc: bool,
                            emit_bc_compressed: bool,
                            outputs: &OutputFilenames) -> CompiledModule {
        let object = if emit_obj {
            Some(outputs.temp_path(OutputType::Object, Some(&self.name)))
        } else {
            None
        };
        let bytecode = if emit_bc {
            Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)))
        } else {
            None
        };
        let bytecode_compressed = if emit_bc_compressed {
            Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))
                        .with_extension(RLIB_BYTECODE_EXTENSION))
        } else {
            None
        };

        CompiledModule {
            name: self.name.clone(),
            kind: self.kind,
            object,
            bytecode,
            bytecode_compressed,
        }
    }
}

struct ModuleLlvm {
    llcx: &'static mut llvm::Context,
    llmod_raw: *const llvm::Module,
    tm: &'static mut llvm::TargetMachine,
}

unsafe impl Send for ModuleLlvm { }
unsafe impl Sync for ModuleLlvm { }

impl ModuleLlvm {
    fn new(sess: &Session, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(sess.fewer_names());
            let llmod_raw = context::create_module(sess, llcx, mod_name) as *const _;

            ModuleLlvm {
                llmod_raw,
                llcx,
                tm: create_target_machine(sess, false),
            }
        }
    }

    fn llmod(&self) -> &llvm::Module {
        unsafe {
            &*self.llmod_raw
        }
    }
}

impl Drop for ModuleLlvm {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
            llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
        }
    }
}

struct CodegenResults {
    crate_name: Symbol,
    modules: Vec<CompiledModule>,
    allocator_module: Option<CompiledModule>,
    metadata_module: CompiledModule,
    crate_hash: Svh,
    metadata: rustc::middle::cstore::EncodedMetadata,
    windows_subsystem: Option<String>,
    linker_info: rustc_codegen_utils::linker::LinkerInfo,
    crate_info: CrateInfo,
}

/// Misc info we load from metadata to persist beyond the tcx
struct CrateInfo {
    panic_runtime: Option<CrateNum>,
    compiler_builtins: Option<CrateNum>,
    profiler_runtime: Option<CrateNum>,
    sanitizer_runtime: Option<CrateNum>,
    is_no_builtins: FxHashSet<CrateNum>,
    native_libraries: FxHashMap<CrateNum, Lrc<Vec<NativeLibrary>>>,
    crate_name: FxHashMap<CrateNum, String>,
    used_libraries: Lrc<Vec<NativeLibrary>>,
    link_args: Lrc<Vec<String>>,
    used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
    used_crates_static: Vec<(CrateNum, LibSource)>,
    used_crates_dynamic: Vec<(CrateNum, LibSource)>,
    wasm_imports: FxHashMap<String, String>,
    lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
    missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
}

__build_diagnostic_array! { librustc_codegen_llvm, DIAGNOSTICS }
<commit_msg>Work around to fix issue https://github.com/rust-lang/rust/issues/53912<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The Rust compiler.
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]

#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(custom_attribute)]
#![feature(extern_types)]
#![feature(in_band_lifetimes)]
#![allow(unused_attributes)]
#![feature(libc)]
#![feature(nll)]
#![feature(quote)]
#![feature(range_contains)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![feature(optin_builtin_traits)]
#![feature(concat_idents)]
#![feature(link_args)]
#![feature(static_nobundle)]

use back::write::create_target_machine;
use rustc::dep_graph::WorkProduct;
use syntax_pos::symbol::Symbol;

#[macro_use] extern crate bitflags;
extern crate flate2;
extern crate libc;
#[macro_use] extern crate rustc;
extern crate jobserver;
extern crate num_cpus;
extern crate rustc_mir;
extern crate rustc_allocator;
extern crate rustc_apfloat;
extern crate rustc_target;
#[macro_use] extern crate rustc_data_structures;
extern crate rustc_demangle;
extern crate rustc_incremental;
extern crate rustc_llvm;
extern crate rustc_platform_intrinsics as intrinsics;
extern crate rustc_codegen_utils;
extern crate rustc_fs_util;

#[macro_use] extern crate log;
#[macro_use] extern crate syntax;
extern crate syntax_pos;
extern crate rustc_errors as errors;
extern crate serialize;
extern crate cc; // Used to locate MSVC
extern crate tempfile;
extern crate memmap;

use back::bytecode::RLIB_BYTECODE_EXTENSION;

pub use llvm_util::target_features;
use std::any::Any;
use std::sync::mpsc;
use rustc_data_structures::sync::Lrc;

use rustc::dep_graph::DepGraph;
use rustc::hir::def_id::CrateNum;
use rustc::middle::cstore::MetadataLoader;
use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource};
use rustc::middle::lang_items::LangItem;
use rustc::session::{Session, CompileIncomplete};
use rustc::session::config::{OutputFilenames, OutputType, PrintRequest};
use rustc::ty::{self, TyCtxt};
use rustc::util::time_graph;
use rustc::util::nodemap::{FxHashSet, FxHashMap};
use rustc::util::profiling::ProfileCategory;
use rustc_mir::monomorphize;
use rustc_codegen_utils::{CompiledModule, ModuleKind};
use rustc_codegen_utils::codegen_backend::CodegenBackend;
use rustc_data_structures::svh::Svh;

mod diagnostics;

mod back {
    mod archive;
    pub mod bytecode;
    pub mod link;
    pub mod lto;
    pub mod write;
    mod rpath;
    pub mod wasm;
}

mod abi;
mod allocator;
mod asm;
mod attributes;
mod base;
mod builder;
mod callee;
mod common;
mod consts;
mod context;
mod debuginfo;
mod declare;
mod glue;
mod intrinsic;

// The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
#[path = "llvm/mod.rs"] mod llvm_; pub mod llvm { pub use super::llvm_::*; }

mod llvm_util;
mod metadata;
mod meth;
mod mir;
mod mono_item;
mod type_;
mod type_of;
mod value;

pub struct LlvmCodegenBackend(());

impl !Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis
impl !Sync for LlvmCodegenBackend {}

impl LlvmCodegenBackend {
    pub fn new() -> Box<dyn CodegenBackend> {
        box LlvmCodegenBackend(())
    }
}

impl CodegenBackend for LlvmCodegenBackend {
    fn init(&self, sess: &Session) {
        llvm_util::init(sess); // Make sure llvm is inited
    }

    fn print(&self, req: PrintRequest, sess: &Session) {
        match req {
            PrintRequest::RelocationModels => {
                println!("Available relocation models:");
                for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
                    println!("    {}", name);
                }
                println!("");
            }
            PrintRequest::CodeModels => {
                println!("Available code models:");
                for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){
                    println!("    {}", name);
                }
                println!("");
            }
            PrintRequest::TlsModels => {
                println!("Available TLS models:");
                for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){
                    println!("    {}", name);
                }
                println!("");
            }
            req => llvm_util::print(req, sess),
        }
    }

    fn print_passes(&self) {
        llvm_util::print_passes();
    }

    fn print_version(&self) {
        llvm_util::print_version();
    }

    fn diagnostics(&self) -> &[(&'static str, &'static str)] {
        &DIAGNOSTICS
    }

    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
        target_features(sess)
    }

    fn metadata_loader(&self) -> Box<dyn MetadataLoader + Sync> {
        box metadata::LlvmMetadataLoader
    }

    fn provide(&self, providers: &mut ty::query::Providers) {
        rustc_codegen_utils::symbol_export::provide(providers);
        rustc_codegen_utils::symbol_names::provide(providers);
        base::provide_both(providers);
        attributes::provide(providers);
    }

    fn provide_extern(&self, providers: &mut ty::query::Providers) {
        rustc_codegen_utils::symbol_export::provide_extern(providers);
        base::provide_both(providers);
        attributes::provide_extern(providers);
    }

    fn codegen_crate<'a, 'tcx>(
        &self,
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        rx: mpsc::Receiver<Box<dyn Any + Send>>
    ) -> Box<dyn Any> {
        box base::codegen_crate(tcx, rx)
    }

    fn join_codegen_and_link(
        &self,
        ongoing_codegen: Box<dyn Any>,
        sess: &Session,
        dep_graph: &DepGraph,
        outputs: &OutputFilenames,
    ) -> Result<(), CompileIncomplete>{
        use rustc::util::common::time;
        let (ongoing_codegen, work_products) =
            ongoing_codegen.downcast::<::back::write::OngoingCodegen>()
                .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>")
                .join(sess);
        if sess.opts.debugging_opts.incremental_info {
            back::write::dump_incremental_data(&ongoing_codegen);
        }

        time(sess,
             "serialize work products",
             move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products));

        sess.compile_status()?;

        if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
                                                   i == OutputType::Metadata) {
            return Ok(());
        }

        // Run the linker on any artifacts that resulted from the LLVM run.
        // This should produce either a finished executable or library.
        sess.profiler(|p| p.start_activity(ProfileCategory::Linking));
        time(sess, "linking", || {
            back::link::link_binary(sess, &ongoing_codegen,
                                    outputs, &ongoing_codegen.crate_name.as_str());
        });
        sess.profiler(|p| p.end_activity(ProfileCategory::Linking));

        // Now that we won't touch anything in the incremental compilation directory
        // any more, we can finalize it (which involves renaming it)
        rustc_incremental::finalize_session_directory(sess, ongoing_codegen.crate_hash);

        Ok(())
    }
}

/// This is the entrypoint for a hot plugged rustc_codegen_llvm
#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    LlvmCodegenBackend::new()
}

struct ModuleCodegen {
    /// The name of the module. When the crate may be saved between
    /// compilations, incremental compilation requires that name be
    /// unique amongst **all** crates.  Therefore, it should contain
    /// something unique to this crate (e.g., a module path) as well
    /// as the crate name and disambiguator.
    /// We currently generate these names via CodegenUnit::build_cgu_name().
    name: String,
    module_llvm: ModuleLlvm,
    kind: ModuleKind,
}

struct CachedModuleCodegen {
    name: String,
    source: WorkProduct,
}

impl ModuleCodegen {
    fn into_compiled_module(self,
                            emit_obj: bool,
                            emit_bc: bool,
                            emit_bc_compressed: bool,
                            outputs: &OutputFilenames) -> CompiledModule {
        let object = if emit_obj {
            Some(outputs.temp_path(OutputType::Object, Some(&self.name)))
        } else {
            None
        };
        let bytecode = if emit_bc {
            Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)))
        } else {
            None
        };
        let bytecode_compressed = if emit_bc_compressed {
            Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))
                        .with_extension(RLIB_BYTECODE_EXTENSION))
        } else {
            None
        };

        CompiledModule {
            name: self.name.clone(),
            kind: self.kind,
            object,
            bytecode,
            bytecode_compressed,
        }
    }
}

struct ModuleLlvm {
    llcx: &'static mut llvm::Context,
    llmod_raw: *const llvm::Module,
    tm: &'static mut llvm::TargetMachine,
}

unsafe impl Send for ModuleLlvm { }
unsafe impl Sync for ModuleLlvm { }

impl ModuleLlvm {
    fn new(sess: &Session, mod_name: &str) -> Self {
        unsafe {
            let llcx = llvm::LLVMRustContextCreate(sess.fewer_names());
            let llmod_raw = context::create_module(sess, llcx, mod_name) as *const _;

            ModuleLlvm {
                llmod_raw,
                llcx,
                tm: create_target_machine(sess, false),
            }
        }
    }

    fn llmod(&self) -> &llvm::Module {
        unsafe {
            &*self.llmod_raw
        }
    }
}

impl Drop for ModuleLlvm {
    fn drop(&mut self) {
        unsafe {
            llvm::LLVMContextDispose(&mut *(self.llcx as *mut _));
            llvm::LLVMRustDisposeTargetMachine(&mut *(self.tm as *mut _));
        }
    }
}

struct CodegenResults {
    crate_name: Symbol,
    modules: Vec<CompiledModule>,
    allocator_module: Option<CompiledModule>,
    metadata_module: CompiledModule,
    crate_hash: Svh,
    metadata: rustc::middle::cstore::EncodedMetadata,
    windows_subsystem: Option<String>,
    linker_info: rustc_codegen_utils::linker::LinkerInfo,
    crate_info: CrateInfo,
}

/// Misc info we load from metadata to persist beyond the tcx
struct CrateInfo {
    panic_runtime: Option<CrateNum>,
    compiler_builtins: Option<CrateNum>,
    profiler_runtime: Option<CrateNum>,
    sanitizer_runtime: Option<CrateNum>,
    is_no_builtins: FxHashSet<CrateNum>,
    native_libraries: FxHashMap<CrateNum, Lrc<Vec<NativeLibrary>>>,
    crate_name: FxHashMap<CrateNum, String>,
    used_libraries: Lrc<Vec<NativeLibrary>>,
    link_args: Lrc<Vec<String>>,
    used_crate_source: FxHashMap<CrateNum, Lrc<CrateSource>>,
    used_crates_static: Vec<(CrateNum, LibSource)>,
    used_crates_dynamic: Vec<(CrateNum, LibSource)>,
    wasm_imports: FxHashMap<String, String>,
    lang_item_to_crate: FxHashMap<LangItem, CrateNum>,
    missing_lang_items: FxHashMap<CrateNum, Vec<LangItem>>,
}

__build_diagnostic_array! { librustc_codegen_llvm, DIAGNOSTICS }
<|endoftext|>


<commit_before>//! Def-use analysis.

use rustc::mir::{Local, Location, Body};
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
use rustc_index::vec::IndexVec;
use std::mem;

pub struct DefUseAnalysis {
    info: IndexVec<Local, Info>,
}

#[derive(Clone)]
pub struct Info {
    pub defs_and_uses: Vec<Use>,
}

#[derive(Clone)]
pub struct Use {
    pub context: PlaceContext,
    pub location: Location,
}

impl DefUseAnalysis {
    pub fn new(body: &Body<'_>) -> DefUseAnalysis {
        DefUseAnalysis {
            info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
        }
    }

    pub fn analyze(&mut self, body: &Body<'_>) {
        self.clear();

        let mut finder = DefUseFinder {
            info: mem::take(&mut self.info),
        };
        finder.visit_body(body);
        self.info = finder.info
    }

    fn clear(&mut self) {
        for info in &mut self.info {
            info.clear();
        }
    }

    pub fn local_info(&self, local: Local) -> &Info {
        &self.info[local]
    }

    fn mutate_defs_and_uses<F>(&self, local: Local, body: &mut Body<'_>, mut callback: F)
                               where F: for<'a> FnMut(&'a mut Local,
                                                      PlaceContext,
                                                      Location) {
        for place_use in &self.info[local].defs_and_uses {
            MutateUseVisitor::new(local,
                                  &mut callback,
                                  body).visit_location(body, place_use.location)
        }
    }

    // FIXME(pcwalton): this should update the def-use chains.
    pub fn replace_all_defs_and_uses_with(&self,
                                          local: Local,
                                          body: &mut Body<'_>,
                                          new_local: Local) {
        self.mutate_defs_and_uses(local, body, |local, _, _| *local = new_local)
    }
}

struct DefUseFinder {
    info: IndexVec<Local, Info>,
}

impl Visitor<'_> for DefUseFinder {
    fn visit_local(&mut self,
                   &local: &Local,
                   context: PlaceContext,
                   location: Location) {
        self.info[local].defs_and_uses.push(Use {
            context,
            location,
        });
    }
}

impl Info {
    fn new() -> Info {
        Info {
            defs_and_uses: vec![],
        }
    }

    fn clear(&mut self) {
        self.defs_and_uses.clear();
    }

    pub fn def_count(&self) -> usize {
        self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
    }

    pub fn def_count_not_including_drop(&self) -> usize {
        self.defs_not_including_drop().count()
    }

    pub fn defs_not_including_drop(
        &self,
    ) -> impl Iterator<Item=&Use> {
        self.defs_and_uses.iter().filter(|place_use| {
            place_use.context.is_mutating_use() && !place_use.context.is_drop()
        })
    }

    pub fn use_count(&self) -> usize {
        self.defs_and_uses.iter().filter(|place_use| {
            place_use.context.is_nonmutating_use()
        }).count()
    }
}

struct MutateUseVisitor<F> {
    query: Local,
    callback: F,
}

impl<F> MutateUseVisitor<F> {
    fn new(query: Local, callback: F, _: &Body<'_>)
           -> MutateUseVisitor<F>
           where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) {
        MutateUseVisitor {
            query,
            callback,
        }
    }
}

impl<F> MutVisitor<'_> for MutateUseVisitor<F>
              where F: for<'a> FnMut(&'a mut Local, PlaceContext, Location) {
    fn visit_local(&mut self,
                    local: &mut Local,
                    context: PlaceContext,
                    location: Location) {
        if *local == self.query {
            (self.callback)(local, context, location)
        }
    }
}
<commit_msg>Prepare def_use MutVisitor to have projections interned<commit_after>//! Def-use analysis.

use rustc::mir::{Body, Local, Location, Place, PlaceElem};
use rustc::mir::visit::{PlaceContext, MutVisitor, Visitor};
use rustc_index::vec::IndexVec;
use std::mem;

pub struct DefUseAnalysis {
    info: IndexVec<Local, Info>,
}

#[derive(Clone)]
pub struct Info {
    pub defs_and_uses: Vec<Use>,
}

#[derive(Clone)]
pub struct Use {
    pub context: PlaceContext,
    pub location: Location,
}

impl DefUseAnalysis {
    pub fn new(body: &Body<'_>) -> DefUseAnalysis {
        DefUseAnalysis {
            info: IndexVec::from_elem_n(Info::new(), body.local_decls.len()),
        }
    }

    pub fn analyze(&mut self, body: &Body<'_>) {
        self.clear();

        let mut finder = DefUseFinder {
            info: mem::take(&mut self.info),
        };
        finder.visit_body(body);
        self.info = finder.info
    }

    fn clear(&mut self) {
        for info in &mut self.info {
            info.clear();
        }
    }

    pub fn local_info(&self, local: Local) -> &Info {
        &self.info[local]
    }

    fn mutate_defs_and_uses<F>(&self, local: Local, body: &mut Body<'_>, callback: F)
                               where F: for<'a> Fn(&'a Local,
                                                      PlaceContext,
                                                      Location) -> Local {
        for place_use in &self.info[local].defs_and_uses {
            MutateUseVisitor::new(local,
                                  &callback,
                                  body).visit_location(body, place_use.location)
        }
    }

    // FIXME(pcwalton): this should update the def-use chains.
    pub fn replace_all_defs_and_uses_with(&self,
                                          local: Local,
                                          body: &mut Body<'_>,
                                          new_local: Local) {
        self.mutate_defs_and_uses(local, body, |_, _, _| new_local)
    }
}

struct DefUseFinder {
    info: IndexVec<Local, Info>,
}

impl Visitor<'_> for DefUseFinder {
    fn visit_local(&mut self,
                   &local: &Local,
                   context: PlaceContext,
                   location: Location) {
        self.info[local].defs_and_uses.push(Use {
            context,
            location,
        });
    }
}

impl Info {
    fn new() -> Info {
        Info {
            defs_and_uses: vec![],
        }
    }

    fn clear(&mut self) {
        self.defs_and_uses.clear();
    }

    pub fn def_count(&self) -> usize {
        self.defs_and_uses.iter().filter(|place_use| place_use.context.is_mutating_use()).count()
    }

    pub fn def_count_not_including_drop(&self) -> usize {
        self.defs_not_including_drop().count()
    }

    pub fn defs_not_including_drop(
        &self,
    ) -> impl Iterator<Item=&Use> {
        self.defs_and_uses.iter().filter(|place_use| {
            place_use.context.is_mutating_use() && !place_use.context.is_drop()
        })
    }

    pub fn use_count(&self) -> usize {
        self.defs_and_uses.iter().filter(|place_use| {
            place_use.context.is_nonmutating_use()
        }).count()
    }
}

struct MutateUseVisitor<F> {
    query: Local,
    callback: F,
}

impl<F> MutateUseVisitor<F> {
    fn new(query: Local, callback: F, _: &Body<'_>)
           -> MutateUseVisitor<F>
           where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local {
        MutateUseVisitor {
            query,
            callback,
        }
    }
}

impl<F> MutVisitor<'_> for MutateUseVisitor<F>
              where F: for<'a> Fn(&'a Local, PlaceContext, Location) -> Local {
    fn visit_local(&mut self,
                    local: &mut Local,
                    context: PlaceContext,
                    location: Location) {
        if *local == self.query {
            *local = (self.callback)(local, context, location)
        }
    }

    fn visit_place(&mut self,
                    place: &mut Place<'tcx>,
                    context: PlaceContext,
                    location: Location) {
        self.visit_place_base(&mut place.base, context, location);

        let new_projection: Vec<_> = place.projection.iter().map(|elem|
            match elem {
                PlaceElem::Index(local) if *local == self.query => {
                    PlaceElem::Index((self.callback)(&local, context, location))
                }
                _ => elem.clone(),
            }
        ).collect();

        place.projection = new_projection.into_boxed_slice();
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use prelude::v1::*;

use alloc::boxed::FnBox;
use io;
use mem;
use libc::c_void;
use ptr;
use sys::c;
use sys::handle::Handle;
use sys_common::thread::*;
use time::Duration;

pub struct Thread {
    handle: Handle
}

impl Thread {
    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                          -> io::Result<Thread> {
        let p = box p;

        // FIXME On UNIX, we guard against stack sizes that are too small but
        // that's because pthreads enforces that stacks are at least
        // PTHREAD_STACK_MIN bytes big.  Windows has no such lower limit, it's
        // just that below a certain threshold you can't do anything useful.
        // That threshold is application and architecture-specific, however.
        // Round up to the next 64 kB because that's what the NT kernel does,
        // might as well make it explicit.
        let stack_size = (stack + 0xfffe) & (!0xfffe);
        let ret = c::CreateThread(ptr::null_mut(), stack_size,
                                  thread_start, &*p as *const _ as *mut _,
                                  0, ptr::null_mut());

        return if ret as usize == 0 {
            Err(io::Error::last_os_error())
        } else {
            mem::forget(p); // ownership passed to CreateThread
            Ok(Thread { handle: Handle::new(ret) })
        };

        extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
            unsafe { start_thread(main); }
            0
        }
    }

    pub fn set_name(_name: &CStr) {
        // Windows threads are nameless
        // The names in MSVC debugger are obtained using a "magic" exception,
        // which requires a use of MS C++ extensions.
        // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
    }

    pub fn join(self) {
        unsafe { c::WaitForSingleObject(self.handle.raw(), c::INFINITE); }
    }

    pub fn yield_now() {
        // This function will return 0 if there are no other threads to execute,
        // but this also means that the yield was useless so this isn't really a
        // case that needs to be worried about.
        unsafe { c::SwitchToThread(); }
    }

    pub fn sleep(dur: Duration) {
        unsafe {
            c::Sleep(super::dur2timeout(dur))
        }
    }

    pub fn handle(&self) -> &Handle { &self.handle }

    pub fn into_handle(self) -> Handle { self.handle }
}

#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    pub unsafe fn current() -> Option<usize> { None }
    pub unsafe fn init() -> Option<usize> { None }
}
<commit_msg>Fixup #32476<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use prelude::v1::*;

use alloc::boxed::FnBox;
use io;
use ffi::CStr;
use mem;
use libc::c_void;
use ptr;
use sys::c;
use sys::handle::Handle;
use sys_common::thread::*;
use time::Duration;

pub struct Thread {
    handle: Handle
}

impl Thread {
    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                          -> io::Result<Thread> {
        let p = box p;

        // FIXME On UNIX, we guard against stack sizes that are too small but
        // that's because pthreads enforces that stacks are at least
        // PTHREAD_STACK_MIN bytes big.  Windows has no such lower limit, it's
        // just that below a certain threshold you can't do anything useful.
        // That threshold is application and architecture-specific, however.
        // Round up to the next 64 kB because that's what the NT kernel does,
        // might as well make it explicit.
        let stack_size = (stack + 0xfffe) & (!0xfffe);
        let ret = c::CreateThread(ptr::null_mut(), stack_size,
                                  thread_start, &*p as *const _ as *mut _,
                                  0, ptr::null_mut());

        return if ret as usize == 0 {
            Err(io::Error::last_os_error())
        } else {
            mem::forget(p); // ownership passed to CreateThread
            Ok(Thread { handle: Handle::new(ret) })
        };

        extern "system" fn thread_start(main: *mut c_void) -> c::DWORD {
            unsafe { start_thread(main); }
            0
        }
    }

    pub fn set_name(_name: &CStr) {
        // Windows threads are nameless
        // The names in MSVC debugger are obtained using a "magic" exception,
        // which requires a use of MS C++ extensions.
        // See https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
    }

    pub fn join(self) {
        unsafe { c::WaitForSingleObject(self.handle.raw(), c::INFINITE); }
    }

    pub fn yield_now() {
        // This function will return 0 if there are no other threads to execute,
        // but this also means that the yield was useless so this isn't really a
        // case that needs to be worried about.
        unsafe { c::SwitchToThread(); }
    }

    pub fn sleep(dur: Duration) {
        unsafe {
            c::Sleep(super::dur2timeout(dur))
        }
    }

    pub fn handle(&self) -> &Handle { &self.handle }

    pub fn into_handle(self) -> Handle { self.handle }
}

#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    pub unsafe fn current() -> Option<usize> { None }
    pub unsafe fn init() -> Option<usize> { None }
}
<|endoftext|>


<commit_before>use lexer::dfa::{self, Ambiguity, DFA, NFAIndex, Precedence};
use lexer::dfa::interpret::interpret;
use lexer::re;

pub fn dfa(inputs: &[(&str, Precedence)]) -> Result<DFA,Ambiguity> {
    let regexs: Result<Vec<_>, _> = inputs.iter().map(|&(s, _)| re::parse_regex(s)).collect();
    let regexs = regexs.unwrap();
    let precedences: Vec<_> = inputs.iter().map(|&(_, p)| p).collect();
    dfa::build_dfa(&regexs, &precedences)
}

const P1: Precedence = Precedence(1);
const P0: Precedence = Precedence(0);

#[test]
fn tokenizer() {
    let dfa = dfa(&[
        /* 0 */ (r#"class"#, P1),
        /* 1 */ (r#"[a-zA-Z_][a-zA-Z0-9_]*"#, P0),
        /* 2 */ (r#"[0-9]+"#, P0),
        /* 3 */ (r#" +"#, P0),
        /* 4 */ (r#">>"#, P0),
        /* 5 */ (r#">"#, P0),
        ]).unwrap();

    assert_eq!(interpret(&dfa, "class Foo"), Some((NFAIndex(0), "class")));
    assert_eq!(interpret(&dfa, "classz Foo"), Some((NFAIndex(1), "classz")));
    assert_eq!(interpret(&dfa, "123"), Some((NFAIndex(2), "123")));
    assert_eq!(interpret(&dfa, "  classz Foo"), Some((NFAIndex(3), "  ")));
    assert_eq!(interpret(&dfa, ">"), Some((NFAIndex(5), ">")));
    assert_eq!(interpret(&dfa, ">>"), Some((NFAIndex(4), ">>")));
}

#[test]
fn ambiguous_regex() {
    // here the keyword and the regex have same precedence, so we have
    // an ambiguity
    assert!(dfa(&[(r#"class"#, P0),
                  (r#"[a-zA-Z_][a-zA-Z0-9_]*"#, P0)]).is_err());
}

#[test]
fn issue_32() {
    assert!(dfa(&[(r#"."#, P0)]).is_ok());
}

#[test]
fn issue_35() {
    assert!(dfa(&[(r#".*"#, P0),
                  (r"[-+]?[0-9]*\.?[0-9]+", P0)]).is_err());
}
<commit_msg>Write tests for dfa with `|`<commit_after>use lexer::dfa::{self, Ambiguity, DFA, NFAIndex, Precedence};
use lexer::dfa::interpret::interpret;
use lexer::re;

pub fn dfa(inputs: &[(&str, Precedence)]) -> Result<DFA,Ambiguity> {
    let regexs: Result<Vec<_>, _> = inputs.iter().map(|&(s, _)| re::parse_regex(s)).collect();
    let regexs = regexs.unwrap();
    let precedences: Vec<_> = inputs.iter().map(|&(_, p)| p).collect();
    dfa::build_dfa(&regexs, &precedences)
}

const P1: Precedence = Precedence(1);
const P0: Precedence = Precedence(0);

#[test]
fn tokenizer() {
    let dfa = dfa(&[
        /* 0 */ (r#"class"#, P1),
        /* 1 */ (r#"[a-zA-Z_][a-zA-Z0-9_]*"#, P0),
        /* 2 */ (r#"[0-9]+"#, P0),
        /* 3 */ (r#" +"#, P0),
        /* 4 */ (r#">>"#, P0),
        /* 5 */ (r#">"#, P0),
        ]).unwrap();

    assert_eq!(interpret(&dfa, "class Foo"), Some((NFAIndex(0), "class")));
    assert_eq!(interpret(&dfa, "classz Foo"), Some((NFAIndex(1), "classz")));
    assert_eq!(interpret(&dfa, "123"), Some((NFAIndex(2), "123")));
    assert_eq!(interpret(&dfa, "  classz Foo"), Some((NFAIndex(3), "  ")));
    assert_eq!(interpret(&dfa, ">"), Some((NFAIndex(5), ">")));
    assert_eq!(interpret(&dfa, ">>"), Some((NFAIndex(4), ">>")));
}

#[test]
fn ambiguous_regex() {
    // here the keyword and the regex have same precedence, so we have
    // an ambiguity
    assert!(dfa(&[(r#"class"#, P0),
                  (r#"[a-zA-Z_][a-zA-Z0-9_]*"#, P0)]).is_err());
}

#[test]
fn issue_32() {
    assert!(dfa(&[(r#"."#, P0)]).is_ok());
}

#[test]
fn issue_35() {
    assert!(dfa(&[(r#".*"#, P0),
                  (r"[-+]?[0-9]*\.?[0-9]+", P0)]).is_err());
}

#[test]
fn alternatives() {
    let dfa = dfa(&[(r#"abc|abd"#, P0)]).unwrap();
    assert_eq!(interpret(&dfa, "abc"), Some((NFAIndex(0), "abc")));
    assert_eq!(interpret(&dfa, "abd"), Some((NFAIndex(0), "abd")));
    assert_eq!(interpret(&dfa, "123"), None);
}

#[test]
fn alternatives_extension() {
    let dfa = dfa(&[(r#"abc|abcd"#, P0)]).unwrap();
    assert_eq!(interpret(&dfa, "abc"), Some((NFAIndex(0), "abc")));
    assert_eq!(interpret(&dfa, "abcd"), Some((NFAIndex(0), "abcd")));
    assert_eq!(interpret(&dfa, "123"), None);
}

#[test]
fn alternatives_contraction() {
    let dfa = dfa(&[(r#"abcd|abc"#, P0)]).unwrap();
    assert_eq!(interpret(&dfa, "abc"), Some((NFAIndex(0), "abc")));
    assert_eq!(interpret(&dfa, "abcd"), Some((NFAIndex(0), "abcd")));
    assert_eq!(interpret(&dfa, "123"), None);
}
<|endoftext|>


<commit_before>use glob::glob;
use std::env;
use std::env::consts::EXE_EXTENSION;
use std::path::Path;
use std::process::Command;

#[test]
fn book_test() {
    let mut book_path = env::current_dir().unwrap();
    book_path.push(
        Path::new(file!())
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("../website/content/creating-messages"),
    ); // For some reasons, calling .parent() once more gives us None...

    for md in glob(&format!("{}/*.md", book_path.to_str().unwrap())).unwrap() {
        skeptic_test(&md.unwrap());
    }
}

fn skeptic_test(path: &Path) {
    let rustdoc = Path::new("rustdoc").with_extension(EXE_EXTENSION);
    let exe = env::current_exe().unwrap();
    let depdir = exe.parent().unwrap();

    let mut cmd = Command::new(rustdoc);
    cmd.args(&["--verbose", "--test"])
        .arg("-L")
        .arg(&depdir)
        .arg(path);

    let result = cmd
        .spawn()
        .expect("Failed to spawn process")
        .wait()
        .expect("Failed to run process");

    assert!(
        result.success(),
        format!("Failed to run rustdoc tests on {:?}!", path)
    );
}
<commit_msg>fix(doc): Add a test on README example (refs #333)<commit_after>use glob::glob;
use std::env;
use std::env::consts::EXE_EXTENSION;
use std::path::Path;
use std::process::Command;

#[test]
fn book_test() {
    let mut book_path = env::current_dir().unwrap();
    let readme = Path::new(file!())
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("../README.md");
    book_path.push(
        Path::new(file!())
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .parent()
            .unwrap()
            .join("../website/content/creating-messages"),
    ); // For some reasons, calling .parent() once more gives us None...

    for md in glob(&format!("{}/*.md", book_path.to_str().unwrap())).unwrap() {
        skeptic_test(&md.unwrap());
    }
    skeptic_test(&readme);
}

fn skeptic_test(path: &Path) {
    let rustdoc = Path::new("rustdoc").with_extension(EXE_EXTENSION);
    let exe = env::current_exe().unwrap();
    let depdir = exe.parent().unwrap();

    let mut cmd = Command::new(rustdoc);
    cmd.args(&["--verbose", "--test"])
        .arg("-L")
        .arg(&depdir)
        .arg(path);

    let result = cmd
        .spawn()
        .expect("Failed to spawn process")
        .wait()
        .expect("Failed to run process");

    assert!(
        result.success(),
        format!("Failed to run rustdoc tests on {:?}!", path)
    );
}
<|endoftext|>


<commit_before>use ra_ide_api::{
    AnalysisChange,
    CrateGraph, FileId, mock_analysis::{MockAnalysis, single_file, single_file_with_position}, Query,
};
use ra_syntax::TextRange;
use insta::assert_debug_snapshot_matches;

#[test]
fn test_unresolved_module_diagnostic() {
    let (analysis, file_id) = single_file("mod foo;");
    let diagnostics = analysis.diagnostics(file_id).unwrap();
    assert_debug_snapshot_matches!("unresolved_module_diagnostic", &diagnostics);
}

// FIXME: move this test to hir
#[test]
fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
    let (analysis, file_id) = single_file("mod foo {}");
    let diagnostics = analysis.diagnostics(file_id).unwrap();
    assert!(diagnostics.is_empty());
}

#[test]
fn test_resolve_crate_root() {
    let mock = MockAnalysis::with_files(
        "
        //- /bar.rs
        mod foo;
        //- /bar/foo.rs
        // emtpy <|>
    ",
    );
    let root_file = mock.id_of("/bar.rs");
    let mod_file = mock.id_of("/bar/foo.rs");
    let mut host = mock.analysis_host();
    assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());

    let mut crate_graph = CrateGraph::default();
    let crate_id = crate_graph.add_crate_root(root_file);
    let mut change = AnalysisChange::new();
    change.set_crate_graph(crate_graph);
    host.apply_change(change);

    assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
}

fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
    let (analysis, position) = single_file_with_position(text);
    analysis.find_all_refs(position).unwrap()
}

#[test]
fn test_find_all_refs_for_local() {
    let code = r#"
    fn main() {
        let mut i = 1;
        let j = 1;
        i = i<|> + j;

        {
            i = 0;
        }

        i = 5;
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 5);
}

#[test]
fn test_find_all_refs_for_param_inside() {
    let code = r#"
    fn foo(i : u32) -> u32 {
        i<|>
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 2);
}

#[test]
fn test_find_all_refs_for_fn_param() {
    let code = r#"
    fn foo(i<|> : u32) -> u32 {
        i
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 2);
}

#[test]
fn world_symbols_include_stuff_from_macros() {
    let (analysis, _) = single_file(
        "
salsa::query_group! {
pub trait HirDatabase: SyntaxDatabase {}
}
    ",
    );

    let mut symbols = analysis.symbol_search(Query::new("Hir".into())).unwrap();
    let s = symbols.pop().unwrap();
    assert_eq!(s.name(), "HirDatabase");
    assert_eq!(s.full_range(), TextRange::from_to(33.into(), 44.into()));
}
<commit_msg>Update test to use correct paths<commit_after>use insta::assert_debug_snapshot_matches;
use ra_ide_api::{
    mock_analysis::{single_file, single_file_with_position, MockAnalysis},
    AnalysisChange, CrateGraph, FileId, Query,
};
use ra_syntax::TextRange;

#[test]
fn test_unresolved_module_diagnostic() {
    let (analysis, file_id) = single_file("mod foo;");
    let diagnostics = analysis.diagnostics(file_id).unwrap();
    assert_debug_snapshot_matches!("unresolved_module_diagnostic", &diagnostics);
}

// FIXME: move this test to hir
#[test]
fn test_unresolved_module_diagnostic_no_diag_for_inline_mode() {
    let (analysis, file_id) = single_file("mod foo {}");
    let diagnostics = analysis.diagnostics(file_id).unwrap();
    assert!(diagnostics.is_empty());
}

#[test]
fn test_resolve_crate_root() {
    let mock = MockAnalysis::with_files(
        "
        //- /bar.rs
        mod foo;
        //- /foo.rs
        // empty <|>
    ",
    );
    let root_file = mock.id_of("/bar.rs");
    let mod_file = mock.id_of("/foo.rs");
    let mut host = mock.analysis_host();
    assert!(host.analysis().crate_for(mod_file).unwrap().is_empty());

    let mut crate_graph = CrateGraph::default();
    let crate_id = crate_graph.add_crate_root(root_file);
    let mut change = AnalysisChange::new();
    change.set_crate_graph(crate_graph);
    host.apply_change(change);

    assert_eq!(host.analysis().crate_for(mod_file).unwrap(), vec![crate_id]);
}

fn get_all_refs(text: &str) -> Vec<(FileId, TextRange)> {
    let (analysis, position) = single_file_with_position(text);
    analysis.find_all_refs(position).unwrap()
}

#[test]
fn test_find_all_refs_for_local() {
    let code = r#"
    fn main() {
        let mut i = 1;
        let j = 1;
        i = i<|> + j;

        {
            i = 0;
        }

        i = 5;
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 5);
}

#[test]
fn test_find_all_refs_for_param_inside() {
    let code = r#"
    fn foo(i : u32) -> u32 {
        i<|>
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 2);
}

#[test]
fn test_find_all_refs_for_fn_param() {
    let code = r#"
    fn foo(i<|> : u32) -> u32 {
        i
    }"#;

    let refs = get_all_refs(code);
    assert_eq!(refs.len(), 2);
}

#[test]
fn world_symbols_include_stuff_from_macros() {
    let (analysis, _) = single_file(
        "
salsa::query_group! {
pub trait HirDatabase: SyntaxDatabase {}
}
    ",
    );

    let mut symbols = analysis.symbol_search(Query::new("Hir".into())).unwrap();
    let s = symbols.pop().unwrap();
    assert_eq!(s.name(), "HirDatabase");
    assert_eq!(s.full_range(), TextRange::from_to(33.into(), 44.into()));
}
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// 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::{cmp, thread};
use std::time::Duration;
use std::sync::{Arc, RwLock};
use std::sync::atomic::{AtomicBool, Ordering};
use time;

use chain;
use core::core::hash::{Hash, Hashed};
use core::core::target::Difficulty;
use core::global;
use p2p::{self, Peer, Peers};
use types::Error;
use util::LOGGER;

/// Starts the syncing loop, just spawns two threads that loop forever
pub fn run_sync(
	currently_syncing: Arc<AtomicBool>,
	awaiting_peers: Arc<AtomicBool>,
	peers: Arc<p2p::Peers>,
	chain: Arc<chain::Chain>,
	skip_sync_wait: bool,
	archive_mode: bool,
	stop: Arc<AtomicBool>,
) {
	let chain = chain.clone();
	let _ = thread::Builder::new()
		.name("sync".to_string())
		.spawn(move || {
			let mut prev_body_sync = time::now_utc();
			let mut prev_header_sync = prev_body_sync.clone();
			let mut prev_fast_sync = prev_body_sync.clone() - time::Duration::seconds(5 * 60);
			let mut highest_height = 0;

			// initial sleep to give us time to peer with some nodes
			if !skip_sync_wait {
				awaiting_peers.store(true, Ordering::Relaxed);
				thread::sleep(Duration::from_secs(30));
				awaiting_peers.store(false, Ordering::Relaxed);
			}

			// fast sync has 3 states:
			// * syncing headers
			// * once all headers are sync'd, requesting the txhashset state
			// * once we have the state, get blocks after that
			//
			// full sync gets rid of the middle step and just starts from
			// the genesis state

			loop {
				let horizon = global::cut_through_horizon() as u64;
				let head = chain.head().unwrap();
				let header_head = chain.get_header_head().unwrap();

				// is syncing generally needed when we compare our state with others
				let (syncing, most_work_height) =
					needs_syncing(currently_syncing.as_ref(), peers.clone(), chain.clone());

				if most_work_height > 0 {
					// we can occasionally get a most work height of 0 if read locks fail
					highest_height = most_work_height;
				}

				// in archival nodes (no fast sync) we just consider we have the whole
				// state already, then fast sync triggers if other peers are much
				// further ahead
				let fast_sync_enabled =
					!archive_mode && highest_height.saturating_sub(head.height) > horizon;

				debug!(LOGGER, "syncing: {}, fast: {}", syncing, fast_sync_enabled);
				debug!(
					LOGGER,
					"heights: {}, vs local {}", highest_height, header_head.height
				);

				let current_time = time::now_utc();
				if syncing {
					// run the header sync every 10s
					if current_time - prev_header_sync > time::Duration::seconds(10) {
						header_sync(peers.clone(), chain.clone());
						prev_header_sync = current_time;
					}

					// run the body_sync every 5s
					if !fast_sync_enabled
						&& current_time - prev_body_sync > time::Duration::seconds(5)
					{
						body_sync(peers.clone(), chain.clone());
						prev_body_sync = current_time;
					}

					// run fast sync if applicable, every 5 min
					if fast_sync_enabled && header_head.height == highest_height {
						if current_time - prev_fast_sync > time::Duration::seconds(5 * 60) {
							fast_sync(peers.clone(), chain.clone(), &header_head);
							prev_fast_sync = current_time;
						}
					}
				}
				currently_syncing.store(syncing, Ordering::Relaxed);

				thread::sleep(Duration::from_secs(1));

				if stop.load(Ordering::Relaxed) {
					break;
				}
			}
		});
}

fn body_sync(peers: Arc<Peers>, chain: Arc<chain::Chain>) {
	let body_head: chain::Tip = chain.head().unwrap();
	let header_head: chain::Tip = chain.get_header_head().unwrap();
	let sync_head: chain::Tip = chain.get_sync_head().unwrap();

	debug!(
		LOGGER,
		"body_sync: body_head - {}, {}, header_head - {}, {}, sync_head - {}, {}",
		body_head.last_block_h,
		body_head.height,
		header_head.last_block_h,
		header_head.height,
		sync_head.last_block_h,
		sync_head.height,
	);

	let mut hashes = vec![];

	if header_head.total_difficulty > body_head.total_difficulty {
		let mut current = chain.get_block_header(&header_head.last_block_h);
		while let Ok(header) = current {
			// break out of the while loop when we find a header common
			// between the this chain and the current chain
			if let Ok(_) = chain.is_on_current_chain(&header) {
				break;
			}

			hashes.push(header.hash());
			current = chain.get_block_header(&header.previous);
		}
	}
	hashes.reverse();

	// if we have 5 peers to sync from then ask for 50 blocks total (peer_count *
	// 10) max will be 80 if all 8 peers are advertising more work
	let peer_count = cmp::min(peers.more_work_peers().len(), 10);
	let block_count = peer_count * 10;

	let hashes_to_get = hashes
		.iter()
		.filter(|x| {
			// only ask for blocks that we have not yet processed
			// either successfully stored or in our orphan list
			!chain.get_block(x).is_ok() && !chain.is_orphan(x)
		})
		.take(block_count)
		.cloned()
		.collect::<Vec<_>>();

	if hashes_to_get.len() > 0 {
		debug!(
			LOGGER,
			"block_sync: {}/{} requesting blocks {:?} from {} peers",
			body_head.height,
			header_head.height,
			hashes_to_get,
			peer_count,
		);

		for hash in hashes_to_get.clone() {
			// TODO - Is there a threshold where we sync from most_work_peer (not
			// more_work_peer)?
			let peer = peers.more_work_peer();
			if let Some(peer) = peer {
				if let Ok(peer) = peer.try_read() {
					if let Err(e) = peer.send_block_request(hash) {
						debug!(LOGGER, "Skipped request to {}: {:?}", peer.info.addr, e);
					}
				}
			}
		}
	}
}

fn header_sync(peers: Arc<Peers>, chain: Arc<chain::Chain>) {
	if let Ok(header_head) = chain.get_header_head() {
		let difficulty = header_head.total_difficulty;

		if let Some(peer) = peers.most_work_peer() {
			if let Ok(p) = peer.try_read() {
				let peer_difficulty = p.info.total_difficulty.clone();
				if peer_difficulty > difficulty {
					let _ = request_headers(peer.clone(), chain.clone());
				}
			}
		}
	}
}

fn fast_sync(peers: Arc<Peers>, chain: Arc<chain::Chain>, header_head: &chain::Tip) {
	let horizon = global::cut_through_horizon() as u64;

	if let Some(peer) = peers.most_work_peer() {
		if let Ok(p) = peer.try_read() {
			debug!(
				LOGGER,
				"Header head before txhashset request: {} / {}",
				header_head.height,
				header_head.last_block_h
			);

			// ask for txhashset at horizon
			let mut txhashset_head = chain.get_block_header(&header_head.prev_block_h).unwrap();
			for _ in 0..horizon.saturating_sub(20) {
				txhashset_head = chain.get_block_header(&txhashset_head.previous).unwrap();
			}
			p.send_txhashset_request(txhashset_head.height, txhashset_head.hash())
				.unwrap();
		}
	}
}

/// Request some block headers from a peer to advance us.
fn request_headers(peer: Arc<RwLock<Peer>>, chain: Arc<chain::Chain>) -> Result<(), Error> {
	let locator = get_locator(chain)?;
	if let Ok(peer) = peer.try_read() {
		debug!(
			LOGGER,
			"sync: request_headers: asking {} for headers, {:?}", peer.info.addr, locator,
		);
		let _ = peer.send_header_request(locator);
	} else {
		// not much we can do here, log and try again next time
		debug!(
			LOGGER,
			"sync: request_headers: failed to get read lock on peer",
		);
	}
	Ok(())
}

/// Whether we're currently syncing the chain or we're fully caught up and
/// just receiving blocks through gossip.
fn needs_syncing(
	currently_syncing: &AtomicBool,
	peers: Arc<Peers>,
	chain: Arc<chain::Chain>,
) -> (bool, u64) {
	let local_diff = chain.total_difficulty();
	let peer = peers.most_work_peer();
	let is_syncing = currently_syncing.load(Ordering::Relaxed);
	let mut most_work_height = 0;

	// if we're already syncing, we're caught up if no peer has a higher
	// difficulty than us
	if is_syncing {
		if let Some(peer) = peer {
			if let Ok(peer) = peer.try_read() {
				debug!(
					LOGGER,
					"needs_syncing {} {}", local_diff, peer.info.total_difficulty
				);
				most_work_height = peer.info.height;

				if peer.info.total_difficulty <= local_diff {
					let ch = chain.head().unwrap();
					info!(
						LOGGER,
						"synchronised at {} @ {} [{}]",
						local_diff.into_num(),
						ch.height,
						ch.last_block_h
					);

					let _ = chain.reset_head();
					return (false, 0);
				}
			}
		} else {
			warn!(LOGGER, "sync: no peers available, disabling sync");
			return (false, 0);
		}
	} else {
		if let Some(peer) = peer {
			if let Ok(peer) = peer.try_read() {
				most_work_height = peer.info.height;

				// sum the last 5 difficulties to give us the threshold
				let threshold = chain
					.difficulty_iter()
					.filter_map(|x| x.map(|(_, x)| x).ok())
					.take(5)
					.fold(Difficulty::zero(), |sum, val| sum + val);

				if peer.info.total_difficulty > local_diff.clone() + threshold.clone() {
					info!(
						LOGGER,
						"sync: total_difficulty {}, peer_difficulty {}, threshold {} (last 5 blocks), enabling sync",
						local_diff,
						peer.info.total_difficulty,
						threshold,
					);
					return (true, most_work_height);
				}
			}
		}
	}
	(is_syncing, most_work_height)
}

/// We build a locator based on sync_head.
/// Even if sync_head is significantly out of date we will "reset" it once we start getting
/// headers back from a peer.
fn get_locator(chain: Arc<chain::Chain>) -> Result<Vec<Hash>, Error> {
	let tip = chain.get_sync_head()?;
	let heights = get_locator_heights(tip.height);

	debug!(LOGGER, "sync: locator heights: {:?}", heights);

	let mut locator = vec![];
	let mut current = chain.get_block_header(&tip.last_block_h);
	while let Ok(header) = current {
		if heights.contains(&header.height) {
			locator.push(header.hash());
		}
		current = chain.get_block_header(&header.previous);
	}

	debug!(LOGGER, "sync: locator: {:?}", locator);

	Ok(locator)
}

// current height back to 0 decreasing in powers of 2
fn get_locator_heights(height: u64) -> Vec<u64> {
	let mut current = height.clone();
	let mut heights = vec![];
	while current > 0 {
		heights.push(current);
		let next = 2u64.pow(heights.len() as u32);
		current = if current > next { current - next } else { 0 }
	}
	heights.push(0);
	heights
}

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

	#[test]
	fn test_get_locator_heights() {
		assert_eq!(get_locator_heights(0), vec![0]);
		assert_eq!(get_locator_heights(1), vec![1, 0]);
		assert_eq!(get_locator_heights(2), vec![2, 0]);
		assert_eq!(get_locator_heights(3), vec![3, 1, 0]);
		assert_eq!(get_locator_heights(10), vec![10, 8, 4, 0]);
		assert_eq!(get_locator_heights(100), vec![100, 98, 94, 86, 70, 38, 0]);
		assert_eq!(
			get_locator_heights(1000),
			vec![1000, 998, 994, 986, 970, 938, 874, 746, 490, 0]
		);
		// check the locator is still a manageable length, even for large numbers of
		// headers
		assert_eq!(
			get_locator_heights(10000),
			vec![
				10000, 9998, 9994, 9986, 9970, 9938, 9874, 9746, 9490, 8978, 7954, 5906, 1810, 0
			]
		);
	}
}
<commit_msg>Minor log cleanup<commit_after>// Copyright 2018 The Grin Developers
//
// 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::{cmp, thread};
use std::time::Duration;
use std::sync::{Arc, RwLock};
use std::sync::atomic::{AtomicBool, Ordering};
use time;

use chain;
use core::core::hash::{Hash, Hashed};
use core::core::target::Difficulty;
use core::global;
use p2p::{self, Peer, Peers};
use types::Error;
use util::LOGGER;

/// Starts the syncing loop, just spawns two threads that loop forever
pub fn run_sync(
	currently_syncing: Arc<AtomicBool>,
	awaiting_peers: Arc<AtomicBool>,
	peers: Arc<p2p::Peers>,
	chain: Arc<chain::Chain>,
	skip_sync_wait: bool,
	archive_mode: bool,
	stop: Arc<AtomicBool>,
) {
	let chain = chain.clone();
	let _ = thread::Builder::new()
		.name("sync".to_string())
		.spawn(move || {
			let mut prev_body_sync = time::now_utc();
			let mut prev_header_sync = prev_body_sync.clone();
			let mut prev_fast_sync = prev_body_sync.clone() - time::Duration::seconds(5 * 60);
			let mut highest_height = 0;

			// initial sleep to give us time to peer with some nodes
			if !skip_sync_wait {
				awaiting_peers.store(true, Ordering::Relaxed);
				thread::sleep(Duration::from_secs(30));
				awaiting_peers.store(false, Ordering::Relaxed);
			}

			// fast sync has 3 states:
			// * syncing headers
			// * once all headers are sync'd, requesting the txhashset state
			// * once we have the state, get blocks after that
			//
			// full sync gets rid of the middle step and just starts from
			// the genesis state

			loop {
				let horizon = global::cut_through_horizon() as u64;
				let head = chain.head().unwrap();
				let header_head = chain.get_header_head().unwrap();

				// is syncing generally needed when we compare our state with others
				let (syncing, most_work_height) =
					needs_syncing(currently_syncing.as_ref(), peers.clone(), chain.clone());

				if most_work_height > 0 {
					// we can occasionally get a most work height of 0 if read locks fail
					highest_height = most_work_height;
				}

				// in archival nodes (no fast sync) we just consider we have the whole
				// state already, then fast sync triggers if other peers are much
				// further ahead
				let fast_sync_enabled =
					!archive_mode && highest_height.saturating_sub(head.height) > horizon;

				let current_time = time::now_utc();
				if syncing {
					// run the header sync every 10s
					if current_time - prev_header_sync > time::Duration::seconds(10) {
						header_sync(peers.clone(), chain.clone());
						prev_header_sync = current_time;
					}

					// run the body_sync every 5s
					if !fast_sync_enabled
						&& current_time - prev_body_sync > time::Duration::seconds(5)
					{
						body_sync(peers.clone(), chain.clone());
						prev_body_sync = current_time;
					}

					// run fast sync if applicable, every 5 min
					if fast_sync_enabled && header_head.height == highest_height {
						if current_time - prev_fast_sync > time::Duration::seconds(5 * 60) {
							fast_sync(peers.clone(), chain.clone(), &header_head);
							prev_fast_sync = current_time;
						}
					}
				}
				currently_syncing.store(syncing, Ordering::Relaxed);

				thread::sleep(Duration::from_secs(1));

				if stop.load(Ordering::Relaxed) {
					break;
				}
			}
		});
}

fn body_sync(peers: Arc<Peers>, chain: Arc<chain::Chain>) {
	let body_head: chain::Tip = chain.head().unwrap();
	let header_head: chain::Tip = chain.get_header_head().unwrap();
	let sync_head: chain::Tip = chain.get_sync_head().unwrap();

	debug!(
		LOGGER,
		"body_sync: body_head - {}, {}, header_head - {}, {}, sync_head - {}, {}",
		body_head.last_block_h,
		body_head.height,
		header_head.last_block_h,
		header_head.height,
		sync_head.last_block_h,
		sync_head.height,
	);

	let mut hashes = vec![];

	if header_head.total_difficulty > body_head.total_difficulty {
		let mut current = chain.get_block_header(&header_head.last_block_h);
		while let Ok(header) = current {
			// break out of the while loop when we find a header common
			// between the this chain and the current chain
			if let Ok(_) = chain.is_on_current_chain(&header) {
				break;
			}

			hashes.push(header.hash());
			current = chain.get_block_header(&header.previous);
		}
	}
	hashes.reverse();

	// if we have 5 peers to sync from then ask for 50 blocks total (peer_count *
	// 10) max will be 80 if all 8 peers are advertising more work
	let peer_count = cmp::min(peers.more_work_peers().len(), 10);
	let block_count = peer_count * 10;

	let hashes_to_get = hashes
		.iter()
		.filter(|x| {
			// only ask for blocks that we have not yet processed
			// either successfully stored or in our orphan list
			!chain.get_block(x).is_ok() && !chain.is_orphan(x)
		})
		.take(block_count)
		.cloned()
		.collect::<Vec<_>>();

	if hashes_to_get.len() > 0 {
		debug!(
			LOGGER,
			"block_sync: {}/{} requesting blocks {:?} from {} peers",
			body_head.height,
			header_head.height,
			hashes_to_get,
			peer_count,
		);

		for hash in hashes_to_get.clone() {
			// TODO - Is there a threshold where we sync from most_work_peer (not
			// more_work_peer)?
			let peer = peers.more_work_peer();
			if let Some(peer) = peer {
				if let Ok(peer) = peer.try_read() {
					if let Err(e) = peer.send_block_request(hash) {
						debug!(LOGGER, "Skipped request to {}: {:?}", peer.info.addr, e);
					}
				}
			}
		}
	}
}

fn header_sync(peers: Arc<Peers>, chain: Arc<chain::Chain>) {
	if let Ok(header_head) = chain.get_header_head() {
		let difficulty = header_head.total_difficulty;

		if let Some(peer) = peers.most_work_peer() {
			if let Ok(p) = peer.try_read() {
				let peer_difficulty = p.info.total_difficulty.clone();
				if peer_difficulty > difficulty {
					let _ = request_headers(peer.clone(), chain.clone());
				}
			}
		}
	}
}

fn fast_sync(peers: Arc<Peers>, chain: Arc<chain::Chain>, header_head: &chain::Tip) {
	let horizon = global::cut_through_horizon() as u64;

	if let Some(peer) = peers.most_work_peer() {
		if let Ok(p) = peer.try_read() {
			debug!(
				LOGGER,
				"Header head before txhashset request: {} / {}",
				header_head.height,
				header_head.last_block_h
			);

			// ask for txhashset at horizon
			let mut txhashset_head = chain.get_block_header(&header_head.prev_block_h).unwrap();
			for _ in 0..horizon.saturating_sub(20) {
				txhashset_head = chain.get_block_header(&txhashset_head.previous).unwrap();
			}
			p.send_txhashset_request(txhashset_head.height, txhashset_head.hash())
				.unwrap();
		}
	}
}

/// Request some block headers from a peer to advance us.
fn request_headers(peer: Arc<RwLock<Peer>>, chain: Arc<chain::Chain>) -> Result<(), Error> {
	let locator = get_locator(chain)?;
	if let Ok(peer) = peer.try_read() {
		debug!(
			LOGGER,
			"sync: request_headers: asking {} for headers, {:?}", peer.info.addr, locator,
		);
		let _ = peer.send_header_request(locator);
	} else {
		// not much we can do here, log and try again next time
		debug!(
			LOGGER,
			"sync: request_headers: failed to get read lock on peer",
		);
	}
	Ok(())
}

/// Whether we're currently syncing the chain or we're fully caught up and
/// just receiving blocks through gossip.
fn needs_syncing(
	currently_syncing: &AtomicBool,
	peers: Arc<Peers>,
	chain: Arc<chain::Chain>,
) -> (bool, u64) {
	let local_diff = chain.total_difficulty();
	let peer = peers.most_work_peer();
	let is_syncing = currently_syncing.load(Ordering::Relaxed);
	let mut most_work_height = 0;

	// if we're already syncing, we're caught up if no peer has a higher
	// difficulty than us
	if is_syncing {
		if let Some(peer) = peer {
			if let Ok(peer) = peer.try_read() {
				debug!(
					LOGGER,
					"needs_syncing {} {}", local_diff, peer.info.total_difficulty
				);
				most_work_height = peer.info.height;

				if peer.info.total_difficulty <= local_diff {
					let ch = chain.head().unwrap();
					info!(
						LOGGER,
						"synchronised at {} @ {} [{}]",
						local_diff.into_num(),
						ch.height,
						ch.last_block_h
					);

					let _ = chain.reset_head();
					return (false, 0);
				}
			}
		} else {
			warn!(LOGGER, "sync: no peers available, disabling sync");
			return (false, 0);
		}
	} else {
		if let Some(peer) = peer {
			if let Ok(peer) = peer.try_read() {
				most_work_height = peer.info.height;

				// sum the last 5 difficulties to give us the threshold
				let threshold = chain
					.difficulty_iter()
					.filter_map(|x| x.map(|(_, x)| x).ok())
					.take(5)
					.fold(Difficulty::zero(), |sum, val| sum + val);

				if peer.info.total_difficulty > local_diff.clone() + threshold.clone() {
					info!(
						LOGGER,
						"sync: total_difficulty {}, peer_difficulty {}, threshold {} (last 5 blocks), enabling sync",
						local_diff,
						peer.info.total_difficulty,
						threshold,
					);
					return (true, most_work_height);
				}
			}
		}
	}
	(is_syncing, most_work_height)
}

/// We build a locator based on sync_head.
/// Even if sync_head is significantly out of date we will "reset" it once we start getting
/// headers back from a peer.
fn get_locator(chain: Arc<chain::Chain>) -> Result<Vec<Hash>, Error> {
	let tip = chain.get_sync_head()?;
	let heights = get_locator_heights(tip.height);

	debug!(LOGGER, "sync: locator heights: {:?}", heights);

	let mut locator = vec![];
	let mut current = chain.get_block_header(&tip.last_block_h);
	while let Ok(header) = current {
		if heights.contains(&header.height) {
			locator.push(header.hash());
		}
		current = chain.get_block_header(&header.previous);
	}

	debug!(LOGGER, "sync: locator: {:?}", locator);

	Ok(locator)
}

// current height back to 0 decreasing in powers of 2
fn get_locator_heights(height: u64) -> Vec<u64> {
	let mut current = height.clone();
	let mut heights = vec![];
	while current > 0 {
		heights.push(current);
		let next = 2u64.pow(heights.len() as u32);
		current = if current > next { current - next } else { 0 }
	}
	heights.push(0);
	heights
}

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

	#[test]
	fn test_get_locator_heights() {
		assert_eq!(get_locator_heights(0), vec![0]);
		assert_eq!(get_locator_heights(1), vec![1, 0]);
		assert_eq!(get_locator_heights(2), vec![2, 0]);
		assert_eq!(get_locator_heights(3), vec![3, 1, 0]);
		assert_eq!(get_locator_heights(10), vec![10, 8, 4, 0]);
		assert_eq!(get_locator_heights(100), vec![100, 98, 94, 86, 70, 38, 0]);
		assert_eq!(
			get_locator_heights(1000),
			vec![1000, 998, 994, 986, 970, 938, 874, 746, 490, 0]
		);
		// check the locator is still a manageable length, even for large numbers of
		// headers
		assert_eq!(
			get_locator_heights(10000),
			vec![
				10000, 9998, 9994, 9986, 9970, 9938, 9874, 9746, 9490, 8978, 7954, 5906, 1810, 0
			]
		);
	}
}
<|endoftext|>