<commit_before>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 std::sync::atomic::{AtomicI32, Ordering};
use std::time::Instant;
use libc;

const FUTEX_WAIT: i32 = 0;
const FUTEX_WAKE: i32 = 1;
const FUTEX_PRIVATE: i32 = 128;

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
    futex: AtomicI32,
}

impl ThreadParker {
    pub fn new() -> ThreadParker {
        ThreadParker {
            futex: AtomicI32::new(0),
        }
    }

    // Prepares the parker. This should be called before adding it to the queue.
    pub unsafe fn prepare_park(&self) {
        self.futex.store(1, Ordering::Relaxed);
    }

    // Checks if the park timed out. This should be called while holding the
    // queue lock after park_until has returned false.
    pub unsafe fn timed_out(&self) -> bool {
        self.futex.load(Ordering::Relaxed) != 0
    }

    // Parks the thread until it is unparked. This should be called after it has
    // been added to the queue, after unlocking the queue.
    pub unsafe fn park(&self) {
        while self.futex.load(Ordering::Acquire) != 0 {
            let r = libc::syscall(
                libc::SYS_futex,
                &self.futex,
                FUTEX_WAIT | FUTEX_PRIVATE,
                1,
                0,
            );
            debug_assert!(r == 0 || r == -1);
            if r == -1 {
                debug_assert!(
                    *libc::__errno_location() == libc::EINTR
                        || *libc::__errno_location() == libc::EAGAIN
                );
            }
        }
    }

    // Parks the thread until it is unparked or the timeout is reached. This
    // should be called after it has been added to the queue, after unlocking
    // the queue. Returns true if we were unparked and false if we timed out.
    pub unsafe fn park_until(&self, timeout: Instant) -> bool {
        while self.futex.load(Ordering::Acquire) != 0 {
            let now = Instant::now();
            if timeout <= now {
                return false;
            }
            let diff = timeout - now;
            if diff.as_secs() as libc::time_t as u64 != diff.as_secs() {
                // Timeout overflowed, just sleep indefinitely
                self.park();
                return true;
            }
            let ts = libc::timespec {
                tv_sec: diff.as_secs() as libc::time_t,
                tv_nsec: diff.subsec_nanos() as libc::c_long,
            };
            let r = libc::syscall(
                libc::SYS_futex,
                &self.futex,
                FUTEX_WAIT | FUTEX_PRIVATE,
                1,
                &ts,
            );
            debug_assert!(r == 0 || r == -1);
            if r == -1 {
                debug_assert!(
                    *libc::__errno_location() == libc::EINTR
                        || *libc::__errno_location() == libc::EAGAIN
                        || *libc::__errno_location() == libc::ETIMEDOUT
                );
            }
        }
        true
    }

    // Locks the parker to prevent the target thread from exiting. This is
    // necessary to ensure that thread-local ThreadData objects remain valid.
    // This should be called while holding the queue lock.
    pub unsafe fn unpark_lock(&self) -> UnparkHandle {
        // We don't need to lock anything, just clear the state
        self.futex.store(0, Ordering::Release);

        UnparkHandle { futex: &self.futex }
    }
}

// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle {
    futex: *const AtomicI32,
}

impl UnparkHandle {
    // Wakes up the parked thread. This should be called after the queue lock is
    // released to avoid blocking the queue for too long.
    pub unsafe fn unpark(self) {
        // The thread data may have been freed at this point, but it doesn't
        // matter since the syscall will just return EFAULT in that case.
        let r = libc::syscall(libc::SYS_futex, self.futex, FUTEX_WAKE | FUTEX_PRIVATE, 1);
        debug_assert!(r == 0 || r == 1 || r == -1);
        if r == -1 {
            debug_assert_eq!(*libc::__errno_location(), libc::EFAULT);
        }
    }
}
<commit_msg>Fix compilation issue on x32 Linux (wrong type for tv_nsec)<commit_after>// Copyright 2016 Amanieu d'Antras
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 std::sync::atomic::{AtomicI32, Ordering};
use std::time::Instant;
use libc;

const FUTEX_WAIT: i32 = 0;
const FUTEX_WAKE: i32 = 1;
const FUTEX_PRIVATE: i32 = 128;

// x32 Linux uses a non-standard type for tv_nsec in timespec.
// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437
#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))]
type tv_nsec_t = libc::i64;
#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))]
type tv_nsec_t = libc::c_long;

// Helper type for putting a thread to sleep until some other thread wakes it up
pub struct ThreadParker {
    futex: AtomicI32,
}

impl ThreadParker {
    pub fn new() -> ThreadParker {
        ThreadParker {
            futex: AtomicI32::new(0),
        }
    }

    // Prepares the parker. This should be called before adding it to the queue.
    pub unsafe fn prepare_park(&self) {
        self.futex.store(1, Ordering::Relaxed);
    }

    // Checks if the park timed out. This should be called while holding the
    // queue lock after park_until has returned false.
    pub unsafe fn timed_out(&self) -> bool {
        self.futex.load(Ordering::Relaxed) != 0
    }

    // Parks the thread until it is unparked. This should be called after it has
    // been added to the queue, after unlocking the queue.
    pub unsafe fn park(&self) {
        while self.futex.load(Ordering::Acquire) != 0 {
            let r = libc::syscall(
                libc::SYS_futex,
                &self.futex,
                FUTEX_WAIT | FUTEX_PRIVATE,
                1,
                0,
            );
            debug_assert!(r == 0 || r == -1);
            if r == -1 {
                debug_assert!(
                    *libc::__errno_location() == libc::EINTR
                        || *libc::__errno_location() == libc::EAGAIN
                );
            }
        }
    }

    // Parks the thread until it is unparked or the timeout is reached. This
    // should be called after it has been added to the queue, after unlocking
    // the queue. Returns true if we were unparked and false if we timed out.
    pub unsafe fn park_until(&self, timeout: Instant) -> bool {
        while self.futex.load(Ordering::Acquire) != 0 {
            let now = Instant::now();
            if timeout <= now {
                return false;
            }
            let diff = timeout - now;
            if diff.as_secs() as libc::time_t as u64 != diff.as_secs() {
                // Timeout overflowed, just sleep indefinitely
                self.park();
                return true;
            }
            let ts = libc::timespec {
                tv_sec: diff.as_secs() as libc::time_t,
                tv_nsec: diff.subsec_nanos() as tv_nsec_t,
            };
            let r = libc::syscall(
                libc::SYS_futex,
                &self.futex,
                FUTEX_WAIT | FUTEX_PRIVATE,
                1,
                &ts,
            );
            debug_assert!(r == 0 || r == -1);
            if r == -1 {
                debug_assert!(
                    *libc::__errno_location() == libc::EINTR
                        || *libc::__errno_location() == libc::EAGAIN
                        || *libc::__errno_location() == libc::ETIMEDOUT
                );
            }
        }
        true
    }

    // Locks the parker to prevent the target thread from exiting. This is
    // necessary to ensure that thread-local ThreadData objects remain valid.
    // This should be called while holding the queue lock.
    pub unsafe fn unpark_lock(&self) -> UnparkHandle {
        // We don't need to lock anything, just clear the state
        self.futex.store(0, Ordering::Release);

        UnparkHandle { futex: &self.futex }
    }
}

// Handle for a thread that is about to be unparked. We need to mark the thread
// as unparked while holding the queue lock, but we delay the actual unparking
// until after the queue lock is released.
pub struct UnparkHandle {
    futex: *const AtomicI32,
}

impl UnparkHandle {
    // Wakes up the parked thread. This should be called after the queue lock is
    // released to avoid blocking the queue for too long.
    pub unsafe fn unpark(self) {
        // The thread data may have been freed at this point, but it doesn't
        // matter since the syscall will just return EFAULT in that case.
        let r = libc::syscall(libc::SYS_futex, self.futex, FUTEX_WAKE | FUTEX_PRIVATE, 1);
        debug_assert!(r == 0 || r == 1 || r == -1);
        if r == -1 {
            debug_assert_eq!(*libc::__errno_location(), libc::EFAULT);
        }
    }
}
<|endoftext|>


<commit_before>//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
//! `OUT_DIR`.
//!
//! `proc-macro-test` itself contains only a path to that artifact.

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

use cargo_metadata::Message;

fn main() {
    println!("cargo:rerun-if-changed=imp");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir);

    let name = "proc-macro-test-impl";
    let version = "0.0.0";

    let imp_dir = std::env::current_dir().unwrap().join("imp");

    let staging_dir = out_dir.join("proc-macro-test-imp-staging");
    // this'll error out if the staging dir didn't previously exist. using
    // `std::fs::exists` would suffer from TOCTOU so just do our best to
    // wipe it and ignore errors.
    let _ = std::fs::remove_dir_all(&staging_dir);

    println!("Creating {}", staging_dir.display());
    std::fs::create_dir_all(&staging_dir).unwrap();

    let src_dir = staging_dir.join("src");
    println!("Creating {}", src_dir.display());
    std::fs::create_dir_all(src_dir).unwrap();

    for item_els in [&["Cargo.toml"][..], &["src", "lib.rs"]] {
        let mut src = imp_dir.clone();
        let mut dst = staging_dir.clone();
        for el in item_els {
            src.push(el);
            dst.push(el);
        }
        println!("Copying {} to {}", src.display(), dst.display());
        std::fs::copy(src, dst).unwrap();
    }

    let target_dir = out_dir.join("target");
    let output = Command::new(toolchain::cargo())
        .current_dir(&staging_dir)
        .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
        // Explicit override the target directory to avoid using the same one which the parent
        // cargo is using, or we'll deadlock.
        // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
        // instance to use the same target directory.
        .arg("--target-dir")
        .arg(&target_dir)
        .output()
        .unwrap();
    if !output.status.success() {
        println!("proc-macro-test-impl failed to build");
        println!("============ stdout ============");
        println!("{}", String::from_utf8_lossy(&output.stdout));
        println!("============ stderr ============");
        println!("{}", String::from_utf8_lossy(&output.stderr));
        panic!("proc-macro-test-impl failed to build");
    }

    let mut artifact_path = None;
    for message in Message::parse_stream(output.stdout.as_slice()) {
        match message.unwrap() {
            Message::CompilerArtifact(artifact) => {
                if artifact.target.kind.contains(&"proc-macro".to_string()) {
                    let repr = format!("{} {}", name, version);
                    if artifact.package_id.repr.starts_with(&repr) {
                        artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
                    }
                }
            }
            _ => (), // Unknown message
        }
    }

    // This file is under `target_dir` and is already under `OUT_DIR`.
    let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found");

    let info_path = out_dir.join("proc_macro_test_location.txt");
    fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
}
<commit_msg>Add PROC_MACRO_TEST_TOOLCHAIN environment variable<commit_after>//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
//! `OUT_DIR`.
//!
//! `proc-macro-test` itself contains only a path to that artifact.
//!
//! The `PROC_MACRO_TEST_TOOLCHAIN` environment variable can be exported to use
//! a specific rustup toolchain: this allows testing against older ABIs (e.g.
//! 1.58) and future ABIs (stage1, nightly)

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

use cargo_metadata::Message;

fn main() {
    println!("cargo:rerun-if-changed=imp");
    println!("cargo:rerun-if-env-changed=PROC_MACRO_TEST_TOOLCHAIN");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir);

    let name = "proc-macro-test-impl";
    let version = "0.0.0";

    let imp_dir = std::env::current_dir().unwrap().join("imp");

    let staging_dir = out_dir.join("proc-macro-test-imp-staging");
    // this'll error out if the staging dir didn't previously exist. using
    // `std::fs::exists` would suffer from TOCTOU so just do our best to
    // wipe it and ignore errors.
    let _ = std::fs::remove_dir_all(&staging_dir);

    println!("Creating {}", staging_dir.display());
    std::fs::create_dir_all(&staging_dir).unwrap();

    let src_dir = staging_dir.join("src");
    println!("Creating {}", src_dir.display());
    std::fs::create_dir_all(src_dir).unwrap();

    for item_els in [&["Cargo.toml"][..], &["src", "lib.rs"]] {
        let mut src = imp_dir.clone();
        let mut dst = staging_dir.clone();
        for el in item_els {
            src.push(el);
            dst.push(el);
        }
        println!("Copying {} to {}", src.display(), dst.display());
        std::fs::copy(src, dst).unwrap();
    }

    let target_dir = out_dir.join("target");

    let mut cmd = if let Ok(toolchain) = std::env::var("PROC_MACRO_TEST_TOOLCHAIN") {
        // leverage rustup to find user-specific toolchain
        let mut cmd = Command::new("cargo");
        cmd.arg(format!("+{toolchain}"));
        cmd
    } else {
        Command::new(toolchain::cargo())
    };

    let output = cmd
        .current_dir(&staging_dir)
        .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
        // Explicit override the target directory to avoid using the same one which the parent
        // cargo is using, or we'll deadlock.
        // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
        // instance to use the same target directory.
        .arg("--target-dir")
        .arg(&target_dir)
        .output()
        .unwrap();
    if !output.status.success() {
        println!("proc-macro-test-impl failed to build");
        println!("============ stdout ============");
        println!("{}", String::from_utf8_lossy(&output.stdout));
        println!("============ stderr ============");
        println!("{}", String::from_utf8_lossy(&output.stderr));
        panic!("proc-macro-test-impl failed to build");
    }

    let mut artifact_path = None;
    for message in Message::parse_stream(output.stdout.as_slice()) {
        match message.unwrap() {
            Message::CompilerArtifact(artifact) => {
                if artifact.target.kind.contains(&"proc-macro".to_string()) {
                    let repr = format!("{} {}", name, version);
                    if artifact.package_id.repr.starts_with(&repr) {
                        artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
                    }
                }
            }
            _ => (), // Unknown message
        }
    }

    // This file is under `target_dir` and is already under `OUT_DIR`.
    let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found");

    let info_path = out_dir.join("proc_macro_test_location.txt");
    fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
}
<|endoftext|>


<commit_before>//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
//! `OUT_DIR`.
//!
//! `proc-macro-test` itself contains only a path to that artifact.

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

use cargo_metadata::Message;

fn main() {
    let out_dir = env::var_os("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir);

    let name = "proc-macro-test-impl";
    let version = "0.0.0";

    let imp_dir = std::env::current_dir().unwrap().join("imp");
    let staging_dir = out_dir.join("staging");
    std::fs::create_dir_all(&staging_dir).unwrap();
    std::fs::create_dir_all(staging_dir.join("src")).unwrap();

    for item_els in [&["Cargo.toml"][..], &["Cargo.lock"], &["src", "lib.rs"]] {
        let mut src = imp_dir.clone();
        let mut dst = staging_dir.clone();
        for el in item_els {
            src.push(el);
            dst.push(el);
        }
        std::fs::copy(src, dst).unwrap();
    }

    let target_dir = out_dir.join("target");
    let output = Command::new(toolchain::cargo())
        .current_dir(&staging_dir)
        .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
        // Explicit override the target directory to avoid using the same one which the parent
        // cargo is using, or we'll deadlock.
        // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
        // instance to use the same target directory.
        .arg("--target-dir")
        .arg(&target_dir)
        .output()
        .unwrap();
    if !output.status.success() {
        println!("proc-macro-test-impl failed to build");
        println!("============ stdout ============");
        println!("{}", String::from_utf8_lossy(&output.stdout));
        println!("============ stderr ============");
        println!("{}", String::from_utf8_lossy(&output.stderr));
        panic!("proc-macro-test-impl failed to build");
    }

    let mut artifact_path = None;
    for message in Message::parse_stream(output.stdout.as_slice()) {
        match message.unwrap() {
            Message::CompilerArtifact(artifact) => {
                if artifact.target.kind.contains(&"proc-macro".to_string()) {
                    let repr = format!("{} {}", name, version);
                    if artifact.package_id.repr.starts_with(&repr) {
                        artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
                    }
                }
            }
            _ => (), // Unknown message
        }
    }

    // This file is under `target_dir` and is already under `OUT_DIR`.
    let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found");

    let info_path = out_dir.join("proc_macro_test_location.txt");
    fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
}
<commit_msg>proc-macro-test build script: wipe before, be more verbose<commit_after>//! This will build the proc macro in `imp`, and copy the resulting dylib artifact into the
//! `OUT_DIR`.
//!
//! `proc-macro-test` itself contains only a path to that artifact.

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

use cargo_metadata::Message;

fn main() {
    println!("cargo:rerun-if-changed=imp");

    let out_dir = env::var_os("OUT_DIR").unwrap();
    let out_dir = Path::new(&out_dir);

    let name = "proc-macro-test-impl";
    let version = "0.0.0";

    let imp_dir = std::env::current_dir().unwrap().join("imp");

    let staging_dir = out_dir.join("proc-macro-test-imp-staging");
    // this'll error out if the staging dir didn't previously. using
    // `std::fs::exists` would suffer from TOCTOU so just do our best to
    // wip it and ignore errors.
    let _ = std::fs::remove_dir_all(&staging_dir);

    println!("Creating {}", staging_dir.display());
    std::fs::create_dir_all(&staging_dir).unwrap();

    let src_dir = staging_dir.join("src");
    println!("Creating {}", src_dir.display());
    std::fs::create_dir_all(src_dir).unwrap();

    for item_els in [&["Cargo.toml"][..], &["Cargo.lock"], &["src", "lib.rs"]] {
        let mut src = imp_dir.clone();
        let mut dst = staging_dir.clone();
        for el in item_els {
            src.push(el);
            dst.push(el);
        }
        println!("Copying {} to {}", src.display(), dst.display());
        std::fs::copy(src, dst).unwrap();
    }

    let target_dir = out_dir.join("target");
    let output = Command::new(toolchain::cargo())
        .current_dir(&staging_dir)
        .args(&["build", "-p", "proc-macro-test-impl", "--message-format", "json"])
        // Explicit override the target directory to avoid using the same one which the parent
        // cargo is using, or we'll deadlock.
        // This can happen when `CARGO_TARGET_DIR` is set or global config forces all cargo
        // instance to use the same target directory.
        .arg("--target-dir")
        .arg(&target_dir)
        .output()
        .unwrap();
    if !output.status.success() {
        println!("proc-macro-test-impl failed to build");
        println!("============ stdout ============");
        println!("{}", String::from_utf8_lossy(&output.stdout));
        println!("============ stderr ============");
        println!("{}", String::from_utf8_lossy(&output.stderr));
        panic!("proc-macro-test-impl failed to build");
    }

    let mut artifact_path = None;
    for message in Message::parse_stream(output.stdout.as_slice()) {
        match message.unwrap() {
            Message::CompilerArtifact(artifact) => {
                if artifact.target.kind.contains(&"proc-macro".to_string()) {
                    let repr = format!("{} {}", name, version);
                    if artifact.package_id.repr.starts_with(&repr) {
                        artifact_path = Some(PathBuf::from(&artifact.filenames[0]));
                    }
                }
            }
            _ => (), // Unknown message
        }
    }

    // This file is under `target_dir` and is already under `OUT_DIR`.
    let artifact_path = artifact_path.expect("no dylib for proc-macro-test-impl found");

    let info_path = out_dir.join("proc_macro_test_location.txt");
    fs::write(info_path, artifact_path.to_str().unwrap()).unwrap();
}
<|endoftext|>


<commit_before>//! Loads "sysroot" crate.
//!
//! One confusing point here is that normally sysroot is a bunch of `.rlib`s,
//! but we can't process `.rlib` and need source code instead. The source code
//! is typically installed with `rustup component add rust-src` command.

use std::{convert::TryFrom, env, ops, path::PathBuf, process::Command};

use anyhow::{format_err, Result};
use arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};

use crate::utf8_stdout;

#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct Sysroot {
    crates: Arena<SysrootCrateData>,
}

pub type SysrootCrate = Idx<SysrootCrateData>;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SysrootCrateData {
    pub name: String,
    pub root: AbsPathBuf,
    pub deps: Vec<SysrootCrate>,
}

impl ops::Index<SysrootCrate> for Sysroot {
    type Output = SysrootCrateData;
    fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
        &self.crates[index]
    }
}

impl Sysroot {
    pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate)> + '_ {
        // core is added as a dependency before std in order to
        // mimic rustcs dependency order
        vec!["core", "alloc", "std"].into_iter().filter_map(move |it| Some((it, self.by_name(it)?)))
    }

    pub fn proc_macro(&self) -> Option<SysrootCrate> {
        self.by_name("proc_macro")
    }

    pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
        self.crates.iter().map(|(id, _data)| id)
    }

    pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
        let current_dir = cargo_toml.parent().unwrap();
        let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?;
        let res = Sysroot::load(&sysroot_src_dir)?;
        Ok(res)
    }

    pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
        let mut sysroot = Sysroot { crates: Arena::default() };

        for name in SYSROOT_CRATES.trim().lines() {
            // FIXME: first path when 1.47 comes out
            // https://github.com/rust-lang/rust/pull/73265
            let root = [format!("lib{}/lib.rs", name), format!("{}/src/lib.rs", name)]
                .iter()
                .map(|it| sysroot_src_dir.join(it))
                .find(|it| it.exists());

            if let Some(root) = root {
                sysroot.crates.alloc(SysrootCrateData {
                    name: name.into(),
                    root,
                    deps: Vec::new(),
                });
            }
        }

        if let Some(std) = sysroot.by_name("std") {
            for dep in STD_DEPS.trim().lines() {
                if let Some(dep) = sysroot.by_name(dep) {
                    sysroot.crates[std].deps.push(dep)
                }
            }
        }

        if let Some(alloc) = sysroot.by_name("alloc") {
            if let Some(core) = sysroot.by_name("core") {
                sysroot.crates[alloc].deps.push(core);
            }
        }

        if sysroot.by_name("core").is_none() {
            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
            } else {
                ""
            };
            anyhow::bail!(
                "could not find libcore in sysroot path `{}`{}",
                sysroot_src_dir.as_ref().display(),
                var_note,
            );
        }

        Ok(sysroot)
    }

    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
        let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
        Some(id)
    }
}

fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
    if let Ok(path) = env::var("RUST_SRC_PATH") {
        let path = AbsPathBuf::try_from(path.as_str())
            .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
        return Ok(path);
    }

    let sysroot_path = {
        let mut rustc = Command::new(toolchain::rustc());
        rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
        let stdout = utf8_stdout(rustc)?;
        AbsPathBuf::assert(PathBuf::from(stdout))
    };

    get_rust_src(&sysroot_path)
        .or_else(|| {
            let mut rustup = Command::new(toolchain::rustup());
            rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
            utf8_stdout(rustup).ok()?;
            get_rust_src(&sysroot_path)
        })
        .ok_or_else(|| {
            format_err!(
                "\
can't load standard library from sysroot
{}
(discovered via `rustc --print sysroot`)
try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
                sysroot_path.display(),
            )
        })
}

fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
    // Try the new path first since the old one still exists.
    //
    // FIXME: remove `src` when 1.47 comes out
    // https://github.com/rust-lang/rust/pull/73265
    let rust_src = sysroot_path.join("lib/rustlib/src/rust");
    ["library", "src"].iter().map(|it| rust_src.join(it)).find(|it| it.exists())
}

impl SysrootCrateData {
    pub fn root_dir(&self) -> &AbsPath {
        self.root.parent().unwrap()
    }
}

const SYSROOT_CRATES: &str = "
alloc
core
panic_abort
panic_unwind
proc_macro
profiler_builtins
rtstartup
std
stdarch
term
test
unwind";

const STD_DEPS: &str = "
alloc
core
panic_abort
panic_unwind
profiler_builtins
rtstartup
proc_macro
stdarch
term
test
unwind";
<commit_msg>Log around sysroot discovery<commit_after>//! Loads "sysroot" crate.
//!
//! One confusing point here is that normally sysroot is a bunch of `.rlib`s,
//! but we can't process `.rlib` and need source code instead. The source code
//! is typically installed with `rustup component add rust-src` command.

use std::{convert::TryFrom, env, ops, path::PathBuf, process::Command};

use anyhow::{format_err, Result};
use arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};

use crate::utf8_stdout;

#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct Sysroot {
    crates: Arena<SysrootCrateData>,
}

pub type SysrootCrate = Idx<SysrootCrateData>;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SysrootCrateData {
    pub name: String,
    pub root: AbsPathBuf,
    pub deps: Vec<SysrootCrate>,
}

impl ops::Index<SysrootCrate> for Sysroot {
    type Output = SysrootCrateData;
    fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
        &self.crates[index]
    }
}

impl Sysroot {
    pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate)> + '_ {
        // core is added as a dependency before std in order to
        // mimic rustcs dependency order
        vec!["core", "alloc", "std"].into_iter().filter_map(move |it| Some((it, self.by_name(it)?)))
    }

    pub fn proc_macro(&self) -> Option<SysrootCrate> {
        self.by_name("proc_macro")
    }

    pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
        self.crates.iter().map(|(id, _data)| id)
    }

    pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
        log::debug!("Discovering sysroot for {}", cargo_toml.display());
        let current_dir = cargo_toml.parent().unwrap();
        let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?;
        let res = Sysroot::load(&sysroot_src_dir)?;
        Ok(res)
    }

    pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
        let mut sysroot = Sysroot { crates: Arena::default() };

        for name in SYSROOT_CRATES.trim().lines() {
            // FIXME: first path when 1.47 comes out
            // https://github.com/rust-lang/rust/pull/73265
            let root = [format!("lib{}/lib.rs", name), format!("{}/src/lib.rs", name)]
                .iter()
                .map(|it| sysroot_src_dir.join(it))
                .find(|it| it.exists());

            if let Some(root) = root {
                sysroot.crates.alloc(SysrootCrateData {
                    name: name.into(),
                    root,
                    deps: Vec::new(),
                });
            }
        }

        if let Some(std) = sysroot.by_name("std") {
            for dep in STD_DEPS.trim().lines() {
                if let Some(dep) = sysroot.by_name(dep) {
                    sysroot.crates[std].deps.push(dep)
                }
            }
        }

        if let Some(alloc) = sysroot.by_name("alloc") {
            if let Some(core) = sysroot.by_name("core") {
                sysroot.crates[alloc].deps.push(core);
            }
        }

        if sysroot.by_name("core").is_none() {
            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
            } else {
                ""
            };
            anyhow::bail!(
                "could not find libcore in sysroot path `{}`{}",
                sysroot_src_dir.as_ref().display(),
                var_note,
            );
        }

        Ok(sysroot)
    }

    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
        let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
        Some(id)
    }
}

fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
    if let Ok(path) = env::var("RUST_SRC_PATH") {
        let path = AbsPathBuf::try_from(path.as_str())
            .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
        log::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
        return Ok(path);
    }

    let sysroot_path = {
        let mut rustc = Command::new(toolchain::rustc());
        rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
        log::debug!("Discovering sysroot by {:?}", rustc);
        let stdout = utf8_stdout(rustc)?;
        AbsPathBuf::assert(PathBuf::from(stdout))
    };

    get_rust_src(&sysroot_path)
        .or_else(|| {
            let mut rustup = Command::new(toolchain::rustup());
            rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
            utf8_stdout(rustup).ok()?;
            get_rust_src(&sysroot_path)
        })
        .ok_or_else(|| {
            format_err!(
                "\
can't load standard library from sysroot
{}
(discovered via `rustc --print sysroot`)
try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
                sysroot_path.display(),
            )
        })
}

fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
    // Try the new path first since the old one still exists.
    //
    // FIXME: remove `src` when 1.47 comes out
    // https://github.com/rust-lang/rust/pull/73265
    let rust_src = sysroot_path.join("lib/rustlib/src/rust");
    log::debug!("Checking sysroot (looking for `library` and `src` dirs): {}", rust_src.display());
    ["library", "src"].iter().map(|it| rust_src.join(it)).find(|it| it.exists())
}

impl SysrootCrateData {
    pub fn root_dir(&self) -> &AbsPath {
        self.root.parent().unwrap()
    }
}

const SYSROOT_CRATES: &str = "
alloc
core
panic_abort
panic_unwind
proc_macro
profiler_builtins
rtstartup
std
stdarch
term
test
unwind";

const STD_DEPS: &str = "
alloc
core
panic_abort
panic_unwind
profiler_builtins
rtstartup
proc_macro
stdarch
term
test
unwind";
<|endoftext|>


<commit_before>use std::{collections::HashSet, time::Instant, fmt::Write};

use ra_db::SourceDatabase;
use ra_batch::BatchDatabase;
use ra_hir::{Crate, ModuleDef, Ty, ImplItem};
use ra_syntax::AstNode;

use crate::Result;

pub fn run(verbose: bool, path: &str, only: Option<&str>) -> Result<()> {
    let db_load_time = Instant::now();
    let (db, roots) = BatchDatabase::load_cargo(path)?;
    println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
    let analysis_time = Instant::now();
    let mut num_crates = 0;
    let mut visited_modules = HashSet::new();
    let mut visit_queue = Vec::new();
    for root in roots {
        for krate in Crate::source_root_crates(&db, root) {
            num_crates += 1;
            let module = krate.root_module(&db).expect("crate in source root without root module");
            visit_queue.push(module);
        }
    }
    println!("Crates in this dir: {}", num_crates);
    let mut num_decls = 0;
    let mut funcs = Vec::new();
    while let Some(module) = visit_queue.pop() {
        if visited_modules.insert(module) {
            visit_queue.extend(module.children(&db));

            for decl in module.declarations(&db) {
                num_decls += 1;
                match decl {
                    ModuleDef::Function(f) => funcs.push(f),
                    _ => {}
                }
            }

            for impl_block in module.impl_blocks(&db) {
                for item in impl_block.items(&db) {
                    num_decls += 1;
                    match item {
                        ImplItem::Method(f) => funcs.push(f),
                        _ => {}
                    }
                }
            }
        }
    }
    println!("Total modules found: {}", visited_modules.len());
    println!("Total declarations: {}", num_decls);
    println!("Total functions: {}", funcs.len());
    let bar = indicatif::ProgressBar::new(funcs.len() as u64);
    bar.set_style(
        indicatif::ProgressStyle::default_bar().template("{wide_bar} {pos}/{len}\n{msg}"),
    );
    bar.tick();
    let mut num_exprs = 0;
    let mut num_exprs_unknown = 0;
    let mut num_exprs_partially_unknown = 0;
    for f in funcs {
        let name = f.name(&db);
        let mut msg = format!("processing: {}", name);
        if verbose {
            let (file_id, source) = f.source(&db);
            let original_file = file_id.original_file(&db);
            let path = db.file_relative_path(original_file);
            let syntax_range = source.syntax().range();
            write!(msg, " ({:?} {})", path, syntax_range).unwrap();
        }
        bar.set_message(&msg);
        if let Some(only_name) = only {
            if name.to_string() != only_name {
                continue;
            }
        }
        let body = f.body(&db);
        let inference_result = f.infer(&db);
        for (expr_id, _) in body.exprs() {
            let ty = &inference_result[expr_id];
            num_exprs += 1;
            if let Ty::Unknown = ty {
                num_exprs_unknown += 1;
            } else {
                let mut is_partially_unknown = false;
                ty.walk(&mut |ty| {
                    if let Ty::Unknown = ty {
                        is_partially_unknown = true;
                    }
                });
                if is_partially_unknown {
                    num_exprs_partially_unknown += 1;
                }
            }
        }
        bar.inc(1);
    }
    bar.finish_and_clear();
    println!("Total expressions: {}", num_exprs);
    println!(
        "Expressions of unknown type: {} ({}%)",
        num_exprs_unknown,
        (num_exprs_unknown * 100 / num_exprs)
    );
    println!(
        "Expressions of partially unknown type: {} ({}%)",
        num_exprs_partially_unknown,
        (num_exprs_partially_unknown * 100 / num_exprs)
    );
    println!("Analysis: {:?}", analysis_time.elapsed());
    Ok(())
}
<commit_msg>output the progress for real<commit_after>use std::{collections::HashSet, time::Instant, fmt::Write};

use ra_db::SourceDatabase;
use ra_batch::BatchDatabase;
use ra_hir::{Crate, ModuleDef, Ty, ImplItem};
use ra_syntax::AstNode;

use crate::Result;

pub fn run(verbose: bool, path: &str, only: Option<&str>) -> Result<()> {
    let db_load_time = Instant::now();
    let (db, roots) = BatchDatabase::load_cargo(path)?;
    println!("Database loaded, {} roots, {:?}", roots.len(), db_load_time.elapsed());
    let analysis_time = Instant::now();
    let mut num_crates = 0;
    let mut visited_modules = HashSet::new();
    let mut visit_queue = Vec::new();
    for root in roots {
        for krate in Crate::source_root_crates(&db, root) {
            num_crates += 1;
            let module = krate.root_module(&db).expect("crate in source root without root module");
            visit_queue.push(module);
        }
    }
    println!("Crates in this dir: {}", num_crates);
    let mut num_decls = 0;
    let mut funcs = Vec::new();
    while let Some(module) = visit_queue.pop() {
        if visited_modules.insert(module) {
            visit_queue.extend(module.children(&db));

            for decl in module.declarations(&db) {
                num_decls += 1;
                match decl {
                    ModuleDef::Function(f) => funcs.push(f),
                    _ => {}
                }
            }

            for impl_block in module.impl_blocks(&db) {
                for item in impl_block.items(&db) {
                    num_decls += 1;
                    match item {
                        ImplItem::Method(f) => funcs.push(f),
                        _ => {}
                    }
                }
            }
        }
    }
    println!("Total modules found: {}", visited_modules.len());
    println!("Total declarations: {}", num_decls);
    println!("Total functions: {}", funcs.len());
    let bar = indicatif::ProgressBar::with_draw_target(
        funcs.len() as u64,
        indicatif::ProgressDrawTarget::stderr_nohz(),
    );
    bar.set_style(
        indicatif::ProgressStyle::default_bar().template("{wide_bar} {pos}/{len}\n{msg}"),
    );
    bar.tick();
    let mut num_exprs = 0;
    let mut num_exprs_unknown = 0;
    let mut num_exprs_partially_unknown = 0;
    for f in funcs {
        let name = f.name(&db);
        let mut msg = format!("processing: {}", name);
        if verbose {
            let (file_id, source) = f.source(&db);
            let original_file = file_id.original_file(&db);
            let path = db.file_relative_path(original_file);
            let syntax_range = source.syntax().range();
            write!(msg, " ({:?} {})", path, syntax_range).unwrap();
        }
        bar.set_message(&msg);
        if let Some(only_name) = only {
            if name.to_string() != only_name {
                continue;
            }
        }
        let body = f.body(&db);
        let inference_result = f.infer(&db);
        for (expr_id, _) in body.exprs() {
            let ty = &inference_result[expr_id];
            num_exprs += 1;
            if let Ty::Unknown = ty {
                num_exprs_unknown += 1;
            } else {
                let mut is_partially_unknown = false;
                ty.walk(&mut |ty| {
                    if let Ty::Unknown = ty {
                        is_partially_unknown = true;
                    }
                });
                if is_partially_unknown {
                    num_exprs_partially_unknown += 1;
                }
            }
        }
        bar.inc(1);
    }
    bar.finish_and_clear();
    println!("Total expressions: {}", num_exprs);
    println!(
        "Expressions of unknown type: {} ({}%)",
        num_exprs_unknown,
        (num_exprs_unknown * 100 / num_exprs)
    );
    println!(
        "Expressions of partially unknown type: {} ({}%)",
        num_exprs_partially_unknown,
        (num_exprs_partially_unknown * 100 / num_exprs)
    );
    println!("Analysis: {:?}", analysis_time.elapsed());
    Ok(())
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;

use std::vec::Vec;
use autograd::variable::*;
use RcMut;

pub struct Function<T> {
    saved_variables: Vec<SavedVariable<T>>,
    next_functions: Vec<(RcMut<Function<T>>, usize)>,
}
impl<T> Function<T> {
    pub fn new() -> Self {
        Function {
            saved_variables: Vec::new(),
            next_functions: Vec::new(),
        }
    }
    pub fn do_forward(&mut self,
                      func: &mut FuncIntf<T>,
                      mut args: &mut Vec<Variable<T>>)
                      -> Vec<Variable<T>> {
        // do start graph stuff
        let v = func.forward(&mut args);
        // do end graph stuff
        v
    }
}

pub trait FuncIntf<T> {
    fn delegate(&mut self) -> &mut Function<T>;
    fn forward(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    // Borrowing rules prevent this, but each FuncIntf implementer needs to implement
    // the following function:
    //    fn f(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
    //    	  self.delegate().do_forward(&mut self, input)
    //    }
}
<commit_msg>make f work<commit_after>use std::rc::Rc;
use std::cell::RefCell;

use std::vec::Vec;
use autograd::variable::*;
use RcMut;

pub struct Function<T> {
    saved_variables: Vec<SavedVariable<T>>,
    next_functions: Vec<(RcMut<Function<T>>, usize)>,
}
impl<T> Function<T> {
    pub fn new() -> Self {
        Function {
            saved_variables: Vec::new(),
            next_functions: Vec::new(),
        }
    }
}

pub trait FuncIntf<T> {
    fn delegate(&mut self) -> &mut Function<T>;
    fn forward(&mut self, input: &mut Vec<Variable<T>>) -> Vec<Variable<T>>;
    fn f(&mut self, mut input: &mut Vec<Variable<T>>) -> Vec<Variable<T>> {
        {
            let f = self.delegate();
        }
        // do start graph stuff with f
        let v = self.forward(&mut input);
        // do end graph stuff
        v
    }
}
<|endoftext|>


<commit_before>use hyper;
use hyper::StatusCode;
use chrono;
use std::io::Error as IOError;
use std::io::Read;
use std::num;
use xml::BuilderError as XMLError;
use url::ParseError as URLParseError;
use azure::core::enumerations::ParsingError;
use azure::core::range::ParseError;
use serde_json;
use futures::Future;
use futures::Stream;

#[derive(Debug, Clone, PartialEq)]
pub struct UnexpectedHTTPResult {
    expected: StatusCode,
    received: StatusCode,
    body: String,
}

impl UnexpectedHTTPResult {
    pub fn new(expected: StatusCode, received: StatusCode, body: &str) -> UnexpectedHTTPResult {
        UnexpectedHTTPResult {
            expected: expected,
            received: received,
            body: body.to_owned(),
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum AzureError {
        JSONError(err: serde_json::Error) {
            from()
            display("json error: {}", err)
            cause(err)
        }
        HyperError(err: hyper::error::Error){
            from()
            display("Hyper error: {}", err)
            cause(err)
        }
        IOError(err: IOError){
            from()
            display("IO error: {}", err)
            cause(err)
        }
        XMLError(err: XMLError){
            from()
            display("XML error: {}", err)
            cause(err)
        }
        UnexpectedHTTPResult(err: UnexpectedHTTPResult){
            from()
            display("UnexpectedHTTPResult error")
        }
        HeaderNotFound(msg: String) {
            display("Header not found: {}", msg)
        }
        ResponseParsingError(err: TraversingError){
            from()
            display("Traversing error: {}", err)
            cause(err)
        }
        ParseIntError(err: num::ParseIntError){
            from()
            display("Parse int error: {}", err)
            cause(err)
        }
        ParseError(err: ParseError){
            from()
            display("Parse error")
        }
        GenericError
        ParsingError(err: ParsingError){
            from()
            display("Parsing error")
        }
        InputParametersError(msg: String) {
            display("Input parameters error: {}", msg)
        }
        URLParseError(err: URLParseError){
            from()
            display("URL parse error: {}", err)
            cause(err)
        }
        URIParseError(err: hyper::error::UriError) {
            from()
            display("URI parse error: {}", err)
            cause(err)
        }
        ChronoParserError(err: chrono::ParseError) {
            from()
            display("Chrono parser error: {}", err)
            cause(err)
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum TraversingError {
        PathNotFound(msg: String) {
            display("Path not found: {}", msg)
        }
        MultipleNode(msg: String) {
            display("Multiple node: {}", msg)
        }
        EnumerationNotMatched(msg: String) {
            display("Enumeration not matched: {}", msg)
        }
        DateTimeParseError(err: chrono::format::ParseError){
            from()
            display("DateTime parse error: {}", err)
            cause(err)
        }
        TextNotFound
        ParseIntError(err: num::ParseIntError){
            from()
            display("Parse int error: {}", err)
            cause(err)
        }
        GenericParseError(msg: String) {
            display("Generic parse error: {}", msg)
        }
        ParsingError(err: ParsingError){
            from()
            display("Parsing error")
        }
    }
}

impl From<()> for AzureError {
    fn from(_: ()) -> AzureError {
        AzureError::GenericError
    }
}

#[inline]
pub fn check_status(
    resp: hyper::client::FutureResponse,
    s: StatusCode,
) -> Result<Future, AzureError> {

    resp.and_then(|res| if res.status() != s {
        let resp_s = res.body().concat2();
        return Err(AzureError::UnexpectedHTTPResult(
            UnexpectedHTTPResult::new(s, res.status(), &resp_s),
        ));
    });
    // let mut resp_s = String::new();
    //resp.read_to_string(&mut resp_s)?;

    //        return Err(AzureError::UnexpectedHTTPResult(UnexpectedHTTPResult::new(s,
    //                                                                         resp.status,
    //                                                                       &resp_s)));
    //  }

    Ok(())
}

pub fn check_status_extract_body(
    resp: &mut hyper::client::response::Response,
    s: StatusCode,
) -> Result<String, AzureError> {

    check_status(resp, s)?;

    let mut resp_s = String::new();
    resp.read_to_string(&mut resp_s)?;

    debug!("resp_s == {}", resp_s);

    Ok(resp_s)
}
<commit_msg>futures? :(<commit_after>use hyper;
use hyper::StatusCode;
use chrono;
use std::io::Error as IOError;
use std::io::Read;
use std::num;
use xml::BuilderError as XMLError;
use url::ParseError as URLParseError;
use azure::core::enumerations::ParsingError;
use azure::core::range::ParseError;
use serde_json;
use futures::Future;
use futures::Stream;

#[derive(Debug, Clone, PartialEq)]
pub struct UnexpectedHTTPResult {
    expected: StatusCode,
    received: StatusCode,
    body: String,
}

impl UnexpectedHTTPResult {
    pub fn new(expected: StatusCode, received: StatusCode, body: &str) -> UnexpectedHTTPResult {
        UnexpectedHTTPResult {
            expected: expected,
            received: received,
            body: body.to_owned(),
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum AzureError {
        JSONError(err: serde_json::Error) {
            from()
            display("json error: {}", err)
            cause(err)
        }
        HyperError(err: hyper::error::Error){
            from()
            display("Hyper error: {}", err)
            cause(err)
        }
        IOError(err: IOError){
            from()
            display("IO error: {}", err)
            cause(err)
        }
        XMLError(err: XMLError){
            from()
            display("XML error: {}", err)
            cause(err)
        }
        UnexpectedHTTPResult(err: UnexpectedHTTPResult){
            from()
            display("UnexpectedHTTPResult error")
        }
        HeaderNotFound(msg: String) {
            display("Header not found: {}", msg)
        }
        ResponseParsingError(err: TraversingError){
            from()
            display("Traversing error: {}", err)
            cause(err)
        }
        ParseIntError(err: num::ParseIntError){
            from()
            display("Parse int error: {}", err)
            cause(err)
        }
        ParseError(err: ParseError){
            from()
            display("Parse error")
        }
        GenericError
        ParsingError(err: ParsingError){
            from()
            display("Parsing error")
        }
        InputParametersError(msg: String) {
            display("Input parameters error: {}", msg)
        }
        URLParseError(err: URLParseError){
            from()
            display("URL parse error: {}", err)
            cause(err)
        }
        URIParseError(err: hyper::error::UriError) {
            from()
            display("URI parse error: {}", err)
            cause(err)
        }
        ChronoParserError(err: chrono::ParseError) {
            from()
            display("Chrono parser error: {}", err)
            cause(err)
        }
    }
}

quick_error! {
    #[derive(Debug)]
    pub enum TraversingError {
        PathNotFound(msg: String) {
            display("Path not found: {}", msg)
        }
        MultipleNode(msg: String) {
            display("Multiple node: {}", msg)
        }
        EnumerationNotMatched(msg: String) {
            display("Enumeration not matched: {}", msg)
        }
        DateTimeParseError(err: chrono::format::ParseError){
            from()
            display("DateTime parse error: {}", err)
            cause(err)
        }
        TextNotFound
        ParseIntError(err: num::ParseIntError){
            from()
            display("Parse int error: {}", err)
            cause(err)
        }
        GenericParseError(msg: String) {
            display("Generic parse error: {}", msg)
        }
        ParsingError(err: ParsingError){
            from()
            display("Parsing error")
        }
    }
}

impl From<()> for AzureError {
    fn from(_: ()) -> AzureError {
        AzureError::GenericError
    }
}

#[inline]
pub fn check_status(resp: hyper::client::FutureResponse,
                    s: StatusCode)
                    -> Box<Future<Item = (), Error = AzureError>> {

    resp.and_then(|res| if res.status() != s {
        let resp_s = res.body().concat2();
        return Err(AzureError::UnexpectedHTTPResult(UnexpectedHTTPResult::new(s,
                                                                              res.status(),
                                                                              &resp_s)));
    })
    // let mut resp_s = String::new();
    //resp.read_to_string(&mut resp_s)?;

    //        return Err(AzureError::UnexpectedHTTPResult(UnexpectedHTTPResult::new(s,
    //                                                                         resp.status,
    //                                                                       &resp_s)));
    //  }

    //Ok(())
}

pub fn check_status_extract_body(resp: &mut hyper::client::response::Response,
                                 s: StatusCode)
                                 -> Result<String, AzureError> {

    check_status(resp, s)?;

    let mut resp_s = String::new();
    resp.read_to_string(&mut resp_s)?;

    debug!("resp_s == {}", resp_s);

    Ok(resp_s)
}
<|endoftext|>


<commit_before>use std::io::prelude::*;
use std::fs::File;
use std::error::Error;
use std::io::BufWriter;

pub struct BitInputStream {
	buffer : u16,
	pos : usize,
	bits_in_buffer : i16,
	eof: bool,
	bytes : Vec<u8>,
	len : usize,
}

pub struct BitOutputStream {
	out : BufWriter<File>,
	buffer : u16,
	bits_in_buffer : i16,
	written: usize
}

impl BitInputStream {

	pub fn new(file:&String) -> BitInputStream {
		let mut bis = BitInputStream {
			buffer : 0,
			pos : 0,
			bits_in_buffer : 0,
			eof: false,
			bytes : match File::open(file) {
						Err(e) => panic!("No pudo abrir archivo {}, causa: {}", file, e.description()),
						Ok(mut f) => {
							let mut buffer = Vec::new();
							f.read_to_end(&mut buffer).unwrap();
							buffer
						}
					},
			len : 0
		};
		bis.len = bis.bytes.len();
		bis.fill_buffer();
		bis
	}

	pub fn get_bytes(&mut self) -> &Vec<u8> { &self.bytes }

	pub fn read_char(&mut self) -> u8 {
		if self.eof { panic!("reading from empty input stream"); }

		let mut x = self.buffer;
		if self.bits_in_buffer == 8 {
			self.fill_buffer();
		} else {
			x = x << (8 - self.bits_in_buffer);
			let temp = self.bits_in_buffer;
			self.fill_buffer();
			self.bits_in_buffer = temp;
			x |= self.buffer >> self.bits_in_buffer;
		}
		(x & 0xFF) as u8
	}

	pub fn read_bool(&mut self) -> bool {
		if self.eof { panic!("reading from empty input stream"); }

		self.bits_in_buffer -= 1;
		let bit = ((self.buffer >> self.bits_in_buffer) & 1) == 1;
		if self.bits_in_buffer == 0 {
			self.fill_buffer();
		}
		bit
	}

	pub fn read_int(&mut self) -> u32 {
		let mut x : u32 = self.read_char() as u32;
		x = (x << 8) | self.read_char() as u32;
		x = (x << 8) | self.read_char() as u32;
		x = (x << 8) | self.read_char() as u32;
		x
	}

	fn fill_buffer(&mut self) {
		if self.pos == self.len {
			self.eof = true;
		} else {
			self.buffer = self.bytes[self.pos] as u16;
			self.bits_in_buffer = 8;
			self.pos += 1;
		}
	}
}

impl BitOutputStream {

	pub fn new(output: &String) -> BitOutputStream {
		BitOutputStream {
			out: BufWriter::new(File::create(output).unwrap()),
			buffer : 0 ,
			bits_in_buffer : 0,
			written: 0
		}
	}

	pub fn write_bit(&mut self, bit: u8) {
		if bit != 0 && bit != 1 { panic!("argument must be 0 or 1., received {}", bit); }
		self.buffer = (self.buffer << 1) | (bit as u16);
		self.bits_in_buffer += 1;
		if self.bits_in_buffer == 8 {
			self.clear_buffer();
		}
	}

	pub fn write_int(&mut self, i: u32) {
		self.write_byte(((i >> 24) & 0xFF) as u16);
    	self.write_byte(((i >> 16) & 0xFF) as u16);
    	self.write_byte(((i >>  8) & 0xFF) as u16);
    	self.write_byte(((i >>  0) & 0xFF) as u16);
	}

	pub fn write_byte(&mut self, byte: u16) {
		for i in 0..8 {
			let bit  = (byte >> (8 - i -1)) & 1;
			self.write_bit(bit as u8);
		}
	}

	fn clear_buffer(&mut self) {
		if self.bits_in_buffer == 0 {
			return
		}
		if self.bits_in_buffer > 0 {
			self.buffer = self.buffer << (8 - self.bits_in_buffer);
		}
		self.out.write(&[self.buffer as u8]).unwrap();
		self.buffer = 0;
		self.bits_in_buffer = 0;
		self.written += 1;
	}

	pub fn close(&mut self) {
    	self.clear_buffer();
    	self.out.flush().unwrap();
    }
}<commit_msg>drops unnecesary counter in rust<commit_after>use std::io::prelude::*;
use std::fs::File;
use std::error::Error;
use std::io::BufWriter;

pub struct BitInputStream {
	buffer : u16,
	pos : usize,
	bits_in_buffer : i16,
	eof: bool,
	bytes : Vec<u8>,
	len : usize,
}

pub struct BitOutputStream {
	out : BufWriter<File>,
	buffer : u16,
	bits_in_buffer : i16,
}

impl BitInputStream {

	pub fn new(file:&String) -> BitInputStream {
		let mut bis = BitInputStream {
			buffer : 0,
			pos : 0,
			bits_in_buffer : 0,
			eof: false,
			bytes : match File::open(file) {
						Err(e) => panic!("No pudo abrir archivo {}, causa: {}", file, e.description()),
						Ok(mut f) => {
							let mut buffer = Vec::new();
							f.read_to_end(&mut buffer).unwrap();
							buffer
						}
					},
			len : 0
		};
		bis.len = bis.bytes.len();
		bis.fill_buffer();
		bis
	}

	pub fn get_bytes(&mut self) -> &Vec<u8> { &self.bytes }

	pub fn read_char(&mut self) -> u8 {
		if self.eof { panic!("reading from empty input stream"); }

		let mut x = self.buffer;
		if self.bits_in_buffer == 8 {
			self.fill_buffer();
		} else {
			x = x << (8 - self.bits_in_buffer);
			let temp = self.bits_in_buffer;
			self.fill_buffer();
			self.bits_in_buffer = temp;
			x |= self.buffer >> self.bits_in_buffer;
		}
		(x & 0xFF) as u8
	}

	pub fn read_bool(&mut self) -> bool {
		if self.eof { panic!("reading from empty input stream"); }

		self.bits_in_buffer -= 1;
		let bit = ((self.buffer >> self.bits_in_buffer) & 1) == 1;
		if self.bits_in_buffer == 0 {
			self.fill_buffer();
		}
		bit
	}

	pub fn read_int(&mut self) -> u32 {
		let mut x : u32 = self.read_char() as u32;
		x = (x << 8) | self.read_char() as u32;
		x = (x << 8) | self.read_char() as u32;
		x = (x << 8) | self.read_char() as u32;
		x
	}

	fn fill_buffer(&mut self) {
		if self.pos == self.len {
			self.eof = true;
		} else {
			self.buffer = self.bytes[self.pos] as u16;
			self.bits_in_buffer = 8;
			self.pos += 1;
		}
	}
}

impl BitOutputStream {

	pub fn new(output: &String) -> BitOutputStream {
		BitOutputStream {
			out: BufWriter::new(File::create(output).unwrap()),
			buffer : 0 ,
			bits_in_buffer : 0
		}
	}

	pub fn write_bit(&mut self, bit: u8) {
		if bit != 0 && bit != 1 { panic!("argument must be 0 or 1., received {}", bit); }
		self.buffer = (self.buffer << 1) | (bit as u16);
		self.bits_in_buffer += 1;
		if self.bits_in_buffer == 8 {
			self.clear_buffer();
		}
	}

	pub fn write_int(&mut self, i: u32) {
		self.write_byte(((i >> 24) & 0xFF) as u16);
    	self.write_byte(((i >> 16) & 0xFF) as u16);
    	self.write_byte(((i >>  8) & 0xFF) as u16);
    	self.write_byte(((i >>  0) & 0xFF) as u16);
	}

	pub fn write_byte(&mut self, byte: u16) {
		for i in 0..8 {
			let bit  = (byte >> (8 - i -1)) & 1;
			self.write_bit(bit as u8);
		}
	}

	fn clear_buffer(&mut self) {
		if self.bits_in_buffer == 0 {
			return
		}
		if self.bits_in_buffer > 0 {
			self.buffer = self.buffer << (8 - self.bits_in_buffer);
		}
		self.out.write(&[self.buffer as u8]).unwrap();
		self.buffer = 0;
		self.bits_in_buffer = 0;
	}

	pub fn close(&mut self) {
    	self.clear_buffer();
    	self.out.flush().unwrap();
    }
}<|endoftext|>


<commit_before>use std::fmt;

/// The broadcast MAC address. Used to broadcast to the local network.
pub static BROADCAST_MAC: MacAddr = MacAddr([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);

/// A MAC address. Six bytes representing a link layer network address.
#[derive(Copy, Clone, Default, Eq, PartialEq, Hash)]
pub struct MacAddr(pub [u8; 6]);

impl MacAddr {
    /// Constructs a `MacAddr` from a slice of bytes.
    /// # Panics
    /// This function panics if the given slice is not 6 bytes long.
    pub fn from_slice(slice: &[u8]) -> MacAddr {
        let mut mac = MacAddr::default();
        <[u8; 6] as AsMut<[u8]>>::as_mut(&mut mac.0).copy_from_slice(slice);
        mac
    }

    /// Constructs a `MacAddr` from six individual bytes.
    pub fn from_bytes(b0: u8, b1: u8, b2: u8, b3: u8, b4: u8, b5: u8) -> MacAddr {
        MacAddr([b0, b1, b2, b3, b4, b5])
    }

    /// Creates a `MacAddr` with the broadcast address consisting of all one
    /// bits.
    pub fn broadcast() -> MacAddr {
        BROADCAST_MAC
    }
}

impl AsRef<[u8]> for MacAddr {
    fn as_ref(&self) -> &[u8] {
        &self.0[..]
    }
}

impl AsRef<[u8; 6]> for MacAddr {
    fn as_ref(&self) -> &[u8; 6] {
        &self.0
    }
}

impl From<[u8; 6]> for MacAddr {
    fn from(data: [u8; 6]) -> Self {
        MacAddr(data)
    }
}

impl fmt::Display for MacAddr {
    /// Format the MAC address with each byte in hexadecimal form and separated
    /// by colons
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
            self.0[0],
            self.0[1],
            self.0[2],
            self.0[3],
            self.0[4],
            self.0[5]
        )
    }
}

impl fmt::Debug for MacAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self as &fmt::Display).fmt(f)
    }
}

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

    #[test]
    fn from_slice() {
        let data = [5, 6, 7, 8, 9, 10];
        let mac = MacAddr::from_slice(&data[..]);
        assert_eq!(data, mac.as_ref());
    }

    #[test]
    #[should_panic]
    fn from_short_slice() {
        MacAddr::from_slice(&[1, 2, 3, 4, 5]);
    }

    #[test]
    #[should_panic]
    fn from_long_slice() {
        MacAddr::from_slice(&[1, 2, 3, 4, 5, 6, 7]);
    }

    #[test]
    fn from_bytes() {
        let mac = MacAddr::from_bytes(2, 3, 4, 5, 6, 7);
        assert_eq!([2, 3, 4, 5, 6, 7], mac.as_ref());
    }

    #[test]
    fn as_ref() {
        let data = [5, 6, 7, 8, 9, 10];
        let mac = MacAddr(data);
        assert_eq!(data, mac.as_ref());
    }

    #[test]
    fn display() {
        let mac = MacAddr([255, 6, 7, 8, 9, 10]);
        assert_eq!("ff:06:07:08:09:0a", mac.to_string());
    }
}
<commit_msg>Add FromStr impl for MacAddr<commit_after>use std::fmt;
use std::str::FromStr;
use std::error::Error;

/// The broadcast MAC address. Used to broadcast to the local network.
pub static BROADCAST_MAC: MacAddr = MacAddr([0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);

#[derive(Debug, Eq, PartialEq)]
pub struct MacAddrLengthError;

impl fmt::Display for MacAddrLengthError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl Error for MacAddrLengthError {
    fn description(&self) -> &str {
        "Given data not six bytes long"
    }
}

/// A MAC address. Six bytes representing a link layer network address.
#[derive(Copy, Clone, Default, Eq, PartialEq, Hash)]
pub struct MacAddr(pub [u8; 6]);

impl MacAddr {
    /// Constructs a `MacAddr` from a slice of bytes.
    /// Will fail if the given slice is not 6 bytes long.
    pub fn try_from_slice(slice: &[u8]) -> Result<MacAddr, MacAddrLengthError> {
        if slice.len() == 6 {
            Ok(Self::from_slice(slice))
        } else {
            Err(MacAddrLengthError)
        }
    }

    /// Constructs a `MacAddr` from a slice of bytes.
    /// # Panics
    /// This function panics if the given slice is not 6 bytes long.
    pub fn from_slice(slice: &[u8]) -> MacAddr {
        let mut mac = MacAddr::default();
        <[u8; 6] as AsMut<[u8]>>::as_mut(&mut mac.0).copy_from_slice(slice);
        mac
    }

    /// Constructs a `MacAddr` from six individual bytes.
    pub fn from_bytes(b0: u8, b1: u8, b2: u8, b3: u8, b4: u8, b5: u8) -> MacAddr {
        MacAddr([b0, b1, b2, b3, b4, b5])
    }

    /// Creates a `MacAddr` with the broadcast address consisting of all one
    /// bits.
    pub fn broadcast() -> MacAddr {
        BROADCAST_MAC
    }
}

impl AsRef<[u8]> for MacAddr {
    fn as_ref(&self) -> &[u8] {
        &self.0[..]
    }
}

impl AsRef<[u8; 6]> for MacAddr {
    fn as_ref(&self) -> &[u8; 6] {
        &self.0
    }
}

impl From<[u8; 6]> for MacAddr {
    fn from(data: [u8; 6]) -> Self {
        MacAddr(data)
    }
}

#[derive(Debug, Eq, PartialEq)]
pub struct MacAddrParseError(String);

impl fmt::Display for MacAddrParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Invalid MAC string: {}", self.0)
    }
}

impl Error for MacAddrParseError {
    fn description(&self) -> &str {
        "Invalid MAC address string"
    }
}

impl FromStr for MacAddr {
    type Err = MacAddrParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use std::num::ParseIntError;

        let bytes: Result<Vec<u8>, ParseIntError> =
            s.split(":").map(|s| u8::from_str_radix(s, 16)).collect();
        match bytes {
            Ok(ref bytes) if bytes.len() == 6 => Ok(Self::from_slice(&bytes)),
            _ => Err(MacAddrParseError(s.to_owned())),
        }
    }
}

impl fmt::Display for MacAddr {
    /// Format the MAC address with each byte in hexadecimal form and separated
    /// by colons
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
            self.0[0],
            self.0[1],
            self.0[2],
            self.0[3],
            self.0[4],
            self.0[5]
        )
    }
}

impl fmt::Debug for MacAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        (self as &fmt::Display).fmt(f)
    }
}

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

    #[test]
    fn from_slice() {
        let data = [5, 6, 7, 8, 9, 10];
        let mac = MacAddr::from_slice(&data[..]);
        assert_eq!(data, mac.as_ref());
    }

    #[test]
    #[should_panic]
    fn from_short_slice() {
        MacAddr::from_slice(&[1, 2, 3, 4, 5]);
    }

    #[test]
    #[should_panic]
    fn from_long_slice() {
        MacAddr::from_slice(&[1, 2, 3, 4, 5, 6, 7]);
    }

    #[test]
    fn from_bytes() {
        let mac = MacAddr::from_bytes(2, 3, 4, 5, 6, 7);
        assert_eq!([2, 3, 4, 5, 6, 7], mac.as_ref());
    }

    #[test]
    fn as_ref() {
        let data = [5, 6, 7, 8, 9, 10];
        let mac = MacAddr(data);
        assert_eq!(data, mac.as_ref());
    }

    #[test]
    fn display() {
        let mac = MacAddr([255, 6, 7, 8, 9, 10]);
        assert_eq!("ff:06:07:08:09:0a", mac.to_string());
    }

    #[test]
    fn from_str() {
        let result = MacAddr::from_str("01:02:ff:ac:13:37");
        assert_eq!(result, Ok(MacAddr([0x01, 0x02, 0xff, 0xac, 0x13, 0x37])));
    }
}
<|endoftext|>


<commit_before><commit_msg>Drain segments based on size in SA recovery<commit_after><|endoftext|>


<commit_before>use std::io::prelude::*;
use std::io;
use std::path::Path;

use analysis::types::IsIncomplete;
use env::Env;
use file_saver::save_to_file;
use library::{Type, MAIN_NAMESPACE};
use nameutil::crate_name;
use codegen::general;

struct CType {
    /// Name of type, as used in C.
    name: String,
    /// Expression describing when type is available (when defined only conditionally).
    cfg_condition: Option<String>,
}

pub fn generate(env :&Env) {
    let tests = env.config.target_path.join("tests");
    let abi_c = tests.join("abi.c");
    let abi_rs = tests.join("abi.rs");
    let manual_h = tests.join("manual.h");

    let ns = env.library.namespace(MAIN_NAMESPACE);
    let ctypes = ns.types
        .iter()
        .filter_map(|t| t.as_ref())
        .filter(|t| !t.is_incomplete(&env.library))
        .filter_map(|t| match *t {
            Type::Alias(_) |
            Type::Class(_) |
            Type::Record(_) |
            Type::Union(_) |
            Type::Enumeration(_) |
            Type::Bitfield(_) |
            Type::Interface(_)
            => {
                let full_name = format!("{}.{}", &ns.name, t.get_name());
                if env.type_status_sys(&full_name).ignored() {
                    return None;
                }
                let name = match t.get_glib_name() {
                    None => return None,
                    Some(name) => name,
                };
                if is_name_made_up(name) {
                    return None;
                }
                let cfg_condition = env.config.objects.get(&full_name).and_then(|obj| {
                    obj.cfg_condition.clone()
                });
                Some(CType {
                    name: name.to_owned(),
                    cfg_condition,
                })
            },
            _ => None,
        })
        .collect::<Vec<_>>();

    if ctypes.is_empty() {
        return;
    }

    if !manual_h.exists() {
        save_to_file(&manual_h, env.config.make_backup, |w| {
            info!("Generating file {:?}", &manual_h);
            writeln!(w, "// Insert manual customizations here, they won't be overwritten.")
        });
    }
    save_to_file(&abi_c, env.config.make_backup, |w| {
        generate_abi_c(env, &abi_c, w)
    });
    save_to_file(&abi_rs, env.config.make_backup, |w| {
        generate_abi_rs(env, &abi_rs, w, &ctypes)
    });
}

/// Checks if type name is unlikely to correspond to a real C type name.
fn is_name_made_up(name: &str) -> bool {
    // Unnamed types are assigned name during parsing, those names contain an underscore.
    name.contains('_')
}

fn generate_abi_c(env: &Env, path: &Path, w: &mut Write) -> io::Result<()> {
    info!("Generating file {:?}", path);
    general::start_comments(w, &env.config)?;
    writeln!(w, "")?;
    writeln!(w, "/* For %z support in printf when using MinGW. */")?;
    writeln!(w, "#define _POSIX_C_SOURCE 200809L")?;
    writeln!(w, "#include <stdalign.h>")?;
    writeln!(w, "#include <stdio.h>")?;
    writeln!(w, "#include \"manual.h\"")?;

    let ns = env.library.namespace(MAIN_NAMESPACE);
    for include in ns.c_includes.iter() {
        writeln!(w, "#include <{}>", include)?;
    }

    writeln!(w, "{}", r##"
int main() {
  printf("%zu\n%zu\n", sizeof(ABI_TEST_TYPE), alignof(ABI_TEST_TYPE));
}"##)

}

fn generate_abi_rs(env: &Env, path: &Path, w: &mut Write, ctypes: &[CType]) -> io::Result<()> {
    info!("Generating file {:?}", path);
    general::start_comments(w, &env.config)?;
    writeln!(w, "")?;
    let name = format!("{}_sys", crate_name(&env.config.library_name));
    writeln!(w, "extern crate {};", &name)?;
    writeln!(w, "extern crate shell_words;")?;
    writeln!(w, "{}", r##"
use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::mem::{align_of, size_of};
use std::process::Command;
use std::str;"##)?;
    writeln!(w, "use {}::*;", &name)?;
    writeln!(w, "{}", r##"

#[derive(Clone, Debug)]
struct Compiler {
    pub args: Vec<String>,
}

impl Compiler {
    pub fn new() -> Result<Compiler, Box<Error>> {
        let mut args = get_var("CC", "cc")?;
        args.extend(get_var("CFLAGS", "")?);
        args.extend(get_var("CPPFLAGS", "")?);
        Ok(Compiler { args })
    }

    pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) {
        let arg = match val.into() {
            None => format!("-D{}", var),
            Some(val) => format!("-D{}={}", var, val),
        };
        self.args.push(arg);
    }

    pub fn to_command(&self) -> Command {
        let mut cmd = Command::new(&self.args[0]);
        cmd.args(&self.args[1..]);
        cmd
    }
}

fn get_var(name: &str, default: &str) -> Result<Vec<String>, Box<Error>> {
    match env::var(name) {
        Ok(value) => Ok(shell_words::split(&value)?),
        Err(env::VarError::NotPresent) => Ok(shell_words::split(default)?),
        Err(err) => Err(format!("{} {}", name, err).into()),
    }
}

fn pkg_config_cflags(package: &str) -> Result<Vec<String>, Box<Error>> {
    let mut cmd = Command::new("pkg-config");
    cmd.arg("--cflags");
    cmd.arg(package);
    let out = cmd.output()?;
    if !out.status.success() {
        return Err(format!("command {:?} returned {}",
                           &cmd, out.status).into());
    }
    let stdout = str::from_utf8(&out.stdout)?;
    Ok(shell_words::split(stdout)?)
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct ABI {
    size: usize,
    alignment: usize,
}

impl ABI {
    pub fn from_type<T: Sized>() -> ABI {
        ABI {
            size: size_of::<T>(),
            alignment: align_of::<T>(),
        }
    }
}

#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
struct TestResults {
    /// Number of successfully completed tests.
    passed: usize,
    /// Total number of failed tests (including those that failed to compile).
    failed: usize,
    /// Number of tests that failed to compile.
    failed_compile: usize,
}

#[test]
fn test_cross_validate_abi_with_c() {
    // Configure compiler instance."##)?;

    let ns = env.library.namespace(MAIN_NAMESPACE);
    let package_name = ns.package_name.as_ref()
        .expect("Missing package name");

    writeln!(w, "\tlet package_name = \"{}\";", package_name)?;
    writeln!(w, "{}", r##"    let mut cc = Compiler::new()
        .expect("compiler from environment");
    let cflags = pkg_config_cflags(package_name)
        .expect("cflags from pkg-config");
    cc.args.extend(cflags);
    cc.args.push("-Wno-deprecated-declarations".to_owned());

    // Sanity check that compilation works.
    assert_eq!(ABI {size: 1, alignment: 1},
               get_c_abi(&cc, "char").expect("C ABI for char"),
               "failed to obtain correct ABI for char type");

    let mut results : TestResults = Default::default();
    for (name, rust_abi) in &get_rust_abi() {
        match get_c_abi(&cc, name) {
            Err(e) => {
                results.failed += 1;
                results.failed_compile += 1;
                eprintln!("{}", e);
                continue;
            },
            Ok(ref c_abi) => {
                if rust_abi == c_abi {
                    results.passed += 1;
                } else {
                    results.failed += 1;
                    eprintln!("ABI mismatch for {}\nRust: {:?}\nC:    {:?}",
                              name, rust_abi, c_abi);
                }
            }
        };
    }

    if results.failed + results.failed_compile != 0 {
        panic!("FAILED\nABI test results: {} passed; {} failed (compilation errors: {})",
               results.passed,
               results.failed,
               results.failed_compile);
    }
}

fn get_c_abi(cc: &Compiler, name: &str) -> Result<ABI, Box<Error>> {
    let mut cc = cc.clone();
    cc.define("ABI_TEST_TYPE", name);
    cc.args.push("tests/abi.c".to_owned());
    cc.args.push("-oabi".to_owned());

    let mut cc_cmd = cc.to_command();
    let status = cc_cmd.spawn()?.wait()?;
    if !status.success() {
        return Err(format!("compilation command {:?} failed, {}",
                           &cc_cmd, status).into());
    }

    let mut abi_cmd = Command::new("./abi");
    let output = abi_cmd.output()?;
    if !output.status.success() {
        return Err(format!("command {:?} failed, {}",
                           &abi_cmd, output.status).into());
    }

    let stdout = str::from_utf8(&output.stdout)?;
    let mut words = stdout.split_whitespace();
    let size = words.next().unwrap().parse().unwrap();
    let alignment = words.next().unwrap().parse().unwrap();
    Ok(ABI {size, alignment})
}

fn get_rust_abi() -> BTreeMap<String, ABI> {
    let mut abi = BTreeMap::new();"##)?;

    for ctype in ctypes {
        general::cfg_condition(w, &ctype.cfg_condition, false, 1)?;
        writeln!(w, r##"    abi.insert("{ctype}".to_owned(), ABI::from_type::<{ctype}>());"##,
                 ctype=ctype.name)?;
    }

    writeln!(w, "{}", r##"    abi
}
"##)

}
<commit_msg>Include stdout and stderr in addition to exit status when command execution fails.<commit_after>use std::io::prelude::*;
use std::io;
use std::path::Path;

use analysis::types::IsIncomplete;
use env::Env;
use file_saver::save_to_file;
use library::{Type, MAIN_NAMESPACE};
use nameutil::crate_name;
use codegen::general;

struct CType {
    /// Name of type, as used in C.
    name: String,
    /// Expression describing when type is available (when defined only conditionally).
    cfg_condition: Option<String>,
}

pub fn generate(env :&Env) {
    let tests = env.config.target_path.join("tests");
    let abi_c = tests.join("abi.c");
    let abi_rs = tests.join("abi.rs");
    let manual_h = tests.join("manual.h");

    let ns = env.library.namespace(MAIN_NAMESPACE);
    let ctypes = ns.types
        .iter()
        .filter_map(|t| t.as_ref())
        .filter(|t| !t.is_incomplete(&env.library))
        .filter_map(|t| match *t {
            Type::Alias(_) |
            Type::Class(_) |
            Type::Record(_) |
            Type::Union(_) |
            Type::Enumeration(_) |
            Type::Bitfield(_) |
            Type::Interface(_)
            => {
                let full_name = format!("{}.{}", &ns.name, t.get_name());
                if env.type_status_sys(&full_name).ignored() {
                    return None;
                }
                let name = match t.get_glib_name() {
                    None => return None,
                    Some(name) => name,
                };
                if is_name_made_up(name) {
                    return None;
                }
                let cfg_condition = env.config.objects.get(&full_name).and_then(|obj| {
                    obj.cfg_condition.clone()
                });
                Some(CType {
                    name: name.to_owned(),
                    cfg_condition,
                })
            },
            _ => None,
        })
        .collect::<Vec<_>>();

    if ctypes.is_empty() {
        return;
    }

    if !manual_h.exists() {
        save_to_file(&manual_h, env.config.make_backup, |w| {
            info!("Generating file {:?}", &manual_h);
            writeln!(w, "// Insert manual customizations here, they won't be overwritten.")
        });
    }
    save_to_file(&abi_c, env.config.make_backup, |w| {
        generate_abi_c(env, &abi_c, w)
    });
    save_to_file(&abi_rs, env.config.make_backup, |w| {
        generate_abi_rs(env, &abi_rs, w, &ctypes)
    });
}

/// Checks if type name is unlikely to correspond to a real C type name.
fn is_name_made_up(name: &str) -> bool {
    // Unnamed types are assigned name during parsing, those names contain an underscore.
    name.contains('_')
}

fn generate_abi_c(env: &Env, path: &Path, w: &mut Write) -> io::Result<()> {
    info!("Generating file {:?}", path);
    general::start_comments(w, &env.config)?;
    writeln!(w, "")?;
    writeln!(w, "/* For %z support in printf when using MinGW. */")?;
    writeln!(w, "#define _POSIX_C_SOURCE 200809L")?;
    writeln!(w, "#include <stdalign.h>")?;
    writeln!(w, "#include <stdio.h>")?;
    writeln!(w, "#include \"manual.h\"")?;

    let ns = env.library.namespace(MAIN_NAMESPACE);
    for include in ns.c_includes.iter() {
        writeln!(w, "#include <{}>", include)?;
    }

    writeln!(w, "{}", r##"
int main() {
  printf("%zu\n%zu\n", sizeof(ABI_TEST_TYPE), alignof(ABI_TEST_TYPE));
}"##)

}

fn generate_abi_rs(env: &Env, path: &Path, w: &mut Write, ctypes: &[CType]) -> io::Result<()> {
    info!("Generating file {:?}", path);
    general::start_comments(w, &env.config)?;
    writeln!(w, "")?;
    let name = format!("{}_sys", crate_name(&env.config.library_name));
    writeln!(w, "extern crate {};", &name)?;
    writeln!(w, "extern crate shell_words;")?;
    writeln!(w, "{}", r##"
use std::collections::BTreeMap;
use std::env;
use std::error::Error;
use std::mem::{align_of, size_of};
use std::process::Command;
use std::str;"##)?;
    writeln!(w, "use {}::*;", &name)?;
    writeln!(w, "{}", r##"

#[derive(Clone, Debug)]
struct Compiler {
    pub args: Vec<String>,
}

impl Compiler {
    pub fn new() -> Result<Compiler, Box<Error>> {
        let mut args = get_var("CC", "cc")?;
        args.extend(get_var("CFLAGS", "")?);
        args.extend(get_var("CPPFLAGS", "")?);
        Ok(Compiler { args })
    }

    pub fn define<'a, V: Into<Option<&'a str>>>(&mut self, var: &str, val: V) {
        let arg = match val.into() {
            None => format!("-D{}", var),
            Some(val) => format!("-D{}={}", var, val),
        };
        self.args.push(arg);
    }

    pub fn to_command(&self) -> Command {
        let mut cmd = Command::new(&self.args[0]);
        cmd.args(&self.args[1..]);
        cmd
    }
}

fn get_var(name: &str, default: &str) -> Result<Vec<String>, Box<Error>> {
    match env::var(name) {
        Ok(value) => Ok(shell_words::split(&value)?),
        Err(env::VarError::NotPresent) => Ok(shell_words::split(default)?),
        Err(err) => Err(format!("{} {}", name, err).into()),
    }
}

fn pkg_config_cflags(package: &str) -> Result<Vec<String>, Box<Error>> {
    let mut cmd = Command::new("pkg-config");
    cmd.arg("--cflags");
    cmd.arg(package);
    let out = cmd.output()?;
    if !out.status.success() {
        return Err(format!("command {:?} returned {}",
                           &cmd, out.status).into());
    }
    let stdout = str::from_utf8(&out.stdout)?;
    Ok(shell_words::split(stdout)?)
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
struct ABI {
    size: usize,
    alignment: usize,
}

impl ABI {
    pub fn from_type<T: Sized>() -> ABI {
        ABI {
            size: size_of::<T>(),
            alignment: align_of::<T>(),
        }
    }
}

#[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
struct TestResults {
    /// Number of successfully completed tests.
    passed: usize,
    /// Total number of failed tests (including those that failed to compile).
    failed: usize,
    /// Number of tests that failed to compile.
    failed_compile: usize,
}

#[test]
fn test_cross_validate_abi_with_c() {
    // Configure compiler instance."##)?;

    let ns = env.library.namespace(MAIN_NAMESPACE);
    let package_name = ns.package_name.as_ref()
        .expect("Missing package name");

    writeln!(w, "\tlet package_name = \"{}\";", package_name)?;
    writeln!(w, "{}", r##"    let mut cc = Compiler::new()
        .expect("compiler from environment");
    let cflags = pkg_config_cflags(package_name)
        .expect("cflags from pkg-config");
    cc.args.extend(cflags);
    cc.args.push("-Wno-deprecated-declarations".to_owned());

    // Sanity check that compilation works.
    assert_eq!(ABI {size: 1, alignment: 1},
               get_c_abi(&cc, "char").expect("C ABI for char"),
               "failed to obtain correct ABI for char type");

    let mut results : TestResults = Default::default();
    for (name, rust_abi) in &get_rust_abi() {
        match get_c_abi(&cc, name) {
            Err(e) => {
                results.failed += 1;
                results.failed_compile += 1;
                eprintln!("{}", e);
                continue;
            },
            Ok(ref c_abi) => {
                if rust_abi == c_abi {
                    results.passed += 1;
                } else {
                    results.failed += 1;
                    eprintln!("ABI mismatch for {}\nRust: {:?}\nC:    {:?}",
                              name, rust_abi, c_abi);
                }
            }
        };
    }

    if results.failed + results.failed_compile != 0 {
        panic!("FAILED\nABI test results: {} passed; {} failed (compilation errors: {})",
               results.passed,
               results.failed,
               results.failed_compile);
    }
}

fn get_c_abi(cc: &Compiler, name: &str) -> Result<ABI, Box<Error>> {
    let mut cc = cc.clone();
    cc.define("ABI_TEST_TYPE", name);
    cc.args.push("tests/abi.c".to_owned());
    cc.args.push("-oabi".to_owned());

    let mut cc_cmd = cc.to_command();
    let status = cc_cmd.spawn()?.wait()?;
    if !status.success() {
        return Err(format!("compilation command {:?} failed, {}",
                           &cc_cmd, status).into());
    }

    let mut abi_cmd = Command::new("./abi");
    let output = abi_cmd.output()?;
    if !output.status.success() {
        return Err(format!("command {:?} failed, {:?}",
                           &abi_cmd, &output).into());
    }

    let stdout = str::from_utf8(&output.stdout)?;
    let mut words = stdout.split_whitespace();
    let size = words.next().unwrap().parse().unwrap();
    let alignment = words.next().unwrap().parse().unwrap();
    Ok(ABI {size, alignment})
}

fn get_rust_abi() -> BTreeMap<String, ABI> {
    let mut abi = BTreeMap::new();"##)?;

    for ctype in ctypes {
        general::cfg_condition(w, &ctype.cfg_condition, false, 1)?;
        writeln!(w, r##"    abi.insert("{ctype}".to_owned(), ABI::from_type::<{ctype}>());"##,
                 ctype=ctype.name)?;
    }

    writeln!(w, "{}", r##"    abi
}
"##)

}
<|endoftext|>