<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use libc::{c_int, c_uchar, c_uint, c_ushort, c_void};

// Reexport items defined in either macos or ios ffi module.
pub use crate::sys::inner::ffi::*;

extern "C" {
    pub fn proc_pidinfo(
        pid: c_int,
        flavor: c_int,
        arg: u64,
        buffer: *mut c_void,
        buffersize: c_int,
    ) -> c_int;
    pub fn proc_listallpids(buffer: *mut c_void, buffersize: c_int) -> c_int;
    //pub fn proc_listpids(kind: u32, x: u32, buffer: *mut c_void, buffersize: c_int) -> c_int;
    //pub fn proc_name(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int;
    //pub fn proc_regionfilename(pid: c_int, address: u64, buffer: *mut c_void,
    //                           buffersize: u32) -> c_int;
    pub fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int;
    pub fn proc_pid_rusage(pid: c_int, flavor: c_int, buffer: *mut c_void) -> c_int;

    pub fn mach_absolute_time() -> u64;
    //pub fn task_for_pid(host: u32, pid: pid_t, task: *mut task_t) -> u32;
    pub fn mach_task_self() -> u32;
    pub fn mach_host_self() -> u32;
    //pub fn task_info(host_info: u32, t: u32, c: *mut c_void, x: *mut u32) -> u32;
    pub fn host_statistics64(
        host_info: u32,
        x: u32,
        y: *mut c_void,
        z: *const u32,
    ) -> kern_return_t;
    pub fn host_processor_info(
        host_info: u32,
        t: u32,
        num_cpu_u: *mut u32,
        cpu_info: *mut *mut i32,
        num_cpu_info: *mut u32,
    ) -> kern_return_t;
    //pub fn host_statistics(host_priv: u32, flavor: u32, host_info: *mut c_void,
    //                       host_count: *const u32) -> u32;
    // pub fn proc_pidpath(pid: i32, buf: *mut i8, bufsize: u32) -> i32;
    // pub fn proc_name(pid: i32, buf: *mut i8, bufsize: u32) -> i32;
    pub fn vm_deallocate(target_task: u32, address: *mut i32, size: u32) -> kern_return_t;
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
macro_rules! cfg_if {
    ($(
        if #[cfg($($meta:meta),*)] { $($it:item)* }
    ) else * else {
        $($it2:item)*
    }) => {
        __cfg_if_items! {
            () ;
            $( ( ($($meta),*) ($($it)*) ), )*
            ( () ($($it2)*) ),
        }
    }
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
macro_rules! __cfg_if_items {
    (($($not:meta,)*) ; ) => {};
    (($($not:meta,)*) ; ( ($($m:meta),*) ($($it:item)*) ), $($rest:tt)*) => {
        __cfg_if_apply! { cfg(all(not(any($($not),*)), $($m,)*)), $($it)* }
        __cfg_if_items! { ($($not,)* $($m,)*) ; $($rest)* }
    }
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
macro_rules! __cfg_if_apply {
    ($m:meta, $($it:item)*) => {
        $(#[$m] $it)*
    }
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
cfg_if! {
    if #[cfg(any(target_arch = "arm", target_arch = "x86"))] {
        pub type timeval32 = libc::timeval;
    } else {
        use libc::timeval32;
    }
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
#[repr(C)]
pub struct if_data64 {
    pub ifi_type: c_uchar,
    pub ifi_typelen: c_uchar,
    pub ifi_physical: c_uchar,
    pub ifi_addrlen: c_uchar,
    pub ifi_hdrlen: c_uchar,
    pub ifi_recvquota: c_uchar,
    pub ifi_xmitquota: c_uchar,
    pub ifi_unused1: c_uchar,
    pub ifi_mtu: u32,
    pub ifi_metric: u32,
    pub ifi_baudrate: u64,
    pub ifi_ipackets: u64,
    pub ifi_ierrors: u64,
    pub ifi_opackets: u64,
    pub ifi_oerrors: u64,
    pub ifi_collisions: u64,
    pub ifi_ibytes: u64,
    pub ifi_obytes: u64,
    pub ifi_imcasts: u64,
    pub ifi_omcasts: u64,
    pub ifi_iqdrops: u64,
    pub ifi_noproto: u64,
    pub ifi_recvtiming: u32,
    pub ifi_xmittiming: u32,
    pub ifi_lastchange: timeval32,
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
#[repr(C)]
pub struct if_msghdr2 {
    pub ifm_msglen: c_ushort,
    pub ifm_version: c_uchar,
    pub ifm_type: c_uchar,
    pub ifm_addrs: c_int,
    pub ifm_flags: c_int,
    pub ifm_index: c_ushort,
    pub ifm_snd_len: c_int,
    pub ifm_snd_maxlen: c_int,
    pub ifm_snd_drops: c_int,
    pub ifm_timer: c_int,
    pub ifm_data: if_data64,
}

#[repr(C)]
pub struct __DADisk(c_void);
#[repr(C)]
pub struct __DASession(c_void);

// #[allow(non_camel_case_types)]
// pub type io_name_t = [u8; 128];
// #[allow(non_camel_case_types)]
// pub type io_registry_entry_t = io_object_t;

//#[allow(non_camel_case_types)]
//pub type policy_t = i32;
#[allow(non_camel_case_types)]
//pub type integer_t = i32;
//#[allow(non_camel_case_types)]
//pub type time_t = i64;
//#[allow(non_camel_case_types)]
//pub type suseconds_t = i32;
//#[allow(non_camel_case_types)]
//pub type mach_vm_size_t = u64;
//#[allow(non_camel_case_types)]
//pub type task_t = u32;
//#[allow(non_camel_case_types)]
//pub type pid_t = i32;
#[allow(non_camel_case_types)]
pub type natural_t = u32;
#[allow(non_camel_case_types)]
pub type mach_port_t = u32;

#[allow(non_camel_case_types)]
pub type boolean_t = c_uint;
#[allow(non_camel_case_types)]
pub type kern_return_t = c_int;
// pub type IOOptionBits = u32;

/*#[repr(C)]
pub struct task_thread_times_info {
    pub user_time: time_value,
    pub system_time: time_value,
}*/

/*#[repr(C)]
pub struct task_basic_info_64 {
    pub suspend_count: integer_t,
    pub virtual_size: mach_vm_size_t,
    pub resident_size: mach_vm_size_t,
    pub user_time: time_value_t,
    pub system_time: time_value_t,
    pub policy: policy_t,
}*/

#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
#[repr(C)]
pub struct vm_statistics64 {
    pub free_count: natural_t,
    pub active_count: natural_t,
    pub inactive_count: natural_t,
    pub wire_count: natural_t,
    pub zero_fill_count: u64,
    pub reactivations: u64,
    pub pageins: u64,
    pub pageouts: u64,
    pub faults: u64,
    pub cow_faults: u64,
    pub lookups: u64,
    pub hits: u64,
    pub purges: u64,
    pub purgeable_count: natural_t,
    pub speculative_count: natural_t,
    pub decompressions: u64,
    pub compressions: u64,
    pub swapins: u64,
    pub swapouts: u64,
    pub compressor_page_count: natural_t,
    pub throttled_count: natural_t,
    pub external_page_count: natural_t,
    pub internal_page_count: natural_t,
    pub total_uncompressed_pages_in_compressor: u64,
}

#[cfg_attr(feature = "debug", derive(Eq, Hash, PartialEq))]
#[derive(Clone)]
#[repr(C)]
pub struct Val_t {
    pub key: [i8; 5],
    pub data_size: u32,
    pub data_type: [i8; 5], // UInt32Char_t
    pub bytes: [i8; 32],    // SMCBytes_t
}

#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
#[repr(C)]
pub struct xsw_usage {
    pub xsu_total: u64,
    pub xsu_avail: u64,
    pub xsu_used: u64,
    pub xsu_pagesize: u32,
    pub xsu_encrypted: boolean_t,
}

// https://github.com/andrewdavidmackenzie/libproc-rs/blob/master/src/libproc/pid_rusage.rs
#[derive(Debug, Default)]
#[repr(C)]
pub struct RUsageInfoV2 {
    pub ri_uuid: [u8; 16],
    pub ri_user_time: u64,
    pub ri_system_time: u64,
    pub ri_pkg_idle_wkups: u64,
    pub ri_interrupt_wkups: u64,
    pub ri_pageins: u64,
    pub ri_wired_size: u64,
    pub ri_resident_size: u64,
    pub ri_phys_footprint: u64,
    pub ri_proc_start_abstime: u64,
    pub ri_proc_exit_abstime: u64,
    pub ri_child_user_time: u64,
    pub ri_child_system_time: u64,
    pub ri_child_pkg_idle_wkups: u64,
    pub ri_child_interrupt_wkups: u64,
    pub ri_child_pageins: u64,
    pub ri_child_elapsed_abstime: u64,
    pub ri_diskio_bytesread: u64,
    pub ri_diskio_byteswritten: u64,
}

//pub const HOST_CPU_LOAD_INFO_COUNT: usize = 4;
//pub const HOST_CPU_LOAD_INFO: u32 = 3;
pub const KERN_SUCCESS: kern_return_t = 0;

pub const HW_NCPU: u32 = 3;
pub const CTL_HW: u32 = 6;
pub const CTL_VM: u32 = 2;
pub const VM_SWAPUSAGE: u32 = 5;
pub const PROCESSOR_CPU_LOAD_INFO: u32 = 2;
pub const CPU_STATE_USER: u32 = 0;
pub const CPU_STATE_SYSTEM: u32 = 1;
pub const CPU_STATE_IDLE: u32 = 2;
pub const CPU_STATE_NICE: u32 = 3;
pub const CPU_STATE_MAX: usize = 4;
pub const HW_MEMSIZE: u32 = 24;

//pub const PROC_ALL_PIDS: c_uint = 1;
pub const PROC_PIDTBSDINFO: c_int = 3;

//pub const TASK_THREAD_TIMES_INFO: u32 = 3;
//pub const TASK_THREAD_TIMES_INFO_COUNT: u32 = 4;
//pub const TASK_BASIC_INFO_64: u32 = 5;
//pub const TASK_BASIC_INFO_64_COUNT: u32 = 10;
pub const HOST_VM_INFO64: u32 = 4;
pub const HOST_VM_INFO64_COUNT: u32 = 38;

pub const PROC_PIDPATHINFO_MAXSIZE: u32 = 4096;
<commit_msg>Remove uneeded cfg_if redeclaration<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use libc::{c_int, c_uchar, c_uint, c_ushort, c_void};

// Reexport items defined in either macos or ios ffi module.
pub use crate::sys::inner::ffi::*;

extern "C" {
    pub fn proc_pidinfo(
        pid: c_int,
        flavor: c_int,
        arg: u64,
        buffer: *mut c_void,
        buffersize: c_int,
    ) -> c_int;
    pub fn proc_listallpids(buffer: *mut c_void, buffersize: c_int) -> c_int;
    //pub fn proc_listpids(kind: u32, x: u32, buffer: *mut c_void, buffersize: c_int) -> c_int;
    //pub fn proc_name(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int;
    //pub fn proc_regionfilename(pid: c_int, address: u64, buffer: *mut c_void,
    //                           buffersize: u32) -> c_int;
    pub fn proc_pidpath(pid: c_int, buffer: *mut c_void, buffersize: u32) -> c_int;
    pub fn proc_pid_rusage(pid: c_int, flavor: c_int, buffer: *mut c_void) -> c_int;

    pub fn mach_absolute_time() -> u64;
    //pub fn task_for_pid(host: u32, pid: pid_t, task: *mut task_t) -> u32;
    pub fn mach_task_self() -> u32;
    pub fn mach_host_self() -> u32;
    //pub fn task_info(host_info: u32, t: u32, c: *mut c_void, x: *mut u32) -> u32;
    pub fn host_statistics64(
        host_info: u32,
        x: u32,
        y: *mut c_void,
        z: *const u32,
    ) -> kern_return_t;
    pub fn host_processor_info(
        host_info: u32,
        t: u32,
        num_cpu_u: *mut u32,
        cpu_info: *mut *mut i32,
        num_cpu_info: *mut u32,
    ) -> kern_return_t;
    //pub fn host_statistics(host_priv: u32, flavor: u32, host_info: *mut c_void,
    //                       host_count: *const u32) -> u32;
    // pub fn proc_pidpath(pid: i32, buf: *mut i8, bufsize: u32) -> i32;
    // pub fn proc_name(pid: i32, buf: *mut i8, bufsize: u32) -> i32;
    pub fn vm_deallocate(target_task: u32, address: *mut i32, size: u32) -> kern_return_t;
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
cfg_if::cfg_if! {
    if #[cfg(any(target_arch = "arm", target_arch = "x86"))] {
        pub type timeval32 = libc::timeval;
    } else {
        use libc::timeval32;
    }
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
#[repr(C)]
pub struct if_data64 {
    pub ifi_type: c_uchar,
    pub ifi_typelen: c_uchar,
    pub ifi_physical: c_uchar,
    pub ifi_addrlen: c_uchar,
    pub ifi_hdrlen: c_uchar,
    pub ifi_recvquota: c_uchar,
    pub ifi_xmitquota: c_uchar,
    pub ifi_unused1: c_uchar,
    pub ifi_mtu: u32,
    pub ifi_metric: u32,
    pub ifi_baudrate: u64,
    pub ifi_ipackets: u64,
    pub ifi_ierrors: u64,
    pub ifi_opackets: u64,
    pub ifi_oerrors: u64,
    pub ifi_collisions: u64,
    pub ifi_ibytes: u64,
    pub ifi_obytes: u64,
    pub ifi_imcasts: u64,
    pub ifi_omcasts: u64,
    pub ifi_iqdrops: u64,
    pub ifi_noproto: u64,
    pub ifi_recvtiming: u32,
    pub ifi_xmittiming: u32,
    pub ifi_lastchange: timeval32,
}

// TODO: waiting for https://github.com/rust-lang/libc/pull/678
#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
#[repr(C)]
pub struct if_msghdr2 {
    pub ifm_msglen: c_ushort,
    pub ifm_version: c_uchar,
    pub ifm_type: c_uchar,
    pub ifm_addrs: c_int,
    pub ifm_flags: c_int,
    pub ifm_index: c_ushort,
    pub ifm_snd_len: c_int,
    pub ifm_snd_maxlen: c_int,
    pub ifm_snd_drops: c_int,
    pub ifm_timer: c_int,
    pub ifm_data: if_data64,
}

#[repr(C)]
pub struct __DADisk(c_void);
#[repr(C)]
pub struct __DASession(c_void);

// #[allow(non_camel_case_types)]
// pub type io_name_t = [u8; 128];
// #[allow(non_camel_case_types)]
// pub type io_registry_entry_t = io_object_t;

//#[allow(non_camel_case_types)]
//pub type policy_t = i32;
#[allow(non_camel_case_types)]
//pub type integer_t = i32;
//#[allow(non_camel_case_types)]
//pub type time_t = i64;
//#[allow(non_camel_case_types)]
//pub type suseconds_t = i32;
//#[allow(non_camel_case_types)]
//pub type mach_vm_size_t = u64;
//#[allow(non_camel_case_types)]
//pub type task_t = u32;
//#[allow(non_camel_case_types)]
//pub type pid_t = i32;
#[allow(non_camel_case_types)]
pub type natural_t = u32;
#[allow(non_camel_case_types)]
pub type mach_port_t = u32;

#[allow(non_camel_case_types)]
pub type boolean_t = c_uint;
#[allow(non_camel_case_types)]
pub type kern_return_t = c_int;
// pub type IOOptionBits = u32;

/*#[repr(C)]
pub struct task_thread_times_info {
    pub user_time: time_value,
    pub system_time: time_value,
}*/

/*#[repr(C)]
pub struct task_basic_info_64 {
    pub suspend_count: integer_t,
    pub virtual_size: mach_vm_size_t,
    pub resident_size: mach_vm_size_t,
    pub user_time: time_value_t,
    pub system_time: time_value_t,
    pub policy: policy_t,
}*/

#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
#[repr(C)]
pub struct vm_statistics64 {
    pub free_count: natural_t,
    pub active_count: natural_t,
    pub inactive_count: natural_t,
    pub wire_count: natural_t,
    pub zero_fill_count: u64,
    pub reactivations: u64,
    pub pageins: u64,
    pub pageouts: u64,
    pub faults: u64,
    pub cow_faults: u64,
    pub lookups: u64,
    pub hits: u64,
    pub purges: u64,
    pub purgeable_count: natural_t,
    pub speculative_count: natural_t,
    pub decompressions: u64,
    pub compressions: u64,
    pub swapins: u64,
    pub swapouts: u64,
    pub compressor_page_count: natural_t,
    pub throttled_count: natural_t,
    pub external_page_count: natural_t,
    pub internal_page_count: natural_t,
    pub total_uncompressed_pages_in_compressor: u64,
}

#[cfg_attr(feature = "debug", derive(Eq, Hash, PartialEq))]
#[derive(Clone)]
#[repr(C)]
pub struct Val_t {
    pub key: [i8; 5],
    pub data_size: u32,
    pub data_type: [i8; 5], // UInt32Char_t
    pub bytes: [i8; 32],    // SMCBytes_t
}

#[cfg_attr(feature = "debug", derive(Debug, Eq, Hash, PartialEq))]
#[repr(C)]
pub struct xsw_usage {
    pub xsu_total: u64,
    pub xsu_avail: u64,
    pub xsu_used: u64,
    pub xsu_pagesize: u32,
    pub xsu_encrypted: boolean_t,
}

// https://github.com/andrewdavidmackenzie/libproc-rs/blob/master/src/libproc/pid_rusage.rs
#[derive(Debug, Default)]
#[repr(C)]
pub struct RUsageInfoV2 {
    pub ri_uuid: [u8; 16],
    pub ri_user_time: u64,
    pub ri_system_time: u64,
    pub ri_pkg_idle_wkups: u64,
    pub ri_interrupt_wkups: u64,
    pub ri_pageins: u64,
    pub ri_wired_size: u64,
    pub ri_resident_size: u64,
    pub ri_phys_footprint: u64,
    pub ri_proc_start_abstime: u64,
    pub ri_proc_exit_abstime: u64,
    pub ri_child_user_time: u64,
    pub ri_child_system_time: u64,
    pub ri_child_pkg_idle_wkups: u64,
    pub ri_child_interrupt_wkups: u64,
    pub ri_child_pageins: u64,
    pub ri_child_elapsed_abstime: u64,
    pub ri_diskio_bytesread: u64,
    pub ri_diskio_byteswritten: u64,
}

//pub const HOST_CPU_LOAD_INFO_COUNT: usize = 4;
//pub const HOST_CPU_LOAD_INFO: u32 = 3;
pub const KERN_SUCCESS: kern_return_t = 0;

pub const HW_NCPU: u32 = 3;
pub const CTL_HW: u32 = 6;
pub const CTL_VM: u32 = 2;
pub const VM_SWAPUSAGE: u32 = 5;
pub const PROCESSOR_CPU_LOAD_INFO: u32 = 2;
pub const CPU_STATE_USER: u32 = 0;
pub const CPU_STATE_SYSTEM: u32 = 1;
pub const CPU_STATE_IDLE: u32 = 2;
pub const CPU_STATE_NICE: u32 = 3;
pub const CPU_STATE_MAX: usize = 4;
pub const HW_MEMSIZE: u32 = 24;

//pub const PROC_ALL_PIDS: c_uint = 1;
pub const PROC_PIDTBSDINFO: c_int = 3;

//pub const TASK_THREAD_TIMES_INFO: u32 = 3;
//pub const TASK_THREAD_TIMES_INFO_COUNT: u32 = 4;
//pub const TASK_BASIC_INFO_64: u32 = 5;
//pub const TASK_BASIC_INFO_64_COUNT: u32 = 10;
pub const HOST_VM_INFO64: u32 = 4;
pub const HOST_VM_INFO64_COUNT: u32 = 38;

pub const PROC_PIDPATHINFO_MAXSIZE: u32 = 4096;
<|endoftext|>


<commit_before>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project\n");
            println!("  test           # run the tests\n");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = Command::new(format!("cargo-{}", cmd))
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_str());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<commit_msg>Remove superfluous newline<commit_after>#![feature(phase)]

extern crate cargo;
extern crate hammer;
extern crate serialize;
#[phase(plugin, link)]
extern crate log;

use hammer::{FlagConfig,FlagConfiguration};
use std::os;
use std::io::process::{Command,InheritFd,ExitStatus,ExitSignal};
use serialize::Encodable;
use cargo::{GlobalFlags, NoFlags, execute_main_without_stdin, handle_error, shell};
use cargo::core::MultiShell;
use cargo::util::important_paths::find_project;
use cargo::util::{CliError, CliResult, Require, config, human};

fn main() {
    execute();
}

#[deriving(Encodable)]
struct ProjectLocation {
    root: String
}

/**
  The top-level `cargo` command handles configuration and project location
  because they are fundamental (and intertwined). Other commands can rely
  on this top-level information.
*/
fn execute() {
    debug!("executing; cmd=cargo; args={}", os::args());

    let (cmd, args) = process(os::args());

    match cmd.as_slice() {
        "config-for-key" => {
            log!(4, "cmd == config-for-key");
            execute_main_without_stdin(config_for_key)
        },
        "config-list" => {
            log!(4, "cmd == config-list");
            execute_main_without_stdin(config_list)
        },
        "locate-project" => {
            log!(4, "cmd == locate-project");
            execute_main_without_stdin(locate_project)
        },
        "--help" | "-h" | "help" | "-?" => {
            println!("Commands:");
            println!("  build          # compile the current project");
            println!("  test           # run the tests\n");

            let (_, options) = hammer::usage::<GlobalFlags>(false);
            println!("Options (for all commands):\n\n{}", options);
        },
        _ => {
            let command = Command::new(format!("cargo-{}", cmd))
                .args(args.as_slice())
                .stdin(InheritFd(0))
                .stdout(InheritFd(1))
                .stderr(InheritFd(2))
                .status();

            match command {
                Ok(ExitStatus(0)) => (),
                Ok(ExitStatus(i)) | Ok(ExitSignal(i)) => {
                    handle_error(CliError::new("", i as uint), &mut shell(false))
                }
                Err(_) => handle_error(CliError::new("No such subcommand", 127), &mut shell(false))
            }
        }
    }
}

fn process(args: Vec<String>) -> (String, Vec<String>) {
    let mut args = Vec::from_slice(args.tail());
    let head = args.shift().unwrap_or("--help".to_str());

    (head, args)
}

#[deriving(Encodable)]
struct ConfigOut {
    values: std::collections::HashMap<String, config::ConfigValue>
}

#[deriving(Decodable)]
struct ConfigForKeyFlags {
    key: String,
    human: bool
}

impl FlagConfig for ConfigForKeyFlags {
    fn config(_: Option<ConfigForKeyFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_for_key(args: ConfigForKeyFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let value = try!(config::get_config(os::getcwd(),
                                        args.key.as_slice()).map_err(|_| {
        CliError::new("Couldn't load configuration",  1)
    }));

    if args.human {
        println!("{}", value);
        Ok(None)
    } else {
        let mut map = std::collections::HashMap::new();
        map.insert(args.key.clone(), value);
        Ok(Some(ConfigOut { values: map }))
    }
}

#[deriving(Decodable)]
struct ConfigListFlags {
    human: bool
}

impl FlagConfig for ConfigListFlags {
    fn config(_: Option<ConfigListFlags>,
              config: FlagConfiguration) -> FlagConfiguration {
        config.short("human", 'h')
    }
}

fn config_list(args: ConfigListFlags, _: &mut MultiShell) -> CliResult<Option<ConfigOut>> {
    let configs = try!(config::all_configs(os::getcwd()).map_err(|_|
        CliError::new("Couldn't load configuration", 1)));

    if args.human {
        for (key, value) in configs.iter() {
            println!("{} = {}", key, value);
        }
        Ok(None)
    } else {
        Ok(Some(ConfigOut { values: configs }))
    }
}

fn locate_project(_: NoFlags, _: &mut MultiShell) -> CliResult<Option<ProjectLocation>> {
    let root = try!(find_project(os::getcwd(), "Cargo.toml").map_err(|e| {
        CliError::from_boxed(e, 1)
    }));

    let string = try!(root.as_str()
                      .require(|| human("Your project path contains characters \
                                         not representable in Unicode"))
                      .map_err(|e| CliError::from_boxed(e, 1)));

    Ok(Some(ProjectLocation { root: string.to_str() }))
}
<|endoftext|>


<commit_before>#![deny(trivial_numeric_casts)]
#![warn(unused_import_braces, unstable_features, unused_extern_crates)]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        float_arithmetic, mut_mut, nonminimal_bool, option_map_unwrap_or, option_map_unwrap_or_else,
        unicode_not_nfc, use_self
    )
)]

extern crate file_per_thread_logger;
#[macro_use]
extern crate cfg_if;
#[cfg(feature = "disas")]
extern crate capstone;
extern crate clap;
extern crate cranelift_codegen;
extern crate cranelift_entity;
extern crate cranelift_filetests;
extern crate cranelift_reader;
extern crate pretty_env_logger;

cfg_if! {
    if #[cfg(feature = "wasm")] {
        extern crate cranelift_wasm;
        extern crate term;
        extern crate wabt;
        mod wasm;
    }
}
extern crate target_lexicon;

use clap::{App, Arg, SubCommand};
use cranelift_codegen::dbg::LOG_FILENAME_PREFIX;
use cranelift_codegen::VERSION;
use std::io::{self, Write};
use std::option::Option;
use std::process;

mod cat;
mod compile;
mod print_cfg;
mod utils;

/// A command either succeeds or fails with an error message.
pub type CommandResult = Result<(), String>;

fn add_input_file_arg<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("file")
        .default_value("-")
        .multiple(true)
        .value_name("file")
        .help("Specify file(s) to be used for test. Defaults to reading from stdin.")
}

fn add_single_input_file_arg<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("single-file")
        .default_value("-")
        .value_name("single-file")
        .help("Specify a file to be used. Defaults to reading from stdin.")
}

fn add_pass_arg<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("pass")
        .required(true)
        .multiple(true)
        .value_name("pass")
        .help("Specify pass(s) to be run on test file")
}

fn add_verbose_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("verbose").short("v").help("Be more verbose")
}

fn add_time_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("time-passes")
        .short("T")
        .help("Print pass timing report for test")
}

fn add_set_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("set")
        .long("set")
        .takes_value(true)
        .multiple(true)
        .help("Configure Cranelift settings")
}

fn add_target_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("target")
        .takes_value(true)
        .long("target")
        .help("Specify the Cranelift target")
}

fn add_print_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("print")
        .short("p")
        .help("Print the resulting Cranelift IR")
}

fn add_debug_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("debug")
        .short("d")
        .help("enable debug output on stderr/stdout")
}

/// Returns a vector of clap value options and changes these options into a vector of strings
fn get_vec<'a>(argument_vec: Option<clap::Values<'a>>) -> Vec<String> {
    let mut ret_vec: Vec<String> = Vec::new();
    if let Some(clap_vec) = argument_vec {
        for val in clap_vec {
            ret_vec.push(val.to_string());
        }
    }

    ret_vec
}

fn add_wasm_or_compile<'a>(cmd: &str) -> clap::App<'a, 'a> {
    let about_str = match cmd {
        "wasm" => "Compiles Cranelift IR into target language",
        "compile" => "Compiles Cranelift IR into target language",
        _ => panic!("Invalid command"),
    };

    SubCommand::with_name(cmd)
        .about(about_str)
        .arg(add_verbose_flag())
        .arg(add_print_flag())
        .arg(add_time_flag())
        .arg(add_set_flag())
        .arg(add_target_flag())
        .arg(add_input_file_arg())
        .arg(add_debug_flag())
}

fn handle_debug_flag(debug: bool) {
    if debug {
        pretty_env_logger::init();
    } else {
        file_per_thread_logger::initialize(LOG_FILENAME_PREFIX);
    }
}

fn main() {
    let app_cmds = App::new("Cranelift code generator utility")
        .version(VERSION)
        .subcommand(
            SubCommand::with_name("test")
                .about("Run Cranelift tests")
                .arg(add_verbose_flag())
                .arg(add_time_flag())
                .arg(add_input_file_arg())
                .arg(add_debug_flag()),
        )
        .subcommand(
            SubCommand::with_name("cat")
                .about("Outputs .clif file")
                .arg(add_input_file_arg())
                .arg(add_debug_flag()),
        )
        .subcommand(
            SubCommand::with_name("print-cfg")
                .about("Prints out cfg in dot format")
                .arg(add_input_file_arg())
                .arg(add_debug_flag()),
        )
        .subcommand(
            add_wasm_or_compile("compile")
                .arg(
                    Arg::with_name("just-decode")
                        .short("t")
                        .help("Just decode WebAssembly to Cranelift IR"),
                )
                .arg(Arg::with_name("check-translation").short("c").help(
                    "Just checks the correctness of Cranelift IR translated from WebAssembly",
                )),
        )
        .subcommand(add_wasm_or_compile("wasm"))
        .subcommand(
            SubCommand::with_name("pass")
                .about("Run specified pass(s) on an input file.")
                .arg(add_single_input_file_arg())
                .arg(add_target_flag())
                .arg(add_pass_arg())
                .arg(add_debug_flag())
                .arg(add_time_flag()),
        );

    let res_util = match app_cmds.get_matches().subcommand() {
        ("cat", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));
            cat::run(&get_vec(rest_cmd.values_of("file")))
        }
        ("test", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));
            cranelift_filetests::run(
                rest_cmd.is_present("verbose"),
                &get_vec(rest_cmd.values_of("file")),
            ).map(|_time| ())
        }
        ("pass", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));

            let mut target_val: &str = "";
            if let Some(clap_target) = rest_cmd.value_of("target") {
                target_val = clap_target;
            }

            // Can be unwrapped because 'single-file' is required
            cranelift_filetests::run_passes(
                rest_cmd.is_present("verbose"),
                &get_vec(rest_cmd.values_of("pass")),
                target_val,
                &rest_cmd.value_of("single-file").unwrap().to_string(),
            ).map(|_time| ())
        }
        ("print-cfg", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));
            print_cfg::run(&get_vec(rest_cmd.values_of("file")))
        }
        ("compile", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));

            let mut target_val: &str = "";
            if let Some(clap_target) = rest_cmd.value_of("target") {
                target_val = clap_target;
            }

            compile::run(
                get_vec(rest_cmd.values_of("file")),
                rest_cmd.is_present("print"),
                &get_vec(rest_cmd.values_of("set")),
                target_val,
            )
        }
        ("wasm", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));

            let mut target_val: &str = "";
            if let Some(clap_target) = rest_cmd.value_of("target") {
                target_val = clap_target;
            }

            #[cfg(feature = "wasm")]
            let result = wasm::run(
                get_vec(rest_cmd.values_of("file")),
                rest_cmd.is_present("verbose"),
                rest_cmd.is_present("just-decode"),
                rest_cmd.is_present("check-translation"),
                rest_cmd.is_present("print"),
                &get_vec(rest_cmd.values_of("set")),
                target_val,
                rest_cmd.is_present("print-size"),
            );

            #[cfg(not(feature = "wasm"))]
            let result = Err("Error: clif-util was compiled without wasm support.".to_owned());

            result
        }
        _ => Err(format!("Invalid subcommand.")),
    };

    if let Err(mut msg) = res_util {
        if !msg.ends_with('\n') {
            msg.push('\n');
        }
        io::stdout().flush().expect("flushing stdout");
        io::stderr().write_all(msg.as_bytes()).unwrap();
        process::exit(1);
    }
}
<commit_msg>clif-util: fix `clif-util pass` subcommand arguments<commit_after>#![deny(trivial_numeric_casts)]
#![warn(unused_import_braces, unstable_features, unused_extern_crates)]
#![cfg_attr(
    feature = "cargo-clippy",
    warn(
        float_arithmetic, mut_mut, nonminimal_bool, option_map_unwrap_or, option_map_unwrap_or_else,
        unicode_not_nfc, use_self
    )
)]

extern crate file_per_thread_logger;
#[macro_use]
extern crate cfg_if;
#[cfg(feature = "disas")]
extern crate capstone;
extern crate clap;
extern crate cranelift_codegen;
extern crate cranelift_entity;
extern crate cranelift_filetests;
extern crate cranelift_reader;
extern crate pretty_env_logger;

cfg_if! {
    if #[cfg(feature = "wasm")] {
        extern crate cranelift_wasm;
        extern crate term;
        extern crate wabt;
        mod wasm;
    }
}
extern crate target_lexicon;

use clap::{App, Arg, SubCommand};
use cranelift_codegen::dbg::LOG_FILENAME_PREFIX;
use cranelift_codegen::VERSION;
use std::io::{self, Write};
use std::option::Option;
use std::process;

mod cat;
mod compile;
mod print_cfg;
mod utils;

/// A command either succeeds or fails with an error message.
pub type CommandResult = Result<(), String>;

fn add_input_file_arg<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("file")
        .default_value("-")
        .multiple(true)
        .value_name("file")
        .help("Specify file(s) to be used for test. Defaults to reading from stdin.")
}

fn add_single_input_file_arg<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("single-file")
        .required(true)
        .value_name("single-file")
        .help("Specify a file to be used. Use '-' for stdin.")
}

fn add_pass_arg<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("pass")
        .required(true)
        .multiple(true)
        .value_name("pass")
        .help("Specify pass(s) to be run on test file")
}

fn add_verbose_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("verbose").short("v").help("Be more verbose")
}

fn add_time_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("time-passes")
        .short("T")
        .help("Print pass timing report for test")
}

fn add_set_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("set")
        .long("set")
        .takes_value(true)
        .multiple(true)
        .help("Configure Cranelift settings")
}

fn add_target_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("target")
        .takes_value(true)
        .long("target")
        .help("Specify the Cranelift target")
}

fn add_print_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("print")
        .short("p")
        .help("Print the resulting Cranelift IR")
}

fn add_debug_flag<'a>() -> clap::Arg<'a, 'a> {
    Arg::with_name("debug")
        .short("d")
        .help("enable debug output on stderr/stdout")
}

/// Returns a vector of clap value options and changes these options into a vector of strings
fn get_vec<'a>(argument_vec: Option<clap::Values<'a>>) -> Vec<String> {
    let mut ret_vec: Vec<String> = Vec::new();
    if let Some(clap_vec) = argument_vec {
        for val in clap_vec {
            ret_vec.push(val.to_string());
        }
    }

    ret_vec
}

fn add_wasm_or_compile<'a>(cmd: &str) -> clap::App<'a, 'a> {
    let about_str = match cmd {
        "wasm" => "Compiles Cranelift IR into target language",
        "compile" => "Compiles Cranelift IR into target language",
        _ => panic!("Invalid command"),
    };

    SubCommand::with_name(cmd)
        .about(about_str)
        .arg(add_verbose_flag())
        .arg(add_print_flag())
        .arg(add_time_flag())
        .arg(add_set_flag())
        .arg(add_target_flag())
        .arg(add_input_file_arg())
        .arg(add_debug_flag())
}

fn handle_debug_flag(debug: bool) {
    if debug {
        pretty_env_logger::init();
    } else {
        file_per_thread_logger::initialize(LOG_FILENAME_PREFIX);
    }
}

fn main() {
    let app_cmds = App::new("Cranelift code generator utility")
        .version(VERSION)
        .subcommand(
            SubCommand::with_name("test")
                .about("Run Cranelift tests")
                .arg(add_verbose_flag())
                .arg(add_time_flag())
                .arg(add_input_file_arg())
                .arg(add_debug_flag()),
        )
        .subcommand(
            SubCommand::with_name("cat")
                .about("Outputs .clif file")
                .arg(add_input_file_arg())
                .arg(add_debug_flag()),
        )
        .subcommand(
            SubCommand::with_name("print-cfg")
                .about("Prints out cfg in dot format")
                .arg(add_input_file_arg())
                .arg(add_debug_flag()),
        )
        .subcommand(
            add_wasm_or_compile("compile")
                .arg(
                    Arg::with_name("just-decode")
                        .short("t")
                        .help("Just decode WebAssembly to Cranelift IR"),
                )
                .arg(Arg::with_name("check-translation").short("c").help(
                    "Just checks the correctness of Cranelift IR translated from WebAssembly",
                )),
        )
        .subcommand(add_wasm_or_compile("wasm"))
        .subcommand(
            SubCommand::with_name("pass")
                .about("Run specified pass(s) on an input file.")
                .arg(add_single_input_file_arg())
                .arg(add_target_flag())
                .arg(add_pass_arg())
                .arg(add_debug_flag())
                .arg(add_time_flag()),
        );

    let res_util = match app_cmds.get_matches().subcommand() {
        ("cat", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));
            cat::run(&get_vec(rest_cmd.values_of("file")))
        }
        ("test", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));
            cranelift_filetests::run(
                rest_cmd.is_present("verbose"),
                &get_vec(rest_cmd.values_of("file")),
            ).map(|_time| ())
        }
        ("pass", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));

            let mut target_val: &str = "";
            if let Some(clap_target) = rest_cmd.value_of("target") {
                target_val = clap_target;
            }

            // Can be unwrapped because 'single-file' is required
            cranelift_filetests::run_passes(
                rest_cmd.is_present("verbose"),
                &get_vec(rest_cmd.values_of("pass")),
                target_val,
                &rest_cmd.value_of("single-file").unwrap().to_string(),
            ).map(|_time| ())
        }
        ("print-cfg", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));
            print_cfg::run(&get_vec(rest_cmd.values_of("file")))
        }
        ("compile", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));

            let mut target_val: &str = "";
            if let Some(clap_target) = rest_cmd.value_of("target") {
                target_val = clap_target;
            }

            compile::run(
                get_vec(rest_cmd.values_of("file")),
                rest_cmd.is_present("print"),
                &get_vec(rest_cmd.values_of("set")),
                target_val,
            )
        }
        ("wasm", Some(rest_cmd)) => {
            handle_debug_flag(rest_cmd.is_present("debug"));

            let mut target_val: &str = "";
            if let Some(clap_target) = rest_cmd.value_of("target") {
                target_val = clap_target;
            }

            #[cfg(feature = "wasm")]
            let result = wasm::run(
                get_vec(rest_cmd.values_of("file")),
                rest_cmd.is_present("verbose"),
                rest_cmd.is_present("just-decode"),
                rest_cmd.is_present("check-translation"),
                rest_cmd.is_present("print"),
                &get_vec(rest_cmd.values_of("set")),
                target_val,
                rest_cmd.is_present("print-size"),
            );

            #[cfg(not(feature = "wasm"))]
            let result = Err("Error: clif-util was compiled without wasm support.".to_owned());

            result
        }
        _ => Err(format!("Invalid subcommand.")),
    };

    if let Err(mut msg) = res_util {
        if !msg.ends_with('\n') {
            msg.push('\n');
        }
        io::stdout().flush().expect("flushing stdout");
        io::stderr().write_all(msg.as_bytes()).unwrap();
        process::exit(1);
    }
}
<|endoftext|>


<commit_before>fn main() {
    let mut doors = [false; 100];
    let mut d;

    for p in 0..100 {
        d = p;
        while d < doors.len() {
            doors[d] = !doors[d];
            d += (p + 1);
        }
    }

    for (i, &d) in doors.iter().enumerate() {
        if d {
            println!("{}", i + 1);
        }
    }
}
<commit_msg>Working simple version<commit_after>fn main() {
    let mut doors = [false; 100];
    let mut d;

    for p in 0..100 {
        d = p;
        while d < doors.len() {
            doors[d] = !doors[d];
            d += p + 1;
        }
    }

    for (i, &d) in doors.iter().enumerate() {
        if d {
            println!("{}", i + 1);
        }
    }
}
<|endoftext|>


<commit_before>use crate::faker::internet::raw::*;
use crate::faker::lorem::raw::Word;
use crate::faker::name::raw::FirstName;
use crate::locales::{Data, EN};
use crate::{Dummy, Fake, Faker};
use rand::distributions::{Distribution, Uniform};
use rand::seq::SliceRandom;
use rand::Rng;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

impl<L: Data> Dummy<FreeEmailProvider<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &FreeEmailProvider<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_FREE_EMAIL_PROVIDER.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<FreeEmailProvider<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &FreeEmailProvider<L>, rng: &mut R) -> Self {
        *L::INTERNET_FREE_EMAIL_PROVIDER.choose(rng).unwrap()
    }
}

impl<L: Data> Dummy<DomainSuffix<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &DomainSuffix<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_DOMAIN_SUFFIX.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<DomainSuffix<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &DomainSuffix<L>, rng: &mut R) -> Self {
        *L::INTERNET_DOMAIN_SUFFIX.choose(rng).unwrap()
    }
}

impl<L: Data + Copy> Dummy<FreeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &FreeEmail<L>, rng: &mut R) -> Self {
        let username: String = Username(c.0).fake_with_rng(rng);
        let provider: String = FreeEmailProvider(c.0).fake_with_rng(rng);
        format!("{}@{}", username, provider)
    }
}

impl<L: Data + Copy> Dummy<SafeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &SafeEmail<L>, rng: &mut R) -> Self {
        let username: String = FirstName(EN).fake_with_rng::<&str, _>(rng).to_lowercase();
        let domain = ["com", "net", "org"].choose(rng).unwrap();
        format!("{}@example.{}", username, domain)
    }
}

impl<L: Data + Copy> Dummy<Username<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &Username<L>, rng: &mut R) -> Self {
        match Faker.fake_with_rng::<u8, _>(rng) {
            0 => FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase(),
            1 | 2 => format!(
                "{}.{}",
                Word(c.0).fake_with_rng::<&str, _>(rng),
                FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase()
            ),
            3 | 4 => format!(
                "{}{}",
                FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase(),
                Faker.fake_with_rng::<u8, _>(rng)
            ),
            _ => format!(
                "{}_{}",
                FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase(),
                Word(c.0).fake_with_rng::<&str, _>(rng),
            ),
        }
    }
}

impl<L: Data> Dummy<Password<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &Password<L>, rng: &mut R) -> Self {
        let len: usize = c.1.fake_with_rng(rng);
        let s: Option<String> = (0..len)
            .map(|_| Some(*L::INTERNET_PASSWORD_CHARS.choose(rng)?))
            .collect();
        s.unwrap_or_default()
    }
}

impl<L: Data> Dummy<IPv4<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv4<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "{}.{}.{}.{}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<IPv4<L>> for Ipv4Addr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv4<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<Ipv4Addr, _>(rng)
    }
}

impl<L: Data> Dummy<IPv6<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv6<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u16::min_value(), u16::max_value());
        format!(
            "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<IPv6<L>> for Ipv6Addr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv6<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<Ipv6Addr, _>(rng)
    }
}

impl<L: Data + Copy> Dummy<IP<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &IP<L>, _rng: &mut R) -> Self {
        IPv4(c.0).fake()
    }
}

impl<L: Data> Dummy<IP<L>> for IpAddr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IP<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<IpAddr, _>(rng)
    }
}

impl<L: Data> Dummy<MACAddress<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &MACAddress<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<UserAgent<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &UserAgent<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_USER_AGENT.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<UserAgent<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &UserAgent<L>, rng: &mut R) -> Self {
        *L::INTERNET_USER_AGENT.choose(rng).unwrap()
    }
}
<commit_msg>Remove hardcoded EN default locale for SafeEmail<commit_after>use crate::faker::internet::raw::*;
use crate::faker::lorem::raw::Word;
use crate::faker::name::raw::FirstName;
use crate::locales::{Data, EN};
use crate::{Dummy, Fake, Faker};
use rand::distributions::{Distribution, Uniform};
use rand::seq::SliceRandom;
use rand::Rng;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

impl<L: Data> Dummy<FreeEmailProvider<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &FreeEmailProvider<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_FREE_EMAIL_PROVIDER.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<FreeEmailProvider<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &FreeEmailProvider<L>, rng: &mut R) -> Self {
        *L::INTERNET_FREE_EMAIL_PROVIDER.choose(rng).unwrap()
    }
}

impl<L: Data> Dummy<DomainSuffix<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &DomainSuffix<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_DOMAIN_SUFFIX.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<DomainSuffix<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &DomainSuffix<L>, rng: &mut R) -> Self {
        *L::INTERNET_DOMAIN_SUFFIX.choose(rng).unwrap()
    }
}

impl<L: Data + Copy> Dummy<FreeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &FreeEmail<L>, rng: &mut R) -> Self {
        let username: String = Username(c.0).fake_with_rng(rng);
        let provider: String = FreeEmailProvider(c.0).fake_with_rng(rng);
        format!("{}@{}", username, provider)
    }
}

impl<L: Data + Copy> Dummy<SafeEmail<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &SafeEmail<L>, rng: &mut R) -> Self {
        let username: String = FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase();
        let domain = ["com", "net", "org"].choose(rng).unwrap();
        format!("{}@example.{}", username, domain)
    }
}

impl<L: Data + Copy> Dummy<Username<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &Username<L>, rng: &mut R) -> Self {
        match Faker.fake_with_rng::<u8, _>(rng) {
            0 => FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase(),
            1 | 2 => format!(
                "{}.{}",
                Word(c.0).fake_with_rng::<&str, _>(rng),
                FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase()
            ),
            3 | 4 => format!(
                "{}{}",
                FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase(),
                Faker.fake_with_rng::<u8, _>(rng)
            ),
            _ => format!(
                "{}_{}",
                FirstName(c.0).fake_with_rng::<&str, _>(rng).to_lowercase(),
                Word(c.0).fake_with_rng::<&str, _>(rng),
            ),
        }
    }
}

impl<L: Data> Dummy<Password<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &Password<L>, rng: &mut R) -> Self {
        let len: usize = c.1.fake_with_rng(rng);
        let s: Option<String> = (0..len)
            .map(|_| Some(*L::INTERNET_PASSWORD_CHARS.choose(rng)?))
            .collect();
        s.unwrap_or_default()
    }
}

impl<L: Data> Dummy<IPv4<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv4<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "{}.{}.{}.{}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<IPv4<L>> for Ipv4Addr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv4<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<Ipv4Addr, _>(rng)
    }
}

impl<L: Data> Dummy<IPv6<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv6<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u16::min_value(), u16::max_value());
        format!(
            "{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}:{:X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<IPv6<L>> for Ipv6Addr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IPv6<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<Ipv6Addr, _>(rng)
    }
}

impl<L: Data + Copy> Dummy<IP<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(c: &IP<L>, _rng: &mut R) -> Self {
        IPv4(c.0).fake()
    }
}

impl<L: Data> Dummy<IP<L>> for IpAddr {
    #[inline]
    fn dummy_with_rng<R: Rng + ?Sized>(_: &IP<L>, rng: &mut R) -> Self {
        Faker.fake_with_rng::<IpAddr, _>(rng)
    }
}

impl<L: Data> Dummy<MACAddress<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &MACAddress<L>, rng: &mut R) -> Self {
        let u = Uniform::new_inclusive(u8::min_value(), u8::max_value());
        format!(
            "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
            u.sample(rng),
        )
    }
}

impl<L: Data> Dummy<UserAgent<L>> for String {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &UserAgent<L>, rng: &mut R) -> Self {
        let s = *L::INTERNET_USER_AGENT.choose(rng).unwrap();
        s.into()
    }
}

impl<L: Data> Dummy<UserAgent<L>> for &str {
    fn dummy_with_rng<R: Rng + ?Sized>(_: &UserAgent<L>, rng: &mut R) -> Self {
        *L::INTERNET_USER_AGENT.choose(rng).unwrap()
    }
}
<|endoftext|>


<commit_before>/// This module contains source for the `generate` command.
use crate::{self as exercise, errors::Result, get, val_as};
use failure::format_err;
use serde_json::Value as JsonValue;
use std::{
    collections::HashMap,
    fs::{self, File, OpenOptions},
    io::Write,
    path::Path,
    process::{Command, Stdio},
};

const GITIGNORE_CONTENT: &str = include_str!("defaults/gitignore");
const EXAMPLE_RS_CONTENT: &str = include_str!("defaults/example.rs");
const DESCRIPTION_MD_CONTENT: &str = include_str!("defaults/description.md");
const METADATA_YML_CONTENT: &str = include_str!("defaults/metadata.yml");

// Generate .meta directory and its contents without using the canonical data
fn generate_meta(exercise_name: &str, exercise_path: &Path) -> Result<()> {
    let meta_dir = exercise_path.join(".meta");
    fs::create_dir(&meta_dir)?;

    for (file, content) in [
        ("description.md", DESCRIPTION_MD_CONTENT),
        ("metadata.yml", METADATA_YML_CONTENT),
    ]
    .iter()
    {
        if !exercise::canonical_file_exists(exercise_name, file)? {
            fs::write(exercise_path.join(".meta").join(file), content)?;
        }
    }

    if fs::read_dir(&meta_dir)?.count() == 0 {
        fs::remove_dir(meta_dir)?;
    }

    Ok(())
}

fn parse_case(
    case: &JsonValue,
    property_functions: &mut HashMap<String, String>,
    test_functions: &mut Vec<String>,
    use_maplit: bool,
) -> Result<()> {
    if let Some(sub_cases) = case.get("cases") {
        for sub_case in val_as!(sub_cases, as_array) {
            parse_case(&sub_case, property_functions, test_functions, use_maplit)?;
        }
    }

    if let Some(property) = case.get("property") {
        let property = val_as!(property, as_str);

        if !property_functions.contains_key(property) {
            property_functions.insert(
                property.to_string(),
                exercise::generate_property_body(property),
            );
        }

        test_functions.push(exercise::generate_test_function(case, use_maplit)?);
    }

    Ok(())
}

// Generate test suite using the canonical data
fn generate_tests_from_canonical_data(
    exercise_name: &str,
    exercise_path: &Path,
    canonical_data: &JsonValue,
    use_maplit: bool,
) -> Result<()> {
    exercise::update_cargo_toml_version(exercise_name, canonical_data)?;

    let tests_path = exercise_path
        .join("tests")
        .join(format!("{}.rs", exercise_name));

    let tests_content = exercise::get_tests_content(exercise_name)?;

    let updated_tests_content = format!(
        "//! Tests for {exercise_name} \n\
        //! \n\
        //! Generated by [utility][utility] using [canonical data][canonical_data]\n\
        //! \n\
        //! [utility]: https://github.com/exercism/rust/tree/master/util/exercise\n\
        //! [canonical_data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/{exercise_name}/canonical-data.json\n\
        \n\
        {} \n\
        ",
        tests_content,
        exercise_name=exercise_name,
    );

    fs::write(&tests_path, updated_tests_content)?;

    let mut property_functions: HashMap<String, String> = HashMap::new();

    let mut test_functions: Vec<String> = Vec::new();

    for case in get!(canonical_data, "cases", as_array) {
        parse_case(
            &case,
            &mut property_functions,
            &mut test_functions,
            use_maplit,
        )?;
    }

    if !test_functions.is_empty() {
        let first_test_function = test_functions.remove(0).replace("#[ignore]\n", "");

        test_functions.insert(0, first_test_function);
    }

    let mut tests_file = OpenOptions::new().append(true).open(&tests_path)?;

    for property_body in property_functions.values() {
        tests_file.write_all(property_body.as_bytes())?;
    }

    tests_file.write_all(test_functions.join("\n\n").as_bytes())?;

    exercise::rustfmt(&tests_path)?;

    Ok(())
}

// Run bin/configlet generate command to generate README for the exercise
fn generate_readme(exercise_name: &str) -> Result<()> {
    println!(
        "Generating README for {} via 'bin/configlet generate'",
        exercise_name
    );

    let problem_specifications_path = Path::new(&*exercise::TRACK_ROOT)
        .join("..")
        .join("problem-specifications");

    if !problem_specifications_path.exists() {
        let problem_specifications_url = "https://github.com/exercism/problem-specifications.git";
        println!(
            "problem-specifications repository not found. Cloning the repository from {}",
            problem_specifications_url
        );

        Command::new("git")
            .current_dir(&*exercise::TRACK_ROOT)
            .stdout(Stdio::inherit())
            .arg("clone")
            .arg(problem_specifications_url)
            .arg(&problem_specifications_path)
            .output()?;
    }

    exercise::run_configlet_command(
        "generate",
        &[
            ".",
            "--only",
            exercise_name,
            "--spec-path",
            problem_specifications_path
                .to_str()
                .ok_or_else(|| format_err!("path inexpressable as str"))?,
        ],
    )?;

    Ok(())
}

// Generate a new exercise with specified name and flags
pub fn generate_exercise(exercise_name: &str, use_maplit: bool) -> Result<()> {
    if exercise::exercise_exists(exercise_name) {
        return Err(format_err!("exercise with the name {} already exists", exercise_name,).into());
    }

    let exercise_path = Path::new(&*exercise::TRACK_ROOT)
        .join("exercises")
        .join(exercise_name);

    println!(
        "Generating a new exercise at path: {}",
        exercise_path
            .to_str()
            .ok_or_else(|| format_err!("path inexpressable as str"))?
    );

    let _cargo_new_output = Command::new("cargo")
        .arg("new")
        .arg("--lib")
        .arg(
            exercise_path
                .to_str()
                .ok_or_else(|| format_err!("path inexpressable as str"))?,
        )
        .output()?;

    fs::write(exercise_path.join(".gitignore"), GITIGNORE_CONTENT)?;

    if use_maplit {
        let mut cargo_toml_file = OpenOptions::new()
            .append(true)
            .open(exercise_path.join("Cargo.toml"))?;

        cargo_toml_file.write_all(b"maplit = \"1.0.1\"")?;
    }

    fs::create_dir(exercise_path.join("tests"))?;

    let mut test_file = File::create(
        exercise_path
            .join("tests")
            .join(format!("{}.rs", exercise_name)),
    )?;

    if use_maplit {
        test_file.write_all(b"#[macro_use]\nextern crate maplit;\n")?;
    }

    test_file
        .write_all(&format!("extern crate {};\n", exercise_name.replace("-", "_")).into_bytes())?;

    test_file
        .write_all(&format!("use {}::*;\n\n", exercise_name.replace("-", "_")).into_bytes())?;

    fs::write(exercise_path.join("example.rs"), EXAMPLE_RS_CONTENT)?;

    match exercise::get_canonical_data(exercise_name) {
        Ok(canonical_data) => {
            println!("Generating tests from canonical data");

            generate_tests_from_canonical_data(
                &exercise_name,
                &exercise_path,
                &canonical_data,
                use_maplit,
            )?;
        }
        Err(_) => {
            println!(
                "No canonical data for exercise '{}' found. Generating standard exercise template.",
                &exercise_name
            );

            test_file.write_all(b"// Add your tests here\n")?;
        }
    }

    generate_meta(&exercise_name, &exercise_path)?;
    generate_readme(&exercise_name)?;

    Ok(())
}
<commit_msg>util/generate: Use the same template for all generations<commit_after>/// This module contains source for the `generate` command.
use crate::{self as exercise, errors::Result, get, val_as};
use failure::format_err;
use serde_json::Value as JsonValue;
use std::{
    collections::HashMap,
    fs::{self, File, OpenOptions},
    io::Write,
    path::Path,
    process::{Command, Stdio},
};

const GITIGNORE_CONTENT: &str = include_str!("defaults/gitignore");
const EXAMPLE_RS_CONTENT: &str = include_str!("defaults/example.rs");
const DESCRIPTION_MD_CONTENT: &str = include_str!("defaults/description.md");
const METADATA_YML_CONTENT: &str = include_str!("defaults/metadata.yml");

// Generate .meta directory and its contents without using the canonical data
fn generate_meta(exercise_name: &str, exercise_path: &Path) -> Result<()> {
    let meta_dir = exercise_path.join(".meta");
    fs::create_dir(&meta_dir)?;

    for (file, content) in [
        ("description.md", DESCRIPTION_MD_CONTENT),
        ("metadata.yml", METADATA_YML_CONTENT),
    ]
    .iter()
    {
        if !exercise::canonical_file_exists(exercise_name, file)? {
            fs::write(exercise_path.join(".meta").join(file), content)?;
        }
    }

    if fs::read_dir(&meta_dir)?.count() == 0 {
        fs::remove_dir(meta_dir)?;
    }

    Ok(())
}

fn parse_case(
    case: &JsonValue,
    property_functions: &mut HashMap<String, String>,
    test_functions: &mut Vec<String>,
    use_maplit: bool,
) -> Result<()> {
    if let Some(sub_cases) = case.get("cases") {
        for sub_case in val_as!(sub_cases, as_array) {
            parse_case(&sub_case, property_functions, test_functions, use_maplit)?;
        }
    }

    if let Some(property) = case.get("property") {
        let property = val_as!(property, as_str);

        if !property_functions.contains_key(property) {
            property_functions.insert(
                property.to_string(),
                exercise::generate_property_body(property),
            );
        }

        test_functions.push(exercise::generate_test_function(case, use_maplit)?);
    }

    Ok(())
}

// Generate test suite using the canonical data
fn generate_tests_from_canonical_data(
    exercise_name: &str,
    tests_path: &Path,
    canonical_data: &JsonValue,
    use_maplit: bool,
) -> Result<()> {
    exercise::update_cargo_toml_version(exercise_name, canonical_data)?;

    let tests_content = exercise::get_tests_content(exercise_name)?;

    let updated_tests_content = format!(
        "//! Tests for {exercise_name} \n\
        //! \n\
        //! Generated by [utility][utility] using [canonical data][canonical_data]\n\
        //! \n\
        //! [utility]: https://github.com/exercism/rust/tree/master/util/exercise\n\
        //! [canonical_data]: https://raw.githubusercontent.com/exercism/problem-specifications/master/exercises/{exercise_name}/canonical-data.json\n\
        \n\
        {} \n\
        ",
        tests_content,
        exercise_name=exercise_name,
    );

    fs::write(&tests_path, updated_tests_content)?;

    let mut property_functions: HashMap<String, String> = HashMap::new();

    let mut test_functions: Vec<String> = Vec::new();

    for case in get!(canonical_data, "cases", as_array) {
        parse_case(
            &case,
            &mut property_functions,
            &mut test_functions,
            use_maplit,
        )?;
    }

    if !test_functions.is_empty() {
        let first_test_function = test_functions.remove(0).replace("#[ignore]\n", "");

        test_functions.insert(0, first_test_function);
    }

    let mut tests_file = OpenOptions::new().append(true).open(&tests_path)?;

    for property_body in property_functions.values() {
        tests_file.write_all(property_body.as_bytes())?;
    }

    tests_file.write_all(test_functions.join("\n\n").as_bytes())?;

    exercise::rustfmt(&tests_path)?;

    Ok(())
}

// Run bin/configlet generate command to generate README for the exercise
fn generate_readme(exercise_name: &str) -> Result<()> {
    println!(
        "Generating README for {} via 'bin/configlet generate'",
        exercise_name
    );

    let problem_specifications_path = Path::new(&*exercise::TRACK_ROOT)
        .join("..")
        .join("problem-specifications");

    if !problem_specifications_path.exists() {
        let problem_specifications_url = "https://github.com/exercism/problem-specifications.git";
        println!(
            "problem-specifications repository not found. Cloning the repository from {}",
            problem_specifications_url
        );

        Command::new("git")
            .current_dir(&*exercise::TRACK_ROOT)
            .stdout(Stdio::inherit())
            .arg("clone")
            .arg(problem_specifications_url)
            .arg(&problem_specifications_path)
            .output()?;
    }

    exercise::run_configlet_command(
        "generate",
        &[
            ".",
            "--only",
            exercise_name,
            "--spec-path",
            problem_specifications_path
                .to_str()
                .ok_or_else(|| format_err!("path inexpressable as str"))?,
        ],
    )?;

    Ok(())
}

// Generate a new exercise with specified name and flags
pub fn generate_exercise(exercise_name: &str, use_maplit: bool) -> Result<()> {
    if exercise::exercise_exists(exercise_name) {
        return Err(format_err!("exercise with the name {} already exists", exercise_name,).into());
    }

    let exercise_path = Path::new(&*exercise::TRACK_ROOT)
        .join("exercises")
        .join(exercise_name);

    println!(
        "Generating a new exercise at path: {}",
        exercise_path
            .to_str()
            .ok_or_else(|| format_err!("path inexpressable as str"))?
    );

    let _cargo_new_output = Command::new("cargo")
        .arg("new")
        .arg("--lib")
        .arg(
            exercise_path
                .to_str()
                .ok_or_else(|| format_err!("path inexpressable as str"))?,
        )
        .output()?;

    fs::write(exercise_path.join(".gitignore"), GITIGNORE_CONTENT)?;

    if use_maplit {
        let mut cargo_toml_file = OpenOptions::new()
            .append(true)
            .open(exercise_path.join("Cargo.toml"))?;

        cargo_toml_file.write_all(b"maplit = \"1.0.1\"")?;
    }

    fs::create_dir(exercise_path.join("tests"))?;

    let test_file_name = exercise_path
        .join("tests")
        .join(format!("{}.rs", exercise_name));

    fs::write(exercise_path.join("example.rs"), EXAMPLE_RS_CONTENT)?;

    match exercise::get_canonical_data(exercise_name) {
        Ok(canonical_data) => {
            println!("Generating tests from canonical data");

            generate_tests_from_canonical_data(
                &exercise_name,
                &test_file_name,
                &canonical_data,
                use_maplit,
            )?;
        }
        Err(_) => {
            println!(
                "No canonical data for exercise '{}' found. Generating standard exercise template.",
                &exercise_name
            );

            let mut test_file = File::create(test_file_name)?;

            test_file.write_all(
                &format!(
                    "//! Tests for {exercise_name} \n\
                     //! \n\
                     //! Generated by [utility][utility]\n\
                     //! \n\
                     //! [utility]: https://github.com/exercism/rust/tree/master/util/exercise\n\
                     \n",
                    exercise_name = exercise_name,
                )
                .into_bytes(),
            )?;
            if use_maplit {
                test_file.write_all(b"#[macro_use]\nextern crate maplit;\n")?;
            }

            test_file.write_all(
                &format!(
                    "extern crate {escaped_exercise_name};\n\
                     use {escaped_exercise_name}::*;\n\
                     \n",
                    escaped_exercise_name = exercise_name.replace("-", "_"),
                )
                .into_bytes(),
            )?;
        }
    }

    generate_meta(&exercise_name, &exercise_path)?;
    generate_readme(&exercise_name)?;

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Aptos Rosetta API
//!
//! [Rosetta API Spec](https://www.rosetta-api.org/docs/Reference.html)

use crate::{account::CoinCache, error::ApiError};
use aptos_api::runtime::WebServer;
use aptos_config::config::ApiConfig;
use aptos_logger::debug;
use aptos_rest_client::aptos_api_types::Error;
use aptos_types::chain_id::ChainId;
use std::{convert::Infallible, sync::Arc};
use tokio::task::JoinHandle;
use warp::{
    http::{HeaderValue, Method, StatusCode},
    reject::{MethodNotAllowed, PayloadTooLarge, UnsupportedMediaType},
    reply, Filter, Rejection, Reply,
};

mod account;
mod block;
mod construction;
mod network;

pub mod client;
pub mod common;
pub mod error;
pub mod types;

pub const CURRENCY: &str = "APTOS";
pub const NUM_DECIMALS: u64 = 6;
pub const MIDDLEWARE_VERSION: &str = "1.0.0";
pub const NODE_VERSION: &str = "0.1";
pub const ROSETTA_VERSION: &str = "1.4.12";

/// Rosetta API context for use on all APIs
#[derive(Clone, Debug)]
pub struct RosettaContext {
    /// A rest client to connect to a fullnode
    rest_client: Option<aptos_rest_client::Client>,
    /// ChainId of the chain to connect to
    pub chain_id: ChainId,

    pub block_size: u64,
    pub coin_cache: Arc<CoinCache>,
}

impl RosettaContext {
    fn rest_client(&self) -> Result<&aptos_rest_client::Client, ApiError> {
        if let Some(ref client) = self.rest_client {
            Ok(client)
        } else {
            Err(ApiError::NodeIsOffline)
        }
    }
}

/// Creates HTTP server (warp-based) for Rosetta
pub fn bootstrap(
    block_size: u64,
    chain_id: ChainId,
    api_config: ApiConfig,
    rest_client: Option<aptos_rest_client::Client>,
) -> anyhow::Result<tokio::runtime::Runtime> {
    let runtime = tokio::runtime::Builder::new_multi_thread()
        .thread_name("rosetta")
        .enable_all()
        .build()
        .expect("[rosetta] failed to create runtime");

    debug!("Starting up Rosetta server with {:?}", api_config);
    let api = WebServer::from(api_config);

    runtime.spawn(async move {
        let context = RosettaContext {
            block_size,
            rest_client,
            chain_id,
            coin_cache: Arc::new(CoinCache::new()),
        };
        api.serve(routes(context)).await;
    });
    Ok(runtime)
}

pub async fn bootstrap_async(
    chain_id: ChainId,
    api_config: ApiConfig,
    rest_client: Option<aptos_rest_client::Client>,
) -> anyhow::Result<JoinHandle<()>> {
    debug!("Starting up Rosetta server with {:?}", api_config);
    let api = WebServer::from(api_config);
    let handle = tokio::spawn(async move {
        let context = RosettaContext {
            block_size: 1000,
            rest_client,
            chain_id,
            coin_cache: Arc::new(CoinCache::new()),
        };
        api.serve(routes(context)).await;
    });
    Ok(handle)
}

/// Collection of all routes for the server
pub fn routes(
    context: RosettaContext,
) -> impl Filter<Extract = impl Reply, Error = Infallible> + Clone {
    account::routes(context.clone())
        .or(block::block_route(context.clone()))
        .or(construction::combine_route(context.clone()))
        .or(construction::derive_route(context.clone()))
        .or(construction::hash_route(context.clone()))
        .or(construction::metadata_route(context.clone()))
        .or(construction::parse_route(context.clone()))
        .or(construction::payloads_route(context.clone()))
        .or(construction::preprocess_route(context.clone()))
        .or(construction::submit_route(context.clone()))
        .or(network::list_route(context.clone()))
        .or(network::options_route(context.clone()))
        .or(network::status_route(context))
        // TODO: Add health check?
        .with(
            warp::cors()
                .allow_any_origin()
                .allow_methods(vec![Method::GET, Method::POST])
                .allow_headers(vec![warp::http::header::CONTENT_TYPE]),
        )
        .with(aptos_api::log::logger())
        .recover(handle_rejection)
    // TODO metrics?
}

/// Handle error codes from warp
async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
    let code;
    let body;

    println!("Failed with: {:?}", err);

    if err.is_not_found() {
        code = StatusCode::NOT_FOUND;
        body = reply::json(&Error::new(code, "Not Found".to_owned()));
    } else if let Some(cause) = err.find::<warp::cors::CorsForbidden>() {
        code = StatusCode::FORBIDDEN;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<warp::body::BodyDeserializeError>() {
        code = StatusCode::BAD_REQUEST;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<warp::reject::LengthRequired>() {
        code = StatusCode::LENGTH_REQUIRED;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<PayloadTooLarge>() {
        code = StatusCode::PAYLOAD_TOO_LARGE;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<UnsupportedMediaType>() {
        code = StatusCode::UNSUPPORTED_MEDIA_TYPE;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<MethodNotAllowed>() {
        code = StatusCode::METHOD_NOT_ALLOWED;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else {
        code = StatusCode::INTERNAL_SERVER_ERROR;
        body = reply::json(&Error::new(code, format!("unexpected error: {:?}", err)));
    }
    let mut rep = reply::with_status(body, code).into_response();
    rep.headers_mut()
        .insert("access-control-allow-origin", HeaderValue::from_static("*"));
    Ok(rep)
}
<commit_msg>[aptos-rosetta] Add health check<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

//! Aptos Rosetta API
//!
//! [Rosetta API Spec](https://www.rosetta-api.org/docs/Reference.html)

use crate::{
    account::CoinCache,
    common::{handle_request, with_context},
    error::{ApiError, ApiResult},
};
use aptos_api::runtime::WebServer;
use aptos_config::config::ApiConfig;
use aptos_logger::debug;
use aptos_rest_client::aptos_api_types::Error;
use aptos_types::chain_id::ChainId;
use std::{convert::Infallible, sync::Arc};
use tokio::task::JoinHandle;
use warp::{
    http::{HeaderValue, Method, StatusCode},
    reject::{MethodNotAllowed, PayloadTooLarge, UnsupportedMediaType},
    reply, Filter, Rejection, Reply,
};

mod account;
mod block;
mod construction;
mod network;

pub mod client;
pub mod common;
pub mod error;
pub mod types;

pub const CURRENCY: &str = "APTOS";
pub const NUM_DECIMALS: u64 = 6;
pub const MIDDLEWARE_VERSION: &str = "1.0.0";
pub const NODE_VERSION: &str = "0.1";
pub const ROSETTA_VERSION: &str = "1.4.12";

/// Rosetta API context for use on all APIs
#[derive(Clone, Debug)]
pub struct RosettaContext {
    /// A rest client to connect to a fullnode
    rest_client: Option<aptos_rest_client::Client>,
    /// ChainId of the chain to connect to
    pub chain_id: ChainId,

    pub block_size: u64,
    pub coin_cache: Arc<CoinCache>,
}

impl RosettaContext {
    fn rest_client(&self) -> Result<&aptos_rest_client::Client, ApiError> {
        if let Some(ref client) = self.rest_client {
            Ok(client)
        } else {
            Err(ApiError::NodeIsOffline)
        }
    }
}

/// Creates HTTP server (warp-based) for Rosetta
pub fn bootstrap(
    block_size: u64,
    chain_id: ChainId,
    api_config: ApiConfig,
    rest_client: Option<aptos_rest_client::Client>,
) -> anyhow::Result<tokio::runtime::Runtime> {
    let runtime = tokio::runtime::Builder::new_multi_thread()
        .thread_name("rosetta")
        .enable_all()
        .build()
        .expect("[rosetta] failed to create runtime");

    debug!("Starting up Rosetta server with {:?}", api_config);
    let api = WebServer::from(api_config);

    runtime.spawn(async move {
        let context = RosettaContext {
            block_size,
            rest_client,
            chain_id,
            coin_cache: Arc::new(CoinCache::new()),
        };
        api.serve(routes(context)).await;
    });
    Ok(runtime)
}

pub async fn bootstrap_async(
    chain_id: ChainId,
    api_config: ApiConfig,
    rest_client: Option<aptos_rest_client::Client>,
) -> anyhow::Result<JoinHandle<()>> {
    debug!("Starting up Rosetta server with {:?}", api_config);
    let api = WebServer::from(api_config);
    let handle = tokio::spawn(async move {
        let context = RosettaContext {
            block_size: 1000,
            rest_client,
            chain_id,
            coin_cache: Arc::new(CoinCache::new()),
        };
        api.serve(routes(context)).await;
    });
    Ok(handle)
}

/// Collection of all routes for the server
pub fn routes(
    context: RosettaContext,
) -> impl Filter<Extract = impl Reply, Error = Infallible> + Clone {
    account::routes(context.clone())
        .or(block::block_route(context.clone()))
        .or(construction::combine_route(context.clone()))
        .or(construction::derive_route(context.clone()))
        .or(construction::hash_route(context.clone()))
        .or(construction::metadata_route(context.clone()))
        .or(construction::parse_route(context.clone()))
        .or(construction::payloads_route(context.clone()))
        .or(construction::preprocess_route(context.clone()))
        .or(construction::submit_route(context.clone()))
        .or(network::list_route(context.clone()))
        .or(network::options_route(context.clone()))
        .or(network::status_route(context.clone()))
        .or(health_check_route(context))
        .with(
            warp::cors()
                .allow_any_origin()
                .allow_methods(vec![Method::GET, Method::POST])
                .allow_headers(vec![warp::http::header::CONTENT_TYPE]),
        )
        .with(aptos_api::log::logger())
        .recover(handle_rejection)
    // TODO metrics?
}

/// Handle error codes from warp
async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
    let code;
    let body;

    println!("Failed with: {:?}", err);

    if err.is_not_found() {
        code = StatusCode::NOT_FOUND;
        body = reply::json(&Error::new(code, "Not Found".to_owned()));
    } else if let Some(cause) = err.find::<warp::cors::CorsForbidden>() {
        code = StatusCode::FORBIDDEN;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<warp::body::BodyDeserializeError>() {
        code = StatusCode::BAD_REQUEST;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<warp::reject::LengthRequired>() {
        code = StatusCode::LENGTH_REQUIRED;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<PayloadTooLarge>() {
        code = StatusCode::PAYLOAD_TOO_LARGE;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<UnsupportedMediaType>() {
        code = StatusCode::UNSUPPORTED_MEDIA_TYPE;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else if let Some(cause) = err.find::<MethodNotAllowed>() {
        code = StatusCode::METHOD_NOT_ALLOWED;
        body = reply::json(&Error::new(code, cause.to_string()));
    } else {
        code = StatusCode::INTERNAL_SERVER_ERROR;
        body = reply::json(&Error::new(code, format!("unexpected error: {:?}", err)));
    }
    let mut rep = reply::with_status(body, code).into_response();
    rep.headers_mut()
        .insert("access-control-allow-origin", HeaderValue::from_static("*"));
    Ok(rep)
}

/// These parameters are directly passed onto the underlying rest server for a healthcheck
#[derive(serde::Deserialize)]
struct HealthCheckParams {
    pub duration_secs: Option<u64>,
}

/// Default amount of time the fullnode is accepted to be behind (arbitrarily it's 5 minutes)
const HEALTH_CHECK_DEFAULT_SECS: u64 = 300;

#[derive(Debug)]
struct HealthCheckError;
impl warp::reject::Reject for HealthCheckError {}

pub fn health_check_route(
    server_context: RosettaContext,
) -> impl Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone {
    warp::path!("-" / "healthy")
        .and(warp::path::end())
        .and(warp::query().map(move |params: HealthCheckParams| params))
        .and(with_context(server_context))
        .and_then(handle_request(health_check))
}

/// Calls the underlying REST health check
async fn health_check(
    params: HealthCheckParams,
    server_context: RosettaContext,
) -> ApiResult<&'static str> {
    let rest_client = server_context.rest_client()?;
    let duration_secs = params.duration_secs.unwrap_or(HEALTH_CHECK_DEFAULT_SECS);
    rest_client.health_check(duration_secs).await?;

    Ok("aptos-node:ok")
}
<|endoftext|>


<commit_before>use core::cmp::max;

use redox::*;

pub fn main() {
    let url = match args().get(1) {
        Option::Some(arg) => arg.clone(),
        Option::None => "none://".to_string(),
    };

    let mut resource = File::open(&url);

    let mut vec: Vec<u8> = Vec::new();
    resource.read_to_end(&mut vec);

    let bmp = BMP::from_data(&vec);

    let mut window = Window::new((rand() % 400 + 50) as isize, (rand() % 300 + 50) as isize,
                                max(320, bmp.width()), bmp.height(),
                                &("Viewer (".to_string() + &url + ")"));
    window.image(0, 0, bmp.width(), bmp.height(), bmp.as_slice());
    window.sync();

    while let Option::Some(event) = window.poll() {
        match event.to_option() {
            EventOption::Key(key_event) => {
                if key_event.pressed && key_event.scancode == K_ESC {
                    break;
                }
            }
            _ => (),
        }
    }
}
<commit_msg>Fix viewer clearing<commit_after>use core::cmp::max;

use redox::*;

pub fn main() {
    let url = match args().get(1) {
        Option::Some(arg) => arg.clone(),
        Option::None => "none://".to_string(),
    };

    let mut resource = File::open(&url);

    let mut vec: Vec<u8> = Vec::new();
    resource.read_to_end(&mut vec);

    let bmp = BMP::from_data(&vec);

    let mut window = Window::new((rand() % 400 + 50) as isize, (rand() % 300 + 50) as isize,
                                max(320, bmp.width()), bmp.height(),
                                &("Viewer (".to_string() + &url + ")"));
    window.set([0, 0, 0, 255]);
    window.image(0, 0, bmp.width(), bmp.height(), bmp.as_slice());
    window.sync();

    while let Option::Some(event) = window.poll() {
        match event.to_option() {
            EventOption::Key(key_event) => {
                if key_event.pressed && key_event.scancode == K_ESC {
                    break;
                }
            }
            _ => (),
        }
    }
}
<|endoftext|>


<commit_before>#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private, quote)]

extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;

use rustc_plugin::Registry;
use syntax::ast::{FnDecl, Ident, ItemKind, LitKind, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::codemap::Span;
use syntax::symbol::Symbol;

fn get_js_name(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem) -> String {
    let meta_items = meta_item.meta_item_list().unwrap_or_else(|| {
        ecx.struct_span_err(span, "incorrect use of napi_callback attribute")
            .help("usage: #[napi_callback(\"jsFunctionName\")]")
            .emit();
        ecx.span_fatal(span, "invalid attribute usage");
    });

    if meta_items.len() != 1 {
        ecx.struct_span_err(span, "incorrect use of napi_callback attribute")
            .help("usage: #[napi_callback(\"jsFunctionName\")]")
            .emit();
        ecx.span_fatal(span, "attribute requires exactly one argument");
    }

    let name_meta_item = &meta_items[0];

    let name = name_meta_item
        .literal()
        .and_then(|literal| match literal.node {
            LitKind::Str(ref s, _) => Some(s.as_str()),
            _ => None,
        })
        .unwrap_or_else(|| {
            ecx.span_fatal(
                name_meta_item.span(),
                "attribute argument must be a string",
            );
        });

    String::from(&*name)
}

struct Function {
    pub ident: Ident,
    pub decl: FnDecl,
}

impl Function {
    fn from_annotatable(
        ecx: &mut ExtCtxt,
        annotated: &Annotatable,
    ) -> Function {
        let report_error = |span| {
            ecx.span_fatal(
                span,
                "napi_callback attribute can only be used on \
                functions, but was applied to this item.",
            );
        };

        match *annotated {
            Annotatable::Item(ref item) => {
                match item.node {
                    ItemKind::Fn(ref decl, ..) => Function {
                        ident: item.ident,
                        decl: decl.clone().unwrap(),
                    },
                    _ => report_error(item.span),
                }
            }
            Annotatable::TraitItem(ref item) => report_error(item.span),
            Annotatable::ImplItem(ref item) => report_error(item.span),
        }
    }
}

fn create_napi_callback(ecx: &mut ExtCtxt, function: &Function) -> Annotatable {
    let fn_ident = function.ident;
    let extern_fn_name = format!("napi_rs_cb_{}", fn_ident.name);
    let extern_fn_ident = Ident::from_str(extern_fn_name.as_str());

    Annotatable::Item(
        quote_item!(ecx,
            #[no_mangle]
            pub extern "C" fn $extern_fn_ident(
                env: ::napi::sys::napi_env,
                info: ::napi::sys::napi_callback_info,
            ) -> ::napi::sys::napi_value {
                use std::error::Error;
                use std::ffi::CString;
                use std::mem;
                use std::ptr;

                use ::napi::NapiResult;
                use ::napi::sys::{napi_get_undefined, napi_throw,
                                  napi_throw_error, napi_value};

                let result: NapiResult<napi_value> = $fn_ident(env, info);

                match result {
                    Ok(value) => return value,
                    Err(error) => {
                        if let Some(exception) = error.exception {
                            unsafe {
                                napi_throw(env, exception);
                            }
                        } else {
                            let message = format!("{}", &error);
                            let c_string =
                                CString::new(message).unwrap_or_else(|_| {
                                    CString::new(error.description()).unwrap()
                                });

                            unsafe {
                                napi_throw_error(
                                    env,
                                    ptr::null(),
                                    c_string.as_ptr(),
                                );
                            }
                        }

                        unsafe {
                            let mut result: napi_value = mem::uninitialized();
                            napi_get_undefined(env, &mut result);
                            result
                        }
                    }
                }
            }
        ).unwrap(),
    )
}

pub fn napi_callback_decorator(
    ecx: &mut ExtCtxt,
    span: Span,
    meta_item: &MetaItem,
    annotated: Annotatable,
) -> Vec<Annotatable> {
    let js_name = get_js_name(ecx, span, meta_item);
    let function = Function::from_annotatable(ecx, &annotated);

    let mut output = Vec::new();

    output.push(create_napi_callback(ecx, &function));
    output.push(annotated);

    output
}

#[plugin_registrar]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_syntax_extension(
        Symbol::intern("napi_callback"),
        SyntaxExtension::MultiModifier(Box::new(napi_callback_decorator)),
    );
}
<commit_msg>style(codegen): remove needless return statement<commit_after>#![crate_type="dylib"]
#![feature(plugin_registrar, rustc_private, quote)]

extern crate syntax;
extern crate rustc;
extern crate rustc_plugin;

use rustc_plugin::Registry;
use syntax::ast::{FnDecl, Ident, ItemKind, LitKind, MetaItem};
use syntax::ext::base::{Annotatable, ExtCtxt, SyntaxExtension};
use syntax::codemap::Span;
use syntax::symbol::Symbol;

fn get_js_name(ecx: &mut ExtCtxt, span: Span, meta_item: &MetaItem) -> String {
    let meta_items = meta_item.meta_item_list().unwrap_or_else(|| {
        ecx.struct_span_err(span, "incorrect use of napi_callback attribute")
            .help("usage: #[napi_callback(\"jsFunctionName\")]")
            .emit();
        ecx.span_fatal(span, "invalid attribute usage");
    });

    if meta_items.len() != 1 {
        ecx.struct_span_err(span, "incorrect use of napi_callback attribute")
            .help("usage: #[napi_callback(\"jsFunctionName\")]")
            .emit();
        ecx.span_fatal(span, "attribute requires exactly one argument");
    }

    let name_meta_item = &meta_items[0];

    let name = name_meta_item
        .literal()
        .and_then(|literal| match literal.node {
            LitKind::Str(ref s, _) => Some(s.as_str()),
            _ => None,
        })
        .unwrap_or_else(|| {
            ecx.span_fatal(
                name_meta_item.span(),
                "attribute argument must be a string",
            );
        });

    String::from(&*name)
}

struct Function {
    pub ident: Ident,
    pub decl: FnDecl,
}

impl Function {
    fn from_annotatable(
        ecx: &mut ExtCtxt,
        annotated: &Annotatable,
    ) -> Function {
        let report_error = |span| {
            ecx.span_fatal(
                span,
                "napi_callback attribute can only be used on \
                functions, but was applied to this item.",
            );
        };

        match *annotated {
            Annotatable::Item(ref item) => {
                match item.node {
                    ItemKind::Fn(ref decl, ..) => Function {
                        ident: item.ident,
                        decl: decl.clone().unwrap(),
                    },
                    _ => report_error(item.span),
                }
            }
            Annotatable::TraitItem(ref item) => report_error(item.span),
            Annotatable::ImplItem(ref item) => report_error(item.span),
        }
    }
}

fn create_napi_callback(ecx: &mut ExtCtxt, function: &Function) -> Annotatable {
    let fn_ident = function.ident;
    let extern_fn_name = format!("napi_rs_cb_{}", fn_ident.name);
    let extern_fn_ident = Ident::from_str(extern_fn_name.as_str());

    Annotatable::Item(
        quote_item!(ecx,
            #[no_mangle]
            pub extern "C" fn $extern_fn_ident(
                env: ::napi::sys::napi_env,
                info: ::napi::sys::napi_callback_info,
            ) -> ::napi::sys::napi_value {
                use std::error::Error;
                use std::ffi::CString;
                use std::mem;
                use std::ptr;

                use ::napi::NapiResult;
                use ::napi::sys::{napi_get_undefined, napi_throw,
                                  napi_throw_error, napi_value};

                let result: NapiResult<napi_value> = $fn_ident(env, info);

                match result {
                    Ok(value) => value,
                    Err(error) => {
                        if let Some(exception) = error.exception {
                            unsafe {
                                napi_throw(env, exception);
                            }
                        } else {
                            let message = format!("{}", &error);
                            let c_string =
                                CString::new(message).unwrap_or_else(|_| {
                                    CString::new(error.description()).unwrap()
                                });

                            unsafe {
                                napi_throw_error(
                                    env,
                                    ptr::null(),
                                    c_string.as_ptr(),
                                );
                            }
                        }

                        unsafe {
                            let mut result: napi_value = mem::uninitialized();
                            napi_get_undefined(env, &mut result);
                            result
                        }
                    }
                }
            }
        ).unwrap(),
    )
}

pub fn napi_callback_decorator(
    ecx: &mut ExtCtxt,
    span: Span,
    meta_item: &MetaItem,
    annotated: Annotatable,
) -> Vec<Annotatable> {
    let js_name = get_js_name(ecx, span, meta_item);
    let function = Function::from_annotatable(ecx, &annotated);

    let mut output = Vec::new();

    output.push(create_napi_callback(ecx, &function));
    output.push(annotated);

    output
}

#[plugin_registrar]
pub fn plugin_registrar(registry: &mut Registry) {
    registry.register_syntax_extension(
        Symbol::intern("napi_callback"),
        SyntaxExtension::MultiModifier(Box::new(napi_callback_decorator)),
    );
}
<|endoftext|>