<commit_before>//! A small library meant to be used as a build dependency with Cargo for easily
//! integrating [ISPC](https://ispc.github.io/) code into Rust projects. The
//! `ispc_rt` crate is specifically targetted at linking with a previously
//! compiled ISPC library and generated bindings (built with `ispc_compile`),
//! to allow end users to link ISPC code without needing the ISPC compiler or clang.
//!
//! This crate also includes the various runtime components for the ISPC
//! language, including the parallel task system and performance instrumentation.
//!

#![allow(dead_code)]

extern crate libc;
extern crate aligned_alloc;
extern crate num_cpus;

pub mod task;
pub mod exec;
pub mod instrument;

use std::mem;
use std::env;
use std::sync::{Once, ONCE_INIT, Arc};
use std::ffi::CStr;
use std::path::{Path, PathBuf};

pub use task::ISPCTaskFn;
pub use exec::{TaskSystem, Parallel};
pub use instrument::{Instrument, SimpleInstrument};

/// Convenience macro for generating the module to hold the raw/unsafe ISPC bindings.
///
/// In addition to building the library with ISPC we use rust-bindgen to generate
/// a rust module containing bindings to the functions exported from ISPC. These
/// can be imported by passing the name of your library to the `ispc_module` macro.
///
/// # Example
///
/// ```ignore
/// #[macro_use]
/// extern crate ispc_rt;
///
/// // Functions exported from foo will be callable under foo::*
/// ispc_module!(foo);
/// ```
#[macro_export]
macro_rules! ispc_module {
    ($lib:ident) => (
        include!(concat!(env!("ISPC_OUT_DIR"), "/", stringify!($lib), ".rs"));
    )
}

/// A `PackagedModule` refers to an ISPC module which was previously
/// built using `ispc_compile`, and is now distributed with
/// the crate.
pub struct PackagedModule {
    path: Option<PathBuf>,
    lib: String,
}

impl PackagedModule {
    /// Create a new `PackagedModule` to link against the previously compiled
    /// library named `lib`. As in `ispc_compile`, the library name should not
    /// have any prefix or suffix. For example, instead of `libexample.a` or
    /// `example.lib`, simple pass `example`
    pub fn new(lib: &str) -> PackagedModule {
        PackagedModule {path: None, lib: lib.to_owned()}
    }
    /// Specify the path to search for the packaged ISPC libraries and bindings
    pub fn lib_path<P: AsRef<Path>>(&mut self, path: P) -> &mut PackagedModule {
        self.path = Some(path.as_ref().to_path_buf());
        self
    }
    /// Link with a previously built ISPC library packaged with the crate
    pub fn link(&self) {
        let libfile = self.lib.clone() + &env::var("HOST").unwrap();
        let bindgen_file = self.lib.clone() + ".rs";
        println!("cargo:rerun-if-changed={}", libfile);
        println!("cargo:rerun-if-changed={}", bindgen_file);
        println!("cargo:rustc-link-lib=static={}", libfile);

        let path = self.get_lib_path();
        println!("cargo:rustc-link-search=native={}", path.display());
        println!("cargo:rustc-env=ISPC_OUT_DIR={}", path.display());
    }
    /// Returns the user-set output directory if they've set one, otherwise
    /// returns env("OUT_DIR")
    fn get_lib_path(&self) -> PathBuf {
        let p = self.path.clone().unwrap_or_else(|| {
            env::var_os("OUT_DIR").map(PathBuf::from).unwrap()
        });
        if p.is_relative() {
            env::current_dir().unwrap().join(p)
        } else {
            p
        }
    }
}

static mut TASK_SYSTEM: Option<&'static TaskSystem> = None;
static TASK_INIT: Once = ONCE_INIT;

static mut INSTRUMENT: Option<&'static Instrument> = None;
static INSTRUMENT_INIT: Once = ONCE_INIT;

/// If you have implemented your own task system you can provide it for use instead
/// of the default threaded one. This must be done prior to calling ISPC code which
/// spawns tasks otherwise the task system will have already been initialized to
/// `Parallel`, which you can also see as an example for implementing a task system.
///
/// Use the function to do any extra initialization for your task system. Note that
/// the task system will be leaked and not destroyed until the program exits and the
/// memory space is cleaned up.
pub fn set_task_system<F: FnOnce() -> Arc<TaskSystem>>(f: F) {
    TASK_INIT.call_once(|| {
        let task_sys = f();
        unsafe {
            let s = &*task_sys as *const (dyn TaskSystem + 'static);
            mem::forget(task_sys);
            TASK_SYSTEM = Some(&*s);
        }
    });
}

fn get_task_system() -> &'static TaskSystem {
    // TODO: This is a bit nasty, but I'm not sure on a nicer solution. Maybe something that
    // would let the user register the desired (or default) task system? But if
    // mutable statics can't have destructors we still couldn't have an Arc or Box to something?
    TASK_INIT.call_once(|| {
        unsafe {
            let task_sys = Parallel::new() as Arc<TaskSystem>;
            let s = &*task_sys as *const (dyn TaskSystem + 'static);
            mem::forget(task_sys);
            TASK_SYSTEM = Some(&*s);
        }
    });
    unsafe { TASK_SYSTEM.unwrap() }
}

/// If you have implemented your own instrument for logging ISPC performance
/// data you can use this function to provide it for use instead of the
/// default one. This function **must** be called before calling into ISPC code,
/// otherwise the instrumenter will already be set to the default.
pub fn set_instrument<F: FnOnce() -> Arc<Instrument>>(f: F) {
    INSTRUMENT_INIT.call_once(|| {
        let instrument = f();
        unsafe {
            let s = &*instrument as *const (dyn Instrument + 'static);
            mem::forget(instrument);
            INSTRUMENT = Some(&*s);
        }
    });
}

/// Print out a summary of performace data gathered from instrumenting ISPC.
/// Must enable instrumenting to have this record and print data, see
/// `Config::instrument`.
pub fn print_instrumenting_summary() {
    get_instrument().print_summary();
}

fn get_instrument() -> &'static Instrument {
    // TODO: This is a bit nasty, like above
    INSTRUMENT_INIT.call_once(|| {
        unsafe {
            let instrument = Arc::new(SimpleInstrument) as Arc<Instrument>;
            let s = &*instrument as *const (dyn Instrument + 'static);
            mem::forget(instrument);
            INSTRUMENT = Some(&*s);
        }
    });
    unsafe { INSTRUMENT.unwrap() }
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCAlloc(handle_ptr: *mut *mut libc::c_void, size: i64,
                                   align: i32) -> *mut libc::c_void {
    get_task_system().alloc(handle_ptr, size, align)
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCLaunch(handle_ptr: *mut *mut libc::c_void, f: *mut libc::c_void,
                                    data: *mut libc::c_void, count0: libc::c_int,
                                    count1: libc::c_int, count2: libc::c_int) {
    let task_fn: ISPCTaskFn = mem::transmute(f);
    get_task_system().launch(handle_ptr, task_fn, data, count0 as i32, count1 as i32, count2 as i32);
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCSync(handle: *mut libc::c_void){
    get_task_system().sync(handle);
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCInstrument(cfile: *const libc::c_char, cnote: *const libc::c_char,
                                        line: libc::c_int, mask: u64) {

    let file_name = CStr::from_ptr(cfile);
    let note = CStr::from_ptr(cnote);
    let active_count = (mask as u64).count_ones();
    get_instrument().instrument(file_name, note, line as i32, mask as u64, active_count);
}

<commit_msg>Update to use dyn explicitly<commit_after>//! A small library meant to be used as a build dependency with Cargo for easily
//! integrating [ISPC](https://ispc.github.io/) code into Rust projects. The
//! `ispc_rt` crate is specifically targetted at linking with a previously
//! compiled ISPC library and generated bindings (built with `ispc_compile`),
//! to allow end users to link ISPC code without needing the ISPC compiler or clang.
//!
//! This crate also includes the various runtime components for the ISPC
//! language, including the parallel task system and performance instrumentation.
//!

#![allow(dead_code)]

extern crate libc;
extern crate aligned_alloc;
extern crate num_cpus;

pub mod task;
pub mod exec;
pub mod instrument;

use std::mem;
use std::env;
use std::sync::{Once, ONCE_INIT, Arc};
use std::ffi::CStr;
use std::path::{Path, PathBuf};

pub use task::ISPCTaskFn;
pub use exec::{TaskSystem, Parallel};
pub use instrument::{Instrument, SimpleInstrument};

/// Convenience macro for generating the module to hold the raw/unsafe ISPC bindings.
///
/// In addition to building the library with ISPC we use rust-bindgen to generate
/// a rust module containing bindings to the functions exported from ISPC. These
/// can be imported by passing the name of your library to the `ispc_module` macro.
///
/// # Example
///
/// ```ignore
/// #[macro_use]
/// extern crate ispc_rt;
///
/// // Functions exported from foo will be callable under foo::*
/// ispc_module!(foo);
/// ```
#[macro_export]
macro_rules! ispc_module {
    ($lib:ident) => (
        include!(concat!(env!("ISPC_OUT_DIR"), "/", stringify!($lib), ".rs"));
    )
}

/// A `PackagedModule` refers to an ISPC module which was previously
/// built using `ispc_compile`, and is now distributed with
/// the crate.
pub struct PackagedModule {
    path: Option<PathBuf>,
    lib: String,
}

impl PackagedModule {
    /// Create a new `PackagedModule` to link against the previously compiled
    /// library named `lib`. As in `ispc_compile`, the library name should not
    /// have any prefix or suffix. For example, instead of `libexample.a` or
    /// `example.lib`, simple pass `example`
    pub fn new(lib: &str) -> PackagedModule {
        PackagedModule {path: None, lib: lib.to_owned()}
    }
    /// Specify the path to search for the packaged ISPC libraries and bindings
    pub fn lib_path<P: AsRef<Path>>(&mut self, path: P) -> &mut PackagedModule {
        self.path = Some(path.as_ref().to_path_buf());
        self
    }
    /// Link with a previously built ISPC library packaged with the crate
    pub fn link(&self) {
        let libfile = self.lib.clone() + &env::var("HOST").unwrap();
        let bindgen_file = self.lib.clone() + ".rs";
        println!("cargo:rerun-if-changed={}", libfile);
        println!("cargo:rerun-if-changed={}", bindgen_file);
        println!("cargo:rustc-link-lib=static={}", libfile);

        let path = self.get_lib_path();
        println!("cargo:rustc-link-search=native={}", path.display());
        println!("cargo:rustc-env=ISPC_OUT_DIR={}", path.display());
    }
    /// Returns the user-set output directory if they've set one, otherwise
    /// returns env("OUT_DIR")
    fn get_lib_path(&self) -> PathBuf {
        let p = self.path.clone().unwrap_or_else(|| {
            env::var_os("OUT_DIR").map(PathBuf::from).unwrap()
        });
        if p.is_relative() {
            env::current_dir().unwrap().join(p)
        } else {
            p
        }
    }
}

static mut TASK_SYSTEM: Option<&'static dyn TaskSystem> = None;
static TASK_INIT: Once = ONCE_INIT;

static mut INSTRUMENT: Option<&'static dyn Instrument> = None;
static INSTRUMENT_INIT: Once = ONCE_INIT;

/// If you have implemented your own task system you can provide it for use instead
/// of the default threaded one. This must be done prior to calling ISPC code which
/// spawns tasks otherwise the task system will have already been initialized to
/// `Parallel`, which you can also see as an example for implementing a task system.
///
/// Use the function to do any extra initialization for your task system. Note that
/// the task system will be leaked and not destroyed until the program exits and the
/// memory space is cleaned up.
pub fn set_task_system<F: FnOnce() -> Arc<dyn TaskSystem>>(f: F) {
    TASK_INIT.call_once(|| {
        let task_sys = f();
        unsafe {
            let s = &*task_sys as *const (dyn TaskSystem + 'static);
            mem::forget(task_sys);
            TASK_SYSTEM = Some(&*s);
        }
    });
}

fn get_task_system() -> &'static dyn TaskSystem {
    // TODO: This is a bit nasty, but I'm not sure on a nicer solution. Maybe something that
    // would let the user register the desired (or default) task system? But if
    // mutable statics can't have destructors we still couldn't have an Arc or Box to something?
    TASK_INIT.call_once(|| {
        unsafe {
            let task_sys = Parallel::new() as Arc<dyn TaskSystem>;
            let s = &*task_sys as *const (dyn TaskSystem + 'static);
            mem::forget(task_sys);
            TASK_SYSTEM = Some(&*s);
        }
    });
    unsafe { TASK_SYSTEM.unwrap() }
}

/// If you have implemented your own instrument for logging ISPC performance
/// data you can use this function to provide it for use instead of the
/// default one. This function **must** be called before calling into ISPC code,
/// otherwise the instrumenter will already be set to the default.
pub fn set_instrument<F: FnOnce() -> Arc<dyn Instrument>>(f: F) {
    INSTRUMENT_INIT.call_once(|| {
        let instrument = f();
        unsafe {
            let s = &*instrument as *const (dyn Instrument + 'static);
            mem::forget(instrument);
            INSTRUMENT = Some(&*s);
        }
    });
}

/// Print out a summary of performace data gathered from instrumenting ISPC.
/// Must enable instrumenting to have this record and print data, see
/// `Config::instrument`.
pub fn print_instrumenting_summary() {
    get_instrument().print_summary();
}

fn get_instrument() -> &'static dyn Instrument {
    // TODO: This is a bit nasty, like above
    INSTRUMENT_INIT.call_once(|| {
        unsafe {
            let instrument = Arc::new(SimpleInstrument) as Arc<dyn Instrument>;
            let s = &*instrument as *const (dyn Instrument + 'static);
            mem::forget(instrument);
            INSTRUMENT = Some(&*s);
        }
    });
    unsafe { INSTRUMENT.unwrap() }
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCAlloc(handle_ptr: *mut *mut libc::c_void, size: i64,
                                   align: i32) -> *mut libc::c_void {
    get_task_system().alloc(handle_ptr, size, align)
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCLaunch(handle_ptr: *mut *mut libc::c_void, f: *mut libc::c_void,
                                    data: *mut libc::c_void, count0: libc::c_int,
                                    count1: libc::c_int, count2: libc::c_int) {
    let task_fn: ISPCTaskFn = mem::transmute(f);
    get_task_system().launch(handle_ptr, task_fn, data, count0 as i32, count1 as i32, count2 as i32);
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCSync(handle: *mut libc::c_void){
    get_task_system().sync(handle);
}

#[allow(non_snake_case)]
#[doc(hidden)]
#[no_mangle]
pub unsafe extern "C" fn ISPCInstrument(cfile: *const libc::c_char, cnote: *const libc::c_char,
                                        line: libc::c_int, mask: u64) {

    let file_name = CStr::from_ptr(cfile);
    let note = CStr::from_ptr(cnote);
    let active_count = (mask as u64).count_ones();
    get_instrument().instrument(file_name, note, line as i32, mask as u64, active_count);
}

<|endoftext|>


<commit_before>use crate::common::util::*;

#[test]
fn test_rm_one_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_rm_one_file";

    at.touch(file);

    ucmd.arg(file).succeeds().no_stderr();

    assert!(!at.file_exists(file));
}

#[test]
fn test_rm_failed() {
    let (_at, mut ucmd) = at_and_ucmd!();
    let file = "test_rm_one_file";

    ucmd.arg(file).fails(); // Doesn't exist
}

#[test]
fn test_rm_multiple_files() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file_a = "test_rm_multiple_file_a";
    let file_b = "test_rm_multiple_file_b";

    at.touch(file_a);
    at.touch(file_b);

    ucmd.arg(file_a).arg(file_b).succeeds().no_stderr();

    assert!(!at.file_exists(file_a));
    assert!(!at.file_exists(file_b));
}

#[test]
fn test_rm_interactive() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    let file_a = "test_rm_interactive_file_a";
    let file_b = "test_rm_interactive_file_b";

    at.touch(file_a);
    at.touch(file_b);

    scene
        .ucmd()
        .arg("-i")
        .arg(file_a)
        .arg(file_b)
        .pipe_in("n")
        .succeeds();

    assert!(at.file_exists(file_a));
    assert!(at.file_exists(file_b));

    scene
        .ucmd()
        .arg("-i")
        .arg(file_a)
        .arg(file_b)
        .pipe_in("Yesh")
        .succeeds();

    assert!(!at.file_exists(file_a));
    assert!(at.file_exists(file_b));
}

#[test]
fn test_rm_force() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file_a = "test_rm_force_a";
    let file_b = "test_rm_force_b";

    ucmd.arg("-f")
        .arg(file_a)
        .arg(file_b)
        .succeeds()
        .no_stderr();

    assert!(!at.file_exists(file_a));
    assert!(!at.file_exists(file_b));
}

#[test]
fn test_rm_force_multiple() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file_a = "test_rm_force_a";
    let file_b = "test_rm_force_b";

    ucmd.arg("-f")
        .arg("-f")
        .arg("-f")
        .arg(file_a)
        .arg(file_b)
        .succeeds()
        .no_stderr();

    assert!(!at.file_exists(file_a));
    assert!(!at.file_exists(file_b));
}

#[test]
fn test_rm_empty_directory() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_rm_empty_directory";

    at.mkdir(dir);

    ucmd.arg("-d").arg(dir).succeeds().no_stderr();

    assert!(!at.dir_exists(dir));
}

#[test]
fn test_rm_recursive() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_rm_recursive_directory";
    let file_a = "test_rm_recursive_directory/test_rm_recursive_file_a";
    let file_b = "test_rm_recursive_directory/test_rm_recursive_file_b";

    at.mkdir(dir);
    at.touch(file_a);
    at.touch(file_b);

    ucmd.arg("-r").arg(dir).succeeds().no_stderr();

    assert!(!at.dir_exists(dir));
    assert!(!at.file_exists(file_a));
    assert!(!at.file_exists(file_b));
}

#[test]
fn test_rm_errors() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_rm_errors_directory";
    let file_a = "test_rm_errors_directory/test_rm_errors_file_a";
    let file_b = "test_rm_errors_directory/test_rm_errors_file_b";

    at.mkdir(dir);
    at.touch(file_a);
    at.touch(file_b);

    // $ rm test_rm_errors_directory
    // rm: error: could not remove directory 'test_rm_errors_directory' (did you mean to pass '-r'?)
    ucmd.arg(dir).fails().stderr_is(
        "rm: error: could not remove directory 'test_rm_errors_directory' (did you mean \
                to pass '-r'?)\n",
    );
}

#[test]
fn test_rm_verbose() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file_a = "test_rm_verbose_file_a";
    let file_b = "test_rm_verbose_file_b";

    at.touch(file_a);
    at.touch(file_b);

    ucmd.arg("-v")
        .arg(file_a)
        .arg(file_b)
        .succeeds()
        .stdout_only(format!("removed '{}'\nremoved '{}'\n", file_a, file_b));
}

#[test]
fn test_rm_dir_symlink() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_rm_dir_symlink_dir";
    let link = "test_rm_dir_symlink_link";

    at.mkdir(dir);
    at.symlink_dir(dir, link);

    ucmd.arg(link).succeeds();
}

#[test]
fn test_rm_invalid_symlink() {
    let (at, mut ucmd) = at_and_ucmd!();
    let link = "test_rm_invalid_symlink";

    at.symlink_file(link, link);

    ucmd.arg(link).succeeds();
}

#[test]
fn test_rm_force_no_operand() {
    let mut ucmd = new_ucmd!();

    ucmd.arg("-f").succeeds().no_stderr();
}

#[test]
fn test_rm_no_operand() {
    let mut ucmd = new_ucmd!();

    ucmd.fails()
        .stderr_is("rm: error: missing an argument\nrm: error: for help, try 'rm --help'\n");
}
<commit_msg>Update test_rm.rs<commit_after>use crate::common::util::*;

#[test]
fn test_rm_one_file() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file = "test_rm_one_file";

    at.touch(file);

    ucmd.arg(file).succeeds().no_stderr();

    assert!(!at.file_exists(file));
}

#[test]
fn test_rm_failed() {
    let (_at, mut ucmd) = at_and_ucmd!();
    let file = "test_rm_one_file";

    ucmd.arg(file).fails(); // Doesn't exist
}

#[test]
fn test_rm_multiple_files() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file_a = "test_rm_multiple_file_a";
    let file_b = "test_rm_multiple_file_b";

    at.touch(file_a);
    at.touch(file_b);

    ucmd.arg(file_a).arg(file_b).succeeds().no_stderr();

    assert!(!at.file_exists(file_a));
    assert!(!at.file_exists(file_b));
}

#[test]
fn test_rm_interactive() {
    let scene = TestScenario::new(util_name!());
    let at = &scene.fixtures;

    let file_a = "test_rm_interactive_file_a";
    let file_b = "test_rm_interactive_file_b";

    at.touch(file_a);
    at.touch(file_b);

    scene
        .ucmd()
        .arg("-i")
        .arg(file_a)
        .arg(file_b)
        .pipe_in("n")
        .succeeds();

    assert!(at.file_exists(file_a));
    assert!(at.file_exists(file_b));

    scene
        .ucmd()
        .arg("-i")
        .arg(file_a)
        .arg(file_b)
        .pipe_in("Yesh")
        .succeeds();

    assert!(!at.file_exists(file_a));
    assert!(at.file_exists(file_b));
}

#[test]
fn test_rm_force() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file_a = "test_rm_force_a";
    let file_b = "test_rm_force_b";

    ucmd.arg("-f")
        .arg(file_a)
        .arg(file_b)
        .succeeds()
        .no_stderr();

    assert!(!at.file_exists(file_a));
    assert!(!at.file_exists(file_b));
}

#[test]
fn test_rm_force_multiple() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file_a = "test_rm_force_a";
    let file_b = "test_rm_force_b";

    ucmd.arg("-f")
        .arg("-f")
        .arg("-f")
        .arg(file_a)
        .arg(file_b)
        .succeeds()
        .no_stderr();

    assert!(!at.file_exists(file_a));
    assert!(!at.file_exists(file_b));
}

#[test]
fn test_rm_empty_directory() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_rm_empty_directory";

    at.mkdir(dir);

    ucmd.arg("-d").arg(dir).succeeds().no_stderr();

    assert!(!at.dir_exists(dir));
}

#[test]
fn test_rm_recursive() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_rm_recursive_directory";
    let file_a = "test_rm_recursive_directory/test_rm_recursive_file_a";
    let file_b = "test_rm_recursive_directory/test_rm_recursive_file_b";

    at.mkdir(dir);
    at.touch(file_a);
    at.touch(file_b);

    ucmd.arg("-r").arg(dir).succeeds().no_stderr();

    assert!(!at.dir_exists(dir));
    assert!(!at.file_exists(file_a));
    assert!(!at.file_exists(file_b));
}

#[test]
fn test_rm_errors() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_rm_errors_directory";
    let file_a = "test_rm_errors_directory/test_rm_errors_file_a";
    let file_b = "test_rm_errors_directory/test_rm_errors_file_b";

    at.mkdir(dir);
    at.touch(file_a);
    at.touch(file_b);

    // $ rm test_rm_errors_directory
    // rm: error: could not remove directory 'test_rm_errors_directory' (did you mean to pass '-r'?)
    ucmd.arg(dir).fails().stderr_is(
        "rm: error: could not remove directory 'test_rm_errors_directory' (did you mean \
                to pass '-r' or '-R'?)\n",
    );
}

#[test]
fn test_rm_verbose() {
    let (at, mut ucmd) = at_and_ucmd!();
    let file_a = "test_rm_verbose_file_a";
    let file_b = "test_rm_verbose_file_b";

    at.touch(file_a);
    at.touch(file_b);

    ucmd.arg("-v")
        .arg(file_a)
        .arg(file_b)
        .succeeds()
        .stdout_only(format!("removed '{}'\nremoved '{}'\n", file_a, file_b));
}

#[test]
fn test_rm_dir_symlink() {
    let (at, mut ucmd) = at_and_ucmd!();
    let dir = "test_rm_dir_symlink_dir";
    let link = "test_rm_dir_symlink_link";

    at.mkdir(dir);
    at.symlink_dir(dir, link);

    ucmd.arg(link).succeeds();
}

#[test]
fn test_rm_invalid_symlink() {
    let (at, mut ucmd) = at_and_ucmd!();
    let link = "test_rm_invalid_symlink";

    at.symlink_file(link, link);

    ucmd.arg(link).succeeds();
}

#[test]
fn test_rm_force_no_operand() {
    let mut ucmd = new_ucmd!();

    ucmd.arg("-f").succeeds().no_stderr();
}

#[test]
fn test_rm_no_operand() {
    let mut ucmd = new_ucmd!();

    ucmd.fails()
        .stderr_is("rm: error: missing an argument\nrm: error: for help, try 'rm --help'\n");
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::option::Option;
use std::sync::{Arc, RwLock};
use std::vec::Vec;
use std::thread;
use std::boxed::Box;
use std::net::SocketAddr;

use rocksdb::DB;
use mio::{Token, Handler, EventLoop, EventSet, PollOpt};
use mio::tcp::{TcpListener, TcpStream};
use mio::util::Slab;

use raftserver::{Result, other};
use raftserver::store::cmd_resp;
use kvproto::raft_serverpb::{Message, MessageType};
use kvproto::raft_cmdpb::{RaftCommandRequest, RaftCommandResponse};
use super::{Msg, SendCh, ConnData};
use super::conn::Conn;
use super::config::Config;
use super::transport::ServerTransport;
use super::node::Node;
use pd::PdClient;
use util::HandyRwLock;

const SERVER_TOKEN: Token = Token(1);
const FIRST_CUSTOM_TOKEN: Token = Token(1024);
const INVALID_TOKEN: Token = Token(0);

pub struct Server<T: PdClient + 'static> {
    cfg: Config,

    listener: TcpListener,
    conns: Slab<Conn>,
    sendch: SendCh,

    peers: HashMap<String, Token>,

    store_handles: HashMap<u64, thread::JoinHandle<()>>,

    trans: Arc<RwLock<ServerTransport<T>>>,

    node: Node<T, ServerTransport<T>>,
}

pub fn create_event_loop<T: PdClient + 'static>() -> Result<EventLoop<Server<T>>> {
    let event_loop = try!(EventLoop::new());
    Ok(event_loop)
}

impl<T: PdClient + 'static> Server<T> {
    // Create a server with already initialized engines.
    // We must bootstrap all stores before running the server.
    pub fn new(event_loop: &mut EventLoop<Self>,
               cfg: Config,
               engines: Vec<Arc<DB>>,
               pd_client: Arc<RwLock<T>>)
               -> Result<Server<T>> {
        try!(cfg.validate());

        let addr = try!((&cfg.addr).parse());
        let listener = try!(TcpListener::bind(&addr));

        try!(event_loop.register(&listener,
                                 SERVER_TOKEN,
                                 EventSet::readable(),
                                 PollOpt::edge()));

        let sendch = SendCh::new(event_loop.channel());

        let max_conn_capacity = cfg.max_conn_capacity;
        let trans = Arc::new(RwLock::new(ServerTransport::new(cfg.cluster_id,
                                                              sendch.clone(),
                                                              pd_client.clone())));

        let node = Node::new(&cfg, pd_client, trans.clone());

        let mut svr = Server {
            cfg: cfg,
            listener: listener,
            sendch: sendch,
            conns: Slab::new_starting_at(FIRST_CUSTOM_TOKEN, max_conn_capacity),
            peers: HashMap::new(),
            store_handles: HashMap::new(),
            trans: trans,
            node: node,
        };

        try!(svr.node.start(engines));

        Ok(svr)
    }

    pub fn run(&mut self, event_loop: &mut EventLoop<Self>) -> Result<()> {
        try!(event_loop.run(self));
        Ok(())
    }

    pub fn get_node_id(&self) -> u64 {
        self.node.get_node_id()
    }

    pub fn get_sendch(&self) -> SendCh {
        self.sendch.clone()
    }

    // Return listening address, this may only be used for outer test
    // to get the real address because we may use "127.0.0.1:0"
    // in test to avoid port conflict.
    pub fn listening_addr(&self) -> Result<SocketAddr> {
        let addr = try!(self.listener.local_addr());
        Ok(addr)
    }

    fn remove_conn(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        let conn = self.conns.remove(token);
        match conn {
            Some(conn) => {
                // if connected to remote peer, remove this too.
                if let Some(addr) = conn.peer_addr {
                    self.peers.remove(&addr);
                }

                if let Err(e) = event_loop.deregister(&conn.sock) {
                    error!("deregister conn err {:?}", e);
                }
            }
            None => {
                warn!("missing connection for token {}", token.as_usize());
            }
        }
    }

    fn add_new_conn(&mut self,
                    event_loop: &mut EventLoop<Self>,
                    sock: TcpStream,
                    peer_addr: Option<String>)
                    -> Result<Token> {
        try!(sock.set_nodelay(true));

        // TODO: now slab crate doesn't support insert_with_opt, we should use it instead later.
        self.conns
            .insert_with(|new_token: Token| -> Conn {
                // TODO: if insert_with_opt used, we will return None for register error.
                // Now, just panic for this.
                event_loop.register(&sock,
                                    new_token,
                                    EventSet::readable() | EventSet::hup(),
                                    PollOpt::edge())
                          .unwrap();

                Conn::new(sock, new_token, peer_addr)
            })
            .ok_or_else(|| other("add new connection failed"))
    }

    fn handle_conn_readable(&mut self,
                            event_loop: &mut EventLoop<Self>,
                            token: Token)
                            -> Result<()> {
        let msgs = try!(match self.conns.get_mut(token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return Ok(());
            }
            Some(conn) => conn.read(event_loop),
        });

        if msgs.is_empty() {
            // Read no message, no need to handle.
            return Ok(());
        }

        let mut res = vec![];
        for msg in msgs {
            let resp = try!(self.handle_conn_msg(token, msg));
            if let Some(resp) = resp {
                res.push(resp);
            }

        }

        if res.is_empty() {
            return Ok(());
        }

        // append to write buffer here, no need using sender to notify.
        if let Some(conn) = self.conns.get_mut(token) {
            for data in res {
                try!(conn.append_write_buf(event_loop, data));
            }
        }

        Ok(())
    }

    fn handle_conn_msg(&mut self, token: Token, data: ConnData) -> Result<Option<ConnData>> {
        let msg_id = data.msg_id;
        let mut msg = data.msg;

        let msg_type = msg.get_msg_type();
        let res = try!(match msg_type {
            MessageType::Raft => {
                if let Err(e) = self.trans.rl().send_raft_msg(msg.take_raft()) {
                    // Should we return error to let outer close this connection later?
                    error!("send raft message for token {:?} with msg id {} err {:?}",
                           token,
                           msg_id,
                           e);
                }
                Ok(None)
            }
            MessageType::Command => self.handle_conn_command(token, msg_id, msg.take_cmd_req()),
            MessageType::CommandResp => {
                // Now we have no way to handle CommandResp type,
                // so log an error here and do nothing.
                error!("unsupported command response msg {:?} for token {:?} with msg id {}",
                       msg,
                       token,
                       msg_id);
                Ok(None)
            }
            _ => {
                Err(other(format!("unsupported message {:?} for token {:?} with msg id {}",
                                  msg_type,
                                  token,
                                  msg_id)))
            }

        });

        Ok(res)
    }

    fn handle_conn_command(&mut self,
                           token: Token,
                           msg_id: u64,
                           msg: RaftCommandRequest)
                           -> Result<Option<ConnData>> {
        let ch = self.sendch.clone();
        let cb = Box::new(move |resp: RaftCommandResponse| -> Result<()> {
            let mut resp_msg = Message::new();
            resp_msg.set_msg_type(MessageType::CommandResp);
            resp_msg.set_cmd_resp(resp);
            // Use send channel to let server return the
            // response to the specified connection with token.
            ch.write_data(token, ConnData::new(msg_id, resp_msg))
        });

        let uuid = msg.get_header().get_uuid().to_vec();
        if let Err(e) = self.trans.rl().send_command(msg, cb) {
            // send error, reply an error response.
            warn!("send command for token {:?} with msg id {} err {:?}",
                  token,
                  msg_id,
                  e);
            let mut resp = cmd_resp::new_error(e);
            resp.mut_header().set_uuid(uuid);
            let mut resp_msg = Message::new();
            resp_msg.set_msg_type(MessageType::CommandResp);
            resp_msg.set_cmd_resp(resp);
            return Ok(Some(ConnData::new(msg_id, resp_msg)));
        }

        Ok(None)
    }

    fn handle_readable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        match token {
            SERVER_TOKEN => {
                loop {
                    // For edge trigger, we must accept all connections until None.
                    let sock = match self.listener.accept() {
                        Err(e) => {
                            error!("accept error: {:?}", e);
                            return;
                        }
                        Ok(None) => {
                            debug!("no connection, accept later.");
                            return;
                        }
                        Ok(Some((sock, addr))) => {
                            debug!("accept conn {}", addr);
                            sock
                        }
                    };

                    if let Err(e) = self.add_new_conn(event_loop, sock, None) {
                        error!("register conn err {:?}", e);
                    }
                }
            }
            token => {
                if let Err(e) = self.handle_conn_readable(event_loop, token) {
                    warn!("handle read conn for token {:?} err {:?}, remove", token, e);
                    self.remove_conn(event_loop, token);
                }
            }

        }
    }

    fn handle_writable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        let res = match self.conns.get_mut(token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return;
            }
            Some(conn) => conn.write(event_loop),
        };

        if let Err(e) = res {
            warn!("handle write conn err {:?}, remove", e);
            self.remove_conn(event_loop, token);
        }
    }

    fn handle_writedata(&mut self,
                        event_loop: &mut EventLoop<Self>,
                        token: Token,
                        data: ConnData) {
        let res = match self.conns.get_mut(token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return;
            }
            Some(conn) => conn.append_write_buf(event_loop, data),
        };

        if let Err(e) = res {
            warn!("handle write data err {:?}, remove", e);
            self.remove_conn(event_loop, token);
        }
    }

    fn connect_peer(&mut self, event_loop: &mut EventLoop<Self>, addr: &str) -> Result<Token> {
        let peer_addr = try!(addr.parse());
        let sock = try!(TcpStream::connect(&peer_addr));
        let token = try!(self.add_new_conn(event_loop, sock, Some(addr.to_string())));
        self.peers.insert(addr.to_owned(), token);
        Ok(token)
    }

    fn handle_sendpeer(&mut self, event_loop: &mut EventLoop<Self>, addr: String, data: ConnData) {
        // check the corresponding token for peer address.
        let mut token = self.peers.get(&addr).map_or(INVALID_TOKEN, |t| *t);

        if token == INVALID_TOKEN {
            match self.connect_peer(event_loop, &addr) {
                Err(e) => {
                    error!("connect {:?} err {:?}", addr, e);
                    return;
                }
                Ok(new_token) => token = new_token,
            }
        }

        self.handle_writedata(event_loop, token, data);
    }
}

impl<T: PdClient + 'static> Handler for Server<T> {
    type Timeout = Msg;
    type Message = Msg;

    fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
        if events.is_hup() || events.is_error() {
            self.remove_conn(event_loop, token);
            return;
        }

        if events.is_readable() {
            self.handle_readable(event_loop, token);
        }

        if events.is_writable() {
            self.handle_writable(event_loop, token);
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Msg) {
        match msg {
            Msg::Quit => event_loop.shutdown(),
            Msg::WriteData{token, data} => self.handle_writedata(event_loop, token, data),
            Msg::SendPeer{addr, data} => self.handle_sendpeer(event_loop, addr, data),
            _ => panic!("unexpected msg"),
        }
    }

    fn timeout(&mut self, _: &mut EventLoop<Self>, _: Msg) {
        // nothing to do now.
    }

    fn interrupted(&mut self, event_loop: &mut EventLoop<Self>) {
        event_loop.shutdown();
    }

    fn tick(&mut self, _: &mut EventLoop<Self>) {
        // tick is called in the end of the loop, so if we notify to quit,
        // we will quit the server here.
        // TODO: handle quit server if event_loop is_running() returns false.
    }
}
<commit_msg>*: use HashMap again to avoid same token reusing<commit_after>use std::collections::HashMap;
use std::option::Option;
use std::sync::{Arc, RwLock};
use std::vec::Vec;
use std::thread;
use std::boxed::Box;
use std::net::SocketAddr;

use rocksdb::DB;
use mio::{Token, Handler, EventLoop, EventSet, PollOpt};
use mio::tcp::{TcpListener, TcpStream};

use raftserver::{Result, other};
use raftserver::store::cmd_resp;
use kvproto::raft_serverpb::{Message, MessageType};
use kvproto::raft_cmdpb::{RaftCommandRequest, RaftCommandResponse};
use super::{Msg, SendCh, ConnData};
use super::conn::Conn;
use super::config::Config;
use super::transport::ServerTransport;
use super::node::Node;
use pd::PdClient;
use util::HandyRwLock;

const SERVER_TOKEN: Token = Token(1);
const FIRST_CUSTOM_TOKEN: Token = Token(1024);
const INVALID_TOKEN: Token = Token(0);

pub struct Server<T: PdClient + 'static> {
    cfg: Config,

    listener: TcpListener,
    // We use HashMap instead of common use mio slab to avoid token reusing.
    // In our raft server, a client with token 1 sends a raft command, we will
    // propose this command, execute it then send the response to the client with
    // token 1. But before the response, the client connection is broken and another
    // new client connects, mio slab may reuse the token 1 for it. So the subsequent
    // response will be sent to the new client.
    // To avoid this, we use the HashMap instead and can guarantee the token id is
    // unique and can't be reused.
    conns: HashMap<Token, Conn>,
    conn_token_counter: usize,
    sendch: SendCh,

    peers: HashMap<String, Token>,

    store_handles: HashMap<u64, thread::JoinHandle<()>>,

    trans: Arc<RwLock<ServerTransport<T>>>,

    node: Node<T, ServerTransport<T>>,
}

pub fn create_event_loop<T: PdClient + 'static>() -> Result<EventLoop<Server<T>>> {
    let event_loop = try!(EventLoop::new());
    Ok(event_loop)
}

impl<T: PdClient + 'static> Server<T> {
    // Create a server with already initialized engines.
    // We must bootstrap all stores before running the server.
    pub fn new(event_loop: &mut EventLoop<Self>,
               cfg: Config,
               engines: Vec<Arc<DB>>,
               pd_client: Arc<RwLock<T>>)
               -> Result<Server<T>> {
        try!(cfg.validate());

        let addr = try!((&cfg.addr).parse());
        let listener = try!(TcpListener::bind(&addr));

        try!(event_loop.register(&listener,
                                 SERVER_TOKEN,
                                 EventSet::readable(),
                                 PollOpt::edge()));

        let sendch = SendCh::new(event_loop.channel());

        let trans = Arc::new(RwLock::new(ServerTransport::new(cfg.cluster_id,
                                                              sendch.clone(),
                                                              pd_client.clone())));

        let node = Node::new(&cfg, pd_client, trans.clone());

        let mut svr = Server {
            cfg: cfg,
            listener: listener,
            sendch: sendch,
            conns: HashMap::new(),
            conn_token_counter: FIRST_CUSTOM_TOKEN.as_usize(),
            peers: HashMap::new(),
            store_handles: HashMap::new(),
            trans: trans,
            node: node,
        };

        try!(svr.node.start(engines));

        Ok(svr)
    }

    pub fn run(&mut self, event_loop: &mut EventLoop<Self>) -> Result<()> {
        try!(event_loop.run(self));
        Ok(())
    }

    pub fn get_node_id(&self) -> u64 {
        self.node.get_node_id()
    }

    pub fn get_sendch(&self) -> SendCh {
        self.sendch.clone()
    }

    // Return listening address, this may only be used for outer test
    // to get the real address because we may use "127.0.0.1:0"
    // in test to avoid port conflict.
    pub fn listening_addr(&self) -> Result<SocketAddr> {
        let addr = try!(self.listener.local_addr());
        Ok(addr)
    }

    fn remove_conn(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        let conn = self.conns.remove(&token);
        match conn {
            Some(conn) => {
                // if connected to remote peer, remove this too.
                if let Some(addr) = conn.peer_addr {
                    self.peers.remove(&addr);
                }

                if let Err(e) = event_loop.deregister(&conn.sock) {
                    error!("deregister conn err {:?}", e);
                }
            }
            None => {
                warn!("missing connection for token {}", token.as_usize());
            }
        }
    }

    fn add_new_conn(&mut self,
                    event_loop: &mut EventLoop<Self>,
                    sock: TcpStream,
                    peer_addr: Option<String>)
                    -> Result<Token> {
        let new_token = Token(self.conn_token_counter);
        self.conn_token_counter += 1;

        // TODO: check conn max capacity.

        try!(sock.set_nodelay(true));

        try!(event_loop.register(&sock,
                                 new_token,
                                 EventSet::readable() | EventSet::hup(),
                                 PollOpt::edge()));

        let conn = Conn::new(sock, new_token, peer_addr);
        self.conns.insert(new_token, conn);

        Ok(new_token)
    }

    fn handle_conn_readable(&mut self,
                            event_loop: &mut EventLoop<Self>,
                            token: Token)
                            -> Result<()> {
        let msgs = try!(match self.conns.get_mut(&token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return Ok(());
            }
            Some(conn) => conn.read(event_loop),
        });

        if msgs.is_empty() {
            // Read no message, no need to handle.
            return Ok(());
        }

        let mut res = vec![];
        for msg in msgs {
            let resp = try!(self.handle_conn_msg(token, msg));
            if let Some(resp) = resp {
                res.push(resp);
            }

        }

        if res.is_empty() {
            return Ok(());
        }

        // append to write buffer here, no need using sender to notify.
        if let Some(conn) = self.conns.get_mut(&token) {
            for data in res {
                try!(conn.append_write_buf(event_loop, data));
            }
        }

        Ok(())
    }

    fn handle_conn_msg(&mut self, token: Token, data: ConnData) -> Result<Option<ConnData>> {
        let msg_id = data.msg_id;
        let mut msg = data.msg;

        let msg_type = msg.get_msg_type();
        let res = try!(match msg_type {
            MessageType::Raft => {
                if let Err(e) = self.trans.rl().send_raft_msg(msg.take_raft()) {
                    // Should we return error to let outer close this connection later?
                    error!("send raft message for token {:?} with msg id {} err {:?}",
                           token,
                           msg_id,
                           e);
                }
                Ok(None)
            }
            MessageType::Command => self.handle_conn_command(token, msg_id, msg.take_cmd_req()),
            MessageType::CommandResp => {
                // Now we have no way to handle CommandResp type,
                // so log an error here and do nothing.
                error!("unsupported command response msg {:?} for token {:?} with msg id {}",
                       msg,
                       token,
                       msg_id);
                Ok(None)
            }
            _ => {
                Err(other(format!("unsupported message {:?} for token {:?} with msg id {}",
                                  msg_type,
                                  token,
                                  msg_id)))
            }

        });

        Ok(res)
    }

    fn handle_conn_command(&mut self,
                           token: Token,
                           msg_id: u64,
                           msg: RaftCommandRequest)
                           -> Result<Option<ConnData>> {
        let ch = self.sendch.clone();
        let cb = Box::new(move |resp: RaftCommandResponse| -> Result<()> {
            let mut resp_msg = Message::new();
            resp_msg.set_msg_type(MessageType::CommandResp);
            resp_msg.set_cmd_resp(resp);
            // Use send channel to let server return the
            // response to the specified connection with token.
            ch.write_data(token, ConnData::new(msg_id, resp_msg))
        });

        let uuid = msg.get_header().get_uuid().to_vec();
        if let Err(e) = self.trans.rl().send_command(msg, cb) {
            // send error, reply an error response.
            warn!("send command for token {:?} with msg id {} err {:?}",
                  token,
                  msg_id,
                  e);
            let mut resp = cmd_resp::new_error(e);
            resp.mut_header().set_uuid(uuid);
            let mut resp_msg = Message::new();
            resp_msg.set_msg_type(MessageType::CommandResp);
            resp_msg.set_cmd_resp(resp);
            return Ok(Some(ConnData::new(msg_id, resp_msg)));
        }

        Ok(None)
    }

    fn handle_readable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        match token {
            SERVER_TOKEN => {
                loop {
                    // For edge trigger, we must accept all connections until None.
                    let sock = match self.listener.accept() {
                        Err(e) => {
                            error!("accept error: {:?}", e);
                            return;
                        }
                        Ok(None) => {
                            debug!("no connection, accept later.");
                            return;
                        }
                        Ok(Some((sock, addr))) => {
                            debug!("accept conn {}", addr);
                            sock
                        }
                    };

                    if let Err(e) = self.add_new_conn(event_loop, sock, None) {
                        error!("register conn err {:?}", e);
                    }
                }
            }
            token => {
                if let Err(e) = self.handle_conn_readable(event_loop, token) {
                    warn!("handle read conn for token {:?} err {:?}, remove", token, e);
                    self.remove_conn(event_loop, token);
                }
            }

        }
    }

    fn handle_writable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {
        let res = match self.conns.get_mut(&token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return;
            }
            Some(conn) => conn.write(event_loop),
        };

        if let Err(e) = res {
            warn!("handle write conn err {:?}, remove", e);
            self.remove_conn(event_loop, token);
        }
    }

    fn handle_writedata(&mut self,
                        event_loop: &mut EventLoop<Self>,
                        token: Token,
                        data: ConnData) {
        let res = match self.conns.get_mut(&token) {
            None => {
                warn!("missing conn for token {:?}", token);
                return;
            }
            Some(conn) => conn.append_write_buf(event_loop, data),
        };

        if let Err(e) = res {
            warn!("handle write data err {:?}, remove", e);
            self.remove_conn(event_loop, token);
        }
    }

    fn connect_peer(&mut self, event_loop: &mut EventLoop<Self>, addr: &str) -> Result<Token> {
        let peer_addr = try!(addr.parse());
        let sock = try!(TcpStream::connect(&peer_addr));
        let token = try!(self.add_new_conn(event_loop, sock, Some(addr.to_string())));
        self.peers.insert(addr.to_owned(), token);
        Ok(token)
    }

    fn handle_sendpeer(&mut self, event_loop: &mut EventLoop<Self>, addr: String, data: ConnData) {
        // check the corresponding token for peer address.
        let mut token = self.peers.get(&addr).map_or(INVALID_TOKEN, |t| *t);

        if token == INVALID_TOKEN {
            match self.connect_peer(event_loop, &addr) {
                Err(e) => {
                    error!("connect {:?} err {:?}", addr, e);
                    return;
                }
                Ok(new_token) => token = new_token,
            }
        }

        self.handle_writedata(event_loop, token, data);
    }
}

impl<T: PdClient + 'static> Handler for Server<T> {
    type Timeout = Msg;
    type Message = Msg;

    fn ready(&mut self, event_loop: &mut EventLoop<Self>, token: Token, events: EventSet) {
        if events.is_hup() || events.is_error() {
            self.remove_conn(event_loop, token);
            return;
        }

        if events.is_readable() {
            self.handle_readable(event_loop, token);
        }

        if events.is_writable() {
            self.handle_writable(event_loop, token);
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Self>, msg: Msg) {
        match msg {
            Msg::Quit => event_loop.shutdown(),
            Msg::WriteData{token, data} => self.handle_writedata(event_loop, token, data),
            Msg::SendPeer{addr, data} => self.handle_sendpeer(event_loop, addr, data),
            _ => panic!("unexpected msg"),
        }
    }

    fn timeout(&mut self, _: &mut EventLoop<Self>, _: Msg) {
        // nothing to do now.
    }

    fn interrupted(&mut self, event_loop: &mut EventLoop<Self>) {
        event_loop.shutdown();
    }

    fn tick(&mut self, _: &mut EventLoop<Self>) {
        // tick is called in the end of the loop, so if we notify to quit,
        // we will quit the server here.
        // TODO: handle quit server if event_loop is_running() returns false.
    }
}
<|endoftext|>


<commit_before>use std::result::Result;

use super::script::*;

///
/// Represents a parse error
///
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

impl ParseError {
    pub fn new() -> ParseError {
        ParseError { }
    }
}

struct ParseState<'a> {
    remaining: &'a [ScriptToken]
}

impl<'a> ParseState<'a> {
    ///
    /// Returns true if a token is considered syntax (gets returned from lookahead)
    ///
    fn is_syntax(token: &ScriptToken) -> bool {
        match token.token {
            ScriptLexerToken::Whitespace    |
            ScriptLexerToken::Comment       => false,

            _                               => true
        }
    }

    ///
    /// Looks ahead to the next syntactically relevant lexer match (and returns the tokens after it)
    ///
    fn lookahead(&self) -> Option<(&'a ScriptToken, &'a [ScriptToken])> {
        let mut index   = 0;
        let len         = self.remaining.len();

        loop {
            if index >= len {
                return None;
            } else if ParseState::is_syntax(&self.remaining[index]) {
                let token       = &self.remaining[index];
                let remaining   = &self.remaining[index+1..len];
                return Some((token, remaining));
            }

            index += 1;
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn lookahead_is(&self, token: ScriptLexerToken) -> bool {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches
                true
            } else {
                // Token does not match
                false
            }
        } else {
            // End of file
            if token == ScriptLexerToken::EndOfFile {
                // With lookahead_is we can look for the end of file (but we can't accept it because there's no token data associated with it)
                true
            } else {
                false
            }
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn accept(&mut self, token: ScriptLexerToken) -> Option<&'a ScriptToken> {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches: remove it from the input and return it
                self.remaining = remaining;
                Some(lookahead)
            } else {
                // Next token does not match
                None
            }
        } else {
            // Reached the end of file
            None
        }
    }

    ///
    /// Parses a statement
    ///
    pub fn parse_statement(&mut self) -> Result<Script, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Newlines are ignored
            self.parse_statement()
        } else if self.accept(ScriptLexerToken::Let).is_some() {
            // self.parse_let()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Var).is_some() {
            // self.parse_var()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Def).is_some() {
            // self.parse_def()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::If).is_some() {
            // self.parse_if()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Using).is_some() {
            // self.parse_using()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::While).is_some() {
            // self.parse_while()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Loop).is_some() {
            // self.parse_loop()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::For).is_some() {
            // self.parse_for()
            unimplemented!()
        } else if self.lookahead_is(ScriptLexerToken::Identifier) {
            // While commands are either <Expression> or <Expression> <Expression>, we
            // force the first expression to be an identifier at the moment
            self.parse_command()
        } else {
            // Unrecognised token
            Err(ParseError::new())
        }
    }

    ///
    /// Parses a command
    ///
    /// Syntax '<expression>', '<expression> <expression>'
    ///
    pub fn parse_command(&mut self) -> Result<Script, ParseError> {
        // Starts with an expression specifying the command to run
        self.parse_expression().and_then(move |command_expression| {
            // Followed by arguments (or an end-of-expression marker)
            if self.accept(ScriptLexerToken::Newline).is_some()
               || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                // Newline or EOF ends a command
                Ok(Script::RunCommand(command_expression, None))

            } else {
                // Anything else should be an argument expression
                self.parse_expression().and_then(move |argument_expression| {
                    Ok(Script::RunCommand(command_expression, Some(argument_expression)))

                }).and_then(move |command| {
                    // Command must be followed by a newline
                    if self.accept(ScriptLexerToken::Newline).is_some()
                       || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                        Ok(command)
                    } else {
                        Err(ParseError::new())
                    }

                })

            }
        })
    }

    ///
    /// Parses an Expression
    ///
    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        unimplemented!()
        /*
        if let Some((lookahead1, remainder1)) = lookahead(input) {
            let expr1 = match lookahead1.token {
                ScriptLexerToken::Identifier    => Ok((Expression::Identifier(lookahead1.clone()), remainder)),
                ScriptLexerToken::Number        |
                ScriptLexerToken::HexNumber     => Ok((Expression::Number(lookahead1.clone()), remainder)),
                ScriptLexerToken::String        => Ok((Expression::String(lookahead1.clone()), remainder)),

                _ => Err(ParseError::new())
            };

            expr1
        } else {
            // EOF
            Err(ParseError::new())
        }
        */
    }

    /*
    pub fn parse_let<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_var<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_def<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_if<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_using<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_while<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_loop<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_for<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }
    */
}

impl ParseScriptTool {
    ///
    /// Creates a new script parsing tool
    ///
    pub fn new() -> ParseScriptTool {
        ParseScriptTool { }
    }
}<commit_msg>Basic implementation of the expression parser (can’t do complicated expressions yet…)<commit_after>use std::result::Result;

use super::script::*;

///
/// Represents a parse error
///
pub struct ParseError {

}

///
/// Tool that parses our scripting language
///
pub struct ParseScriptTool {
}

impl ParseError {
    pub fn new() -> ParseError {
        ParseError { }
    }
}

struct ParseState<'a> {
    remaining: &'a [ScriptToken]
}

impl<'a> ParseState<'a> {
    ///
    /// Returns true if a token is considered syntax (gets returned from lookahead)
    ///
    fn is_syntax(token: &ScriptToken) -> bool {
        match token.token {
            ScriptLexerToken::Whitespace    |
            ScriptLexerToken::Comment       => false,

            _                               => true
        }
    }

    ///
    /// Looks ahead to the next syntactically relevant lexer match (and returns the tokens after it)
    ///
    fn lookahead(&self) -> Option<(&'a ScriptToken, &'a [ScriptToken])> {
        let mut index   = 0;
        let len         = self.remaining.len();

        loop {
            if index >= len {
                return None;
            } else if ParseState::is_syntax(&self.remaining[index]) {
                let token       = &self.remaining[index];
                let remaining   = &self.remaining[index+1..len];
                return Some((token, remaining));
            }

            index += 1;
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn lookahead_is(&self, token: ScriptLexerToken) -> bool {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches
                true
            } else {
                // Token does not match
                false
            }
        } else {
            // End of file
            if token == ScriptLexerToken::EndOfFile {
                // With lookahead_is we can look for the end of file (but we can't accept it because there's no token data associated with it)
                true
            } else {
                false
            }
        }
    }

    ///
    /// If the next token matches the specified token, consumes it and returns
    /// its content.
    ///
    fn accept(&mut self, token: ScriptLexerToken) -> Option<&'a ScriptToken> {
        if let Some((lookahead, remaining)) = self.lookahead() {
            if lookahead.token == token {
                // Token matches: remove it from the input and return it
                self.remaining = remaining;
                Some(lookahead)
            } else {
                // Next token does not match
                None
            }
        } else {
            // Reached the end of file
            None
        }
    }

    ///
    /// Parses a statement
    ///
    pub fn parse_statement(&mut self) -> Result<Script, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Newlines are ignored
            self.parse_statement()
        } else if self.accept(ScriptLexerToken::Let).is_some() {
            // self.parse_let()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Var).is_some() {
            // self.parse_var()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Def).is_some() {
            // self.parse_def()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::If).is_some() {
            // self.parse_if()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Using).is_some() {
            // self.parse_using()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::While).is_some() {
            // self.parse_while()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::Loop).is_some() {
            // self.parse_loop()
            unimplemented!()
        } else if self.accept(ScriptLexerToken::For).is_some() {
            // self.parse_for()
            unimplemented!()
        } else if self.lookahead_is(ScriptLexerToken::Identifier) {
            // While commands are either <Expression> or <Expression> <Expression>, we
            // force the first expression to be an identifier at the moment
            self.parse_command()
        } else {
            // Unrecognised token
            Err(ParseError::new())
        }
    }

    ///
    /// Parses a command
    ///
    /// Syntax '<expression>', '<expression> <expression>'
    ///
    pub fn parse_command(&mut self) -> Result<Script, ParseError> {
        // Starts with an expression specifying the command to run
        self.parse_expression().and_then(move |command_expression| {
            // Followed by arguments (or an end-of-expression marker)
            if self.accept(ScriptLexerToken::Newline).is_some()
               || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                // Newline or EOF ends a command
                Ok(Script::RunCommand(command_expression, None))

            } else {
                // Anything else should be an argument expression
                self.parse_expression().and_then(move |argument_expression| {
                    Ok(Script::RunCommand(command_expression, Some(argument_expression)))

                }).and_then(move |command| {
                    // Command must be followed by a newline
                    if self.accept(ScriptLexerToken::Newline).is_some()
                       || self.lookahead_is(ScriptLexerToken::EndOfFile) {
                        Ok(command)
                    } else {
                        Err(ParseError::new())
                    }

                })

            }
        })
    }

    ///
    /// Parses an Expression
    ///
    pub fn parse_expression(&mut self) -> Result<Expression, ParseError> {
        if self.accept(ScriptLexerToken::Newline).is_some() {
            // Ignore newlines within an expression
            self.parse_expression()

        } else if let Some(identifier) = self.accept(ScriptLexerToken::Identifier) {
            // Simple expression
            Ok(Expression::Identifier(identifier.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::Number) {
            // Simple expression
            Ok(Expression::Number(number.clone()))

        } else if let Some(number) = self.accept(ScriptLexerToken::HexNumber) {
            // Hex numbers work like normal numbers
            Ok(Expression::Number(number.clone()))

        } else if let Some(string) = self.accept(ScriptLexerToken::String) {
            // Simple expression
            Ok(Expression::String(string.clone()))

        } else {
            // Syntax error
            Err(ParseError::new())

        }
    }

    /*
    pub fn parse_let<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_var<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_def<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_if<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_using<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_while<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_loop<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }

    pub fn parse_for<'a>(input: &'a [ScriptToken]) -> Result<(Script, &'a [ScriptToken]), ParseError> {
        unimplemented!()
    }
    */
}

impl ParseScriptTool {
    ///
    /// Creates a new script parsing tool
    ///
    pub fn new() -> ParseScriptTool {
        ParseScriptTool { }
    }
}<|endoftext|>


<commit_before>#![cfg(not(syn_disable_nightly_tests))]
#![cfg(not(miri))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]
#![allow(clippy::manual_assert)]

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_error_messages;
extern crate rustc_errors;
extern crate rustc_expand;
extern crate rustc_parse as parse;
extern crate rustc_session;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use rustc_ast::ast::{
    AngleBracketedArg, AngleBracketedArgs, Crate, GenericArg, GenericParamKind, Generics,
    WhereClause,
};
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_error_messages::{DiagnosticMessage, FluentArgs, LazyFallbackBundle};
use rustc_errors::{Diagnostic, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
use rustc_span::FileName;
use std::fs;
use std::panic;
use std::path::Path;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

#[test]
fn test_round_trip() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all round_trip tests");
    }

    let failed = AtomicUsize::new(0);

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if !path.is_dir() {
                test(path, &failed, abort_after);
            }
        });

    let failed = failed.load(Ordering::Relaxed);
    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test(path: &Path, failed: &AtomicUsize, abort_after: usize) {
    let content = fs::read_to_string(path).unwrap();

    let start = Instant::now();
    let (krate, elapsed) = match syn::parse_file(&content) {
        Ok(krate) => (krate, start.elapsed()),
        Err(msg) => {
            errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg);
            let prev_failed = failed.fetch_add(1, Ordering::Relaxed);
            if prev_failed + 1 >= abort_after {
                process::exit(1);
            }
            return;
        }
    };
    let back = quote!(#krate).to_string();
    let edition = repo::edition(path).parse().unwrap();

    rustc_span::create_session_if_not_set_then(edition, |_| {
        let equal = match panic::catch_unwind(|| {
            let sess = ParseSess::new(FilePathMapping::empty());
            let before = match librustc_parse(content, &sess) {
                Ok(before) => before,
                Err(diagnostic) => {
                    errorf!(
                        "=== {}: ignore - librustc failed to parse original content: {}\n",
                        path.display(),
                        translate_message(&diagnostic),
                    );
                    diagnostic.cancel();
                    return Err(true);
                }
            };
            let after = match librustc_parse(back, &sess) {
                Ok(after) => after,
                Err(mut diagnostic) => {
                    errorf!("=== {}: librustc failed to parse", path.display());
                    diagnostic.emit();
                    return Err(false);
                }
            };
            Ok((before, after))
        }) {
            Err(_) => {
                errorf!("=== {}: ignoring librustc panic\n", path.display());
                true
            }
            Ok(Err(equal)) => equal,
            Ok(Ok((mut before, mut after))) => {
                normalize(&mut before);
                normalize(&mut after);
                if SpanlessEq::eq(&before, &after) {
                    errorf!(
                        "=== {}: pass in {}ms\n",
                        path.display(),
                        elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_nanos()) / 1_000_000
                    );
                    true
                } else {
                    errorf!(
                        "=== {}: FAIL\nbefore: {:#?}\nafter: {:#?}\n",
                        path.display(),
                        before,
                        after,
                    );
                    false
                }
            }
        };
        if !equal {
            let prev_failed = failed.fetch_add(1, Ordering::Relaxed);
            if prev_failed + 1 >= abort_after {
                process::exit(1);
            }
        }
    });
}

fn librustc_parse(content: String, sess: &ParseSess) -> PResult<Crate> {
    static COUNTER: AtomicUsize = AtomicUsize::new(0);
    let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
    let name = FileName::Custom(format!("test_round_trip{}", counter));
    parse::parse_crate_from_source_str(name, content, sess)
}

fn translate_message(diagnostic: &Diagnostic) -> String {
    thread_local! {
        static FLUENT_BUNDLE: LazyFallbackBundle = {
            let resources = rustc_error_messages::DEFAULT_LOCALE_RESOURCES;
            let with_directionality_markers = false;
            rustc_error_messages::fallback_fluent_bundle(resources, with_directionality_markers)
        };
    }

    let message = &diagnostic.message[0].0;
    let args = diagnostic.args().iter().cloned().collect::<FluentArgs>();

    let (identifier, attr) = match message {
        DiagnosticMessage::Str(msg) => return msg.clone(),
        DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
    };

    FLUENT_BUNDLE.with(|fluent_bundle| {
        let message = fluent_bundle
            .get_message(identifier)
            .expect("missing diagnostic in fluent bundle");
        let value = match attr {
            Some(attr) => message
                .get_attribute(attr)
                .expect("missing attribute in fluent message")
                .value(),
            None => message.value().expect("missing value in fluent message"),
        };

        let mut err = Vec::new();
        let translated = fluent_bundle.format_pattern(value, Some(&args), &mut err);
        assert!(err.is_empty());
        translated.into_owned()
    })
}

fn normalize(krate: &mut Crate) {
    struct NormalizeVisitor;

    impl MutVisitor for NormalizeVisitor {
        fn visit_angle_bracketed_parameter_data(&mut self, e: &mut AngleBracketedArgs) {
            #[derive(Ord, PartialOrd, Eq, PartialEq)]
            enum Group {
                Lifetimes,
                TypesAndConsts,
                Constraints,
            }
            e.args.sort_by_key(|arg| match arg {
                AngleBracketedArg::Arg(arg) => match arg {
                    GenericArg::Lifetime(_) => Group::Lifetimes,
                    GenericArg::Type(_) | GenericArg::Const(_) => Group::TypesAndConsts,
                },
                AngleBracketedArg::Constraint(_) => Group::Constraints,
            });
            mut_visit::noop_visit_angle_bracketed_parameter_data(e, self);
        }

        fn visit_generics(&mut self, e: &mut Generics) {
            #[derive(Ord, PartialOrd, Eq, PartialEq)]
            enum Group {
                Lifetimes,
                TypesAndConsts,
            }
            e.params.sort_by_key(|param| match param.kind {
                GenericParamKind::Lifetime => Group::Lifetimes,
                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                    Group::TypesAndConsts
                }
            });
            mut_visit::noop_visit_generics(e, self);
        }

        fn visit_where_clause(&mut self, e: &mut WhereClause) {
            if e.predicates.is_empty() {
                e.has_where_token = false;
            }
        }
    }

    NormalizeVisitor.visit_crate(krate);
}
<commit_msg>Update test suite to nightly-2022-10-13<commit_after>#![cfg(not(syn_disable_nightly_tests))]
#![cfg(not(miri))]
#![recursion_limit = "1024"]
#![feature(rustc_private)]
#![allow(clippy::manual_assert)]

extern crate rustc_ast;
extern crate rustc_data_structures;
extern crate rustc_error_messages;
extern crate rustc_errors;
extern crate rustc_expand;
extern crate rustc_parse as parse;
extern crate rustc_session;
extern crate rustc_span;

use crate::common::eq::SpanlessEq;
use quote::quote;
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use rustc_ast::ast::{
    AngleBracketedArg, AngleBracketedArgs, Crate, GenericArg, GenericParamKind, Generics,
    WhereClause,
};
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_error_messages::{DiagnosticMessage, LazyFallbackBundle};
use rustc_errors::{translation, Diagnostic, PResult};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
use rustc_span::FileName;
use std::fs;
use std::panic;
use std::path::Path;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::time::Instant;
use walkdir::{DirEntry, WalkDir};

#[macro_use]
mod macros;

#[allow(dead_code)]
mod common;

mod repo;

#[test]
fn test_round_trip() {
    common::rayon_init();
    repo::clone_rust();
    let abort_after = common::abort_after();
    if abort_after == 0 {
        panic!("Skipping all round_trip tests");
    }

    let failed = AtomicUsize::new(0);

    WalkDir::new("tests/rust")
        .sort_by(|a, b| a.file_name().cmp(b.file_name()))
        .into_iter()
        .filter_entry(repo::base_dir_filter)
        .collect::<Result<Vec<DirEntry>, walkdir::Error>>()
        .unwrap()
        .into_par_iter()
        .for_each(|entry| {
            let path = entry.path();
            if !path.is_dir() {
                test(path, &failed, abort_after);
            }
        });

    let failed = failed.load(Ordering::Relaxed);
    if failed > 0 {
        panic!("{} failures", failed);
    }
}

fn test(path: &Path, failed: &AtomicUsize, abort_after: usize) {
    let content = fs::read_to_string(path).unwrap();

    let start = Instant::now();
    let (krate, elapsed) = match syn::parse_file(&content) {
        Ok(krate) => (krate, start.elapsed()),
        Err(msg) => {
            errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg);
            let prev_failed = failed.fetch_add(1, Ordering::Relaxed);
            if prev_failed + 1 >= abort_after {
                process::exit(1);
            }
            return;
        }
    };
    let back = quote!(#krate).to_string();
    let edition = repo::edition(path).parse().unwrap();

    rustc_span::create_session_if_not_set_then(edition, |_| {
        let equal = match panic::catch_unwind(|| {
            let sess = ParseSess::new(FilePathMapping::empty());
            let before = match librustc_parse(content, &sess) {
                Ok(before) => before,
                Err(diagnostic) => {
                    errorf!(
                        "=== {}: ignore - librustc failed to parse original content: {}\n",
                        path.display(),
                        translate_message(&diagnostic),
                    );
                    diagnostic.cancel();
                    return Err(true);
                }
            };
            let after = match librustc_parse(back, &sess) {
                Ok(after) => after,
                Err(mut diagnostic) => {
                    errorf!("=== {}: librustc failed to parse", path.display());
                    diagnostic.emit();
                    return Err(false);
                }
            };
            Ok((before, after))
        }) {
            Err(_) => {
                errorf!("=== {}: ignoring librustc panic\n", path.display());
                true
            }
            Ok(Err(equal)) => equal,
            Ok(Ok((mut before, mut after))) => {
                normalize(&mut before);
                normalize(&mut after);
                if SpanlessEq::eq(&before, &after) {
                    errorf!(
                        "=== {}: pass in {}ms\n",
                        path.display(),
                        elapsed.as_secs() * 1000 + u64::from(elapsed.subsec_nanos()) / 1_000_000
                    );
                    true
                } else {
                    errorf!(
                        "=== {}: FAIL\nbefore: {:#?}\nafter: {:#?}\n",
                        path.display(),
                        before,
                        after,
                    );
                    false
                }
            }
        };
        if !equal {
            let prev_failed = failed.fetch_add(1, Ordering::Relaxed);
            if prev_failed + 1 >= abort_after {
                process::exit(1);
            }
        }
    });
}

fn librustc_parse(content: String, sess: &ParseSess) -> PResult<Crate> {
    static COUNTER: AtomicUsize = AtomicUsize::new(0);
    let counter = COUNTER.fetch_add(1, Ordering::Relaxed);
    let name = FileName::Custom(format!("test_round_trip{}", counter));
    parse::parse_crate_from_source_str(name, content, sess)
}

fn translate_message(diagnostic: &Diagnostic) -> String {
    thread_local! {
        static FLUENT_BUNDLE: LazyFallbackBundle = {
            let resources = rustc_error_messages::DEFAULT_LOCALE_RESOURCES;
            let with_directionality_markers = false;
            rustc_error_messages::fallback_fluent_bundle(resources, with_directionality_markers)
        };
    }

    let message = &diagnostic.message[0].0;
    let args = translation::to_fluent_args(diagnostic.args());

    let (identifier, attr) = match message {
        DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => return msg.clone(),
        DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr),
    };

    FLUENT_BUNDLE.with(|fluent_bundle| {
        let message = fluent_bundle
            .get_message(identifier)
            .expect("missing diagnostic in fluent bundle");
        let value = match attr {
            Some(attr) => message
                .get_attribute(attr)
                .expect("missing attribute in fluent message")
                .value(),
            None => message.value().expect("missing value in fluent message"),
        };

        let mut err = Vec::new();
        let translated = fluent_bundle.format_pattern(value, Some(&args), &mut err);
        assert!(err.is_empty());
        translated.into_owned()
    })
}

fn normalize(krate: &mut Crate) {
    struct NormalizeVisitor;

    impl MutVisitor for NormalizeVisitor {
        fn visit_angle_bracketed_parameter_data(&mut self, e: &mut AngleBracketedArgs) {
            #[derive(Ord, PartialOrd, Eq, PartialEq)]
            enum Group {
                Lifetimes,
                TypesAndConsts,
                Constraints,
            }
            e.args.sort_by_key(|arg| match arg {
                AngleBracketedArg::Arg(arg) => match arg {
                    GenericArg::Lifetime(_) => Group::Lifetimes,
                    GenericArg::Type(_) | GenericArg::Const(_) => Group::TypesAndConsts,
                },
                AngleBracketedArg::Constraint(_) => Group::Constraints,
            });
            mut_visit::noop_visit_angle_bracketed_parameter_data(e, self);
        }

        fn visit_generics(&mut self, e: &mut Generics) {
            #[derive(Ord, PartialOrd, Eq, PartialEq)]
            enum Group {
                Lifetimes,
                TypesAndConsts,
            }
            e.params.sort_by_key(|param| match param.kind {
                GenericParamKind::Lifetime => Group::Lifetimes,
                GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                    Group::TypesAndConsts
                }
            });
            mut_visit::noop_visit_generics(e, self);
        }

        fn visit_where_clause(&mut self, e: &mut WhereClause) {
            if e.predicates.is_empty() {
                e.has_where_token = false;
            }
        }
    }

    NormalizeVisitor.visit_crate(krate);
}
<|endoftext|>


<commit_before>use std::env;

use support::registry::Package;
use support::{basic_bin_manifest, basic_manifest, git, main_file, project};

#[test]
fn cargo_clean_simple() {
    let p = project()
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
        .build();

    p.cargo("build").run();
    assert!(p.build_dir().is_dir());

    p.cargo("clean").run();
    assert!(!p.build_dir().is_dir());
}

#[test]
fn different_dir() {
    let p = project()
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
        .file("src/bar/a.rs", "")
        .build();

    p.cargo("build").run();
    assert!(p.build_dir().is_dir());

    p.cargo("clean")
        .cwd(&p.root().join("src"))
        .with_stdout("")
        .run();
    assert!(!p.build_dir().is_dir());
}

#[test]
fn clean_multiple_packages() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.d1]
                path = "d1"
            [dependencies.d2]
                path = "d2"

            [[bin]]
                name = "foo"
        "#,
        ).file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
        .file("d1/Cargo.toml", &basic_bin_manifest("d1"))
        .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }")
        .file("d2/Cargo.toml", &basic_bin_manifest("d2"))
        .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }")
        .build();

    p.cargo("build -p d1 -p d2 -p foo").run();

    let d1_path = &p
        .build_dir()
        .join("debug")
        .join(format!("d1{}", env::consts::EXE_SUFFIX));
    let d2_path = &p
        .build_dir()
        .join("debug")
        .join(format!("d2{}", env::consts::EXE_SUFFIX));

    assert!(p.bin("foo").is_file());
    assert!(d1_path.is_file());
    assert!(d2_path.is_file());

    p.cargo("clean -p d1 -p d2")
        .cwd(&p.root().join("src"))
        .with_stdout("")
        .run();
    assert!(p.bin("foo").is_file());
    assert!(!d1_path.is_file());
    assert!(!d2_path.is_file());
}

#[test]
fn clean_release() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#,
        ).file("src/main.rs", "fn main() {}")
        .file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
        .file("a/src/lib.rs", "")
        .build();

    p.cargo("build --release").run();

    p.cargo("clean -p foo").run();
    p.cargo("build --release").with_stdout("").run();

    p.cargo("clean -p foo --release").run();
    p.cargo("build --release")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] release [optimized] target(s) in [..]
",
        ).run();
}

#[test]
fn clean_doc() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#,
        ).file("src/main.rs", "fn main() {}")
        .file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
        .file("a/src/lib.rs", "")
        .build();

    p.cargo("doc").run();

    let doc_path = &p.build_dir().join("doc");

    assert!(doc_path.is_dir());

    p.cargo("clean --doc").run();

    assert!(!doc_path.is_dir());
    assert!(p.build_dir().is_dir());
}

#[test]
fn build_script() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"
        "#,
        ).file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
            use std::path::PathBuf;
            use std::env;

            fn main() {
                let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
                if env::var("FIRST").is_ok() {
                    std::fs::File::create(out.join("out")).unwrap();
                } else {
                    assert!(!std::fs::metadata(out.join("out")).is_ok());
                }
            }
        "#,
        ).file("a/src/lib.rs", "")
        .build();

    p.cargo("build").env("FIRST", "1").run();
    p.cargo("clean -p foo").run();
    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[RUNNING] `rustc [..] build.rs [..]`
[RUNNING] `[..]build-script-build`
[RUNNING] `rustc [..] src/main.rs [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
        ).run();
}

#[test]
fn clean_git() {
    let git = git::new("dep", |project| {
        project
            .file("Cargo.toml", &basic_manifest("dep", "0.5.0"))
            .file("src/lib.rs", "")
    }).unwrap();

    let p = project()
        .file(
            "Cargo.toml",
            &format!(
                r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            dep = {{ git = '{}' }}
        "#,
                git.url()
            ),
        ).file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build").run();
    p.cargo("clean -p dep").with_stdout("").run();
    p.cargo("build").run();
}

#[test]
fn registry() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = "0.1"
        "#,
        ).file("src/main.rs", "fn main() {}")
        .build();

    Package::new("bar", "0.1.0").publish();

    p.cargo("build").run();
    p.cargo("clean -p bar").with_stdout("").run();
    p.cargo("build").run();
}

#[test]
fn clean_verbose() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
        [package]
        name = "foo"
        version = "0.0.1"

        [dependencies]
        bar = "0.1"
    "#,
        ).file("src/main.rs", "fn main() {}")
        .build();

    Package::new("bar", "0.1.0").publish();

    p.cargo("build").run();
    p.cargo("clean -p bar --verbose")
        .with_stderr(
            "\
[REMOVING] [..]
[REMOVING] [..]
",
        ).run();
    p.cargo("build").run();
}
<commit_msg>test cargo clean with --release option<commit_after>use std::env;

use support::registry::Package;
use support::{basic_bin_manifest, basic_manifest, git, main_file, project};

#[test]
fn cargo_clean_simple() {
    let p = project()
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
        .build();

    p.cargo("build").run();
    assert!(p.build_dir().is_dir());

    p.cargo("clean").run();
    assert!(!p.build_dir().is_dir());
}

#[test]
fn different_dir() {
    let p = project()
        .file("Cargo.toml", &basic_bin_manifest("foo"))
        .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
        .file("src/bar/a.rs", "")
        .build();

    p.cargo("build").run();
    assert!(p.build_dir().is_dir());

    p.cargo("clean")
        .cwd(&p.root().join("src"))
        .with_stdout("")
        .run();
    assert!(!p.build_dir().is_dir());
}

#[test]
fn clean_multiple_packages() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies.d1]
                path = "d1"
            [dependencies.d2]
                path = "d2"

            [[bin]]
                name = "foo"
        "#,
        ).file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
        .file("d1/Cargo.toml", &basic_bin_manifest("d1"))
        .file("d1/src/main.rs", "fn main() { println!(\"d1\"); }")
        .file("d2/Cargo.toml", &basic_bin_manifest("d2"))
        .file("d2/src/main.rs", "fn main() { println!(\"d2\"); }")
        .build();

    p.cargo("build -p d1 -p d2 -p foo").run();

    let d1_path = &p
        .build_dir()
        .join("debug")
        .join(format!("d1{}", env::consts::EXE_SUFFIX));
    let d2_path = &p
        .build_dir()
        .join("debug")
        .join(format!("d2{}", env::consts::EXE_SUFFIX));

    assert!(p.bin("foo").is_file());
    assert!(d1_path.is_file());
    assert!(d2_path.is_file());

    p.cargo("clean -p d1 -p d2")
        .cwd(&p.root().join("src"))
        .with_stdout("")
        .run();
    assert!(p.bin("foo").is_file());
    assert!(!d1_path.is_file());
    assert!(!d2_path.is_file());
}

#[test]
fn clean_release() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#,
        ).file("src/main.rs", "fn main() {}")
        .file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
        .file("a/src/lib.rs", "")
        .build();

    p.cargo("build --release").run();

    p.cargo("clean -p foo").run();
    p.cargo("build --release").with_stdout("").run();

    p.cargo("clean -p foo --release").run();
    p.cargo("build --release")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[FINISHED] release [optimized] target(s) in [..]
",
        ).run();

    p.cargo("clean").arg("--release").run();
    assert!(!p.build_dir().join("release").is_dir());
}

#[test]
fn clean_doc() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            a = { path = "a" }
        "#,
        ).file("src/main.rs", "fn main() {}")
        .file("a/Cargo.toml", &basic_manifest("a", "0.0.1"))
        .file("a/src/lib.rs", "")
        .build();

    p.cargo("doc").run();

    let doc_path = &p.build_dir().join("doc");

    assert!(doc_path.is_dir());

    p.cargo("clean --doc").run();

    assert!(!doc_path.is_dir());
    assert!(p.build_dir().is_dir());
}

#[test]
fn build_script() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []
            build = "build.rs"
        "#,
        ).file("src/main.rs", "fn main() {}")
        .file(
            "build.rs",
            r#"
            use std::path::PathBuf;
            use std::env;

            fn main() {
                let out = PathBuf::from(env::var_os("OUT_DIR").unwrap());
                if env::var("FIRST").is_ok() {
                    std::fs::File::create(out.join("out")).unwrap();
                } else {
                    assert!(!std::fs::metadata(out.join("out")).is_ok());
                }
            }
        "#,
        ).file("a/src/lib.rs", "")
        .build();

    p.cargo("build").env("FIRST", "1").run();
    p.cargo("clean -p foo").run();
    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] foo v0.0.1 ([..])
[RUNNING] `rustc [..] build.rs [..]`
[RUNNING] `[..]build-script-build`
[RUNNING] `rustc [..] src/main.rs [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
        ).run();
}

#[test]
fn clean_git() {
    let git = git::new("dep", |project| {
        project
            .file("Cargo.toml", &basic_manifest("dep", "0.5.0"))
            .file("src/lib.rs", "")
    }).unwrap();

    let p = project()
        .file(
            "Cargo.toml",
            &format!(
                r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            dep = {{ git = '{}' }}
        "#,
                git.url()
            ),
        ).file("src/main.rs", "fn main() {}")
        .build();

    p.cargo("build").run();
    p.cargo("clean -p dep").with_stdout("").run();
    p.cargo("build").run();
}

#[test]
fn registry() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"
            authors = []

            [dependencies]
            bar = "0.1"
        "#,
        ).file("src/main.rs", "fn main() {}")
        .build();

    Package::new("bar", "0.1.0").publish();

    p.cargo("build").run();
    p.cargo("clean -p bar").with_stdout("").run();
    p.cargo("build").run();
}

#[test]
fn clean_verbose() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
        [package]
        name = "foo"
        version = "0.0.1"

        [dependencies]
        bar = "0.1"
    "#,
        ).file("src/main.rs", "fn main() {}")
        .build();

    Package::new("bar", "0.1.0").publish();

    p.cargo("build").run();
    p.cargo("clean -p bar --verbose")
        .with_stderr(
            "\
[REMOVING] [..]
[REMOVING] [..]
",
        ).run();
    p.cargo("build").run();
}
<|endoftext|>