<commit_before>extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let windows = target.contains("windows");

    // OSX ships libcurl by default, so we just use that version
    // unconditionally.
    if target.contains("apple") {
        return println!("cargo:rustc-flags=-l curl");
    }

    // Next, fall back and try to use pkg-config if its available.
    match pkg_config::find_library("libcurl") {
        Ok(..) => return,
        Err(e) => println!("Couldn't find libcurl from \
                           pkgconfig ({:?}), compiling it from source...", e),
    }

    if !Path::new("curl/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=curl");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
    if windows {
        println!("cargo:rustc-flags=-l ws2_32");
    }

    // MSVC builds are just totally different
    if target.contains("msvc") {
        return build_msvc(&target);
    }

    let cfg = gcc::Config::new();
    let compiler = cfg.get_compiler();

    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("sh");
    let mut cflags = OsString::new();
    for arg in compiler.args() {
        cflags.push(arg);
        cflags.push(" ");
    }
    cmd.env("CC", compiler.path())
       .env("CFLAGS", cflags)
       .env("LD", &which("ld").unwrap())
       .current_dir(&dst.join("build"))
       .arg(src.join("curl/configure").to_str().unwrap()
               .replace("C:\\", "/c/")
               .replace("\\", "/"));
    if windows {
        cmd.arg("--with-winssl");
    } else {
        cmd.arg("--without-ca-bundle");
        cmd.arg("--without-ca-path");

        // DEP_OPENSSL_ROOT was what cargo used to use via overrides, and
        // OPENSSL_ROOT_DIR is also used by libssh2 which cargo uses and can be
        // set by various build scripts.
        let openssl_root = env::var("DEP_OPENSSL_ROOT").or_else(|_| {
            env::var("OPENSSL_ROOT_DIR")
        });
        if let Ok(s) = openssl_root {
            cmd.arg(format!("--with-ssl={}", s));
        }
    }
    cmd.arg("--enable-static=yes");
    cmd.arg("--enable-shared=no");
    cmd.arg("--enable-optimize");
    cmd.arg(format!("--prefix={}", dst.display()));

    if target != host {
        cmd.arg(format!("--host={}", host));
        cmd.arg(format!("--target={}", target));
    }

    cmd.arg("--without-librtmp");
    cmd.arg("--without-libidn");
    cmd.arg("--without-libssh2");
    cmd.arg("--without-nghttp2");
    cmd.arg("--disable-ldap");
    cmd.arg("--disable-ldaps");
    cmd.arg("--disable-ftp");
    cmd.arg("--disable-rtsp");
    cmd.arg("--disable-dict");
    cmd.arg("--disable-telnet");
    cmd.arg("--disable-tftp");
    cmd.arg("--disable-pop3");
    cmd.arg("--disable-imap");
    cmd.arg("--disable-smtp");
    cmd.arg("--disable-gopher");
    cmd.arg("--disable-manual");

    // Can't run ./configure directly on msys2 b/c we're handing in
    // Windows-style paths (those starting with C:\), but it chokes on those.
    // For that reason we build up a shell script with paths converted to
    // posix versions hopefully...
    //
    // Also apparently the buildbots choke unless we manually set LD, who knows
    // why?!
    run(&mut cmd);
    run(Command::new(make())
                .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                .current_dir(&dst.join("build")));

    // Don't run `make install` because apparently it's a little buggy on mingw
    // for windows.
    let _ = fs::create_dir_all(&dst.join("lib/pkgconfig"));

    // Which one does windows generate? Who knows!
    let p1 = dst.join("build/lib/.libs/libcurl.a");
    let p2 = dst.join("build/lib/.libs/libcurl.lib");
    if fs::metadata(&p1).is_ok() {
        t!(fs::copy(&p1, &dst.join("lib/libcurl.a")));
    } else {
        t!(fs::copy(&p2, &dst.join("lib/libcurl.a")));
    }
    t!(fs::copy(&dst.join("build/libcurl.pc"),
                  &dst.join("lib/pkgconfig/libcurl.pc")));
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    assert!(t!(cmd.status()).success());
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn which(cmd: &str) -> Option<PathBuf> {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let paths = env::var_os("PATH").unwrap();
    env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| {
        fs::metadata(p).is_ok()
    })
}

fn build_msvc(target: &str) {
    let cmd = gcc::windows_registry::find(target, "nmake.exe");
    let mut cmd = cmd.unwrap_or(Command::new("nmake.exe"));
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let machine = if target.starts_with("x86_64") {
        "x64"
    } else if target.starts_with("i686") {
        "x86"
    } else {
        panic!("unknown msvc target: {}", target);
    };

    t!(fs::create_dir_all(dst.join("include/curl")));
    t!(fs::create_dir_all(dst.join("lib")));

    cmd.current_dir(src.join("curl/winbuild"));
    cmd.arg("/f").arg("Makefile.vc")
       .arg("MODE=static")
       .arg("ENABLE_IDN=yes")
       .arg("DEBUG=no")
       .arg("GEN_PDB=no")
       .arg("ENABLE_WINSSL=yes")
       .arg("ENABLE_SSPI=yes")
       .arg(format!("MACHINE={}", machine));

    if let Some(inc) = env::var_os("DEP_Z_ROOT") {
        let inc = PathBuf::from(inc);
        let mut s = OsString::from("WITH_DEVEL=");
        s.push(&inc);
        cmd.arg("WITH_ZLIB=static").arg(s);

        // the build system for curl expects this library to be called
        // zlib_a.lib, so make sure it's named correctly (where libz-sys just
        // produces zlib.lib)
        let _ = fs::remove_file(&inc.join("lib/zlib_a.lib"));
        t!(fs::hard_link(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib")));
    }
    run(&mut cmd);

    let name = format!("libcurl-vc-{}-release-static-zlib-static-\
                        ipv6-sspi-winssl", machine);
    let libs = src.join("curl/builds").join(name);

    t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib")));
    for f in t!(fs::read_dir(libs.join("include/curl"))) {
        let path = t!(f).path();
        let dst = dst.join("include/curl").join(path.file_name().unwrap());
        t!(fs::copy(path, dst));
    }
    t!(fs::remove_dir_all(src.join("curl/builds")));
    println!("cargo:rustc-link-lib=wldap32");
    println!("cargo:rustc-link-lib=advapi32");
    println!("cargo:rustc-link-lib=normaliz");
}
<commit_msg>Let's rediscover why `make install` is bad<commit_after>extern crate pkg_config;
extern crate gcc;

use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::{PathBuf, Path};
use std::process::Command;

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(t) => t,
        Err(e) => panic!("{} return the error {}", stringify!($e), e),
    })
}

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let windows = target.contains("windows");

    // OSX ships libcurl by default, so we just use that version
    // unconditionally.
    if target.contains("apple") {
        return println!("cargo:rustc-flags=-l curl");
    }

    // Next, fall back and try to use pkg-config if its available.
    match pkg_config::find_library("libcurl") {
        Ok(..) => return,
        Err(e) => println!("Couldn't find libcurl from \
                           pkgconfig ({:?}), compiling it from source...", e),
    }

    if !Path::new("curl/.git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    println!("cargo:rustc-link-search={}/lib", dst.display());
    println!("cargo:rustc-link-lib=static=curl");
    println!("cargo:root={}", dst.display());
    println!("cargo:include={}/include", dst.display());
    if windows {
        println!("cargo:rustc-flags=-l ws2_32");
    }

    // MSVC builds are just totally different
    if target.contains("msvc") {
        return build_msvc(&target);
    }

    let cfg = gcc::Config::new();
    let compiler = cfg.get_compiler();

    let _ = fs::create_dir(&dst.join("build"));

    let mut cmd = Command::new("sh");
    let mut cflags = OsString::new();
    for arg in compiler.args() {
        cflags.push(arg);
        cflags.push(" ");
    }

    // Can't run ./configure directly on msys2 b/c we're handing in
    // Windows-style paths (those starting with C:\), but it chokes on those.
    // For that reason we build up a shell script with paths converted to
    // posix versions hopefully...
    //
    // Also apparently the buildbots choke unless we manually set LD, who knows
    // why?!
    cmd.env("CC", compiler.path())
       .env("CFLAGS", cflags)
       .env("LD", &which("ld").unwrap())
       .current_dir(&dst.join("build"))
       .arg(src.join("curl/configure").to_str().unwrap()
               .replace("C:\\", "/c/")
               .replace("\\", "/"));

    if windows {
        cmd.arg("--with-winssl");
    } else {
        cmd.arg("--without-ca-bundle");
        cmd.arg("--without-ca-path");

        // DEP_OPENSSL_ROOT was what cargo used to use via overrides, and
        // OPENSSL_ROOT_DIR is also used by libssh2 which cargo uses and can be
        // set by various build scripts.
        let openssl_root = env::var("DEP_OPENSSL_ROOT").or_else(|_| {
            env::var("OPENSSL_ROOT_DIR")
        });
        if let Ok(s) = openssl_root {
            cmd.arg(format!("--with-ssl={}", s));
        }
    }
    cmd.arg("--enable-static=yes");
    cmd.arg("--enable-shared=no");
    cmd.arg("--enable-optimize");
    cmd.arg(format!("--prefix={}", dst.display()));

    if target != host {
        cmd.arg(format!("--host={}", host));
        cmd.arg(format!("--target={}", target));
    }

    cmd.arg("--without-librtmp");
    cmd.arg("--without-libidn");
    cmd.arg("--without-libssh2");
    cmd.arg("--without-nghttp2");
    cmd.arg("--disable-ldap");
    cmd.arg("--disable-ldaps");
    cmd.arg("--disable-ftp");
    cmd.arg("--disable-rtsp");
    cmd.arg("--disable-dict");
    cmd.arg("--disable-telnet");
    cmd.arg("--disable-tftp");
    cmd.arg("--disable-pop3");
    cmd.arg("--disable-imap");
    cmd.arg("--disable-smtp");
    cmd.arg("--disable-gopher");
    cmd.arg("--disable-manual");

    run(&mut cmd);
    run(Command::new(make())
                .arg(&format!("-j{}", env::var("NUM_JOBS").unwrap()))
                .arg("install")
                .current_dir(&dst.join("build")));
}

fn run(cmd: &mut Command) {
    println!("running: {:?}", cmd);
    assert!(t!(cmd.status()).success());
}

fn make() -> &'static str {
    if cfg!(target_os = "freebsd") {"gmake"} else {"make"}
}

fn which(cmd: &str) -> Option<PathBuf> {
    let cmd = format!("{}{}", cmd, env::consts::EXE_SUFFIX);
    let paths = env::var_os("PATH").unwrap();
    env::split_paths(&paths).map(|p| p.join(&cmd)).find(|p| {
        fs::metadata(p).is_ok()
    })
}

fn build_msvc(target: &str) {
    let cmd = gcc::windows_registry::find(target, "nmake.exe");
    let mut cmd = cmd.unwrap_or(Command::new("nmake.exe"));
    let src = env::current_dir().unwrap();
    let dst = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let machine = if target.starts_with("x86_64") {
        "x64"
    } else if target.starts_with("i686") {
        "x86"
    } else {
        panic!("unknown msvc target: {}", target);
    };

    t!(fs::create_dir_all(dst.join("include/curl")));
    t!(fs::create_dir_all(dst.join("lib")));

    cmd.current_dir(src.join("curl/winbuild"));
    cmd.arg("/f").arg("Makefile.vc")
       .arg("MODE=static")
       .arg("ENABLE_IDN=yes")
       .arg("DEBUG=no")
       .arg("GEN_PDB=no")
       .arg("ENABLE_WINSSL=yes")
       .arg("ENABLE_SSPI=yes")
       .arg(format!("MACHINE={}", machine));

    if let Some(inc) = env::var_os("DEP_Z_ROOT") {
        let inc = PathBuf::from(inc);
        let mut s = OsString::from("WITH_DEVEL=");
        s.push(&inc);
        cmd.arg("WITH_ZLIB=static").arg(s);

        // the build system for curl expects this library to be called
        // zlib_a.lib, so make sure it's named correctly (where libz-sys just
        // produces zlib.lib)
        let _ = fs::remove_file(&inc.join("lib/zlib_a.lib"));
        t!(fs::hard_link(inc.join("lib/zlib.lib"), inc.join("lib/zlib_a.lib")));
    }
    run(&mut cmd);

    let name = format!("libcurl-vc-{}-release-static-zlib-static-\
                        ipv6-sspi-winssl", machine);
    let libs = src.join("curl/builds").join(name);

    t!(fs::copy(libs.join("lib/libcurl_a.lib"), dst.join("lib/curl.lib")));
    for f in t!(fs::read_dir(libs.join("include/curl"))) {
        let path = t!(f).path();
        let dst = dst.join("include/curl").join(path.file_name().unwrap());
        t!(fs::copy(path, dst));
    }
    t!(fs::remove_dir_all(src.join("curl/builds")));
    println!("cargo:rustc-link-lib=wldap32");
    println!("cargo:rustc-link-lib=advapi32");
    println!("cargo:rustc-link-lib=normaliz");
}
<|endoftext|>


<commit_before>extern crate clap;

use std::{cmp, f64, fs, io};
use std::collections::HashMap;
use std::io::{BufRead, Error, ErrorKind};
use clap::{App, Arg};

macro_rules! some {
    ( $e : expr ) => { match $e { Some(x) => x, None => return None } }
}

fn generate(vocab_file: &str, vectors_file: &str) -> Result<HashMap<String, Vec<f64>>, Error> {
    let mut map = HashMap::<String, Vec<f64>>::new();
    let f = io::BufReader::new(fs::File::open(vectors_file)?);
    for line in f.lines() {
        let line = line?;
        let s = line.trim();
        if s.len() == 0 { break; }
        let mut it = s.split_whitespace();
        let w = it.next().ok_or(Error::new(ErrorKind::InvalidData, "Bad line"))?;
        let mut v = Vec::<f64>::new();
        for x in it {
            match x.parse::<f64>() {
                Ok(val) => v.push(val),
                Err(e) => return Err(Error::new(ErrorKind::InvalidData, e)),
            }
        }
        let norm = v.iter().map(|x| x * x).sum::<f64>().sqrt();
        for x in v.iter_mut() { *x /= norm; }
        map.insert(w.to_string(), v);
    }
    // normalize: pending
    Ok(map)
}

fn word_analogy<'a>(map: &'a HashMap<String, Vec<f64>>, w1: &str, w2: &str, w3: &str) -> Option<Vec<(&'a str, f64)>> {
    let mut vec = some!(map.get(w2)).clone();
    let it2 = some!(map.get(w1)).iter();
    for (x, y) in vec.iter_mut().zip(it2) { *x -= *y; }
    let it3 = some!(map.get(w3)).iter();
    for (x, y) in vec.iter_mut().zip(it3) { *x += *y; }
    let norm = vec.iter().map(|x| x * x).sum::<f64>().sqrt();
    for x in vec.iter_mut() { *x /= norm; }
    let mut wv: Vec<(&'a str, f64)> = map.iter().map(|(w, v)| {
        if w != w1 && w != w2 && w != w3 {
            // inner product
            (w.as_str(), vec.iter().zip(v).map(|(x, y)| x * y).sum())
        }
        else { (w.as_str(), f64::NEG_INFINITY) }
    }).collect();
    wv.sort_by(|x,y| (y.1).partial_cmp(&x.1).unwrap_or(cmp::Ordering::Less));
    Some(wv)
}

fn main() {
    let matches = App::new("distance")
        .about("Get distance between 2 vectors.")
        .arg(Arg::with_name("vocab_file")
            .default_value("vocab.txt"))
        .arg(Arg::with_name("vectors_file")
             .default_value("vectors.txt"))
        .get_matches();

    println!("vocab_file: {}", matches.value_of("vocab_file").unwrap());
    println!("vectors_file: {}", matches.value_of("vectors_file").unwrap());
    let word_vector = generate(matches.value_of("vocab_file").unwrap(),
                            matches.value_of("vectors_file").unwrap()).unwrap();
    println!("Enter 3 words (EXIT to break)");
    loop {
        let mut line = String::new();
        if io::stdin().read_line(&mut line).is_err() { break; }
        let line = line.trim().to_string();
        if line == "EXIT" { break; }
        let words: Vec<_> = line.split_whitespace().collect();
        if words.len() == 3 {
            let v = word_analogy(&word_vector, words[0], words[1], words[2]).unwrap_or(vec![]);
            for (x, _) in v.iter().zip(0 .. 10) {
                println!("{:?}", x);
            }
        }
        println!("Enter 3 words (EXIT to break)");
    }
}
<commit_msg>Delete unused parameter<commit_after>extern crate clap;

use std::{cmp, f64, fs, io};
use std::collections::HashMap;
use std::io::{BufRead, Error, ErrorKind};
use clap::{App, Arg};

macro_rules! some {
    ( $e : expr ) => { match $e { Some(x) => x, None => return None } }
}

fn generate(vectors_file: &str) -> Result<HashMap<String, Vec<f64>>, Error> {
    let mut map = HashMap::<String, Vec<f64>>::new();
    let f = io::BufReader::new(fs::File::open(vectors_file)?);
    for line in f.lines() {
        let line = line?;
        let s = line.trim();
        if s.len() == 0 { break; }
        let mut it = s.split_whitespace();
        let w = it.next().ok_or(Error::new(ErrorKind::InvalidData, "Bad line"))?;
        let mut v = Vec::<f64>::new();
        for x in it {
            match x.parse::<f64>() {
                Ok(val) => v.push(val),
                Err(e) => return Err(Error::new(ErrorKind::InvalidData, e)),
            }
        }
        let norm = v.iter().map(|x| x * x).sum::<f64>().sqrt();
        for x in v.iter_mut() { *x /= norm; }
        map.insert(w.to_string(), v);
    }
    // normalize: pending
    Ok(map)
}

fn word_analogy<'a>(map: &'a HashMap<String, Vec<f64>>, w1: &str, w2: &str, w3: &str) -> Option<Vec<(&'a str, f64)>> {
    let mut vec = some!(map.get(w2)).clone();
    let it2 = some!(map.get(w1)).iter();
    for (x, y) in vec.iter_mut().zip(it2) { *x -= *y; }
    let it3 = some!(map.get(w3)).iter();
    for (x, y) in vec.iter_mut().zip(it3) { *x += *y; }
    let norm = vec.iter().map(|x| x * x).sum::<f64>().sqrt();
    for x in vec.iter_mut() { *x /= norm; }
    let mut wv: Vec<(&'a str, f64)> = map.iter().map(|(w, v)| {
        if w != w1 && w != w2 && w != w3 {
            // inner product
            (w.as_str(), vec.iter().zip(v).map(|(x, y)| x * y).sum())
        }
        else { (w.as_str(), f64::NEG_INFINITY) }
    }).collect();
    wv.sort_by(|x,y| (y.1).partial_cmp(&x.1).unwrap_or(cmp::Ordering::Less));
    Some(wv)
}

fn main() {
    let matches = App::new("distance")
        .about("Get distance between 2 vectors.")
        .arg(Arg::with_name("vectors_file")
             .default_value("vectors.txt"))
        .get_matches();

    println!("vectors_file: {}", matches.value_of("vectors_file").unwrap());
    let word_vector = generate(matches.value_of("vectors_file").unwrap()).unwrap();
    println!("Enter 3 words (EXIT to break)");
    loop {
        let mut line = String::new();
        if io::stdin().read_line(&mut line).is_err() { break; }
        let line = line.trim().to_string();
        if line == "EXIT" { break; }
        let words: Vec<_> = line.split_whitespace().collect();
        if words.len() == 3 {
            let v = word_analogy(&word_vector, words[0], words[1], words[2]).unwrap_or(vec![]);
            for (x, _) in v.iter().zip(0 .. 10) {
                println!("{:?}", x);
            }
        }
        println!("Enter 3 words (EXIT to break)");
    }
}
<|endoftext|>


<commit_before>// #[warn(deprecated_mode)];
// #[warn(deprecated_pattern)];

import syntax::print::pprust::{expr_to_str};

// Helper functions related to manipulating region types.

fn replace_bound_regions_in_fn_ty(
    tcx: ty::ctxt,
    isr: isr_alist,
    self_info: option<self_info>,
    fn_ty: &ty::fn_ty,
    mapf: fn(ty::bound_region) -> ty::region) ->
    {isr: isr_alist, self_info: option<self_info>, fn_ty: ty::fn_ty} {

    // Take self_info apart; the self_ty part is the only one we want
    // to update here.
    let self_ty = match self_info {
      some(s) => some(s.self_ty),
      none => none
    };

    let mut all_tys = ty::tys_in_fn_ty(fn_ty);

    match self_info {
      some({explicit_self: ast::sty_region(m), _}) => {
        let region = ty::re_bound(ty::br_self);
        let ty = ty::mk_rptr(tcx, region,
                             { ty: ty::mk_self(tcx), mutbl: m });
        vec::push(all_tys, ty);
      }
      _ => {}
    }

    for self_ty.each |t| { vec::push(all_tys, t) }

    debug!{"replace_bound_regions_in_fn_ty(self_info.self_ty=%?, fn_ty=%s, \
                all_tys=%?)",
           self_ty.map(|t| ty_to_str(tcx, t)),
           ty_to_str(tcx, ty::mk_fn(tcx, *fn_ty)),
           all_tys.map(|t| ty_to_str(tcx, t))};
    let _i = indenter();

    let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| {
        debug!{"br=%?", br};
        mapf(br)
    };
    let ty_fn = ty::ty_fn(*fn_ty);
    let t_fn = ty::fold_sty_to_ty(tcx, &ty_fn, |t| {
        replace_bound_regions(tcx, isr, t)
    });
    let t_self = self_ty.map(|t| replace_bound_regions(tcx, isr, t));

    debug!{"result of replace_bound_regions_in_fn_ty: self_info.self_ty=%?, \
                fn_ty=%s",
           t_self.map(|t| ty_to_str(tcx, t)),
           ty_to_str(tcx, t_fn)};

    // Glue updated self_ty back together with its original def_id.
    let new_self_info = match self_info {
        some(s) => match check t_self {
          some(t) => some({self_ty: t with s})
          // this 'none' case shouldn't happen
        },
        none => none
    };

    return {isr: isr,
         self_info: new_self_info,
         fn_ty: match check ty::get(t_fn).struct { ty::ty_fn(o) => o }};

    // Takes `isr`, a (possibly empty) mapping from in-scope region
    // names ("isr"s) to their corresponding regions; `tys`, a list of
    // types, and `to_r`, a closure that takes a bound_region and
    // returns a region.  Returns an updated version of `isr`,
    // extended with the in-scope region names from all of the bound
    // regions appearing in the types in the `tys` list (if they're
    // not in `isr` already), with each of those in-scope region names
    // mapped to a region that's the result of applying `to_r` to
    // itself.
    fn create_bound_region_mapping(
        tcx: ty::ctxt,
        isr: isr_alist,
        tys: ~[ty::t],
        to_r: fn(ty::bound_region) -> ty::region) -> isr_alist {

        // Takes `isr` (described above), `to_r` (described above),
        // and `r`, a region.  If `r` is anything other than a bound
        // region, or if it's a bound region that already appears in
        // `isr`, then we return `isr` unchanged.  If `r` is a bound
        // region that doesn't already appear in `isr`, we return an
        // updated isr_alist that now contains a mapping from `r` to
        // the result of calling `to_r` on it.
        fn append_isr(isr: isr_alist,
                      to_r: fn(ty::bound_region) -> ty::region,
                      r: ty::region) -> isr_alist {
            match r {
              ty::re_free(_, _) | ty::re_static | ty::re_scope(_) |
              ty::re_var(_) => {
                isr
              }
              ty::re_bound(br) => {
                match isr.find(br) {
                  some(_) => isr,
                  none => @cons((br, to_r(br)), isr)
                }
              }
            }
        }

        // For each type `ty` in `tys`...
        do tys.foldl(isr) |isr, ty| {
            let mut isr = isr;

            // Using fold_regions is inefficient, because it
            // constructs new types, but it avoids code duplication in
            // terms of locating all the regions within the various
            // kinds of types.  This had already caused me several
            // bugs so I decided to switch over.
            do ty::fold_regions(tcx, ty) |r, in_fn| {
                if !in_fn { isr = append_isr(isr, to_r, r); }
                r
            };

            isr
        }
    }

    // Takes `isr`, a mapping from in-scope region names ("isr"s) to
    // their corresponding regions; and `ty`, a type.  Returns an
    // updated version of `ty`, in which bound regions in `ty` have
    // been replaced with the corresponding bindings in `isr`.
    fn replace_bound_regions(
        tcx: ty::ctxt,
        isr: isr_alist,
        ty: ty::t) -> ty::t {

        do ty::fold_regions(tcx, ty) |r, in_fn| {
            match r {
              // As long as we are not within a fn() type, `&T` is
              // mapped to the free region anon_r.  But within a fn
              // type, it remains bound.
              ty::re_bound(ty::br_anon) if in_fn => r,

              ty::re_bound(br) => {
                match isr.find(br) {
                  // In most cases, all named, bound regions will be
                  // mapped to some free region.
                  some(fr) => fr,

                  // But in the case of a fn() type, there may be
                  // named regions within that remain bound:
                  none if in_fn => r,
                  none => {
                    tcx.sess.bug(
                        fmt!{"Bound region not found in \
                              in_scope_regions list: %s",
                             region_to_str(tcx, r)});
                  }
                }
              }

              // Free regions like these just stay the same:
              ty::re_static |
              ty::re_scope(_) |
              ty::re_free(_, _) |
              ty::re_var(_) => r
            }
        }
    }
}
<commit_msg>Remove a `match check`<commit_after>// #[warn(deprecated_mode)];
// #[warn(deprecated_pattern)];

import syntax::print::pprust::{expr_to_str};

// Helper functions related to manipulating region types.

fn replace_bound_regions_in_fn_ty(
    tcx: ty::ctxt,
    isr: isr_alist,
    self_info: option<self_info>,
    fn_ty: &ty::fn_ty,
    mapf: fn(ty::bound_region) -> ty::region) ->
    {isr: isr_alist, self_info: option<self_info>, fn_ty: ty::fn_ty} {

    // Take self_info apart; the self_ty part is the only one we want
    // to update here.
    let self_ty = match self_info {
      some(s) => some(s.self_ty),
      none => none
    };

    let mut all_tys = ty::tys_in_fn_ty(fn_ty);

    match self_info {
      some({explicit_self: ast::sty_region(m), _}) => {
        let region = ty::re_bound(ty::br_self);
        let ty = ty::mk_rptr(tcx, region,
                             { ty: ty::mk_self(tcx), mutbl: m });
        vec::push(all_tys, ty);
      }
      _ => {}
    }

    for self_ty.each |t| { vec::push(all_tys, t) }

    debug!{"replace_bound_regions_in_fn_ty(self_info.self_ty=%?, fn_ty=%s, \
                all_tys=%?)",
           self_ty.map(|t| ty_to_str(tcx, t)),
           ty_to_str(tcx, ty::mk_fn(tcx, *fn_ty)),
           all_tys.map(|t| ty_to_str(tcx, t))};
    let _i = indenter();

    let isr = do create_bound_region_mapping(tcx, isr, all_tys) |br| {
        debug!{"br=%?", br};
        mapf(br)
    };
    let ty_fn = ty::ty_fn(*fn_ty);
    let t_fn = ty::fold_sty_to_ty(tcx, &ty_fn, |t| {
        replace_bound_regions(tcx, isr, t)
    });
    let t_self = self_ty.map(|t| replace_bound_regions(tcx, isr, t));

    debug!{"result of replace_bound_regions_in_fn_ty: self_info.self_ty=%?, \
                fn_ty=%s",
           t_self.map(|t| ty_to_str(tcx, t)),
           ty_to_str(tcx, t_fn)};

    // Glue updated self_ty back together with its original def_id.
    let new_self_info = match self_info {
        some(s) => {
            match t_self {
                some(t) => some({self_ty: t with s}),
                none => {
                    tcx.sess.bug(~"unexpected t_self in \
                                   replace_bound_regions_in_fn_ty()");
                }
            }
        },
        none => none
    };

    return {isr: isr,
         self_info: new_self_info,
         fn_ty: match check ty::get(t_fn).struct { ty::ty_fn(o) => o }};

    // Takes `isr`, a (possibly empty) mapping from in-scope region
    // names ("isr"s) to their corresponding regions; `tys`, a list of
    // types, and `to_r`, a closure that takes a bound_region and
    // returns a region.  Returns an updated version of `isr`,
    // extended with the in-scope region names from all of the bound
    // regions appearing in the types in the `tys` list (if they're
    // not in `isr` already), with each of those in-scope region names
    // mapped to a region that's the result of applying `to_r` to
    // itself.
    fn create_bound_region_mapping(
        tcx: ty::ctxt,
        isr: isr_alist,
        tys: ~[ty::t],
        to_r: fn(ty::bound_region) -> ty::region) -> isr_alist {

        // Takes `isr` (described above), `to_r` (described above),
        // and `r`, a region.  If `r` is anything other than a bound
        // region, or if it's a bound region that already appears in
        // `isr`, then we return `isr` unchanged.  If `r` is a bound
        // region that doesn't already appear in `isr`, we return an
        // updated isr_alist that now contains a mapping from `r` to
        // the result of calling `to_r` on it.
        fn append_isr(isr: isr_alist,
                      to_r: fn(ty::bound_region) -> ty::region,
                      r: ty::region) -> isr_alist {
            match r {
              ty::re_free(_, _) | ty::re_static | ty::re_scope(_) |
              ty::re_var(_) => {
                isr
              }
              ty::re_bound(br) => {
                match isr.find(br) {
                  some(_) => isr,
                  none => @cons((br, to_r(br)), isr)
                }
              }
            }
        }

        // For each type `ty` in `tys`...
        do tys.foldl(isr) |isr, ty| {
            let mut isr = isr;

            // Using fold_regions is inefficient, because it
            // constructs new types, but it avoids code duplication in
            // terms of locating all the regions within the various
            // kinds of types.  This had already caused me several
            // bugs so I decided to switch over.
            do ty::fold_regions(tcx, ty) |r, in_fn| {
                if !in_fn { isr = append_isr(isr, to_r, r); }
                r
            };

            isr
        }
    }

    // Takes `isr`, a mapping from in-scope region names ("isr"s) to
    // their corresponding regions; and `ty`, a type.  Returns an
    // updated version of `ty`, in which bound regions in `ty` have
    // been replaced with the corresponding bindings in `isr`.
    fn replace_bound_regions(
        tcx: ty::ctxt,
        isr: isr_alist,
        ty: ty::t) -> ty::t {

        do ty::fold_regions(tcx, ty) |r, in_fn| {
            match r {
              // As long as we are not within a fn() type, `&T` is
              // mapped to the free region anon_r.  But within a fn
              // type, it remains bound.
              ty::re_bound(ty::br_anon) if in_fn => r,

              ty::re_bound(br) => {
                match isr.find(br) {
                  // In most cases, all named, bound regions will be
                  // mapped to some free region.
                  some(fr) => fr,

                  // But in the case of a fn() type, there may be
                  // named regions within that remain bound:
                  none if in_fn => r,
                  none => {
                    tcx.sess.bug(
                        fmt!{"Bound region not found in \
                              in_scope_regions list: %s",
                             region_to_str(tcx, r)});
                  }
                }
              }

              // Free regions like these just stay the same:
              ty::re_static |
              ty::re_scope(_) |
              ty::re_free(_, _) |
              ty::re_var(_) => r
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    account, deploy,
    shared::{self, MAIN_PKG_PATH},
};
use anyhow::{anyhow, Context, Result};
use diem_config::config::{NodeConfig, DEFAULT_PORT};
use diem_crypto::PrivateKey;
use diem_sdk::{
    client::{AccountAddress, BlockingClient},
    transaction_builder::TransactionFactory,
    types::LocalAccount,
};
use diem_types::{chain_id::ChainId, transaction::authenticator::AuthenticationKey};
use move_cli::package::cli;
use move_package::BuildConfig;
use shared::Home;
use std::{
    panic,
    path::{Path, PathBuf},
    process::Command,
};
use structopt::StructOpt;
use url::Url;

pub async fn run_e2e_tests(home: &Home, project_path: &Path, network: Url) -> Result<()> {
    let _config = shared::read_project_config(project_path)?;
    shared::generate_typescript_libraries(project_path)?;

    let config = NodeConfig::load(&home.get_validator_config_path()).with_context(|| {
        format!(
            "Failed to load NodeConfig from file: {:?}",
            home.get_validator_config_path()
        )
    })?;
    println!("Connecting to {}...", network.as_str());
    let client = BlockingClient::new(network.as_str());
    let factory = TransactionFactory::new(ChainId::test());

    let new_account = create_test_account(home, &client, &factory)?;
    create_receiver_account(home, &client, &factory)?;
    deploy::handle(home, project_path, network.clone()).await?;

    run_deno_test(
        project_path,
        &config,
        &network,
        home.get_test_key_path(),
        new_account.address(),
    )
}

// Set up a new test account
fn create_test_account(
    home: &Home,
    client: &BlockingClient,
    factory: &TransactionFactory,
) -> Result<LocalAccount> {
    let mut root_account = account::get_root_account(client, home.get_root_key_path());
    // TODO: generate random key by using let new_account_key = generate_key::generate_key();
    let new_account_key = generate_key::load_key(home.get_latest_key_path());
    let public_key = new_account_key.public_key();
    let derived_address = AuthenticationKey::ed25519(&public_key).derived_address();
    let new_account = LocalAccount::new(derived_address, new_account_key, 0);
    account::create_account_onchain(&mut root_account, &new_account, factory, client)?;
    Ok(new_account)
}

// Set up a new test account
fn create_receiver_account(
    home: &Home,
    client: &BlockingClient,
    factory: &TransactionFactory,
) -> Result<LocalAccount> {
    let mut root_account = account::get_root_account(client, home.get_root_key_path());
    let receiver_account_key = generate_key::load_key(home.get_test_key_path());
    let public_key = receiver_account_key.public_key();
    let address = AuthenticationKey::ed25519(&public_key).derived_address();
    let receiver_account = LocalAccount::new(address, receiver_account_key, 0);
    account::create_account_onchain(&mut root_account, &receiver_account, factory, client)?;

    Ok(receiver_account)
}

// Run shuffle test using deno
fn run_deno_test(
    project_path: &Path,
    config: &NodeConfig,
    network: &Url,
    key_path: &Path,
    sender_address: AccountAddress,
) -> Result<()> {
    let tests_path_string = project_path
        .join("e2e")
        .as_path()
        .to_string_lossy()
        .to_string();

    let filtered_envs =
        shared::get_filtered_envs_for_deno(project_path, network, key_path, sender_address);
    Command::new("deno")
        .args([
            "test",
            "--unstable",
            tests_path_string.as_str(),
            "--allow-env=PROJECT_PATH,SHUFFLE_HOME,SHUFFLE_NETWORK,PRIVATE_KEY_PATH,SENDER_ADDRESS",
            "--allow-read",
            format!(
                "--allow-net=:{},:{}",
                DEFAULT_PORT,
                config.json_rpc.address.port()
            )
            .as_str(),
        ])
        .envs(&filtered_envs)
        .spawn()
        .expect("deno failed to start, is it installed? brew install deno")
        .wait()?;
    Ok(())
}

fn run_move_unit_tests(project_path: &Path) -> Result<()> {
    let unit_test_cmd = cli::PackageCommand::UnitTest {
        // Setting to default values with exception of report_storage_on_error
        // to get more information about a failed test
        instruction_execution_bound: 5000,
        filter: None,
        list: false,
        num_threads: 8,
        report_statistics: false,
        report_storage_on_error: true,
        check_stackless_vm: false,
        verbose_mode: false,
        compute_coverage: false,
    };

    panic::set_hook(Box::new(|_info| {
        // Allows us to return the error below instead of panic!
        // todo: Remove all panic catching after @tzakian PR lands
    }));

    let result = panic::catch_unwind(|| {
        cli::handle_package_commands(
            &Some(project_path.join(MAIN_PKG_PATH)),
            generate_build_config_for_testing()?,
            &unit_test_cmd,
            diem_vm::natives::diem_natives(),
        )
    });

    match result {
        Ok(_) => Ok(()),
        Err(_) => Err(anyhow!("Run move package build in the main folder of the project directory, then rerun shuffle test [subcommand]")),
    }
}

fn generate_build_config_for_testing() -> Result<BuildConfig> {
    Ok(BuildConfig {
        dev_mode: true,
        test_mode: true,
        generate_docs: false,
        generate_abis: true,
        install_dir: None,
        force_recompilation: false,
    })
}

#[derive(Debug, StructOpt)]
pub enum TestCommand {
    #[structopt(about = "Runs end to end test in shuffle")]
    E2e {
        #[structopt(short, long)]
        project_path: Option<PathBuf>,

        #[structopt(short, long)]
        network: Option<String>,
    },

    #[structopt(about = "Runs move move unit tests in project folder")]
    Unit {
        #[structopt(short, long)]
        project_path: Option<PathBuf>,
    },

    #[structopt(
        about = "Runs both end to end test in shuffle and move move unit tests in project folder"
    )]
    All {
        #[structopt(short, long)]
        project_path: Option<PathBuf>,

        #[structopt(short, long)]
        network: Option<String>,
    },
}

pub async fn handle(home: &Home, cmd: TestCommand) -> Result<()> {
    match cmd {
        TestCommand::E2e {
            project_path,
            network,
        } => {
            run_e2e_tests(
                home,
                shared::normalized_project_path(project_path)?.as_path(),
                shared::normalized_network(home, network)?,
            )
            .await
        }
        TestCommand::Unit { project_path } => {
            run_move_unit_tests(shared::normalized_project_path(project_path)?.as_path())
        }
        TestCommand::All {
            project_path,
            network,
        } => {
            let normalized_path = shared::normalized_project_path(project_path)?;
            run_move_unit_tests(normalized_path.as_path())?;
            run_e2e_tests(
                home,
                normalized_path.as_path(),
                shared::normalized_network(home, network)?,
            )
            .await
        }
    }
}
<commit_msg>[shuffle] removed panic handling in move_unit_tests<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    account, deploy,
    shared::{self, MAIN_PKG_PATH},
};
use anyhow::{Context, Result};
use diem_config::config::{NodeConfig, DEFAULT_PORT};
use diem_crypto::PrivateKey;
use diem_sdk::{
    client::{AccountAddress, BlockingClient},
    transaction_builder::TransactionFactory,
    types::LocalAccount,
};
use diem_types::{chain_id::ChainId, transaction::authenticator::AuthenticationKey};
use move_cli::package::cli;
use move_package::BuildConfig;
use shared::Home;
use std::{
    path::{Path, PathBuf},
    process::Command,
};
use structopt::StructOpt;
use url::Url;

pub async fn run_e2e_tests(home: &Home, project_path: &Path, network: Url) -> Result<()> {
    let _config = shared::read_project_config(project_path)?;
    shared::generate_typescript_libraries(project_path)?;

    let config = NodeConfig::load(&home.get_validator_config_path()).with_context(|| {
        format!(
            "Failed to load NodeConfig from file: {:?}",
            home.get_validator_config_path()
        )
    })?;
    println!("Connecting to {}...", network.as_str());
    let client = BlockingClient::new(network.as_str());
    let factory = TransactionFactory::new(ChainId::test());

    let new_account = create_test_account(home, &client, &factory)?;
    create_receiver_account(home, &client, &factory)?;
    deploy::handle(home, project_path, network.clone()).await?;

    run_deno_test(
        project_path,
        &config,
        &network,
        home.get_test_key_path(),
        new_account.address(),
    )
}

// Set up a new test account
fn create_test_account(
    home: &Home,
    client: &BlockingClient,
    factory: &TransactionFactory,
) -> Result<LocalAccount> {
    let mut root_account = account::get_root_account(client, home.get_root_key_path());
    // TODO: generate random key by using let new_account_key = generate_key::generate_key();
    let new_account_key = generate_key::load_key(home.get_latest_key_path());
    let public_key = new_account_key.public_key();
    let derived_address = AuthenticationKey::ed25519(&public_key).derived_address();
    let new_account = LocalAccount::new(derived_address, new_account_key, 0);
    account::create_account_onchain(&mut root_account, &new_account, factory, client)?;
    Ok(new_account)
}

// Set up a new test account
fn create_receiver_account(
    home: &Home,
    client: &BlockingClient,
    factory: &TransactionFactory,
) -> Result<LocalAccount> {
    let mut root_account = account::get_root_account(client, home.get_root_key_path());
    let receiver_account_key = generate_key::load_key(home.get_test_key_path());
    let public_key = receiver_account_key.public_key();
    let address = AuthenticationKey::ed25519(&public_key).derived_address();
    let receiver_account = LocalAccount::new(address, receiver_account_key, 0);
    account::create_account_onchain(&mut root_account, &receiver_account, factory, client)?;

    Ok(receiver_account)
}

// Run shuffle test using deno
fn run_deno_test(
    project_path: &Path,
    config: &NodeConfig,
    network: &Url,
    key_path: &Path,
    sender_address: AccountAddress,
) -> Result<()> {
    let tests_path_string = project_path
        .join("e2e")
        .as_path()
        .to_string_lossy()
        .to_string();

    let filtered_envs =
        shared::get_filtered_envs_for_deno(project_path, network, key_path, sender_address);
    Command::new("deno")
        .args([
            "test",
            "--unstable",
            tests_path_string.as_str(),
            "--allow-env=PROJECT_PATH,SHUFFLE_HOME,SHUFFLE_NETWORK,PRIVATE_KEY_PATH,SENDER_ADDRESS",
            "--allow-read",
            format!(
                "--allow-net=:{},:{}",
                DEFAULT_PORT,
                config.json_rpc.address.port()
            )
            .as_str(),
        ])
        .envs(&filtered_envs)
        .spawn()
        .expect("deno failed to start, is it installed? brew install deno")
        .wait()?;
    Ok(())
}

fn run_move_unit_tests(project_path: &Path) -> Result<()> {
    let unit_test_cmd = cli::PackageCommand::UnitTest {
        // Setting to default values with exception of report_storage_on_error
        // to get more information about a failed test
        instruction_execution_bound: 5000,
        filter: None,
        list: false,
        num_threads: 8,
        report_statistics: false,
        report_storage_on_error: true,
        check_stackless_vm: false,
        verbose_mode: false,
        compute_coverage: false,
    };

    cli::handle_package_commands(
        &Some(project_path.join(MAIN_PKG_PATH)),
        generate_build_config_for_testing()?,
        &unit_test_cmd,
        diem_vm::natives::diem_natives(),
    )
}

fn generate_build_config_for_testing() -> Result<BuildConfig> {
    Ok(BuildConfig {
        dev_mode: true,
        test_mode: true,
        generate_docs: false,
        generate_abis: true,
        install_dir: None,
        force_recompilation: false,
    })
}

#[derive(Debug, StructOpt)]
pub enum TestCommand {
    #[structopt(about = "Runs end to end test in shuffle")]
    E2e {
        #[structopt(short, long)]
        project_path: Option<PathBuf>,

        #[structopt(short, long)]
        network: Option<String>,
    },

    #[structopt(about = "Runs move move unit tests in project folder")]
    Unit {
        #[structopt(short, long)]
        project_path: Option<PathBuf>,
    },

    #[structopt(
        about = "Runs both end to end test in shuffle and move move unit tests in project folder"
    )]
    All {
        #[structopt(short, long)]
        project_path: Option<PathBuf>,

        #[structopt(short, long)]
        network: Option<String>,
    },
}

pub async fn handle(home: &Home, cmd: TestCommand) -> Result<()> {
    match cmd {
        TestCommand::E2e {
            project_path,
            network,
        } => {
            run_e2e_tests(
                home,
                shared::normalized_project_path(project_path)?.as_path(),
                shared::normalized_network(home, network)?,
            )
            .await
        }
        TestCommand::Unit { project_path } => {
            run_move_unit_tests(shared::normalized_project_path(project_path)?.as_path())
        }
        TestCommand::All {
            project_path,
            network,
        } => {
            let normalized_path = shared::normalized_project_path(project_path)?;
            run_move_unit_tests(normalized_path.as_path())?;
            run_e2e_tests(
                home,
                normalized_path.as_path(),
                shared::normalized_network(home, network)?,
            )
            .await
        }
    }
}
<|endoftext|>


<commit_before>use crate::raw::Bucket;
use crate::raw::{RawIterRange, RawTable};
use crate::scopeguard::guard;
use alloc::alloc::dealloc;
use core::marker::PhantomData;
use core::mem;
use core::ptr::NonNull;
use rayon::iter::{
    plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer},
    ParallelIterator,
};

/// Parallel iterator which returns a raw pointer to every full bucket in the table.
pub struct RawParIter<T> {
    iter: RawIterRange<T>,
}

impl<T> ParallelIterator for RawParIter<T> {
    type Item = Bucket<T>;

    #[cfg_attr(feature = "inline-more", inline)]
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: UnindexedConsumer<Self::Item>,
    {
        let producer = ParIterProducer { iter: self.iter };
        plumbing::bridge_unindexed(producer, consumer)
    }
}

/// Producer which returns a `Bucket<T>` for every element.
struct ParIterProducer<T> {
    iter: RawIterRange<T>,
}

impl<T> UnindexedProducer for ParIterProducer<T> {
    type Item = Bucket<T>;

    #[cfg_attr(feature = "inline-more", inline)]
    fn split(self) -> (Self, Option<Self>) {
        let (left, right) = self.iter.split();
        let left = ParIterProducer { iter: left };
        let right = right.map(|right| ParIterProducer { iter: right });
        (left, right)
    }

    #[cfg_attr(feature = "inline-more", inline)]
    fn fold_with<F>(self, folder: F) -> F
    where
        F: Folder<Self::Item>,
    {
        folder.consume_iter(self.iter)
    }
}

/// Parallel iterator which consumes a table and returns elements.
pub struct RawIntoParIter<T> {
    table: RawTable<T>,
}

impl<T: Send> ParallelIterator for RawIntoParIter<T> {
    type Item = T;

    #[cfg_attr(feature = "inline-more", inline)]
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: UnindexedConsumer<Self::Item>,
    {
        let iter = unsafe { self.table.iter().iter };
        let _guard = guard(self.table.into_alloc(), |alloc| {
            if let Some((ptr, layout)) = *alloc {
                unsafe {
                    dealloc(ptr.as_ptr(), layout);
                }
            }
        });
        let producer = ParDrainProducer { iter };
        plumbing::bridge_unindexed(producer, consumer)
    }
}

/// Parallel iterator which consumes elements without freeing the table storage.
pub struct RawParDrain<'a, T> {
    // We don't use a &'a mut RawTable<T> because we want RawParDrain to be
    // covariant over T.
    table: NonNull<RawTable<T>>,
    marker: PhantomData<&'a RawTable<T>>,
}

unsafe impl<T> Send for RawParDrain<'_, T> {}

impl<T: Send> ParallelIterator for RawParDrain<'_, T> {
    type Item = T;

    #[cfg_attr(feature = "inline-more", inline)]
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: UnindexedConsumer<Self::Item>,
    {
        let _guard = guard(self.table, |table| unsafe {
            table.as_mut().clear_no_drop()
        });
        let iter = unsafe { self.table.as_ref().iter().iter };
        mem::forget(self);
        let producer = ParDrainProducer { iter };
        plumbing::bridge_unindexed(producer, consumer)
    }
}

impl<T> Drop for RawParDrain<'_, T> {
    fn drop(&mut self) {
        // If drive_unindexed is not called then simply clear the table.
        unsafe { self.table.as_mut().clear() }
    }
}

/// Producer which will consume all elements in the range, even if it is dropped
/// halfway through.
struct ParDrainProducer<T> {
    iter: RawIterRange<T>,
}

impl<T: Send> UnindexedProducer for ParDrainProducer<T> {
    type Item = T;

    #[cfg_attr(feature = "inline-more", inline)]
    fn split(self) -> (Self, Option<Self>) {
        let (left, right) = self.iter.clone().split();
        mem::forget(self);
        let left = ParDrainProducer { iter: left };
        let right = right.map(|right| ParDrainProducer { iter: right });
        (left, right)
    }

    #[cfg_attr(feature = "inline-more", inline)]
    fn fold_with<F>(mut self, mut folder: F) -> F
    where
        F: Folder<Self::Item>,
    {
        // Make sure to modify the iterator in-place so that any remaining
        // elements are processed in our Drop impl.
        while let Some(item) = self.iter.next() {
            folder = folder.consume(unsafe { item.read() });
            if folder.full() {
                return folder;
            }
        }

        // If we processed all elements then we don't need to run the drop.
        mem::forget(self);
        folder
    }
}

impl<T> Drop for ParDrainProducer<T> {
    #[cfg_attr(feature = "inline-more", inline)]
    fn drop(&mut self) {
        // Drop all remaining elements
        if mem::needs_drop::<T>() {
            while let Some(item) = self.iter.next() {
                unsafe {
                    item.drop();
                }
            }
        }
    }
}

impl<T> RawTable<T> {
    /// Returns a parallel iterator over the elements in a `RawTable`.
    #[cfg_attr(feature = "inline-more", inline)]
    pub unsafe fn par_iter(&self) -> RawParIter<T> {
        RawParIter {
            iter: self.iter().iter,
        }
    }

    /// Returns a parallel iterator over the elements in a `RawTable`.
    #[cfg_attr(feature = "inline-more", inline)]
    pub fn into_par_iter(self) -> RawIntoParIter<T> {
        RawIntoParIter { table: self }
    }

    /// Returns a parallel iterator which consumes all elements of a `RawTable`
    /// without freeing its memory allocation.
    #[cfg_attr(feature = "inline-more", inline)]
    pub fn par_drain(&mut self) -> RawParDrain<'_, T> {
        RawParDrain {
            table: NonNull::from(self),
            marker: PhantomData,
        }
    }
}
<commit_msg>Allow re-using RawIter to make ParRawIter<commit_after>use crate::raw::Bucket;
use crate::raw::{RawIter, RawIterRange, RawTable};
use crate::scopeguard::guard;
use alloc::alloc::dealloc;
use core::marker::PhantomData;
use core::mem;
use core::ptr::NonNull;
use rayon::iter::{
    plumbing::{self, Folder, UnindexedConsumer, UnindexedProducer},
    ParallelIterator,
};

/// Parallel iterator which returns a raw pointer to every full bucket in the table.
pub struct RawParIter<T> {
    iter: RawIterRange<T>,
}

impl<T> From<RawIter<T>> for RawParIter<T> {
    fn from(it: RawIter<T>) -> Self {
        RawParIter { iter: it.iter }
    }
}

impl<T> ParallelIterator for RawParIter<T> {
    type Item = Bucket<T>;

    #[cfg_attr(feature = "inline-more", inline)]
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: UnindexedConsumer<Self::Item>,
    {
        let producer = ParIterProducer { iter: self.iter };
        plumbing::bridge_unindexed(producer, consumer)
    }
}

/// Producer which returns a `Bucket<T>` for every element.
struct ParIterProducer<T> {
    iter: RawIterRange<T>,
}

impl<T> UnindexedProducer for ParIterProducer<T> {
    type Item = Bucket<T>;

    #[cfg_attr(feature = "inline-more", inline)]
    fn split(self) -> (Self, Option<Self>) {
        let (left, right) = self.iter.split();
        let left = ParIterProducer { iter: left };
        let right = right.map(|right| ParIterProducer { iter: right });
        (left, right)
    }

    #[cfg_attr(feature = "inline-more", inline)]
    fn fold_with<F>(self, folder: F) -> F
    where
        F: Folder<Self::Item>,
    {
        folder.consume_iter(self.iter)
    }
}

/// Parallel iterator which consumes a table and returns elements.
pub struct RawIntoParIter<T> {
    table: RawTable<T>,
}

impl<T: Send> ParallelIterator for RawIntoParIter<T> {
    type Item = T;

    #[cfg_attr(feature = "inline-more", inline)]
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: UnindexedConsumer<Self::Item>,
    {
        let iter = unsafe { self.table.iter().iter };
        let _guard = guard(self.table.into_alloc(), |alloc| {
            if let Some((ptr, layout)) = *alloc {
                unsafe {
                    dealloc(ptr.as_ptr(), layout);
                }
            }
        });
        let producer = ParDrainProducer { iter };
        plumbing::bridge_unindexed(producer, consumer)
    }
}

/// Parallel iterator which consumes elements without freeing the table storage.
pub struct RawParDrain<'a, T> {
    // We don't use a &'a mut RawTable<T> because we want RawParDrain to be
    // covariant over T.
    table: NonNull<RawTable<T>>,
    marker: PhantomData<&'a RawTable<T>>,
}

unsafe impl<T> Send for RawParDrain<'_, T> {}

impl<T: Send> ParallelIterator for RawParDrain<'_, T> {
    type Item = T;

    #[cfg_attr(feature = "inline-more", inline)]
    fn drive_unindexed<C>(self, consumer: C) -> C::Result
    where
        C: UnindexedConsumer<Self::Item>,
    {
        let _guard = guard(self.table, |table| unsafe {
            table.as_mut().clear_no_drop()
        });
        let iter = unsafe { self.table.as_ref().iter().iter };
        mem::forget(self);
        let producer = ParDrainProducer { iter };
        plumbing::bridge_unindexed(producer, consumer)
    }
}

impl<T> Drop for RawParDrain<'_, T> {
    fn drop(&mut self) {
        // If drive_unindexed is not called then simply clear the table.
        unsafe { self.table.as_mut().clear() }
    }
}

/// Producer which will consume all elements in the range, even if it is dropped
/// halfway through.
struct ParDrainProducer<T> {
    iter: RawIterRange<T>,
}

impl<T: Send> UnindexedProducer for ParDrainProducer<T> {
    type Item = T;

    #[cfg_attr(feature = "inline-more", inline)]
    fn split(self) -> (Self, Option<Self>) {
        let (left, right) = self.iter.clone().split();
        mem::forget(self);
        let left = ParDrainProducer { iter: left };
        let right = right.map(|right| ParDrainProducer { iter: right });
        (left, right)
    }

    #[cfg_attr(feature = "inline-more", inline)]
    fn fold_with<F>(mut self, mut folder: F) -> F
    where
        F: Folder<Self::Item>,
    {
        // Make sure to modify the iterator in-place so that any remaining
        // elements are processed in our Drop impl.
        while let Some(item) = self.iter.next() {
            folder = folder.consume(unsafe { item.read() });
            if folder.full() {
                return folder;
            }
        }

        // If we processed all elements then we don't need to run the drop.
        mem::forget(self);
        folder
    }
}

impl<T> Drop for ParDrainProducer<T> {
    #[cfg_attr(feature = "inline-more", inline)]
    fn drop(&mut self) {
        // Drop all remaining elements
        if mem::needs_drop::<T>() {
            while let Some(item) = self.iter.next() {
                unsafe {
                    item.drop();
                }
            }
        }
    }
}

impl<T> RawTable<T> {
    /// Returns a parallel iterator over the elements in a `RawTable`.
    #[cfg_attr(feature = "inline-more", inline)]
    pub unsafe fn par_iter(&self) -> RawParIter<T> {
        RawParIter {
            iter: self.iter().iter,
        }
    }

    /// Returns a parallel iterator over the elements in a `RawTable`.
    #[cfg_attr(feature = "inline-more", inline)]
    pub fn into_par_iter(self) -> RawIntoParIter<T> {
        RawIntoParIter { table: self }
    }

    /// Returns a parallel iterator which consumes all elements of a `RawTable`
    /// without freeing its memory allocation.
    #[cfg_attr(feature = "inline-more", inline)]
    pub fn par_drain(&mut self) -> RawParDrain<'_, T> {
        RawParDrain {
            table: NonNull::from(self),
            marker: PhantomData,
        }
    }
}
<|endoftext|>


<commit_before>// run-pass

#![allow(warnings)]

use std::iter::Zip;

fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter }

fn main() { }
<commit_msg>Rollup merge of #72902 - cuviper:fuse-covariant, r=nikomatsakis<commit_after>// run-pass

#![allow(dead_code)]

use std::iter::{Fuse, Zip};

fn fuse_covariant<'a, I>(iter: Fuse<&'static I>) -> Fuse<&'a I> { iter }
fn zip_covariant<'a, A, B>(iter: Zip<&'static A, &'static B>) -> Zip<&'a A, &'a B> { iter }

fn main() { }
<|endoftext|>


<commit_before>use ecs::*;
use game::*;
use game::data::*;
use game::terrain::util;
use coord::Coord;

const STAIR_COORDS: [Coord; 2] = [
    Coord { x: 7, y: 9 },
    Coord { x: 22, y: 17 },
];

const START_COORD: Coord = STAIR_COORDS[0];

pub fn demo_c<S: TurnScheduleQueue>(ids: &EntityIdReserver,
                                  rng: &GameRng,
                                  schedule: &mut S,
                                  g: &mut EcsAction,
                                  parent: ParentLevelCtx) -> TerrainMetadata {

    let (width, height) = util::terrain_from_strings(&level_str(), None, ids, schedule, g);

    util::generate_clouds(width, height, ids, rng, schedule, g);

    let mut connections = LevelConnectionReport::new();
    let mut count = 0;

    if let Some(entrance_group) = parent.level.ecs.level_switch_group(parent.entrance_entity_id) {

        // loop through all level switches with groups in the parent level
        for (id, group) in parent.level.ecs.level_switch_group_iter() {

            // check if the group is the same as the group of the current level switch
            if group == entrance_group {

                // create corresponding up stairs
                let local_id = ids.new_id();

                let existing = ExistingLevel {
                    level_id: parent.level_id,
                    entrance_entity_id: id,
                };

                prototypes::up_stairs(g.entity_mut(local_id),
                                      STAIR_COORDS[count],
                                      LevelSwitch::ExistingLevel(existing),
                                      Some(count));

                // the group is used to distinguish between stairs later
                count += 1;

                // connect the level switch in the parent to the new level switch
                connections.connect(id, local_id);

            }
        }
    } else {
        let local_id = ids.new_id();

        let existing = ExistingLevel {
            level_id: parent.level_id,
            entrance_entity_id: parent.entrance_entity_id,
        };

        prototypes::up_stairs(g.entity_mut(local_id),
                              STAIR_COORDS[count],
                              LevelSwitch::ExistingLevel(existing),
                              Some(count));

        connections.connect(parent.entrance_entity_id, local_id);
    }

    TerrainMetadata {
        width: width,
        height: height,
        start_coord: START_COORD,
        connection_report: connections,
    }
}

fn level_str() -> Vec<&'static str> {
    vec!["#########################################",
         "#.......................................#",
         "#.......................................#",
         "#....................######.............#",
         "#....................#..................#",
         "#....................#..................#",
         "#####.....############..................#",
         "#....................#..................#",
         "#....................#........#.........#",
         "#.............................#.........#",
         "#....................#........#.........#",
         "#....................#........#.........#",
         "#....................#........#.........#",
         "#######.##########################......#",
         "#............#...................#......#",
         "#............#...................#......#",
         "#............#..........................#",
         "#................................#......#",
         "#............#...................#......#",
         "#............#...................#......#",
         "#########################################",]
}
<commit_msg>First entrance to demo_c starts in correct place<commit_after>use ecs::*;
use game::*;
use game::data::*;
use game::terrain::util;
use coord::Coord;

const STAIR_COORDS: [Coord; 2] = [
    Coord { x: 7, y: 9 },
    Coord { x: 22, y: 17 },
];

pub fn demo_c<S: TurnScheduleQueue>(ids: &EntityIdReserver,
                                  rng: &GameRng,
                                  schedule: &mut S,
                                  g: &mut EcsAction,
                                  parent: ParentLevelCtx) -> TerrainMetadata {

    let (width, height) = util::terrain_from_strings(&level_str(), None, ids, schedule, g);

    util::generate_clouds(width, height, ids, rng, schedule, g);

    let mut connections = LevelConnectionReport::new();
    let mut count = 0;

    let mut start_coord = None;

    if let Some(entrance_group) = parent.level.ecs.level_switch_group(parent.entrance_entity_id) {

        // loop through all level switches with groups in the parent level
        for (id, group) in parent.level.ecs.level_switch_group_iter() {

            // check if the group is the same as the group of the current level switch
            if group == entrance_group {

                if id == parent.entrance_entity_id {
                    start_coord = Some(STAIR_COORDS[count]);
                }

                // create corresponding up stairs
                let local_id = ids.new_id();

                let existing = ExistingLevel {
                    level_id: parent.level_id,
                    entrance_entity_id: id,
                };

                prototypes::up_stairs(g.entity_mut(local_id),
                                      STAIR_COORDS[count],
                                      LevelSwitch::ExistingLevel(existing),
                                      Some(count));

                // the group is used to distinguish between stairs later
                count += 1;

                // connect the level switch in the parent to the new level switch
                connections.connect(id, local_id);
            }
        }
    } else {

        start_coord = Some(STAIR_COORDS[count]);

        let local_id = ids.new_id();

        let existing = ExistingLevel {
            level_id: parent.level_id,
            entrance_entity_id: parent.entrance_entity_id,
        };

        prototypes::up_stairs(g.entity_mut(local_id),
                              STAIR_COORDS[count],
                              LevelSwitch::ExistingLevel(existing),
                              Some(count));

        connections.connect(parent.entrance_entity_id, local_id);
    }

    TerrainMetadata {
        width: width,
        height: height,
        start_coord: start_coord.expect("Expected start coordinate"),
        connection_report: connections,
    }
}

fn level_str() -> Vec<&'static str> {
    vec!["#########################################",
         "#.......................................#",
         "#.......................................#",
         "#....................######.............#",
         "#....................#..................#",
         "#....................#..................#",
         "#####.....############..................#",
         "#....................#..................#",
         "#....................#........#.........#",
         "#.............................#.........#",
         "#....................#........#.........#",
         "#....................#........#.........#",
         "#....................#........#.........#",
         "#######.##########################......#",
         "#............#...................#......#",
         "#............#...................#......#",
         "#............#..........................#",
         "#................................#......#",
         "#............#...................#......#",
         "#............#...................#......#",
         "#########################################",]
}
<|endoftext|>


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

use stb_image::bindgen::*;

use std::any::Any;
use libc;
use libc::{c_void, c_int};
use std::slice::raw::buf_as_slice;

pub struct Image<T> {
    pub width   : uint,
    pub height  : uint,
    pub depth   : uint,
    pub data    : Vec<T>,
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: Vec<T>) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

pub enum LoadResult {
    Error(~str),
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

impl LoadResult {
    pub fn from_result(res: Result<LoadResult,Box<Any>>)-> LoadResult {
        match res {
            Ok(res) => res,
            Err(e)  => Error(e.to_str()),
        }
    }
}

pub fn load(path: &Path) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

fn load_internal<T: Clone>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = buf_as_slice(buf, (w * h * d) as uint, |s| { Vec::from_slice(s) });
        libc::free(buf as *mut c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: &Path, force_depth: uint, convert_hdr: bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let path_as_str = match path.as_str() {
            Some(s) => s,
            None => return Error("path is not valid utf8".to_owned()),
        };
        path_as_str.with_c_str(|bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(bytes,
                                        &mut width,
                                        &mut height,
                                        &mut depth,
                                        force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_loadf failed".to_owned())
                } else {
                    ImageF32(load_internal(buffer, width, height, depth))
                }
            } else {
                let buffer = stbi_load(bytes,
                                       &mut width,
                                       &mut height,
                                       &mut depth,
                                       force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_load failed".to_owned())
                } else {
                    ImageU8(load_internal(buffer, width, height, depth))
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        if !convert_hdr && stbi_is_hdr_from_memory(buffer.as_ptr(), buffer.len() as c_int) != 0 {
            let buffer = stbi_loadf_from_memory(buffer.as_ptr(),
                                                buffer.len() as c_int,
                                                &mut width,
                                                &mut height,
                                                &mut depth,
                                                force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_loadf_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageF32(load_internal(buffer, width, height, actual_depth))
            }
        } else {
            let buffer = stbi_load_from_memory(buffer.as_ptr(),
                                               buffer.len() as c_int,
                                               &mut width,
                                               &mut height,
                                               &mut depth,
                                               force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_load_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageU8(load_internal(buffer, width, height, actual_depth))
            }
        }
    }
}
<commit_msg>Updated to latest Rust: ~str -> StrBuf<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use stb_image::bindgen::*;

use std::any::Any;
use libc;
use libc::{c_void, c_int};
use std::slice::raw::buf_as_slice;

pub struct Image<T> {
    pub width   : uint,
    pub height  : uint,
    pub depth   : uint,
    pub data    : Vec<T>,
}

pub fn new_image<T>(width: uint, height: uint, depth: uint, data: Vec<T>) -> Image<T> {
    Image::<T> {
        width   : width,
        height  : height,
        depth   : depth,
        data    : data,
    }
}

pub enum LoadResult {
    Error(StrBuf),
    ImageU8(Image<u8>),
    ImageF32(Image<f32>),
}

impl LoadResult {
    pub fn from_result(res: Result<LoadResult,Box<Any>>)-> LoadResult {
        match res {
            Ok(res) => res,
            Err(e)  => Error(e.to_str()),
        }
    }
}

pub fn load(path: &Path) -> LoadResult {
    let force_depth = 0;
    load_with_depth(path, force_depth, false)
}

fn load_internal<T: Clone>(buf : *T, w : c_int, h : c_int, d : c_int) -> Image<T> {
    unsafe {
        // FIXME: Shouldn't copy; instead we should use a sendable resource. They
        // aren't particularly safe yet though.
        let data = buf_as_slice(buf, (w * h * d) as uint, |s| { Vec::from_slice(s) });
        libc::free(buf as *mut c_void);
        Image::<T>{
            width   : w as uint,
            height  : h as uint,
            depth   : d as uint,
            data    : data}
    }
}

pub fn load_with_depth(path: &Path, force_depth: uint, convert_hdr: bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        let path_as_str = match path.as_str() {
            Some(s) => s,
            None => return Error("path is not valid utf8".to_owned()),
        };
        path_as_str.with_c_str(|bytes| {
            if !convert_hdr && stbi_is_hdr(bytes)!=0   {
                let buffer = stbi_loadf(bytes,
                                        &mut width,
                                        &mut height,
                                        &mut depth,
                                        force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_loadf failed".to_owned())
                } else {
                    ImageF32(load_internal(buffer, width, height, depth))
                }
            } else {
                let buffer = stbi_load(bytes,
                                       &mut width,
                                       &mut height,
                                       &mut depth,
                                       force_depth as c_int);
                if buffer.is_null() {
                    Error("stbi_load failed".to_owned())
                } else {
                    ImageU8(load_internal(buffer, width, height, depth))
                }
            }
        })
    }
}

pub fn load_from_memory(buffer: &[u8]) -> LoadResult {
    let force_depth = 0;
    load_from_memory_with_depth(buffer, force_depth, false)
}

pub fn load_from_memory_with_depth(buffer: &[u8], force_depth: uint, convert_hdr:bool) -> LoadResult {
    unsafe {
        let mut width = 0 as c_int;
        let mut height = 0 as c_int;
        let mut depth = 0 as c_int;
        if !convert_hdr && stbi_is_hdr_from_memory(buffer.as_ptr(), buffer.len() as c_int) != 0 {
            let buffer = stbi_loadf_from_memory(buffer.as_ptr(),
                                                buffer.len() as c_int,
                                                &mut width,
                                                &mut height,
                                                &mut depth,
                                                force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_loadf_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageF32(load_internal(buffer, width, height, actual_depth))
            }
        } else {
            let buffer = stbi_load_from_memory(buffer.as_ptr(),
                                               buffer.len() as c_int,
                                               &mut width,
                                               &mut height,
                                               &mut depth,
                                               force_depth as c_int);
            if buffer.is_null() {
                Error("stbi_load_from_memory failed".to_owned())
            } else {
                let actual_depth = if force_depth != 0 { force_depth as c_int } else { depth };
                ImageU8(load_internal(buffer, width, height, actual_depth))
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Hook into libgraphviz for rendering dataflow graphs for MIR.

use rustc_hir::def_id::DefId;
use rustc_middle::mir::{BasicBlock, Body};

use std::fs;
use std::io;
use std::marker::PhantomData;
use std::path::Path;

use crate::util::graphviz_safe_def_name;

use super::DataflowBuilder;
use super::DebugFormatted;
use super::{BitDenotation, DataflowState};

pub trait MirWithFlowState<'tcx> {
    type BD: BitDenotation<'tcx>;
    fn def_id(&self) -> DefId;
    fn body(&self) -> &Body<'tcx>;
    fn flow_state(&self) -> &DataflowState<'tcx, Self::BD>;
}

impl<'a, 'tcx, BD> MirWithFlowState<'tcx> for DataflowBuilder<'a, 'tcx, BD>
where
    BD: BitDenotation<'tcx>,
{
    type BD = BD;
    fn def_id(&self) -> DefId {
        self.def_id
    }
    fn body(&self) -> &Body<'tcx> {
        self.flow_state.body()
    }
    fn flow_state(&self) -> &DataflowState<'tcx, Self::BD> {
        &self.flow_state.flow_state
    }
}

struct Graph<'a, 'tcx, MWF, P>
where
    MWF: MirWithFlowState<'tcx>,
{
    mbcx: &'a MWF,
    phantom: PhantomData<&'tcx ()>,
    render_idx: P,
}

pub(crate) fn print_borrowck_graph_to<'a, 'tcx, BD, P>(
    mbcx: &DataflowBuilder<'a, 'tcx, BD>,
    path: &Path,
    render_idx: P,
) -> io::Result<()>
where
    BD: BitDenotation<'tcx>,
    P: Fn(&BD, BD::Idx) -> DebugFormatted,
{
    let g = Graph { mbcx, phantom: PhantomData, render_idx };
    let mut v = Vec::new();
    dot::render(&g, &mut v)?;
    debug!("print_borrowck_graph_to path: {} def_id: {:?}", path.display(), mbcx.def_id);
    fs::write(path, v)
}

pub type Node = BasicBlock;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub struct Edge {
    source: BasicBlock,
    index: usize,
}

fn outgoing(body: &Body<'_>, bb: BasicBlock) -> Vec<Edge> {
    (0..body[bb].terminator().successors().count())
        .map(|index| Edge { source: bb, index })
        .collect()
}

impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
where
    MWF: MirWithFlowState<'tcx>,
    P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
{
    type Node = Node;
    type Edge = Edge;
    fn graph_id(&self) -> dot::Id<'_> {
        let name = graphviz_safe_def_name(self.mbcx.def_id());
        dot::Id::new(format!("graph_for_def_id_{}", name)).unwrap()
    }

    fn node_id(&self, n: &Node) -> dot::Id<'_> {
        dot::Id::new(format!("bb_{}", n.index())).unwrap()
    }

    fn node_label(&self, n: &Node) -> dot::LabelText<'_> {
        // Node label is something like this:
        // +---------+----------------------------------+------------------+------------------+
        // | ENTRY   | MIR                              | GEN              | KILL             |
        // +---------+----------------------------------+------------------+------------------+
        // |         |  0: StorageLive(_7)              | bb3[2]: reserved | bb2[0]: reserved |
        // |         |  1: StorageLive(_8)              | bb3[2]: active   | bb2[0]: active   |
        // |         |  2: _8 = &mut _1                 |                  | bb4[2]: reserved |
        // |         |                                  |                  | bb4[2]: active   |
        // |         |                                  |                  | bb9[0]: reserved |
        // |         |                                  |                  | bb9[0]: active   |
        // |         |                                  |                  | bb10[0]: reserved|
        // |         |                                  |                  | bb10[0]: active  |
        // |         |                                  |                  | bb11[0]: reserved|
        // |         |                                  |                  | bb11[0]: active  |
        // +---------+----------------------------------+------------------+------------------+
        // | [00-00] | _7 = const Foo::twiddle(move _8) | [0c-00]          | [f3-0f]          |
        // +---------+----------------------------------+------------------+------------------+
        let mut v = Vec::new();
        self.node_label_internal(n, &mut v, *n, self.mbcx.body()).unwrap();
        dot::LabelText::html(String::from_utf8(v).unwrap())
    }

    fn node_shape(&self, _n: &Node) -> Option<dot::LabelText<'_>> {
        Some(dot::LabelText::label("none"))
    }

    fn edge_label(&'a self, e: &Edge) -> dot::LabelText<'a> {
        let term = self.mbcx.body()[e.source].terminator();
        let label = &term.kind.fmt_successor_labels()[e.index];
        dot::LabelText::label(label.clone())
    }
}

impl<'a, 'tcx, MWF, P> Graph<'a, 'tcx, MWF, P>
where
    MWF: MirWithFlowState<'tcx>,
    P: Fn(&MWF::BD, <MWF::BD as BitDenotation<'tcx>>::Idx) -> DebugFormatted,
{
    /// Generate the node label
    fn node_label_internal<W: io::Write>(
        &self,
        n: &Node,
        w: &mut W,
        block: BasicBlock,
        body: &Body<'_>,
    ) -> io::Result<()> {
        // Header rows
        const HDRS: [&str; 4] = ["ENTRY", "MIR", "BLOCK GENS", "BLOCK KILLS"];
        const HDR_FMT: &str = "bgcolor=\"grey\"";
        write!(w, "

", HDRS.len())?;
        write!(w, "{:?}", block.index())?;
        write!(w, "

")?;
        for hdr in &HDRS {
            write!(w, "{}	", HDR_FMT, hdr)?;
        }
        write!(w, "
")?;

        // Data row
        self.node_label_verbose_row(n, w, block, body)?;
        self.node_label_final_row(n, w, block, body)?;
        write!(w, "
")?;

        Ok(())
    }

    /// Builds the verbose row: full MIR data, and detailed gen/kill/entry sets.
    fn node_label_verbose_row<W: io::Write>(
        &self,
        n: &Node,
        w: &mut W,
        block: BasicBlock,
        body: &Body<'_>,
    ) -> io::Result<()> {
        let i = n.index();

        macro_rules! dump_set_for {
            ($set:ident, $interpret:ident) => {
                write!(w, "")?;

                let flow = self.mbcx.flow_state();
                let entry_interp =
                    flow.$interpret(&flow.operator, flow.sets.$set(i), &self.render_idx);
                for e in &entry_interp {
                    write!(w, "{:?}
", e)?;
                }
                write!(w, "	")?;
            };
        }

        write!(w, "
")?;
        // Entry
        dump_set_for!(entry_set_for, interpret_set);

        // MIR statements
        write!(w, "")?;
        {
            let data = &body[block];
            for (i, statement) in data.statements.iter().enumerate() {
                write!(
                    w,
                    "{}
",
                    dot::escape_html(&format!("{:3}: {:?}", i, statement))
                )?;
            }
        }
        write!(w, "	")?;

        // Gen
        dump_set_for!(gen_set_for, interpret_hybrid_set);

        // Kill
        dump_set_for!(kill_set_for, interpret_hybrid_set);

        write!(w, "
")?;

        Ok(())
    }

    /// Builds the summary row: terminator, gen/kill/entry bit sets.
    fn node_label_final_row<W: io::Write>(
        &self,
        n: &Node,
        w: &mut W,
        block: BasicBlock,
        body: &Body<'_>,
    ) -> io::Result<()> {
        let i = n.index();

        let flow = self.mbcx.flow_state();

        write!(w, "
")?;

        // Entry
        let set = flow.sets.entry_set_for(i);
        write!(w, "{:?}	", dot::escape_html(&set.to_string()))?;

        // Terminator
        write!(w, "")?;
        {
            let data = &body[block];
            let mut terminator_head = String::new();
            data.terminator().kind.fmt_head(&mut terminator_head).unwrap();
            write!(w, "{}", dot::escape_html(&terminator_head))?;
        }
        write!(w, "	")?;

        // Gen/Kill
        let trans = flow.sets.trans_for(i);
        write!(w, "{:?}	", dot::escape_html(&format!("{:?}", trans.gen_set)))?;
        write!(w, "{:?}	", dot::escape_html(&format!("{:?}", trans.kill_set)))?;

        write!(w, "
")?;

        Ok(())
    }
}

impl<'a, 'tcx, MWF, P> dot::GraphWalk<'a> for Graph<'a, 'tcx, MWF, P>
where
    MWF: MirWithFlowState<'tcx>,
{
    type Node = Node;
    type Edge = Edge;
    fn nodes(&self) -> dot::Nodes<'_, Node> {
        self.mbcx.body().basic_blocks().indices().collect::<Vec<_>>().into()
    }

    fn edges(&self) -> dot::Edges<'_, Edge> {
        let body = self.mbcx.body();

        body.basic_blocks().indices().flat_map(|bb| outgoing(body, bb)).collect::<Vec<_>>().into()
    }

    fn source(&self, edge: &Edge) -> Node {
        edge.source
    }

    fn target(&self, edge: &Edge) -> Node {
        let body = self.mbcx.body();
        *body[edge.source].terminator().successors().nth(edge.index).unwrap()
    }
}
<commit_msg>Remove unused graphviz visualization<commit_after><|endoftext|>