<commit_before>use regex::Regex;

//

 to "\n text \n", seems as well that there might be just
 defined without closing tag
// link to single link
// remove other tags for now like

pub enum FormatType {
    Paragraph,
    Link,
    Other,
}

fn replace_paragraphs(s: String) -> String {
    // todo split
    let mut r = replace_paragraphs_opening_tags(&s);
    r = replace_paragraphs_closing_tags(&r);
    r
}

fn replace_paragraphs_closing_tags(s: &str) -> String {
    let re = Regex::new(r"( *
 *)").unwrap();
    re.replace_all(s, "").into_owned()
}

fn replace_paragraphs_opening_tags(s: &str) -> String {
    let re = Regex::new(r"( *
 *)").unwrap();
    re.replace_all(s, "\n").into_owned()
}

fn replace_link_opening_tags(s: &str) -> String {
    let re = Regex::new(r"( *)").unwrap();
    re.replace_all(s, "").into_owned()
}

fn replace_link_closing_tags(s: &str) -> String {
    let re = Regex::new(r"( * *)").unwrap();
    re.replace_all(s, "").into_owned()
}

fn replace_links(s: String) -> String {
    let mut r = replace_link_opening_tags(&s);
    r = replace_link_closing_tags(&r);
    r
}

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

    #[test]
    fn test_replace_paragraphs() {
        let mut s: String = format!("aaaaaa zzz zzaaa

");
        s = replace_paragraphs(s);
        assert_eq!("aaaaaa zzz zzaaa\n", s);

        s = format!("
 para
 ");
        s = replace_paragraphs(s);
        assert_eq!("\npara", s);
    }

    #[test]
    fn test_replace_links() {
        let mut s: String = format!("this is  \
                                     http://www.link.com ");
        s = replace_links(s);
        assert_eq!("this is http://www.link.com", s);
    }

}<commit_msg>made the tag formatting structure cleaner<commit_after>use regex::Regex;

//

 to "\n text \n", seems as well that there might be just
 defined without closing tag
// link to single link
// remove other tags for now like

pub enum FormatType {
    Paragraph,
    Link,
    Other,
}

struct TagFormatter;

impl Formatter for TagFormatter {
    fn format(s: &str) -> String {
        String::from("s")
    }
}

trait Formatter {
    fn format(s: &str) -> String;
}
impl TagFormatter {
    pub fn format_paragraphs(&self, s: &str) -> String {
        // todo split
        let mut r = self.replace_paragraphs_opening_tags(&s, "\n");
        r = self.replace_paragraphs_closing_tags(&r, "");
        r
    }

    pub fn format_links(&self, s: &str) -> String {
        let mut r = self.replace_link_opening_tags(s, "");
        r = self.replace_link_closing_tags(&r, "");
        r
    }

    pub fn format_tags(&self, s: &str) -> String {
        self.replace_tags(s, "")
    }

    fn replace_paragraphs_closing_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *
 *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_paragraphs_opening_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *
 *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_link_opening_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    fn replace_link_closing_tags(&self, s: &str, replacement: &str) -> String {
        let re = Regex::new(r"( * *)").unwrap();
        re.replace_all(s, replacement).into_owned()
    }

    pub fn replace_tags(&self, s: &str, replacement: &str) -> String {
        // will just replace all tags and should be called after other methods have run before
        let re = Regex::new(r"(</?\w+((\s+\w+(\s*=\s*(?:\x22.*?\x22|'.*?'|[\^'\x22>\s]+))?)+\s*|\s*)/?>) *").unwrap();
        re.replace_all(s, replacement).into_owned()
    }
}
#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_replace_paragraphs() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("aaaaaa zzz zzaaa

");
        s = tag_formatter.format_paragraphs(&s);
        assert_eq!("aaaaaa zzz zzaaa\n", s);

        s = format!("
 para
 ");
        s = tag_formatter.format_paragraphs(&s);
        assert_eq!("\npara", s);
    }

    #[test]
    fn test_replace_links() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("this is  \
                                     http://www.link.com ");
        s = tag_formatter.format_links(&s);
        assert_eq!("this is http://www.link.com", s);
    }

    #[test]
    fn test_replace_tags() {
        let tag_formatter = TagFormatter;
        let mut s: String = format!("this is http://www.link.com");
        s = tag_formatter.format_tags(&s);
        assert_eq!("this is http://www.link.com", s);
        s = format!("
 para

div

heading
");
        s = tag_formatter.format_tags(&s);
        assert_eq!("para div heading ", s);
    }

}<|endoftext|>


<commit_before>use super::*;
use crate::test;
#[cfg(target_os = "linux")]
use ci_info;
use envmnt;
#[cfg(target_os = "linux")]
use rust_info::types::RustChannel;

#[test]
#[ignore]
fn get_cargo_home_env() {
    let directory_path = env::current_dir().unwrap();
    let directory = directory_path.to_str().unwrap();
    envmnt::set("CARGO_HOME", directory);

    let output = get_cargo_home().unwrap();
    envmnt::remove("CARGO_HOME");

    assert_eq!(output, directory);
}

#[test]
#[ignore]
fn get_cargo_home_no_env() {
    envmnt::remove("CARGO_HOME");

    let output = get_cargo_home().unwrap();

    assert!(output.contains(".cargo"));
}

#[test]
#[ignore]
fn get_cargo_home_file() {
    let directory_path = env::current_dir().unwrap();
    let directory = directory_path.to_str().unwrap();
    let file_path = Path::new(directory).join("Cargo.toml");
    envmnt::set("CARGO_HOME", file_path);

    let output = get_cargo_home();
    envmnt::remove("CARGO_HOME");

    assert!(output.is_none());
}

#[test]
fn load_crates_toml_valid() {
    let cwd = envmnt::get_or_panic("CARGO_MAKE_WORKING_DIRECTORY");
    let file_path = Path::new(&cwd).join("src/lib/test/test_files");
    let directory = file_path.to_str().unwrap();
    let info_option = load_crates_toml(&directory);

    assert!(info_option.is_some());
    let info = info_option.unwrap();
    assert!(info.v1.is_some());
    assert_eq!(info.v1.unwrap().len(), 3);
}

#[test]
fn load_crates_toml_file_not_found() {
    let cwd = envmnt::get_or_panic("CARGO_MAKE_WORKING_DIRECTORY");
    let info_option = load_crates_toml(&cwd);

    assert!(info_option.is_none());
}

#[test]
fn get_crate_version_from_info_no_info() {
    let info = CratesRegistryInfo { v1: None };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_empty_info() {
    let info = CratesRegistryInfo {
        v1: Some(HashMap::new()),
    };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_not_found() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_found_invalid_line() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_found_invalid_version() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make abc 2".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_valid() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make 1.2.3 2".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    let semver_version = version.unwrap();
    assert_eq!(semver_version.major, 1);
    assert_eq!(semver_version.minor, 2);
    assert_eq!(semver_version.patch, 3);
}

#[test]
#[cfg(target_os = "linux")]
fn get_crate_version_for_rustup_component() {
    if test::is_rust_channel(RustChannel::Stable) || !ci_info::is_ci() {
        let mut version = get_crate_version("rustfmt", None);
        assert!(version.is_none());

        version = get_crate_version("rustfmt", Some("rustfmt"));
        assert!(version.is_some());
    }
}

#[test]
fn is_min_version_valid_for_versions_equal() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_false_major() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("2.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_false_minor() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.3.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_false_patch() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.4").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_true_major() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("2.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_true_minor() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.3.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_true_patch() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.4").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_not_found() {
    let valid = is_min_version_valid("bad_crate", "1.2.3", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_invalid_version() {
    let valid = is_min_version_valid("cargo-make", "bad_version", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_old_version() {
    let valid = is_min_version_valid("cargo-make", "0.0.1", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_newer_version() {
    let valid = is_min_version_valid("cargo-make", "10000.0.0", None);

    assert!(!valid);
}

#[test]
fn is_min_version_valid_same_version() {
    let version = get_crate_version("cargo-make", None).unwrap();
    let mut version_string = String::new();
    version_string.push_str(&version.major.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.minor.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.patch.to_string());

    let valid = is_min_version_valid("cargo-make", &version_string, None);

    assert!(valid);
}

#[test]
fn is_version_valid_for_versions_equal() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_version_valid_for_versions_false_major() {
    let valid = is_version_valid_for_versions(
        &Version::parse("2.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_for_versions_false_minor() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.3.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_for_versions_false_patch() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.2.4").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_not_found() {
    let valid = is_version_valid("bad_crate", "1.2.3", None);

    assert!(valid);
}

#[test]
fn is_version_valid_invalid_version() {
    let valid = is_version_valid("cargo-make", "bad_version", None);

    assert!(valid);
}

#[test]
fn is_version_valid_old_version() {
    let valid = is_version_valid("cargo-make", "0.0.1", None);

    assert!(!valid);
}

#[test]
fn is_version_valid_newer_version() {
    let valid = is_version_valid("cargo-make", "10000.0.0", None);

    assert!(!valid);
}

#[test]
fn is_version_valid_same_version() {
    let version = get_crate_version("cargo-make", None).unwrap();
    let mut version_string = String::new();
    version_string.push_str(&version.major.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.minor.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.patch.to_string());

    let valid = is_min_version_valid("cargo-make", &version_string, None);

    assert!(valid);
}
<commit_msg>fix build<commit_after>use super::*;
use crate::test;
use ci_info;
use envmnt;
use rust_info::types::RustChannel;

#[test]
#[ignore]
fn get_cargo_home_env() {
    let directory_path = env::current_dir().unwrap();
    let directory = directory_path.to_str().unwrap();
    envmnt::set("CARGO_HOME", directory);

    let output = get_cargo_home().unwrap();
    envmnt::remove("CARGO_HOME");

    assert_eq!(output, directory);
}

#[test]
#[ignore]
fn get_cargo_home_no_env() {
    envmnt::remove("CARGO_HOME");

    let output = get_cargo_home().unwrap();

    assert!(output.contains(".cargo"));
}

#[test]
#[ignore]
fn get_cargo_home_file() {
    let directory_path = env::current_dir().unwrap();
    let directory = directory_path.to_str().unwrap();
    let file_path = Path::new(directory).join("Cargo.toml");
    envmnt::set("CARGO_HOME", file_path);

    let output = get_cargo_home();
    envmnt::remove("CARGO_HOME");

    assert!(output.is_none());
}

#[test]
fn load_crates_toml_valid() {
    let cwd = envmnt::get_or_panic("CARGO_MAKE_WORKING_DIRECTORY");
    let file_path = Path::new(&cwd).join("src/lib/test/test_files");
    let directory = file_path.to_str().unwrap();
    let info_option = load_crates_toml(&directory);

    assert!(info_option.is_some());
    let info = info_option.unwrap();
    assert!(info.v1.is_some());
    assert_eq!(info.v1.unwrap().len(), 3);
}

#[test]
fn load_crates_toml_file_not_found() {
    let cwd = envmnt::get_or_panic("CARGO_MAKE_WORKING_DIRECTORY");
    let info_option = load_crates_toml(&cwd);

    assert!(info_option.is_none());
}

#[test]
fn get_crate_version_from_info_no_info() {
    let info = CratesRegistryInfo { v1: None };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_empty_info() {
    let info = CratesRegistryInfo {
        v1: Some(HashMap::new()),
    };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_not_found() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_found_invalid_line() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_found_invalid_version() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make abc 2".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    assert!(version.is_none());
}

#[test]
fn get_crate_version_from_info_valid() {
    let mut map = HashMap::new();
    map.insert("1 1 1".to_string(), vec![]);
    map.insert("cargo-make 1.2.3 2".to_string(), vec![]);
    map.insert("2 2 2".to_string(), vec![]);
    let info = CratesRegistryInfo { v1: Some(map) };
    let version = get_crate_version_from_info("cargo-make", &info);

    let semver_version = version.unwrap();
    assert_eq!(semver_version.major, 1);
    assert_eq!(semver_version.minor, 2);
    assert_eq!(semver_version.patch, 3);
}

#[test]
fn get_crate_version_for_rustup_component() {
    if (test::is_linux() && test::is_rust_channel(RustChannel::Stable)) || !ci_info::is_ci() {
        let mut version = get_crate_version("rustfmt", None);
        assert!(version.is_none());

        version = get_crate_version("rustfmt", Some("rustfmt"));
        assert!(version.is_some());
    }
}

#[test]
fn is_min_version_valid_for_versions_equal() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_false_major() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("2.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_false_minor() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.3.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_false_patch() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.4").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_min_version_valid_for_versions_true_major() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("2.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_true_minor() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.3.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_for_versions_true_patch() {
    let valid = is_min_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.4").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_min_version_valid_not_found() {
    let valid = is_min_version_valid("bad_crate", "1.2.3", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_invalid_version() {
    let valid = is_min_version_valid("cargo-make", "bad_version", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_old_version() {
    let valid = is_min_version_valid("cargo-make", "0.0.1", None);

    assert!(valid);
}

#[test]
fn is_min_version_valid_newer_version() {
    let valid = is_min_version_valid("cargo-make", "10000.0.0", None);

    assert!(!valid);
}

#[test]
fn is_min_version_valid_same_version() {
    let version = get_crate_version("cargo-make", None).unwrap();
    let mut version_string = String::new();
    version_string.push_str(&version.major.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.minor.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.patch.to_string());

    let valid = is_min_version_valid("cargo-make", &version_string, None);

    assert!(valid);
}

#[test]
fn is_version_valid_for_versions_equal() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(valid);
}

#[test]
fn is_version_valid_for_versions_false_major() {
    let valid = is_version_valid_for_versions(
        &Version::parse("2.2.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_for_versions_false_minor() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.3.3").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_for_versions_false_patch() {
    let valid = is_version_valid_for_versions(
        &Version::parse("1.2.4").unwrap(),
        &Version::parse("1.2.3").unwrap(),
    );

    assert!(!valid);
}

#[test]
fn is_version_valid_not_found() {
    let valid = is_version_valid("bad_crate", "1.2.3", None);

    assert!(valid);
}

#[test]
fn is_version_valid_invalid_version() {
    let valid = is_version_valid("cargo-make", "bad_version", None);

    assert!(valid);
}

#[test]
fn is_version_valid_old_version() {
    let valid = is_version_valid("cargo-make", "0.0.1", None);

    assert!(!valid);
}

#[test]
fn is_version_valid_newer_version() {
    let valid = is_version_valid("cargo-make", "10000.0.0", None);

    assert!(!valid);
}

#[test]
fn is_version_valid_same_version() {
    let version = get_crate_version("cargo-make", None).unwrap();
    let mut version_string = String::new();
    version_string.push_str(&version.major.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.minor.to_string());
    version_string.push_str(".");
    version_string.push_str(&version.patch.to_string());

    let valid = is_min_version_valid("cargo-make", &version_string, None);

    assert!(valid);
}
<|endoftext|>


<commit_before>//! Routine to compute the strongly connected components (SCCs) of a
//! graph, as well as the resulting DAG if each SCC is replaced with a
//! node in the graph. This uses Tarjan's algorithm that completes in
//! O(n) time.

use crate::fx::FxHashSet;
use crate::graph::vec_graph::VecGraph;
use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
use rustc_index::vec::{Idx, IndexVec};
use std::ops::Range;

#[cfg(test)]
mod tests;

/// Strongly connected components (SCC) of a graph. The type `N` is
/// the index type for the graph nodes and `S` is the index type for
/// the SCCs. We can map from each node to the SCC that it
/// participates in, and we also have the successors of each SCC.
pub struct Sccs<N: Idx, S: Idx> {
    /// For each node, what is the SCC index of the SCC to which it
    /// belongs.
    scc_indices: IndexVec<N, S>,

    /// Data about each SCC.
    scc_data: SccData<S>,
}

struct SccData<S: Idx> {
    /// For each SCC, the range of `all_successors` where its
    /// successors can be found.
    ranges: IndexVec<S, Range<usize>>,

    /// Contains the successors for all the Sccs, concatenated. The
    /// range of indices corresponding to a given SCC is found in its
    /// SccData.
    all_successors: Vec<S>,
}

impl<N: Idx, S: Idx> Sccs<N, S> {
    pub fn new(graph: &(impl DirectedGraph<Node = N> + WithNumNodes + WithSuccessors)) -> Self {
        SccsConstruction::construct(graph)
    }

    /// Returns the number of SCCs in the graph.
    pub fn num_sccs(&self) -> usize {
        self.scc_data.len()
    }

    /// Returns an iterator over the SCCs in the graph.
    ///
    /// The SCCs will be iterated in **dependency order** (or **post order**),
    /// meaning that if `S1 -> S2`, we will visit `S2` first and `S1` after.
    /// This is convenient when the edges represent dependencies: when you visit
    /// `S1`, the value for `S2` will already have been computed.
    pub fn all_sccs(&self) -> impl Iterator<Item = S> {
        (0..self.scc_data.len()).map(S::new)
    }

    /// Returns the SCC to which a node `r` belongs.
    pub fn scc(&self, r: N) -> S {
        self.scc_indices[r]
    }

    /// Returns the successors of the given SCC.
    pub fn successors(&self, scc: S) -> &[S] {
        self.scc_data.successors(scc)
    }

    /// Construct the reverse graph of the SCC graph.
    pub fn reverse(&self) -> VecGraph<S> {
        VecGraph::new(
            self.num_sccs(),
            self.all_sccs()
                .flat_map(|source| {
                    self.successors(source).iter().map(move |&target| (target, source))
                })
                .collect(),
        )
    }
}

impl<N: Idx, S: Idx> DirectedGraph for Sccs<N, S> {
    type Node = S;
}

impl<N: Idx, S: Idx> WithNumNodes for Sccs<N, S> {
    fn num_nodes(&self) -> usize {
        self.num_sccs()
    }
}

impl<N: Idx, S: Idx> WithNumEdges for Sccs<N, S> {
    fn num_edges(&self) -> usize {
        self.scc_data.all_successors.len()
    }
}

impl<N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs<N, S> {
    type Item = S;

    type Iter = std::iter::Cloned<std::slice::Iter<'graph, S>>;
}

impl<N: Idx, S: Idx> WithSuccessors for Sccs<N, S> {
    fn successors(&self, node: S) -> <Self as GraphSuccessors<'_>>::Iter {
        self.successors(node).iter().cloned()
    }
}

impl<S: Idx> SccData<S> {
    /// Number of SCCs,
    fn len(&self) -> usize {
        self.ranges.len()
    }

    /// Returns the successors of the given SCC.
    fn successors(&self, scc: S) -> &[S] {
        // Annoyingly, `range` does not implement `Copy`, so we have
        // to do `range.start..range.end`:
        let range = &self.ranges[scc];
        &self.all_successors[range.start..range.end]
    }

    /// Creates a new SCC with `successors` as its successors and
    /// returns the resulting index.
    fn create_scc(&mut self, successors: impl IntoIterator<Item = S>) -> S {
        // Store the successors on `scc_successors_vec`, remembering
        // the range of indices.
        let all_successors_start = self.all_successors.len();
        self.all_successors.extend(successors);
        let all_successors_end = self.all_successors.len();

        debug!(
            "create_scc({:?}) successors={:?}",
            self.ranges.len(),
            &self.all_successors[all_successors_start..all_successors_end],
        );

        self.ranges.push(all_successors_start..all_successors_end)
    }
}

struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors, S: Idx> {
    graph: &'c G,

    /// The state of each node; used during walk to record the stack
    /// and after walk to record what cycle each node ended up being
    /// in.
    node_states: IndexVec<G::Node, NodeState<G::Node, S>>,

    /// The stack of nodes that we are visiting as part of the DFS.
    node_stack: Vec<G::Node>,

    /// The stack of successors: as we visit a node, we mark our
    /// position in this stack, and when we encounter a successor SCC,
    /// we push it on the stack. When we complete an SCC, we can pop
    /// everything off the stack that was found along the way.
    successors_stack: Vec<S>,

    /// A set used to strip duplicates. As we accumulate successors
    /// into the successors_stack, we sometimes get duplicate entries.
    /// We use this set to remove those -- we also keep its storage
    /// around between successors to amortize memory allocation costs.
    duplicate_set: FxHashSet<S>,

    scc_data: SccData<S>,
}

#[derive(Copy, Clone, Debug)]
enum NodeState<N, S> {
    /// This node has not yet been visited as part of the DFS.
    ///
    /// After SCC construction is complete, this state ought to be
    /// impossible.
    NotVisited,

    /// This node is currently being walk as part of our DFS. It is on
    /// the stack at the depth `depth`.
    ///
    /// After SCC construction is complete, this state ought to be
    /// impossible.
    BeingVisited { depth: usize },

    /// Indicates that this node is a member of the given cycle.
    InCycle { scc_index: S },

    /// Indicates that this node is a member of whatever cycle
    /// `parent` is a member of. This state is transient: whenever we
    /// see it, we try to overwrite it with the current state of
    /// `parent` (this is the "path compression" step of a union-find
    /// algorithm).
    InCycleWith { parent: N },
}

#[derive(Copy, Clone, Debug)]
enum WalkReturn<S> {
    Cycle { min_depth: usize },
    Complete { scc_index: S },
}

impl<'c, G, S> SccsConstruction<'c, G, S>
where
    G: DirectedGraph + WithNumNodes + WithSuccessors,
    S: Idx,
{
    /// Identifies SCCs in the graph `G` and computes the resulting
    /// DAG. This uses a variant of [Tarjan's
    /// algorithm][wikipedia]. The high-level summary of the algorithm
    /// is that we do a depth-first search. Along the way, we keep a
    /// stack of each node whose successors are being visited. We
    /// track the depth of each node on this stack (there is no depth
    /// if the node is not on the stack). When we find that some node
    /// N with depth D can reach some other node N' with lower depth
    /// D' (i.e., D' < D), we know that N, N', and all nodes in
    /// between them on the stack are part of an SCC.
    ///
    /// [wikipedia]: https://bit.ly/2EZIx84
    fn construct(graph: &'c G) -> Sccs<G::Node, S> {
        let num_nodes = graph.num_nodes();

        let mut this = Self {
            graph,
            node_states: IndexVec::from_elem_n(NodeState::NotVisited, num_nodes),
            node_stack: Vec::with_capacity(num_nodes),
            successors_stack: Vec::new(),
            scc_data: SccData { ranges: IndexVec::new(), all_successors: Vec::new() },
            duplicate_set: FxHashSet::default(),
        };

        let scc_indices = (0..num_nodes)
            .map(G::Node::new)
            .map(|node| match this.walk_node(0, node) {
                WalkReturn::Complete { scc_index } => scc_index,
                WalkReturn::Cycle { min_depth } => {
                    panic!("`walk_node(0, {:?})` returned cycle with depth {:?}", node, min_depth)
                }
            })
            .collect();

        Sccs { scc_indices, scc_data: this.scc_data }
    }

    /// Visits a node during the DFS. We first examine its current
    /// state -- if it is not yet visited (`NotVisited`), we can push
    /// it onto the stack and start walking its successors.
    ///
    /// If it is already on the DFS stack it will be in the state
    /// `BeingVisited`. In that case, we have found a cycle and we
    /// return the depth from the stack.
    ///
    /// Otherwise, we are looking at a node that has already been
    /// completely visited. We therefore return `WalkReturn::Complete`
    /// with its associated SCC index.
    fn walk_node(&mut self, depth: usize, node: G::Node) -> WalkReturn<S> {
        debug!("walk_node(depth = {:?}, node = {:?})", depth, node);
        match self.find_state(node) {
            NodeState::InCycle { scc_index } => WalkReturn::Complete { scc_index },

            NodeState::BeingVisited { depth: min_depth } => WalkReturn::Cycle { min_depth },

            NodeState::NotVisited => self.walk_unvisited_node(depth, node),

            NodeState::InCycleWith { parent } => panic!(
                "`find_state` returned `InCycleWith({:?})`, which ought to be impossible",
                parent
            ),
        }
    }

    /// Fetches the state of the node `r`. If `r` is recorded as being
    /// in a cycle with some other node `r2`, then fetches the state
    /// of `r2` (and updates `r` to reflect current result). This is
    /// basically the "find" part of a standard union-find algorithm
    /// (with path compression).
    fn find_state(&mut self, r: G::Node) -> NodeState<G::Node, S> {
        debug!("find_state(r = {:?} in state {:?})", r, self.node_states[r]);
        match self.node_states[r] {
            NodeState::InCycle { scc_index } => NodeState::InCycle { scc_index },
            NodeState::BeingVisited { depth } => NodeState::BeingVisited { depth },
            NodeState::NotVisited => NodeState::NotVisited,
            NodeState::InCycleWith { parent } => {
                let parent_state = self.find_state(parent);
                debug!("find_state: parent_state = {:?}", parent_state);
                match parent_state {
                    NodeState::InCycle { .. } => {
                        self.node_states[r] = parent_state;
                        parent_state
                    }

                    NodeState::BeingVisited { depth } => {
                        self.node_states[r] =
                            NodeState::InCycleWith { parent: self.node_stack[depth] };
                        parent_state
                    }

                    NodeState::NotVisited | NodeState::InCycleWith { .. } => {
                        panic!("invalid parent state: {:?}", parent_state)
                    }
                }
            }
        }
    }

    /// Walks a node that has never been visited before.
    fn walk_unvisited_node(&mut self, depth: usize, node: G::Node) -> WalkReturn<S> {
        debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node);

        debug_assert!(match self.node_states[node] {
            NodeState::NotVisited => true,
            _ => false,
        });

        // Push `node` onto the stack.
        self.node_states[node] = NodeState::BeingVisited { depth };
        self.node_stack.push(node);

        // Walk each successor of the node, looking to see if any of
        // them can reach a node that is presently on the stack. If
        // so, that means they can also reach us.
        let mut min_depth = depth;
        let mut min_cycle_root = node;
        let successors_len = self.successors_stack.len();
        for successor_node in self.graph.successors(node) {
            debug!("walk_unvisited_node: node = {:?} successor_ode = {:?}", node, successor_node);
            match self.walk_node(depth + 1, successor_node) {
                WalkReturn::Cycle { min_depth: successor_min_depth } => {
                    // Track the minimum depth we can reach.
                    assert!(successor_min_depth <= depth);
                    if successor_min_depth < min_depth {
                        debug!(
                            "walk_unvisited_node: node = {:?} successor_min_depth = {:?}",
                            node, successor_min_depth
                        );
                        min_depth = successor_min_depth;
                        min_cycle_root = successor_node;
                    }
                }

                WalkReturn::Complete { scc_index: successor_scc_index } => {
                    // Push the completed SCC indices onto
                    // the `successors_stack` for later.
                    debug!(
                        "walk_unvisited_node: node = {:?} successor_scc_index = {:?}",
                        node, successor_scc_index
                    );
                    self.successors_stack.push(successor_scc_index);
                }
            }
        }

        // Completed walk, remove `node` from the stack.
        let r = self.node_stack.pop();
        debug_assert_eq!(r, Some(node));

        // If `min_depth == depth`, then we are the root of the
        // cycle: we can't reach anyone further down the stack.
        if min_depth == depth {
            // Note that successor stack may have duplicates, so we
            // want to remove those:
            let deduplicated_successors = {
                let duplicate_set = &mut self.duplicate_set;
                duplicate_set.clear();
                self.successors_stack
                    .drain(successors_len..)
                    .filter(move |&i| duplicate_set.insert(i))
            };
            let scc_index = self.scc_data.create_scc(deduplicated_successors);
            self.node_states[node] = NodeState::InCycle { scc_index };
            WalkReturn::Complete { scc_index }
        } else {
            // We are not the head of the cycle. Return back to our
            // caller. They will take ownership of the
            // `self.successors` data that we pushed.
            self.node_states[node] = NodeState::InCycleWith { parent: min_cycle_root };
            WalkReturn::Cycle { min_depth }
        }
    }
}
<commit_msg>Edit docs for rustc_data_structures::graph::scc<commit_after>//! Routine to compute the strongly connected components (SCCs) of a graph.
//!
//! Also computes as the resulting DAG if each SCC is replaced with a
//! node in the graph. This uses [Tarjan's algorithm](
//! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
//! that completes in *O(n)* time.

use crate::fx::FxHashSet;
use crate::graph::vec_graph::VecGraph;
use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
use rustc_index::vec::{Idx, IndexVec};
use std::ops::Range;

#[cfg(test)]
mod tests;

/// Strongly connected components (SCC) of a graph. The type `N` is
/// the index type for the graph nodes and `S` is the index type for
/// the SCCs. We can map from each node to the SCC that it
/// participates in, and we also have the successors of each SCC.
pub struct Sccs<N: Idx, S: Idx> {
    /// For each node, what is the SCC index of the SCC to which it
    /// belongs.
    scc_indices: IndexVec<N, S>,

    /// Data about each SCC.
    scc_data: SccData<S>,
}

struct SccData<S: Idx> {
    /// For each SCC, the range of `all_successors` where its
    /// successors can be found.
    ranges: IndexVec<S, Range<usize>>,

    /// Contains the successors for all the Sccs, concatenated. The
    /// range of indices corresponding to a given SCC is found in its
    /// SccData.
    all_successors: Vec<S>,
}

impl<N: Idx, S: Idx> Sccs<N, S> {
    pub fn new(graph: &(impl DirectedGraph<Node = N> + WithNumNodes + WithSuccessors)) -> Self {
        SccsConstruction::construct(graph)
    }

    /// Returns the number of SCCs in the graph.
    pub fn num_sccs(&self) -> usize {
        self.scc_data.len()
    }

    /// Returns an iterator over the SCCs in the graph.
    ///
    /// The SCCs will be iterated in **dependency order** (or **post order**),
    /// meaning that if `S1 -> S2`, we will visit `S2` first and `S1` after.
    /// This is convenient when the edges represent dependencies: when you visit
    /// `S1`, the value for `S2` will already have been computed.
    pub fn all_sccs(&self) -> impl Iterator<Item = S> {
        (0..self.scc_data.len()).map(S::new)
    }

    /// Returns the SCC to which a node `r` belongs.
    pub fn scc(&self, r: N) -> S {
        self.scc_indices[r]
    }

    /// Returns the successors of the given SCC.
    pub fn successors(&self, scc: S) -> &[S] {
        self.scc_data.successors(scc)
    }

    /// Construct the reverse graph of the SCC graph.
    pub fn reverse(&self) -> VecGraph<S> {
        VecGraph::new(
            self.num_sccs(),
            self.all_sccs()
                .flat_map(|source| {
                    self.successors(source).iter().map(move |&target| (target, source))
                })
                .collect(),
        )
    }
}

impl<N: Idx, S: Idx> DirectedGraph for Sccs<N, S> {
    type Node = S;
}

impl<N: Idx, S: Idx> WithNumNodes for Sccs<N, S> {
    fn num_nodes(&self) -> usize {
        self.num_sccs()
    }
}

impl<N: Idx, S: Idx> WithNumEdges for Sccs<N, S> {
    fn num_edges(&self) -> usize {
        self.scc_data.all_successors.len()
    }
}

impl<N: Idx, S: Idx> GraphSuccessors<'graph> for Sccs<N, S> {
    type Item = S;

    type Iter = std::iter::Cloned<std::slice::Iter<'graph, S>>;
}

impl<N: Idx, S: Idx> WithSuccessors for Sccs<N, S> {
    fn successors(&self, node: S) -> <Self as GraphSuccessors<'_>>::Iter {
        self.successors(node).iter().cloned()
    }
}

impl<S: Idx> SccData<S> {
    /// Number of SCCs,
    fn len(&self) -> usize {
        self.ranges.len()
    }

    /// Returns the successors of the given SCC.
    fn successors(&self, scc: S) -> &[S] {
        // Annoyingly, `range` does not implement `Copy`, so we have
        // to do `range.start..range.end`:
        let range = &self.ranges[scc];
        &self.all_successors[range.start..range.end]
    }

    /// Creates a new SCC with `successors` as its successors and
    /// returns the resulting index.
    fn create_scc(&mut self, successors: impl IntoIterator<Item = S>) -> S {
        // Store the successors on `scc_successors_vec`, remembering
        // the range of indices.
        let all_successors_start = self.all_successors.len();
        self.all_successors.extend(successors);
        let all_successors_end = self.all_successors.len();

        debug!(
            "create_scc({:?}) successors={:?}",
            self.ranges.len(),
            &self.all_successors[all_successors_start..all_successors_end],
        );

        self.ranges.push(all_successors_start..all_successors_end)
    }
}

struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors, S: Idx> {
    graph: &'c G,

    /// The state of each node; used during walk to record the stack
    /// and after walk to record what cycle each node ended up being
    /// in.
    node_states: IndexVec<G::Node, NodeState<G::Node, S>>,

    /// The stack of nodes that we are visiting as part of the DFS.
    node_stack: Vec<G::Node>,

    /// The stack of successors: as we visit a node, we mark our
    /// position in this stack, and when we encounter a successor SCC,
    /// we push it on the stack. When we complete an SCC, we can pop
    /// everything off the stack that was found along the way.
    successors_stack: Vec<S>,

    /// A set used to strip duplicates. As we accumulate successors
    /// into the successors_stack, we sometimes get duplicate entries.
    /// We use this set to remove those -- we also keep its storage
    /// around between successors to amortize memory allocation costs.
    duplicate_set: FxHashSet<S>,

    scc_data: SccData<S>,
}

#[derive(Copy, Clone, Debug)]
enum NodeState<N, S> {
    /// This node has not yet been visited as part of the DFS.
    ///
    /// After SCC construction is complete, this state ought to be
    /// impossible.
    NotVisited,

    /// This node is currently being walk as part of our DFS. It is on
    /// the stack at the depth `depth`.
    ///
    /// After SCC construction is complete, this state ought to be
    /// impossible.
    BeingVisited { depth: usize },

    /// Indicates that this node is a member of the given cycle.
    InCycle { scc_index: S },

    /// Indicates that this node is a member of whatever cycle
    /// `parent` is a member of. This state is transient: whenever we
    /// see it, we try to overwrite it with the current state of
    /// `parent` (this is the "path compression" step of a union-find
    /// algorithm).
    InCycleWith { parent: N },
}

#[derive(Copy, Clone, Debug)]
enum WalkReturn<S> {
    Cycle { min_depth: usize },
    Complete { scc_index: S },
}

impl<'c, G, S> SccsConstruction<'c, G, S>
where
    G: DirectedGraph + WithNumNodes + WithSuccessors,
    S: Idx,
{
    /// Identifies SCCs in the graph `G` and computes the resulting
    /// DAG. This uses a variant of [Tarjan's
    /// algorithm][wikipedia]. The high-level summary of the algorithm
    /// is that we do a depth-first search. Along the way, we keep a
    /// stack of each node whose successors are being visited. We
    /// track the depth of each node on this stack (there is no depth
    /// if the node is not on the stack). When we find that some node
    /// N with depth D can reach some other node N' with lower depth
    /// D' (i.e., D' < D), we know that N, N', and all nodes in
    /// between them on the stack are part of an SCC.
    ///
    /// [wikipedia]: https://bit.ly/2EZIx84
    fn construct(graph: &'c G) -> Sccs<G::Node, S> {
        let num_nodes = graph.num_nodes();

        let mut this = Self {
            graph,
            node_states: IndexVec::from_elem_n(NodeState::NotVisited, num_nodes),
            node_stack: Vec::with_capacity(num_nodes),
            successors_stack: Vec::new(),
            scc_data: SccData { ranges: IndexVec::new(), all_successors: Vec::new() },
            duplicate_set: FxHashSet::default(),
        };

        let scc_indices = (0..num_nodes)
            .map(G::Node::new)
            .map(|node| match this.walk_node(0, node) {
                WalkReturn::Complete { scc_index } => scc_index,
                WalkReturn::Cycle { min_depth } => {
                    panic!("`walk_node(0, {:?})` returned cycle with depth {:?}", node, min_depth)
                }
            })
            .collect();

        Sccs { scc_indices, scc_data: this.scc_data }
    }

    /// Visits a node during the DFS. We first examine its current
    /// state -- if it is not yet visited (`NotVisited`), we can push
    /// it onto the stack and start walking its successors.
    ///
    /// If it is already on the DFS stack it will be in the state
    /// `BeingVisited`. In that case, we have found a cycle and we
    /// return the depth from the stack.
    ///
    /// Otherwise, we are looking at a node that has already been
    /// completely visited. We therefore return `WalkReturn::Complete`
    /// with its associated SCC index.
    fn walk_node(&mut self, depth: usize, node: G::Node) -> WalkReturn<S> {
        debug!("walk_node(depth = {:?}, node = {:?})", depth, node);
        match self.find_state(node) {
            NodeState::InCycle { scc_index } => WalkReturn::Complete { scc_index },

            NodeState::BeingVisited { depth: min_depth } => WalkReturn::Cycle { min_depth },

            NodeState::NotVisited => self.walk_unvisited_node(depth, node),

            NodeState::InCycleWith { parent } => panic!(
                "`find_state` returned `InCycleWith({:?})`, which ought to be impossible",
                parent
            ),
        }
    }

    /// Fetches the state of the node `r`. If `r` is recorded as being
    /// in a cycle with some other node `r2`, then fetches the state
    /// of `r2` (and updates `r` to reflect current result). This is
    /// basically the "find" part of a standard union-find algorithm
    /// (with path compression).
    fn find_state(&mut self, r: G::Node) -> NodeState<G::Node, S> {
        debug!("find_state(r = {:?} in state {:?})", r, self.node_states[r]);
        match self.node_states[r] {
            NodeState::InCycle { scc_index } => NodeState::InCycle { scc_index },
            NodeState::BeingVisited { depth } => NodeState::BeingVisited { depth },
            NodeState::NotVisited => NodeState::NotVisited,
            NodeState::InCycleWith { parent } => {
                let parent_state = self.find_state(parent);
                debug!("find_state: parent_state = {:?}", parent_state);
                match parent_state {
                    NodeState::InCycle { .. } => {
                        self.node_states[r] = parent_state;
                        parent_state
                    }

                    NodeState::BeingVisited { depth } => {
                        self.node_states[r] =
                            NodeState::InCycleWith { parent: self.node_stack[depth] };
                        parent_state
                    }

                    NodeState::NotVisited | NodeState::InCycleWith { .. } => {
                        panic!("invalid parent state: {:?}", parent_state)
                    }
                }
            }
        }
    }

    /// Walks a node that has never been visited before.
    fn walk_unvisited_node(&mut self, depth: usize, node: G::Node) -> WalkReturn<S> {
        debug!("walk_unvisited_node(depth = {:?}, node = {:?})", depth, node);

        debug_assert!(match self.node_states[node] {
            NodeState::NotVisited => true,
            _ => false,
        });

        // Push `node` onto the stack.
        self.node_states[node] = NodeState::BeingVisited { depth };
        self.node_stack.push(node);

        // Walk each successor of the node, looking to see if any of
        // them can reach a node that is presently on the stack. If
        // so, that means they can also reach us.
        let mut min_depth = depth;
        let mut min_cycle_root = node;
        let successors_len = self.successors_stack.len();
        for successor_node in self.graph.successors(node) {
            debug!("walk_unvisited_node: node = {:?} successor_ode = {:?}", node, successor_node);
            match self.walk_node(depth + 1, successor_node) {
                WalkReturn::Cycle { min_depth: successor_min_depth } => {
                    // Track the minimum depth we can reach.
                    assert!(successor_min_depth <= depth);
                    if successor_min_depth < min_depth {
                        debug!(
                            "walk_unvisited_node: node = {:?} successor_min_depth = {:?}",
                            node, successor_min_depth
                        );
                        min_depth = successor_min_depth;
                        min_cycle_root = successor_node;
                    }
                }

                WalkReturn::Complete { scc_index: successor_scc_index } => {
                    // Push the completed SCC indices onto
                    // the `successors_stack` for later.
                    debug!(
                        "walk_unvisited_node: node = {:?} successor_scc_index = {:?}",
                        node, successor_scc_index
                    );
                    self.successors_stack.push(successor_scc_index);
                }
            }
        }

        // Completed walk, remove `node` from the stack.
        let r = self.node_stack.pop();
        debug_assert_eq!(r, Some(node));

        // If `min_depth == depth`, then we are the root of the
        // cycle: we can't reach anyone further down the stack.
        if min_depth == depth {
            // Note that successor stack may have duplicates, so we
            // want to remove those:
            let deduplicated_successors = {
                let duplicate_set = &mut self.duplicate_set;
                duplicate_set.clear();
                self.successors_stack
                    .drain(successors_len..)
                    .filter(move |&i| duplicate_set.insert(i))
            };
            let scc_index = self.scc_data.create_scc(deduplicated_successors);
            self.node_states[node] = NodeState::InCycle { scc_index };
            WalkReturn::Complete { scc_index }
        } else {
            // We are not the head of the cycle. Return back to our
            // caller. They will take ownership of the
            // `self.successors` data that we pushed.
            self.node_states[node] = NodeState::InCycleWith { parent: min_cycle_root };
            WalkReturn::Cycle { min_depth }
        }
    }
}
<|endoftext|>


<commit_before>//! Translators for various architectures to Falcon IL.
//!
//! Translators in Falcon do not lift individual instructions, but instead lift
//! basic blocks. This is both more performant than lifting individual
//! instructions, and allows Falcon to deal with weird cases such as the delay
//! slot in the MIPS architecture.
//!
//! Translators lift individual instructions to `ControlFlowGraph`, and combine
//! these graphs to form a single block. A single instruction may lift to not
//! only multiple Falcon IL instructions, but also multiple IL blocks.
//!
//! Instructions for direct branches in Falcon IL are omitted in the IL, and
//! instead edges with conditional guards are emitted. The Brc operation is only
//! emitted for indirect branches, and instructions which are typically used to
//! call other functions.
//!
//! If you are lifting directly from loader (Elf/PE/other), you do not need to
//! pay attention to the translators. The correct translator will be chosen
//! automatically.

use error::*;
use il::*;
use memory::MemoryPermissions;
use std::collections::{BTreeMap, VecDeque};

pub mod mips;
pub mod x86;

const DEFAULT_TRANSLATION_BLOCK_BYTES: usize = 64;

/// This trait is used by the translator to continually find and lift bytes from an underlying
/// memory model.
///
/// Anything that implements this trait can be used as a memory backing for lifting.
pub trait TranslationMemory {
    fn permissions(&self, address: u64) -> Option<MemoryPermissions>;

    fn get_u8(&self, address: u64) -> Option<u8>;

    fn get_bytes(&self, address: u64, length: usize) -> Vec<u8> {
        let mut bytes = Vec::new();
        for i in 0..length {
            match self.permissions(address) {
                Some(permissions) => if !permissions.contains(MemoryPermissions::EXECUTE) {
                    break;
                },
                None => break
            }
            match self.get_u8(address + i as u64) {
                Some(u) => bytes.push(u),
                None => break
            };
        }
        bytes
    }
}

/// The result of translating a block from a native architecture.
///
/// # Native blocks translated to `ControlFlowGraph`
///
/// While a block on the native architecture may be a linear sequence of instructions,
/// when lifted this block may actually contain loops, conditionally executed instructions,
/// and a host of other oddness. Translators therefor return a `ControlFlowGraph` for the
/// translation of a block. The *entry* and *exit* for this `ControlFlowGraph` should be
/// set.
#[derive(Clone, Debug)]
pub struct BlockTranslationResult {
    /// A vector of one `ControlFlowGraph` per instruction, which represents the
    /// semantics of this block
    instructions: Vec<(u64, ControlFlowGraph)>,
    /// The address at which this block was translated
    address: u64,
    /// The length of this block in bytes as represented in the host architecture
    length: usize,
    /// Addresses of known successor blocks, and optional conditions to reach them
    successors: Vec<(u64, Option<Expression>)>
}

impl BlockTranslationResult {
    /// Create a new `BlockTranslationResult`.
    ///
    /// # Parameters
    /// * `instructions` - A Vec of address/`ControlFlowGraph` pairs, one per instruction.
    /// * `address` - The address where this block was lifted.
    /// * `length` - The length of the block in bytes.
    /// * `successors` - Tuples of addresses and optional conditions for successors to this block.
    pub fn new(
        instructions: Vec<(u64, ControlFlowGraph)>,
        address: u64,
        length: usize,
        successors: Vec<(u64, Option<Expression>)>
    ) -> BlockTranslationResult {
        BlockTranslationResult {
            instructions: instructions,
            address: address,
            length: length,
            successors: successors
        }
    }

    /// Get the `ControlFlowGraph` for this `BlockTranslationResult`
    pub fn instructions(&self) -> &Vec<(u64, ControlFlowGraph)> {
        &self.instructions
    }

    /// Get the address wherefrom this block was translated.
    pub fn address(&self) -> u64 {
        self.address
    }

    /// Get the length of this block in bytes.
    pub fn length(&self) -> usize {
        self.length
    }

    /// Get the successors for this block.
    pub fn successors(&self) -> &Vec<(u64, Option<Expression>)> {
        &self.successors
    }

    /// Return a single `ControlFlowGraph` for this block
    pub fn blockify(&self) -> Result<ControlFlowGraph> {
        let mut control_flow_graph = ControlFlowGraph::new();

        let block_index = {
            let block = control_flow_graph.new_block()?;
            block.index()
        };

        control_flow_graph.set_entry(block_index)?;
        control_flow_graph.set_exit(block_index)?;

        for &(_, ref cfg) in &self.instructions {
            control_flow_graph.append(&cfg)?;
        }

        control_flow_graph.merge()?;

        Ok(control_flow_graph)
    }
}

/// A generic translation trait, implemented by various architectures.
pub trait Translator: {
    /// Translates a basic block
    fn translate_block(&self, bytes: &[u8], address: u64) -> Result<BlockTranslationResult>;

    /// Translates a function
    fn translate_function(
        &self,
        memory: &TranslationMemory,
        function_address: u64
    ) -> Result<Function> {

        // Addresses of blocks pending translation
        let mut translation_queue: VecDeque<u64> = VecDeque::new();

        // The results of block translations
        let mut translation_results: BTreeMap<u64, BlockTranslationResult> = BTreeMap::new();

        translation_queue.push_front(function_address);

        // translate all blocks in the function
        while !translation_queue.is_empty() {
            let block_address = translation_queue.pop_front().unwrap();

            if translation_results.contains_key(&block_address) {
                continue;
            }

            let block_bytes = memory.get_bytes(block_address, DEFAULT_TRANSLATION_BLOCK_BYTES);
            if block_bytes.len() == 0 {
                let mut control_flow_graph = ControlFlowGraph::new();
                let block_index = control_flow_graph.new_block()?.index();
                control_flow_graph.set_entry(block_index)?;
                control_flow_graph.set_exit(block_index)?;
                translation_results.insert(
                    block_address,
                    BlockTranslationResult::new(
                        vec![(block_address, control_flow_graph)],
                        block_address,
                        0,
                        Vec::new()
                    )
                );
                continue;
            }

            // translate this block
            let block_translation_result = self.translate_block(&block_bytes, block_address)?;

            // enqueue all successors
            for successor in block_translation_result.successors().iter() {
                if !translation_queue.contains(&successor.0) {
                    translation_queue.push_back(successor.0);
                }
            }

            translation_results.insert(block_address, block_translation_result);
        }

        // We now insert all of these blocks into a new control flow graph,
        // keeping track of their new entry and exit indices.

        // A mapping of instruction address to entry/exit vertex indices
        let mut instruction_indices: BTreeMap<u64, (usize, usize)>
            = BTreeMap::new();

        // A mapping of block address to entry/exit vertex indices;
        let mut block_indices: BTreeMap<u64, (usize, usize)> = BTreeMap::new();

        let mut control_flow_graph = ControlFlowGraph::new();
        for result in &translation_results {
            let block_translation_result = result.1;
            let mut block_entry = 0;
            let mut block_exit = 0;
            let mut previous_exit = None;
            for &(address, ref instruction_graph) in block_translation_result.instructions.iter() {
                // Have we already inserted this instruction?
                let (entry, exit) =
                    if instruction_indices.get(&address).is_some() {
                        instruction_indices[&address]
                    }
                    else {
                        let (entry, exit) = control_flow_graph.insert(instruction_graph)?;
                        instruction_indices.insert(address, (entry, exit));
                        (entry, exit)
                    };
                // If this is not our first instruction through this block.
                if let Some(previous_exit) = previous_exit {
                    // If an edge from the previoud block to this block doesn't
                    // exist
                    if control_flow_graph.edge(previous_exit, entry).is_err() {
                        // Create an edge from the previous block to this block.
                        control_flow_graph.unconditional_edge(previous_exit, entry)?;
                    }
                }
                // Our first instruction through this block
                else {
                    block_entry = entry;
                }
                block_exit = exit;
                previous_exit = Some(exit);
            }
            block_indices.insert(*result.0, (block_entry, block_exit));
        }

        // Insert the edges

        // For every block translation result
        for (address, block_translation_result) in translation_results {
            // Get the exit index for the last/tail vertex in this block
            let (_, block_exit) = block_indices[&address];
            // For every successor in the block translation result (this is an
            // (address, condition) tuple)
            for (successor_address, successor_condition)
                in block_translation_result.successors().iter() {

                // get the entry index for the first/head block in the successor
                let (block_entry, _) = block_indices[successor_address];
                // check for duplicate edges
                if control_flow_graph.edge(block_exit, block_entry).is_ok() {
                    continue;
                }
                match successor_condition {
                    Some(ref condition) =>
                        control_flow_graph.conditional_edge(block_exit,
                                                            block_entry,
                                                            condition.clone())?,
                    None => control_flow_graph.unconditional_edge(block_exit,
                                                                  block_entry)?
                }
            }
        }

        // One block is the start of our control_flow_graph
        control_flow_graph.set_entry(block_indices[&function_address].0)?;

        // merge for the user
        control_flow_graph.merge()?;

        Ok(Function::new(function_address, control_flow_graph))
    }
}<commit_msg>Fixing a typo in a comment<commit_after>//! Translators for various architectures to Falcon IL.
//!
//! Translators in Falcon do not lift individual instructions, but instead lift
//! basic blocks. This is both more performant than lifting individual
//! instructions, and allows Falcon to deal with weird cases such as the delay
//! slot in the MIPS architecture.
//!
//! Translators lift individual instructions to `ControlFlowGraph`, and combine
//! these graphs to form a single block. A single instruction may lift to not
//! only multiple Falcon IL instructions, but also multiple IL blocks.
//!
//! Instructions for direct branches in Falcon IL are omitted in the IL, and
//! instead edges with conditional guards are emitted. The Brc operation is only
//! emitted for indirect branches, and instructions which are typically used to
//! call other functions.
//!
//! If you are lifting directly from loader (Elf/PE/other), you do not need to
//! pay attention to the translators. The correct translator will be chosen
//! automatically.

use error::*;
use il::*;
use memory::MemoryPermissions;
use std::collections::{BTreeMap, VecDeque};

pub mod mips;
pub mod x86;

const DEFAULT_TRANSLATION_BLOCK_BYTES: usize = 64;

/// This trait is used by the translator to continually find and lift bytes from an underlying
/// memory model.
///
/// Anything that implements this trait can be used as a memory backing for lifting.
pub trait TranslationMemory {
    fn permissions(&self, address: u64) -> Option<MemoryPermissions>;

    fn get_u8(&self, address: u64) -> Option<u8>;

    fn get_bytes(&self, address: u64, length: usize) -> Vec<u8> {
        let mut bytes = Vec::new();
        for i in 0..length {
            match self.permissions(address) {
                Some(permissions) => if !permissions.contains(MemoryPermissions::EXECUTE) {
                    break;
                },
                None => break
            }
            match self.get_u8(address + i as u64) {
                Some(u) => bytes.push(u),
                None => break
            };
        }
        bytes
    }
}

/// The result of translating a block from a native architecture.
///
/// # Native blocks translated to `ControlFlowGraph`
///
/// While a block on the native architecture may be a linear sequence of instructions,
/// when lifted this block may actually contain loops, conditionally executed instructions,
/// and a host of other oddness. Translators therefor return a `ControlFlowGraph` for the
/// translation of a block. The *entry* and *exit* for this `ControlFlowGraph` should be
/// set.
#[derive(Clone, Debug)]
pub struct BlockTranslationResult {
    /// A vector of one `ControlFlowGraph` per instruction, which represents the
    /// semantics of this block
    instructions: Vec<(u64, ControlFlowGraph)>,
    /// The address at which this block was translated
    address: u64,
    /// The length of this block in bytes as represented in the host architecture
    length: usize,
    /// Addresses of known successor blocks, and optional conditions to reach them
    successors: Vec<(u64, Option<Expression>)>
}

impl BlockTranslationResult {
    /// Create a new `BlockTranslationResult`.
    ///
    /// # Parameters
    /// * `instructions` - A Vec of address/`ControlFlowGraph` pairs, one per instruction.
    /// * `address` - The address where this block was lifted.
    /// * `length` - The length of the block in bytes.
    /// * `successors` - Tuples of addresses and optional conditions for successors to this block.
    pub fn new(
        instructions: Vec<(u64, ControlFlowGraph)>,
        address: u64,
        length: usize,
        successors: Vec<(u64, Option<Expression>)>
    ) -> BlockTranslationResult {
        BlockTranslationResult {
            instructions: instructions,
            address: address,
            length: length,
            successors: successors
        }
    }

    /// Get the `ControlFlowGraph` for this `BlockTranslationResult`
    pub fn instructions(&self) -> &Vec<(u64, ControlFlowGraph)> {
        &self.instructions
    }

    /// Get the address wherefrom this block was translated.
    pub fn address(&self) -> u64 {
        self.address
    }

    /// Get the length of this block in bytes.
    pub fn length(&self) -> usize {
        self.length
    }

    /// Get the successors for this block.
    pub fn successors(&self) -> &Vec<(u64, Option<Expression>)> {
        &self.successors
    }

    /// Return a single `ControlFlowGraph` for this block
    pub fn blockify(&self) -> Result<ControlFlowGraph> {
        let mut control_flow_graph = ControlFlowGraph::new();

        let block_index = {
            let block = control_flow_graph.new_block()?;
            block.index()
        };

        control_flow_graph.set_entry(block_index)?;
        control_flow_graph.set_exit(block_index)?;

        for &(_, ref cfg) in &self.instructions {
            control_flow_graph.append(&cfg)?;
        }

        control_flow_graph.merge()?;

        Ok(control_flow_graph)
    }
}

/// A generic translation trait, implemented by various architectures.
pub trait Translator: {
    /// Translates a basic block
    fn translate_block(&self, bytes: &[u8], address: u64) -> Result<BlockTranslationResult>;

    /// Translates a function
    fn translate_function(
        &self,
        memory: &TranslationMemory,
        function_address: u64
    ) -> Result<Function> {

        // Addresses of blocks pending translation
        let mut translation_queue: VecDeque<u64> = VecDeque::new();

        // The results of block translations
        let mut translation_results: BTreeMap<u64, BlockTranslationResult> = BTreeMap::new();

        translation_queue.push_front(function_address);

        // translate all blocks in the function
        while !translation_queue.is_empty() {
            let block_address = translation_queue.pop_front().unwrap();

            if translation_results.contains_key(&block_address) {
                continue;
            }

            let block_bytes = memory.get_bytes(block_address, DEFAULT_TRANSLATION_BLOCK_BYTES);
            if block_bytes.len() == 0 {
                let mut control_flow_graph = ControlFlowGraph::new();
                let block_index = control_flow_graph.new_block()?.index();
                control_flow_graph.set_entry(block_index)?;
                control_flow_graph.set_exit(block_index)?;
                translation_results.insert(
                    block_address,
                    BlockTranslationResult::new(
                        vec![(block_address, control_flow_graph)],
                        block_address,
                        0,
                        Vec::new()
                    )
                );
                continue;
            }

            // translate this block
            let block_translation_result = self.translate_block(&block_bytes, block_address)?;

            // enqueue all successors
            for successor in block_translation_result.successors().iter() {
                if !translation_queue.contains(&successor.0) {
                    translation_queue.push_back(successor.0);
                }
            }

            translation_results.insert(block_address, block_translation_result);
        }

        // We now insert all of these blocks into a new control flow graph,
        // keeping track of their new entry and exit indices.

        // A mapping of instruction address to entry/exit vertex indices
        let mut instruction_indices: BTreeMap<u64, (usize, usize)>
            = BTreeMap::new();

        // A mapping of block address to entry/exit vertex indices;
        let mut block_indices: BTreeMap<u64, (usize, usize)> = BTreeMap::new();

        let mut control_flow_graph = ControlFlowGraph::new();
        for result in &translation_results {
            let block_translation_result = result.1;
            let mut block_entry = 0;
            let mut block_exit = 0;
            let mut previous_exit = None;
            for &(address, ref instruction_graph) in block_translation_result.instructions.iter() {
                // Have we already inserted this instruction?
                let (entry, exit) =
                    if instruction_indices.get(&address).is_some() {
                        instruction_indices[&address]
                    }
                    else {
                        let (entry, exit) = control_flow_graph.insert(instruction_graph)?;
                        instruction_indices.insert(address, (entry, exit));
                        (entry, exit)
                    };
                // If this is not our first instruction through this block.
                if let Some(previous_exit) = previous_exit {
                    // If an edge from the previous block to this block doesn't
                    // exist
                    if control_flow_graph.edge(previous_exit, entry).is_err() {
                        // Create an edge from the previous block to this block.
                        control_flow_graph.unconditional_edge(previous_exit, entry)?;
                    }
                }
                // Our first instruction through this block
                else {
                    block_entry = entry;
                }
                block_exit = exit;
                previous_exit = Some(exit);
            }
            block_indices.insert(*result.0, (block_entry, block_exit));
        }

        // Insert the edges

        // For every block translation result
        for (address, block_translation_result) in translation_results {
            // Get the exit index for the last/tail vertex in this block
            let (_, block_exit) = block_indices[&address];
            // For every successor in the block translation result (this is an
            // (address, condition) tuple)
            for (successor_address, successor_condition)
                in block_translation_result.successors().iter() {

                // get the entry index for the first/head block in the successor
                let (block_entry, _) = block_indices[successor_address];
                // check for duplicate edges
                if control_flow_graph.edge(block_exit, block_entry).is_ok() {
                    continue;
                }
                match successor_condition {
                    Some(ref condition) =>
                        control_flow_graph.conditional_edge(block_exit,
                                                            block_entry,
                                                            condition.clone())?,
                    None => control_flow_graph.unconditional_edge(block_exit,
                                                                  block_entry)?
                }
            }
        }

        // One block is the start of our control_flow_graph
        control_flow_graph.set_entry(block_indices[&function_address].0)?;

        // merge for the user
        control_flow_graph.merge()?;

        Ok(Function::new(function_address, control_flow_graph))
    }
}<|endoftext|>


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

//! A work queue for scheduling units of work across threads in a fork-join fashion.
//!
//! Data associated with queues is simply a pair of unsigned integers. It is expected that a
//! higher-level API on top of this could allow safe fork-join parallelism.

use task_state;

use native::task::NativeTaskBuilder;
use rand::{Rng, XorShiftRng};
use std::mem;
use std::rand::weak_rng;
use std::sync::atomics::{AtomicUint, SeqCst};
use std::sync::deque::{Abort, BufferPool, Data, Empty, Stealer, Worker};
use std::task::TaskBuilder;

/// A unit of work.
///
/// # Type parameters
///
/// - `QueueData`: global custom data for the entire work queue.
/// - `WorkData`: custom data specific to each unit of work.
pub struct WorkUnit<QueueData, WorkData> {
    /// The function to execute.
    pub fun: extern "Rust" fn(WorkData, &mut WorkerProxy<QueueData, WorkData>),
    /// Arbitrary data.
    pub data: WorkData,
}

/// Messages from the supervisor to the worker.
enum WorkerMsg<QueueData, WorkData> {
    /// Tells the worker to start work.
    StartMsg(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUint, *const QueueData),
    /// Tells the worker to stop. It can be restarted again with a `StartMsg`.
    StopMsg,
    /// Tells the worker thread to terminate.
    ExitMsg,
}

/// Messages to the supervisor.
enum SupervisorMsg<QueueData, WorkData> {
    FinishedMsg,
    ReturnDequeMsg(uint, Worker<WorkUnit<QueueData, WorkData>>),
}

/// Information that the supervisor thread keeps about the worker threads.
struct WorkerInfo<QueueData, WorkData> {
    /// The communication channel to the workers.
    chan: Sender<WorkerMsg<QueueData, WorkData>>,
    /// The worker end of the deque, if we have it.
    deque: Option<Worker<WorkUnit<QueueData, WorkData>>>,
    /// The thief end of the work-stealing deque.
    thief: Stealer<WorkUnit<QueueData, WorkData>>,
}

/// Information specific to each worker thread that the thread keeps.
struct WorkerThread<QueueData, WorkData> {
    /// The index of this worker.
    index: uint,
    /// The communication port from the supervisor.
    port: Receiver<WorkerMsg<QueueData, WorkData>>,
    /// The communication channel on which messages are sent to the supervisor.
    chan: Sender<SupervisorMsg<QueueData, WorkData>>,
    /// The thief end of the work-stealing deque for all other workers.
    other_deques: Vec<Stealer<WorkUnit<QueueData, WorkData>>>,
    /// The random number generator for this worker.
    rng: XorShiftRng,
}

static SPIN_COUNT: uint = 1000;

impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
    /// The main logic. This function starts up the worker and listens for
    /// messages.
    fn start(&mut self) {
        loop {
            // Wait for a start message.
            let (mut deque, ref_count, queue_data) = match self.port.recv() {
                StartMsg(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
                StopMsg => fail!("unexpected stop message"),
                ExitMsg => return,
            };

            // We're off!
            //
            // FIXME(pcwalton): Can't use labeled break or continue cross-crate due to a Rust bug.
            loop {
                // FIXME(pcwalton): Nasty workaround for the lack of labeled break/continue
                // cross-crate.
                let mut work_unit = unsafe {
                    mem::uninitialized()
                };
                match deque.pop() {
                    Some(work) => work_unit = work,
                    None => {
                        // Become a thief.
                        let mut i = 0;
                        let mut should_continue = true;
                        loop {
                            let victim = (self.rng.next_u32() as uint) % self.other_deques.len();
                            match self.other_deques.get_mut(victim).steal() {
                                Empty | Abort => {
                                    // Continue.
                                }
                                Data(work) => {
                                    work_unit = work;
                                    break
                                }
                            }

                            if i == SPIN_COUNT {
                                match self.port.try_recv() {
                                    Ok(StopMsg) => {
                                        should_continue = false;
                                        break
                                    }
                                    Ok(ExitMsg) => return,
                                    Ok(_) => fail!("unexpected message"),
                                    _ => {}
                                }

                                i = 0
                            } else {
                                i += 1
                            }
                        }

                        if !should_continue {
                            break
                        }
                    }
                }

                // At this point, we have some work. Perform it.
                let mut proxy = WorkerProxy {
                    worker: &mut deque,
                    ref_count: ref_count,
                    queue_data: queue_data,
                };
                (work_unit.fun)(work_unit.data, &mut proxy);

                // The work is done. Now decrement the count of outstanding work items. If this was
                // the last work unit in the queue, then send a message on the channel.
                unsafe {
                    if (*ref_count).fetch_sub(1, SeqCst) == 1 {
                        self.chan.send(FinishedMsg)
                    }
                }
            }

            // Give the deque back to the supervisor.
            self.chan.send(ReturnDequeMsg(self.index, deque))
        }
    }
}

/// A handle to the work queue that individual work units have.
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a> {
    worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
    ref_count: *mut AtomicUint,
    queue_data: *const QueueData,
}

impl<'a, QueueData: 'static, WorkData: Send> WorkerProxy<'a, QueueData, WorkData> {
    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        unsafe {
            drop((*self.ref_count).fetch_add(1, SeqCst));
        }
        self.worker.push(work_unit);
    }

    /// Retrieves the queue user data.
    #[inline]
    pub fn user_data<'a>(&'a self) -> &'a QueueData {
        unsafe {
            mem::transmute(self.queue_data)
        }
    }
}

/// A work queue on which units of work can be submitted.
pub struct WorkQueue<QueueData, WorkData> {
    /// Information about each of the workers.
    workers: Vec<WorkerInfo<QueueData, WorkData>>,
    /// A port on which deques can be received from the workers.
    port: Receiver<SupervisorMsg<QueueData, WorkData>>,
    /// The amount of work that has been enqueued.
    work_count: uint,
    /// Arbitrary user data.
    pub data: QueueData,
}

impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
    /// Creates a new work queue and spawns all the threads associated with
    /// it.
    pub fn new(task_name: &'static str,
               state: task_state::TaskState,
               thread_count: uint,
               user_data: QueueData) -> WorkQueue<QueueData, WorkData> {
        // Set up data structures.
        let (supervisor_chan, supervisor_port) = channel();
        let (mut infos, mut threads) = (vec!(), vec!());
        for i in range(0, thread_count) {
            let (worker_chan, worker_port) = channel();
            let pool = BufferPool::new();
            let (worker, thief) = pool.deque();
            infos.push(WorkerInfo {
                chan: worker_chan,
                deque: Some(worker),
                thief: thief,
            });
            threads.push(WorkerThread {
                index: i,
                port: worker_port,
                chan: supervisor_chan.clone(),
                other_deques: vec!(),
                rng: weak_rng(),
            });
        }

        // Connect workers to one another.
        for i in range(0, thread_count) {
            for j in range(0, thread_count) {
                if i != j {
                    threads.get_mut(i).other_deques.push(infos[j].thief.clone())
                }
            }
            assert!(threads[i].other_deques.len() == thread_count - 1)
        }

        // Spawn threads.
        for thread in threads.into_iter() {
            TaskBuilder::new().named(task_name).native().spawn(proc() {
                task_state::initialize(state | task_state::InWorker);
                let mut thread = thread;
                thread.start()
            })
        }

        WorkQueue {
            workers: infos,
            port: supervisor_port,
            work_count: 0,
            data: user_data,
        }
    }

    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        match self.workers.get_mut(0).deque {
            None => {
                fail!("tried to push a block but we don't have the deque?!")
            }
            Some(ref mut deque) => deque.push(work_unit),
        }
        self.work_count += 1
    }

    /// Synchronously runs all the enqueued tasks and waits for them to complete.
    pub fn run(&mut self) {
        // Tell the workers to start.
        let mut work_count = AtomicUint::new(self.work_count);
        for worker in self.workers.iter_mut() {
            worker.chan.send(StartMsg(worker.deque.take().unwrap(), &mut work_count, &self.data))
        }

        // Wait for the work to finish.
        drop(self.port.recv());
        self.work_count = 0;

        // Tell everyone to stop.
        for worker in self.workers.iter() {
            worker.chan.send(StopMsg)
        }

        // Get our deques back.
        for _ in range(0, self.workers.len()) {
            match self.port.recv() {
                ReturnDequeMsg(index, deque) => self.workers.get_mut(index).deque = Some(deque),
                FinishedMsg => fail!("unexpected finished message!"),
            }
        }
    }

    pub fn shutdown(&mut self) {
        for worker in self.workers.iter() {
            worker.chan.send(ExitMsg)
        }
    }
}
<commit_msg>auto merge of #3820 : cgaebel/servo/rebase-lalehs-patch, r=pcwalton<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! A work queue for scheduling units of work across threads in a fork-join fashion.
//!
//! Data associated with queues is simply a pair of unsigned integers. It is expected that a
//! higher-level API on top of this could allow safe fork-join parallelism.

use task_state;

use native::task::NativeTaskBuilder;
use rand::{Rng, XorShiftRng};
use std::mem;
use std::rand::weak_rng;
use std::sync::atomics::{AtomicUint, SeqCst};
use std::sync::deque::{Abort, BufferPool, Data, Empty, Stealer, Worker};
use std::task::TaskBuilder;
use libc::funcs::posix88::unistd::usleep;

/// A unit of work.
///
/// # Type parameters
///
/// - `QueueData`: global custom data for the entire work queue.
/// - `WorkData`: custom data specific to each unit of work.
pub struct WorkUnit<QueueData, WorkData> {
    /// The function to execute.
    pub fun: extern "Rust" fn(WorkData, &mut WorkerProxy<QueueData, WorkData>),
    /// Arbitrary data.
    pub data: WorkData,
}

/// Messages from the supervisor to the worker.
enum WorkerMsg<QueueData, WorkData> {
    /// Tells the worker to start work.
    StartMsg(Worker<WorkUnit<QueueData, WorkData>>, *mut AtomicUint, *const QueueData),
    /// Tells the worker to stop. It can be restarted again with a `StartMsg`.
    StopMsg,
    /// Tells the worker thread to terminate.
    ExitMsg,
}

/// Messages to the supervisor.
enum SupervisorMsg<QueueData, WorkData> {
    FinishedMsg,
    ReturnDequeMsg(uint, Worker<WorkUnit<QueueData, WorkData>>),
}

/// Information that the supervisor thread keeps about the worker threads.
struct WorkerInfo<QueueData, WorkData> {
    /// The communication channel to the workers.
    chan: Sender<WorkerMsg<QueueData, WorkData>>,
    /// The worker end of the deque, if we have it.
    deque: Option<Worker<WorkUnit<QueueData, WorkData>>>,
    /// The thief end of the work-stealing deque.
    thief: Stealer<WorkUnit<QueueData, WorkData>>,
}

/// Information specific to each worker thread that the thread keeps.
struct WorkerThread<QueueData, WorkData> {
    /// The index of this worker.
    index: uint,
    /// The communication port from the supervisor.
    port: Receiver<WorkerMsg<QueueData, WorkData>>,
    /// The communication channel on which messages are sent to the supervisor.
    chan: Sender<SupervisorMsg<QueueData, WorkData>>,
    /// The thief end of the work-stealing deque for all other workers.
    other_deques: Vec<Stealer<WorkUnit<QueueData, WorkData>>>,
    /// The random number generator for this worker.
    rng: XorShiftRng,
}

static SPIN_COUNT: u32 = 128;
static SPINS_UNTIL_BACKOFF: u32 = 100;
static BACKOFF_INCREMENT_IN_US: u32 = 5;

impl<QueueData: Send, WorkData: Send> WorkerThread<QueueData, WorkData> {
    /// The main logic. This function starts up the worker and listens for
    /// messages.
    fn start(&mut self) {
        loop {
            // Wait for a start message.
            let (mut deque, ref_count, queue_data) = match self.port.recv() {
                StartMsg(deque, ref_count, queue_data) => (deque, ref_count, queue_data),
                StopMsg => fail!("unexpected stop message"),
                ExitMsg => return,
            };

            let mut back_off_sleep = 0 as u32;

            // We're off!
            //
            // FIXME(pcwalton): Can't use labeled break or continue cross-crate due to a Rust bug.
            loop {
                // FIXME(pcwalton): Nasty workaround for the lack of labeled break/continue
                // cross-crate.
                let mut work_unit = unsafe {
                    mem::uninitialized()
                };
                match deque.pop() {
                    Some(work) => work_unit = work,
                    None => {
                        // Become a thief.
                        let mut i = 0;
                        let mut should_continue = true;
                        loop {
                            let victim = (self.rng.next_u32() as uint) % self.other_deques.len();
                            match self.other_deques.get_mut(victim).steal() {
                                Empty | Abort => {
                                    // Continue.
                                }
                                Data(work) => {
                                    work_unit = work;
                                    back_off_sleep = 0 as u32;
                                    break
                                }
                            }

                            if i > SPINS_UNTIL_BACKOFF {
                                unsafe {
                                    usleep(back_off_sleep as u32);
                                }
                                back_off_sleep += BACKOFF_INCREMENT_IN_US;
                            }

                            if i == SPIN_COUNT {
                                match self.port.try_recv() {
                                    Ok(StopMsg) => {
                                        should_continue = false;
                                        break
                                    }
                                    Ok(ExitMsg) => return,
                                    Ok(_) => fail!("unexpected message"),
                                    _ => {}
                                }

                                i = 0
                            } else {
                                i += 1
                            }
                        }

                        if !should_continue {
                            break
                        }
                    }
                }

                // At this point, we have some work. Perform it.
                let mut proxy = WorkerProxy {
                    worker: &mut deque,
                    ref_count: ref_count,
                    queue_data: queue_data,
                };
                (work_unit.fun)(work_unit.data, &mut proxy);

                // The work is done. Now decrement the count of outstanding work items. If this was
                // the last work unit in the queue, then send a message on the channel.
                unsafe {
                    if (*ref_count).fetch_sub(1, SeqCst) == 1 {
                        self.chan.send(FinishedMsg)
                    }
                }
            }

            // Give the deque back to the supervisor.
            self.chan.send(ReturnDequeMsg(self.index, deque))
        }
    }
}

/// A handle to the work queue that individual work units have.
pub struct WorkerProxy<'a, QueueData: 'a, WorkData: 'a> {
    worker: &'a mut Worker<WorkUnit<QueueData, WorkData>>,
    ref_count: *mut AtomicUint,
    queue_data: *const QueueData,
}

impl<'a, QueueData: 'static, WorkData: Send> WorkerProxy<'a, QueueData, WorkData> {
    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        unsafe {
            drop((*self.ref_count).fetch_add(1, SeqCst));
        }
        self.worker.push(work_unit);
    }

    /// Retrieves the queue user data.
    #[inline]
    pub fn user_data<'a>(&'a self) -> &'a QueueData {
        unsafe {
            mem::transmute(self.queue_data)
        }
    }
}

/// A work queue on which units of work can be submitted.
pub struct WorkQueue<QueueData, WorkData> {
    /// Information about each of the workers.
    workers: Vec<WorkerInfo<QueueData, WorkData>>,
    /// A port on which deques can be received from the workers.
    port: Receiver<SupervisorMsg<QueueData, WorkData>>,
    /// The amount of work that has been enqueued.
    work_count: uint,
    /// Arbitrary user data.
    pub data: QueueData,
}

impl<QueueData: Send, WorkData: Send> WorkQueue<QueueData, WorkData> {
    /// Creates a new work queue and spawns all the threads associated with
    /// it.
    pub fn new(task_name: &'static str,
               state: task_state::TaskState,
               thread_count: uint,
               user_data: QueueData) -> WorkQueue<QueueData, WorkData> {
        // Set up data structures.
        let (supervisor_chan, supervisor_port) = channel();
        let (mut infos, mut threads) = (vec!(), vec!());
        for i in range(0, thread_count) {
            let (worker_chan, worker_port) = channel();
            let pool = BufferPool::new();
            let (worker, thief) = pool.deque();
            infos.push(WorkerInfo {
                chan: worker_chan,
                deque: Some(worker),
                thief: thief,
            });
            threads.push(WorkerThread {
                index: i,
                port: worker_port,
                chan: supervisor_chan.clone(),
                other_deques: vec!(),
                rng: weak_rng(),
            });
        }

        // Connect workers to one another.
        for i in range(0, thread_count) {
            for j in range(0, thread_count) {
                if i != j {
                    threads.get_mut(i).other_deques.push(infos[j].thief.clone())
                }
            }
            assert!(threads[i].other_deques.len() == thread_count - 1)
        }

        // Spawn threads.
        for thread in threads.into_iter() {
            TaskBuilder::new().named(task_name).native().spawn(proc() {
                task_state::initialize(state | task_state::InWorker);
                let mut thread = thread;
                thread.start()
            })
        }

        WorkQueue {
            workers: infos,
            port: supervisor_port,
            work_count: 0,
            data: user_data,
        }
    }

    /// Enqueues a block into the work queue.
    #[inline]
    pub fn push(&mut self, work_unit: WorkUnit<QueueData, WorkData>) {
        match self.workers.get_mut(0).deque {
            None => {
                fail!("tried to push a block but we don't have the deque?!")
            }
            Some(ref mut deque) => deque.push(work_unit),
        }
        self.work_count += 1
    }

    /// Synchronously runs all the enqueued tasks and waits for them to complete.
    pub fn run(&mut self) {
        // Tell the workers to start.
        let mut work_count = AtomicUint::new(self.work_count);
        for worker in self.workers.iter_mut() {
            worker.chan.send(StartMsg(worker.deque.take().unwrap(), &mut work_count, &self.data))
        }

        // Wait for the work to finish.
        drop(self.port.recv());
        self.work_count = 0;

        // Tell everyone to stop.
        for worker in self.workers.iter() {
            worker.chan.send(StopMsg)
        }

        // Get our deques back.
        for _ in range(0, self.workers.len()) {
            match self.port.recv() {
                ReturnDequeMsg(index, deque) => self.workers.get_mut(index).deque = Some(deque),
                FinishedMsg => fail!("unexpected finished message!"),
            }
        }
    }

    pub fn shutdown(&mut self) {
        for worker in self.workers.iter() {
            worker.chan.send(ExitMsg)
        }
    }
}
<|endoftext|>


<commit_before>use parser::ast::*;
use evaluator::object::*;

pub struct BuiltinsFunctions;

impl BuiltinsFunctions {
    pub fn new() -> Self {
        BuiltinsFunctions {}
    }

    pub fn get_builtins(&self) -> Vec<(Ident, Object)> {
        vec!(
            (Ident(String::from("print")), self.bprint()),
        )
    }

    fn bprint(&self) -> Object {
        Object::Builtin(
            String::from("print"), 1, |args: Vec<Object>| {
                match args[..] {
                    [Object::String(ref t)] => {
                        println!("{}", t);
                        Ok(Object::Null)
                    },
                    [ref o] => {
                        println!("{}", o);
                        Ok(Object::Null)
                    },
                    _ => Err(String::from("invalid arguments for print")),
                }
            }
        )
    }
}
<commit_msg>builtins<commit_after>use parser::ast::*;
use evaluator::object::*;

pub struct BuiltinsFunctions;

impl BuiltinsFunctions {
    pub fn new() -> Self {
        BuiltinsFunctions {}
    }

    pub fn get_builtins(&self) -> Vec<(Ident, Object)> {
        vec!(
            (Ident(String::from("print")), self.bprint()),
            (Ident(String::from("len")), self.blen()),
            (Ident(String::from("head")), self.bhead()),
            (Ident(String::from("tail")), self.btail()),
            (Ident(String::from("cons")), self.bcons()),
        )
    }

    fn bprint(&self) -> Object {
        Object::Builtin(
            String::from("print"), 1, |args: Vec<Object>| {
                match args[..] {
                    [Object::String(ref t)] => {
                        println!("{}", t);
                        Ok(Object::Null)
                    },
                    [ref o] => {
                        println!("{}", o);
                        Ok(Object::Null)
                    },
                    _ => Err(String::from("invalid arguments for print")),
                }
            }
        )
    }

    fn blen(&self) -> Object {
        Object::Builtin(
            String::from("len"), 1, |args: Vec<Object>| {
                match args[..] {
                    [Object::String(ref s)] => Ok(Object::Integer(s.len() as i64)),
                    [Object::Array(ref arr)] => Ok(Object::Integer(arr.len() as i64)),
                    _ => Err(String::from("invalid arguments for len")),
                }
            }
        )
    }

    fn bhead(&self) -> Object {
        Object::Builtin(
            String::from("head"), 1, |args: Vec<Object>| {
                match args[..] {
                    [Object::Array(ref arr)] => {
                        match arr[..] {
                            [] => Err(String::from("empty array")),
                            [ref x, ref _tail..] => Ok(x.clone()),
                        }
                    },
                    _ => Err(String::from("invalid arguments for head")),
                }
            }
        )
    }

    fn btail(&self) -> Object {
        Object::Builtin(
            String::from("tail"), 1, |args: Vec<Object>| {
                match args[..] {
                    [Object::Array(ref arr)] => {
                        match arr[..] {
                            [] => Err(String::from("empty array")),
                            [ref _x, ref tail..] => Ok(Object::Array(tail.to_vec())),
                        }
                    },
                    _ => Err(String::from("invalid arguments for tail")),
                }
            }
        )
    }

    fn bcons(&self) -> Object {
        Object::Builtin(
            String::from("cons"), 2, |args: Vec<Object>| {
                match args[..] {
                    [ref o, Object::Array(ref os)] => {
                        let mut vectors = vec!();
                        vectors.push(o.clone());
                        for object in os { vectors.push(object.clone()); }
                        Ok(Object::Array(vectors))
                    },
                    _ => Err(String::from("invalid arguments for cons")),
                }
            }
        )
    }
}
<|endoftext|>