<commit_before>
#![allow(dead_code,
         non_camel_case_types,
         non_upper_case_globals,
         non_snake_case)]

// extern crate libc;
// use libc::{c_int, c_void, c_uchar, c_char};

use std::os::raw::{c_int, c_void, c_uchar, c_char};
use std::option::Option;

pub type uint8_t = u8;
pub type uint16_t = u16;
pub type uint32_t = u32;

pub enum rtlsdr_dev { }
type rtlsdr_dev_t = rtlsdr_dev;

pub struct Device {
    dev: *mut rtlsdr_dev_t,
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum rtlsdr_tuner {
    RTLSDR_TUNER_UNKNOWN = 0,
    RTLSDR_TUNER_E4000 = 1,
    RTLSDR_TUNER_FC0012 = 2,
    RTLSDR_TUNER_FC0013 = 3,
    RTLSDR_TUNER_FC2580 = 4,
    RTLSDR_TUNER_R820T = 5,
    RTLSDR_TUNER_R828D = 6,
}

#[derive(Copy, Clone)]
#[derive(Debug)]
pub enum Error {
    NoError,
    Io,
    InvalidParam,
    Access,
    NoDevice,
    NotFound,
    Busy,
    Timeout,
    Overflow,
    Pipe,
    Interrupted,
    NoMem,
    NotSupported,
    Other,
}

pub type rtlsdr_read_async_cb_t = Option<unsafe extern "C" fn(buf: *mut c_uchar,
                                                              len: uint32_t,
                                                              ctx: *mut c_void)>;

#[link(name = "rtlsdr")]
extern "C" {
    fn rtlsdr_get_device_count() -> uint32_t;
    fn rtlsdr_get_device_name(index: uint32_t) -> *const c_char;
    fn rtlsdr_get_device_usb_strings(index: uint32_t,
                                     manufact: *mut c_char,
                                     product: *mut c_char,
                                     serial: *mut c_char)
                                     -> c_int;
    fn rtlsdr_get_index_by_serial(serial: *const c_char) -> c_int;

    fn rtlsdr_open(dev: *mut *mut rtlsdr_dev_t, index: uint32_t) -> c_int;
    fn rtlsdr_close(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_xtal_freq(dev: *mut rtlsdr_dev_t,
                            rtl_freq: uint32_t,
                            tuner_freq: uint32_t)
                            -> c_int;
    fn rtlsdr_get_xtal_freq(dev: *mut rtlsdr_dev_t,
                            rtl_freq: *mut uint32_t,
                            tuner_freq: *mut uint32_t)
                            -> c_int;
    fn rtlsdr_get_usb_strings(dev: *mut rtlsdr_dev_t,
                              manufact: *mut c_char,
                              product: *mut c_char,
                              serial: *mut c_char)
                              -> c_int;
    fn rtlsdr_write_eeprom(dev: *mut rtlsdr_dev_t,
                           data: *mut uint8_t,
                           offset: uint8_t,
                           len: uint16_t)
                           -> c_int;
    fn rtlsdr_read_eeprom(dev: *mut rtlsdr_dev_t,
                          data: *mut uint8_t,
                          offset: uint8_t,
                          len: uint16_t)
                          -> c_int;
    fn rtlsdr_set_center_freq(dev: *mut rtlsdr_dev_t, freq: uint32_t) -> c_int;
    fn rtlsdr_get_center_freq(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_freq_correction(dev: *mut rtlsdr_dev_t, ppm: c_int) -> c_int;
    fn rtlsdr_get_freq_correction(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_get_tuner_type(dev: *mut rtlsdr_dev_t) -> rtlsdr_tuner;
    fn rtlsdr_get_tuner_gains(dev: *mut rtlsdr_dev_t, gains: *mut c_int) -> c_int;
    fn rtlsdr_set_tuner_gain(dev: *mut rtlsdr_dev_t, gain: c_int) -> c_int;
    fn rtlsdr_set_tuner_bandwidth(dev: *mut rtlsdr_dev_t, bw: uint32_t) -> c_int;
    fn rtlsdr_get_tuner_gain(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_tuner_if_gain(dev: *mut rtlsdr_dev_t, stage: c_int, gain: c_int) -> c_int;
    fn rtlsdr_set_tuner_gain_mode(dev: *mut rtlsdr_dev_t, manual: c_int) -> c_int;
    fn rtlsdr_set_sample_rate(dev: *mut rtlsdr_dev_t, rate: uint32_t) -> c_int;
    fn rtlsdr_get_sample_rate(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_testmode(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_set_agc_mode(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_set_direct_sampling(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_get_direct_sampling(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_offset_tuning(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_get_offset_tuning(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_reset_buffer(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_read_sync(dev: *mut rtlsdr_dev_t,
                        buf: *mut c_void,
                        len: c_int,
                        n_read: *mut c_int)
                        -> c_int;
    fn rtlsdr_wait_async(dev: *mut rtlsdr_dev_t,
                         cb: rtlsdr_read_async_cb_t,
                         ctx: *mut c_void)
                         -> c_int;
    fn rtlsdr_read_async(dev: *mut rtlsdr_dev_t,
                         cb: rtlsdr_read_async_cb_t,
                         ctx: *mut c_void,
                         buf_num: uint32_t,
                         buf_len: uint32_t)
                         -> c_int;
    fn rtlsdr_cancel_async(dev: *mut rtlsdr_dev_t) -> c_int;
}

fn get_err_msg(e: c_int) -> Error {
    use Error::*;
    match e {
        0 => NoError,
        -1 => Io,
        -2 => InvalidParam,
        -3 => Access,
        -4 => NoDevice,
        -5 => NotFound,
        -6 => Busy,
        -7 => Timeout,
        -8 => Overflow,
        -9 => Pipe,
        -10 => Interrupted,
        -11 => NoMem,
        -12 => NotSupported,
        _ => Other,
    }
}

// pub fn get_device_count() -> i32 {}
// pub fn get_device_name(index: ) ->  {}
// pub fn get_device_usb_strings( ) ->  i32 {}
// pub fn get_index_by_serial( ) ->  {}

pub fn open(index: i32) -> (Device, Error) {
    unsafe {
        let mut dev: *mut rtlsdr_dev_t = std::ptr::null_mut();
        let err = rtlsdr_open(&mut dev as *mut *mut rtlsdr_dev_t, index as uint32_t);
        return (Device { dev: dev }, get_err_msg(err));
    }
}

impl Device {
    pub fn close(&self) -> Error {
        unsafe {
            return get_err_msg(rtlsdr_close(self.dev));
        }
    }

    pub fn set_xtal_freq(&self, rtlFreqHz: u32, tunerFreqHz: u32) -> Error {
        unsafe {
            return get_err_msg(rtlsdr_set_xtal_freq(self.dev,
                                                    rtlFreqHz,
                                                    tunerFreqHz));
        }
    }

    pub fn get_xtal_freq(&self) -> (u32, u32, Error) {
        let mut rtlFreqHz: u32 = 0;
        let mut tunerFreqHz: u32 = 0;
        unsafe {
            let err = rtlsdr_get_xtal_freq(self.dev,
                                           &mut rtlFreqHz as *mut uint32_t,
                                           &mut tunerFreqHz as *mut uint32_t);
            return (rtlFreqHz, tunerFreqHz, get_err_msg(err));
        }
    }
    //     pub fn get_usb_strings() -> Error {}
    //     pub fn write_eeprom() -> Error {}
    //     pub fn read_eeprom() -> Error {}
    //     pub fn set_center_freq() -> Error {}
    //     pub fn get_center_freq() -> Error {}
    //     pub fn set_freq_correction() -> Error {}
    //     pub fn get_freq_correction() -> Error {}
    //     pub fn get_tuner_type() -> rtlsdr_tuner {}
    //     pub fn get_tuner_gains() -> Error {}
    //     pub fn set_tuner_gain() -> Error {}
    //     pub fn set_tuner_bandwidth() -> Error {}
    //     pub fn get_tuner_gain() -> Error {}
    //     pub fn set_tuner_if_gain() -> Error {}
    //     pub fn set_tuner_gain_mode() -> Error {}
    //     pub fn set_sample_rate() -> Error {}
    //     pub fn get_sample_rate() -> Error {}
    //     pub fn set_testmode() -> Error {}
    //     pub fn set_agc_mode() -> Error {}
    //     pub fn set_direct_sampling() -> Error {}
    //     pub fn get_direct_sampling() -> Error {}
    //     pub fn set_offset_tuning() -> Error {}
    //     pub fn get_offset_tuning() -> Error {}
    //     pub fn reset_buffer() -> Error {}
    //     pub fn read_sync() -> Error {}
    //     pub fn wait_async() -> Error {}
    //     pub fn read_async() -> Error {}
    //     pub fn cancel_async() -> Error {}
}

fn main() {
    println!("opening...");

    let (dev, err) = open(0);
    match err {
        Error::NoError => println!("open successful"),
        _ => return,
    }

    let rtl_freq: u32 = 28800000;
	let tuner_freq: u32 = 28800000;
    let err = dev.set_xtal_freq(rtl_freq, tuner_freq);
    match err {
        Error::NoError => println!("set_xtal_freq successful"),
        _ => return,
    }

    let (rtl_freq, tuner_freq, err) = dev.get_xtal_freq();
     println!("rtl_freq: {}, tuner_freq: {}, err: {:?}", rtl_freq, tuner_freq, err);

    let err = dev.close();
    println!("dev close status: {:?}", err);
}
<commit_msg>function comments added<commit_after>
#![allow(dead_code,
         non_camel_case_types,
         non_upper_case_globals,
         non_snake_case)]

// extern crate libc;
// use libc::{c_int, c_void, c_uchar, c_char};

use std::os::raw::{c_int, c_void, c_uchar, c_char};
use std::option::Option;

pub type uint8_t = u8;
pub type uint16_t = u16;
pub type uint32_t = u32;

pub enum rtlsdr_dev { }
type rtlsdr_dev_t = rtlsdr_dev;

pub struct Device {
    dev: *mut rtlsdr_dev_t,
}

#[derive(Copy, Clone)]
#[repr(u32)]
#[derive(Debug)]
pub enum rtlsdr_tuner {
    RTLSDR_TUNER_UNKNOWN = 0,
    RTLSDR_TUNER_E4000 = 1,
    RTLSDR_TUNER_FC0012 = 2,
    RTLSDR_TUNER_FC0013 = 3,
    RTLSDR_TUNER_FC2580 = 4,
    RTLSDR_TUNER_R820T = 5,
    RTLSDR_TUNER_R828D = 6,
}

#[derive(Copy, Clone)]
#[derive(Debug)]
pub enum Error {
    NoError,
    Io,
    InvalidParam,
    Access,
    NoDevice,
    NotFound,
    Busy,
    Timeout,
    Overflow,
    Pipe,
    Interrupted,
    NoMem,
    NotSupported,
    Other,
}

pub type rtlsdr_read_async_cb_t = Option<unsafe extern "C" fn(buf: *mut c_uchar,
                                                              len: uint32_t,
                                                              ctx: *mut c_void)>;

#[link(name = "rtlsdr")]
extern "C" {
    fn rtlsdr_get_device_count() -> uint32_t;
    fn rtlsdr_get_device_name(index: uint32_t) -> *const c_char;
    fn rtlsdr_get_device_usb_strings(index: uint32_t,
                                     manufact: *mut c_char,
                                     product: *mut c_char,
                                     serial: *mut c_char)
                                     -> c_int;
    fn rtlsdr_get_index_by_serial(serial: *const c_char) -> c_int;

    fn rtlsdr_open(dev: *mut *mut rtlsdr_dev_t, index: uint32_t) -> c_int;
    fn rtlsdr_close(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_xtal_freq(dev: *mut rtlsdr_dev_t,
                            rtl_freq: uint32_t,
                            tuner_freq: uint32_t)
                            -> c_int;
    fn rtlsdr_get_xtal_freq(dev: *mut rtlsdr_dev_t,
                            rtl_freq: *mut uint32_t,
                            tuner_freq: *mut uint32_t)
                            -> c_int;
    fn rtlsdr_get_usb_strings(dev: *mut rtlsdr_dev_t,
                              manufact: *mut c_char,
                              product: *mut c_char,
                              serial: *mut c_char)
                              -> c_int;
    fn rtlsdr_write_eeprom(dev: *mut rtlsdr_dev_t,
                           data: *mut uint8_t,
                           offset: uint8_t,
                           len: uint16_t)
                           -> c_int;
    fn rtlsdr_read_eeprom(dev: *mut rtlsdr_dev_t,
                          data: *mut uint8_t,
                          offset: uint8_t,
                          len: uint16_t)
                          -> c_int;
    fn rtlsdr_set_center_freq(dev: *mut rtlsdr_dev_t, freq: uint32_t) -> c_int;
    fn rtlsdr_get_center_freq(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_freq_correction(dev: *mut rtlsdr_dev_t, ppm: c_int) -> c_int;
    fn rtlsdr_get_freq_correction(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_get_tuner_type(dev: *mut rtlsdr_dev_t) -> rtlsdr_tuner;
    fn rtlsdr_get_tuner_gains(dev: *mut rtlsdr_dev_t, gains: *mut c_int) -> c_int;
    fn rtlsdr_set_tuner_gain(dev: *mut rtlsdr_dev_t, gain: c_int) -> c_int;
    fn rtlsdr_set_tuner_bandwidth(dev: *mut rtlsdr_dev_t, bw: uint32_t) -> c_int;
    fn rtlsdr_get_tuner_gain(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_tuner_if_gain(dev: *mut rtlsdr_dev_t, stage: c_int, gain: c_int) -> c_int;
    fn rtlsdr_set_tuner_gain_mode(dev: *mut rtlsdr_dev_t, manual: c_int) -> c_int;
    fn rtlsdr_set_sample_rate(dev: *mut rtlsdr_dev_t, rate: uint32_t) -> c_int;
    fn rtlsdr_get_sample_rate(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_testmode(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_set_agc_mode(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_set_direct_sampling(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_get_direct_sampling(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_set_offset_tuning(dev: *mut rtlsdr_dev_t, on: c_int) -> c_int;
    fn rtlsdr_get_offset_tuning(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_reset_buffer(dev: *mut rtlsdr_dev_t) -> c_int;
    fn rtlsdr_read_sync(dev: *mut rtlsdr_dev_t,
                        buf: *mut c_void,
                        len: c_int,
                        n_read: *mut c_int)
                        -> c_int;
    fn rtlsdr_wait_async(dev: *mut rtlsdr_dev_t,
                         cb: rtlsdr_read_async_cb_t,
                         ctx: *mut c_void)
                         -> c_int;
    fn rtlsdr_read_async(dev: *mut rtlsdr_dev_t,
                         cb: rtlsdr_read_async_cb_t,
                         ctx: *mut c_void,
                         buf_num: uint32_t,
                         buf_len: uint32_t)
                         -> c_int;
    fn rtlsdr_cancel_async(dev: *mut rtlsdr_dev_t) -> c_int;
}

fn get_err_msg(e: c_int) -> Error {
    use Error::*;
    match e {
        0 => NoError,
        -1 => Io,
        -2 => InvalidParam,
        -3 => Access,
        -4 => NoDevice,
        -5 => NotFound,
        -6 => Busy,
        -7 => Timeout,
        -8 => Overflow,
        -9 => Pipe,
        -10 => Interrupted,
        -11 => NoMem,
        -12 => NotSupported,
        _ => Other,
    }
}

// get_device_count returns the number of devices detected.
// pub fn get_device_count() -> i32 {}

// get_device_name returns the name of the device by index.
// pub fn get_device_name(index: ) ->  {}

// get_device_usb_strings returns the information of a device by index.
// pub fn get_device_usb_strings( ) ->  i32 {}

// get_index_by_serial returns a device index by serial id.
// pub fn get_index_by_serial( ) ->  {}

// open returns an opened device based on index.
pub fn open(index: i32) -> (Device, Error) {
    unsafe {
        let mut dev: *mut rtlsdr_dev_t = std::ptr::null_mut();
        let err = rtlsdr_open(&mut dev as *mut *mut rtlsdr_dev_t, index as uint32_t);
        return (Device { dev: dev }, get_err_msg(err));
    }
}

impl Device {
    // close closes the device.
    pub fn close(&self) -> Error {
        unsafe {
            return get_err_msg(rtlsdr_close(self.dev));
        }
    }

    // set_xtal_freq sets the crystal oscillator frequencies.
    //
    // Typically both ICs(rtlsdr and tuner) use the same clock. Changing the
    // clock may make sense if you are applying an external clock to the tuner
    // or to compensate the frequency (and sample rate) error caused by the
    // original (cheap) crystal.
    //
    // Note, call this function only if you fully understand the implications.
    pub fn set_xtal_freq(&self, rtlFreqHz: u32, tunerFreqHz: u32) -> Error {
        unsafe {
            return get_err_msg(rtlsdr_set_xtal_freq(self.dev,
                                                    rtlFreqHz,
                                                    tunerFreqHz));
        }
    }

    // get_xtal_freq returns the crystal oscillator frequencies.
    // Typically both ICs (rtlsdr and tuner) use the same clock.
    pub fn get_xtal_freq(&self) -> (u32, u32, Error) {
        let mut rtlFreqHz: u32 = 0;
        let mut tunerFreqHz: u32 = 0;
        unsafe {
            let err = rtlsdr_get_xtal_freq(self.dev,
                                           &mut rtlFreqHz as *mut uint32_t,
                                           &mut tunerFreqHz as *mut uint32_t);
            return (rtlFreqHz, tunerFreqHz, get_err_msg(err));
        }
    }

    // get_usb_strings returns the device information. Note, strings may be empty.
    // pub fn get_usb_strings(&self) -> Error {}

    // write_eeprom writes data to the EEPROM.
    // pub fn write_eeprom(&self) -> Error {}

    // read_eeprom returns data read from the EEPROM.
    // pub fn read_eeprom(&self) -> Error {}

    // set_center_freq sets the center frequency.
    pub fn set_center_freq(&self, freqHz: u32) -> Error {
        unsafe {
            return get_err_msg(rtlsdr_set_center_freq(self.dev, freqHz));
        }
    }

    // get_center_freq returns the tuned frequency or zero on error.
    pub fn get_center_freq(&self) -> u32 {
        unsafe {
            let freqHz = rtlsdr_get_center_freq(self.dev);
            return freqHz as u32;
        }
    }
    // set_freq_correction sets the frequency correction.
    // pub fn set_freq_correction(&self) -> Error {}

    // get_freq_correction returns the frequency correction value.
    // pub fn get_freq_correction(&self) -> Error {}

    // // get_tuner_type returns the tuner type.
    // pub fn get_tuner_type(&self) -> rtlsdr_tuner {}

    // get_tuner_gains returns a list of supported tuner gains.
    // Values are in tenths of dB, e.g. 115 means 11.5 dB.
    // pub fn get_tuner_gains(&self) -> Error {}

    // set_tuner_gain sets the tuner gain. Note, manual gain mode
    // must be enabled for this to work. Valid gain values may be
    // queried using GetTunerGains.
    //
    // Valid values (in tenths of a dB) are:
    // -10, 15, 40, 65, 90, 115, 140, 165, 190, 215, 240, 290,
    // 340, 420, 430, 450, 470, 490
    //
    // Gain values are in tenths of dB, e.g. 115 means 11.5 dB.
    // pub fn set_tuner_gain(&self) -> Error {}

    // set_tuner_bandwidth sets the device bandwidth.
    // pub fn set_tuner_bandwidth(&self) -> Error {}

    // get_tuner_gain returns the tuner gain.
    //
    // Gain values are in tenths of dB, e.g. 115 means 11.5 dB.
    // pub fn get_tuner_gain(&self) -> Error {}

    // set_tuner_if_gain sets the intermediate frequency gain.
    //
    // Intermediate frequency gain stage number 1 to 6.
    // Gain values are in tenths of dB, e.g. -30 means -3.0 dB.
    // pub fn set_tuner_if_gain(&self) -> Error {}

    // set_tuner_gain_mode sets the gain mode (automatic/manual).
    // Manual gain mode must be enabled for the gain setter function to work.
    // pub fn set_tuner_gain_mode(&self) -> Error {}

    // set_sample_rate sets the sample rate.
    //
    // When applicable, the baseband filters are also selected based
    // on the requested sample rate.
    // pub fn set_sample_rate(&self) -> Error {}

    // get_sample_rate returns the sample rate.
    // pub fn get_sample_rate(&self) -> Error {}

    // set_testmode sets device to  test mode.
    //
    // Test mode returns 8 bit counters instead of samples. Note,
    // the counter is generated inside the device.
    // pub fn set_testmode(&self) -> Error {}

    // set_agc_mode sets the AGC mode.
    // pub fn set_agc_mode(&self) -> Error {}

    // set_direct_sampling sets the direct sampling mode.
    //
    // When enabled, the IF mode of the device is activated, and
    // SetCenterFreq() will control the IF-frequency of the DDC, which
    // can be used to tune from 0 to 28.8 MHz (xtal frequency of the device).
    // pub fn set_direct_sampling(&self) -> Error {}

    // get_direct_sampling returns the state of direct sampling mode.
    // pub fn get_direct_sampling(&self) -> Error {}

    // set_offset_tuning sets the offset tuning mode for zero-IF tuners, which
    // avoids problems caused by the DC offset of the ADCs and 1/f noise.
    // pub fn set_offset_tuning(&self) -> Error {}

    // get_offset_tuning returns the offset tuning mode.
    // pub fn get_offset_tuning(&self) -> Error {}

    // reset_buffer resets the streaming buffer.
    // pub fn reset_buffer(&self) -> Error {}

    // read_sync performs a synchronous read of samples and returns
    // the number of samples read.
    // pub fn read_sync(&self) -> Error {}

    // read_async reads samples asynchronously. Note, this function
    // will block until canceled using CancelAsync. ReadAsyncCbT is
    // a package global variable.
    //
    // Note, please use ReadAsync2 as this method will be deprecated
    // in the future
    //
    // Optional bufNum buffer count, bufNum * bufLen = overall buffer size,
    // set to 0 for default buffer count (32).
    // Optional bufLen buffer length, must be multiple of 512, set to 0 for
    // default buffer length (16 * 32 * 512).
    // pub fn read_async(&self) -> Error {}

    // CancelAsync cancels all pending asynchronous operations.
    // pub fn cancel_async(&self) -> Error {}
}

fn main() {
    println!("opening...");

    let (dev, err) = open(0);
    match err {
        Error::NoError => println!("open successful"),
        _ => return,
    }

    let rtl_freq: u32 = 28800000;
	let tuner_freq: u32 = 28800000;
    let err = dev.set_xtal_freq(rtl_freq, tuner_freq);
    match err {
        Error::NoError => println!("set_xtal_freq successful"),
        _ => return,
    }

    let (rtl_freq, tuner_freq, err) = dev.get_xtal_freq();
     println!("rtl_freq: {}, tuner_freq: {}, err: {:?}", rtl_freq, tuner_freq, err);

    let err = dev.close();
    println!("dev close status: {:?}", err);
}
<|endoftext|>


<commit_before>//! Generate update information from dependency information.

use std::rc::Rc;
use std::collections::HashMap;

use semver::Version;

use dependencies;

/// Stores old and new version.
pub struct Bump {
    /// The old version.
    pub old: Version,
    /// The new version.
    pub new: Version,
}

/// Stores update info for dependency.
pub struct Dependency {
    /// The library name.
    pub name: Rc<String>,
    /// Bump info.
    pub bump: Bump,
}

/// Stores information about a package.
pub struct Package {
    /// The package name.
    pub name: Rc<String>,
    /// The order to update library.
    pub order: u32,
    /// Update information.
    pub bump: Bump,
    /// The dependencies.
    pub dependencies: Vec<Dependency>,
}

/// Generates update info.
pub fn generate_update_info_from(dependency_info: &str) -> Result<String, String> {
    use piston_meta::*;
    use std::iter::FromIterator;

    type PackageIndex = usize;
    type Depth = u32;

    fn depth_of(
        package_index: PackageIndex,
        package_indices: &HashMap<Rc<String>, PackageIndex>,
        depths: &mut HashMap<PackageIndex, Depth>,
        dependencies_data: &[dependencies::Package]
    ) -> Depth {
        let package = &dependencies_data[package_index];
        let d = depths.get(&package_index).map(|d| *d);
        match d {
            None => {
                // The depth of a package equals maximum depth of the dependencies + 1.
                let new_depth: Depth = package.dependencies.iter().map(|dep| {
                        package_indices.get(&dep.name).map(|&p| {
                                depth_of(p, package_indices, depths, dependencies_data)
                            }).unwrap_or(0)
                    }).max().unwrap_or(0) + 1;
                depths.insert(package_index, new_depth);
                new_depth
            }
            Some(x) => x
        }
    }

    // Increment first non-zero number.
    fn increment_version(version: &mut Version) {
        if version.major != 0 { version.increment_major(); }
        else if version.minor != 0 { version.increment_minor(); }
        else { version.increment_patch(); }
    }

    // Parse and convert to dependencies data.
    let dependencies_meta_syntax = include_str!("../assets/dependencies/syntax.txt");
    let dependencies_meta_rules = stderr_unwrap(dependencies_meta_syntax,
        syntax(dependencies_meta_syntax));
    let dependency_info = stderr_unwrap(dependency_info,
        parse(&dependencies_meta_rules, dependency_info));
    let mut ignored = vec![];
    let dependencies_data = try!(dependencies::convert(&dependency_info, &mut ignored)
        .map_err(|_| String::from("Could not convert dependency info")));

    // Stores the package indices using package name as key.
    let package_indices: HashMap<Rc<String>, PackageIndex> =
        HashMap::from_iter(dependencies_data.iter().enumerate().map(
            |(i, p)| {
                (p.name.clone(), i)
            }));

    // Store the depths of libraries.
    let mut depths: HashMap<PackageIndex, Depth> = HashMap::new();
    for i in 0 .. dependencies_data.len() {
        let _depth = depth_of(i, &package_indices, &mut depths, &dependencies_data);
    }

    let mut new_versions: HashMap<Rc<String>, Version> = HashMap::new();
    for package in &dependencies_data {
        // Get latest version used by any dependency.
        for dep in &package.dependencies {
            let version = try!(Version::parse(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for dependency `{}` in `{}`",
                    &dep.version, &dep.name, &package.name)));
            let v = new_versions.get(&dep.name).map(|v| v.clone());
            match v {
                None => {
                    new_versions.insert(dep.name.clone(), version);
                }
                Some(v) => {
                    if v < version {
                        new_versions.insert(dep.name.clone(), version);
                    }
                }
            }
        }
    }

    // Overwrite the versions used by packages.
    for package in &dependencies_data {
        let version = try!(Version::parse(&package.version)
            .map_err(|_| format!("Could not parse version `{}` for `{}`",
                &package.version, &package.name)));
        new_versions.insert(package.name.clone(), version);
    }

    // Create list of sorted package indices by depth.
    let mut sorted_depths: Vec<_> = depths.iter().collect();
    sorted_depths.sort_by(|&(_, da), &(_, db)| da.cmp(db));

    // Stores the update info.
    let mut update_packages: Vec<Package> = vec![];

    for (&package_index, &order) in sorted_depths {
        let package = &dependencies_data[package_index];
        let mut update_dependencies = vec![];

        // Find dependencies that needs update.
        for dep in &package.dependencies {
            let old_version = try!(Version::parse(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for dependency `{}` in `{}`",
                    &dep.version, &dep.name, &package.name)));
            let new_version = new_versions.get(&dep.name).unwrap();
            if *new_version > old_version {
                update_dependencies.push(Dependency {
                        name: dep.name.clone(),
                        bump: Bump {
                            old: old_version,
                            new: new_version.clone(),
                        }
                    });
            }
        }

        // If any dependency needs update, then the package needs update.
        if update_dependencies.len() > 0 {
            let old_version = try!(Version::parse(&package.version)
                .map_err(|_| format!("Could not parse version `{}` for `{}`",
                    &package.version, &package.name)));
            let new_version = new_versions.get_mut(&package.name).unwrap();
            if *new_version == old_version {
                increment_version(new_version);
            }
            update_packages.push(Package {
                    name: package.name.clone(),
                    order: order,
                    bump: Bump {
                        old: old_version,
                        new: new_version.clone(),
                    },
                    dependencies: update_dependencies,
                });
        }
    }

    Ok(String::from(""))
}
<commit_msg>Append a zero if parsing dependency version fails<commit_after>//! Generate update information from dependency information.

use std::rc::Rc;
use std::collections::HashMap;

use semver::{ self, Version };

use dependencies;

/// Stores old and new version.
pub struct Bump {
    /// The old version.
    pub old: Version,
    /// The new version.
    pub new: Version,
}

/// Stores update info for dependency.
pub struct Dependency {
    /// The library name.
    pub name: Rc<String>,
    /// Bump info.
    pub bump: Bump,
}

/// Stores information about a package.
pub struct Package {
    /// The package name.
    pub name: Rc<String>,
    /// The order to update library.
    pub order: u32,
    /// Update information.
    pub bump: Bump,
    /// The dependencies.
    pub dependencies: Vec<Dependency>,
}

/// Generates update info.
pub fn generate_update_info_from(dependency_info: &str) -> Result<String, String> {
    use piston_meta::*;
    use std::iter::FromIterator;

    type PackageIndex = usize;
    type Depth = u32;

    fn depth_of(
        package_index: PackageIndex,
        package_indices: &HashMap<Rc<String>, PackageIndex>,
        depths: &mut HashMap<PackageIndex, Depth>,
        dependencies_data: &[dependencies::Package]
    ) -> Depth {
        let package = &dependencies_data[package_index];
        let d = depths.get(&package_index).map(|d| *d);
        match d {
            None => {
                // The depth of a package equals maximum depth of the dependencies + 1.
                let new_depth: Depth = package.dependencies.iter().map(|dep| {
                        package_indices.get(&dep.name).map(|&p| {
                                depth_of(p, package_indices, depths, dependencies_data)
                            }).unwrap_or(0)
                    }).max().unwrap_or(0) + 1;
                depths.insert(package_index, new_depth);
                new_depth
            }
            Some(x) => x
        }
    }

    // Tries appending zero to version to make it parse.
    fn parse_version(text: &str) -> Result<Version, semver::ParseError> {
        match Version::parse(text) {
            Err(_) => {
                let append_zero = format!("{}.0", text);
                Version::parse(&append_zero)
            }
            x => x
        }
    }

    // Increment first non-zero number.
    fn increment_version(version: &mut Version) {
        if version.major != 0 { version.increment_major(); }
        else if version.minor != 0 { version.increment_minor(); }
        else { version.increment_patch(); }
    }

    // Parse and convert to dependencies data.
    let dependencies_meta_syntax = include_str!("../assets/dependencies/syntax.txt");
    let dependencies_meta_rules = stderr_unwrap(dependencies_meta_syntax,
        syntax(dependencies_meta_syntax));
    let dependency_info = stderr_unwrap(dependency_info,
        parse(&dependencies_meta_rules, dependency_info));
    let mut ignored = vec![];
    let dependencies_data = try!(dependencies::convert(&dependency_info, &mut ignored)
        .map_err(|_| String::from("Could not convert dependency info")));

    // Stores the package indices using package name as key.
    let package_indices: HashMap<Rc<String>, PackageIndex> =
        HashMap::from_iter(dependencies_data.iter().enumerate().map(
            |(i, p)| {
                (p.name.clone(), i)
            }));

    // Store the depths of libraries.
    let mut depths: HashMap<PackageIndex, Depth> = HashMap::new();
    for i in 0 .. dependencies_data.len() {
        let _depth = depth_of(i, &package_indices, &mut depths, &dependencies_data);
    }

    let mut new_versions: HashMap<Rc<String>, Version> = HashMap::new();
    for package in &dependencies_data {
        // Get latest version used by any dependency.
        for dep in &package.dependencies {
            let version = try!(parse_version(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for dependency `{}` in `{}`",
                    &dep.version, &dep.name, &package.name)));
            let v = new_versions.get(&dep.name).map(|v| v.clone());
            match v {
                None => {
                    new_versions.insert(dep.name.clone(), version);
                }
                Some(v) => {
                    if v < version {
                        new_versions.insert(dep.name.clone(), version);
                    }
                }
            }
        }
    }

    // Overwrite the versions used by packages.
    for package in &dependencies_data {
        let version = try!(Version::parse(&package.version)
            .map_err(|_| format!("Could not parse version `{}` for `{}`",
                &package.version, &package.name)));
        new_versions.insert(package.name.clone(), version);
    }

    // Create list of sorted package indices by depth.
    let mut sorted_depths: Vec<_> = depths.iter().collect();
    sorted_depths.sort_by(|&(_, da), &(_, db)| da.cmp(db));

    // Stores the update info.
    let mut update_packages: Vec<Package> = vec![];

    for (&package_index, &order) in sorted_depths {
        let package = &dependencies_data[package_index];
        let mut update_dependencies = vec![];

        // Find dependencies that needs update.
        for dep in &package.dependencies {
            let old_version = try!(parse_version(&dep.version)
                .map_err(|_| format!("Could not parse version `{}` for dependency `{}` in `{}`",
                    &dep.version, &dep.name, &package.name)));
            let new_version = new_versions.get(&dep.name).unwrap();
            if *new_version > old_version {
                update_dependencies.push(Dependency {
                        name: dep.name.clone(),
                        bump: Bump {
                            old: old_version,
                            new: new_version.clone(),
                        }
                    });
            }
        }

        // If any dependency needs update, then the package needs update.
        if update_dependencies.len() > 0 {
            let old_version = try!(Version::parse(&package.version)
                .map_err(|_| format!("Could not parse version `{}` for `{}`",
                    &package.version, &package.name)));
            let new_version = new_versions.get_mut(&package.name).unwrap();
            if *new_version == old_version {
                increment_version(new_version);
            }
            update_packages.push(Package {
                    name: package.name.clone(),
                    order: order,
                    bump: Bump {
                        old: old_version,
                        new: new_version.clone(),
                    },
                    dependencies: update_dependencies,
                });
        }
    }

    Ok(String::from(""))
}
<|endoftext|>


<commit_before>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use gstr;
use gtype::GType;
use ffi;
use ffi::GTypeInstance;
use refcount::{Refcount, RefcountFuncs};
use util::is_false;

use std::mem::transmute;

pub trait ObjectType {
    fn get_type(&self) -> GType;
}

const REFCOUNT_FUNCS: &'static RefcountFuncs = &(
        &ffi::g_object_ref,
        &ffi::g_object_unref
    );

impl<T> Refcount for T where T: ObjectType {
    fn refcount_funcs(&self) -> &'static RefcountFuncs {
        return REFCOUNT_FUNCS;
    }
}

pub trait Upcast<T> {
    fn upcast(&self) -> &T;
    fn upcast_mut(&mut self) -> &mut T;
}

impl<T> Upcast<T> for T {

    #[inline]
    fn upcast(&self) -> &T { self }

    #[inline]
    fn upcast_mut(&mut self) -> &mut T { self }
}

pub fn cast<'a, T: ObjectType, U: ObjectType>(source: &'a T)
                                             -> &'a U {
    unsafe {
        let inst = source as *const T as *const GTypeInstance;
        let dest: &'a U = transmute(source);
        let dest_type = dest.get_type();
        if is_false(ffi::g_type_check_instance_is_a(inst, dest_type)) {
            panic!("invalid cast to type {}",
                   gstr::parse_as_utf8(&ffi::g_type_name(dest_type)).unwrap());
        }
        dest
    }
}

pub fn cast_mut<'a, T: ObjectType, U: ObjectType>(source: &'a mut T)
                                                  -> &'a mut U {
    unsafe {
        let inst = source as *mut T as *const T as *const GTypeInstance;
        let dest: &'a mut U = transmute(source);
        let dest_type = dest.get_type();
        if is_false(ffi::g_type_check_instance_is_a(inst, dest_type)) {
            panic!("invalid cast to type {}",
                   gstr::parse_as_utf8(&ffi::g_type_name(dest_type)).unwrap());
        }
        dest
    }
}
<commit_msg>object: Further cleanup in cast code<commit_after>// This file is part of Grust, GObject introspection bindings for Rust
//
// Copyright (C) 2013, 2014  Mikhail Zabaluev <mikhail.zabaluev@gmail.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

use gstr;
use gtype::GType;
use ffi;
use ffi::GTypeInstance;
use refcount::{Refcount, RefcountFuncs};
use util::is_true;

use std::mem::transmute;

pub trait ObjectType {
    fn get_type(&self) -> GType;
}

const REFCOUNT_FUNCS: &'static RefcountFuncs = &(
        &ffi::g_object_ref,
        &ffi::g_object_unref
    );

impl<T> Refcount for T where T: ObjectType {
    fn refcount_funcs(&self) -> &'static RefcountFuncs {
        return REFCOUNT_FUNCS;
    }
}

pub trait Upcast<T> {
    fn upcast(&self) -> &T;
    fn upcast_mut(&mut self) -> &mut T;
}

impl<T> Upcast<T> for T {

    #[inline]
    fn upcast(&self) -> &T { self }

    #[inline]
    fn upcast_mut(&mut self) -> &mut T { self }
}

pub fn cast<'a, T: ObjectType, U: ObjectType>(source: &'a T)
                                             -> &'a U {
    unsafe {
        let inst = source as *const T as *const GTypeInstance;
        let dest: &'a U = transmute(source);
        let dest_type = dest.get_type();
        assert!(is_true(ffi::g_type_check_instance_is_a(inst, dest_type)),
                "invalid cast to type {}",
                gstr::parse_as_utf8(&ffi::g_type_name(dest_type)).unwrap());
        dest
    }
}

pub fn cast_mut<'a, T: ObjectType, U: ObjectType>(source: &'a mut T)
                                                  -> &'a mut U {
    unsafe {
        let inst = source as *mut T as *const GTypeInstance;
        let dest: &'a mut U = transmute(source);
        let dest_type = dest.get_type();
        assert!(is_true(ffi::g_type_check_instance_is_a(inst, dest_type)),
                "invalid cast to type {}",
                gstr::parse_as_utf8(&ffi::g_type_name(dest_type)).unwrap());
        dest
    }
}
<|endoftext|>


<commit_before>//! This module contains the parallel iterator types for options
//! (`Option<T>`). You will rarely need to interact with it directly
//! unless you have need to name one of the iterator types.

use iter::*;
use iter::plumbing::*;
use std;
use std::sync::atomic::{AtomicBool, Ordering};

/// Parallel iterator over an option
#[derive(Debug, Clone)]
pub struct IntoIter<T: Send> {
    opt: Option<T>,
}

impl<T: Send> IntoParallelIterator for Option<T> {
    type Item = T;
    type Iter = IntoIter<T>;

    fn into_par_iter(self) -> Self::Iter {
        IntoIter { opt: self }
    }
}

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

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.drive(consumer)
    }

    fn opt_len(&self) -> Option<usize> {
        Some(self.len())
    }
}

impl<T: Send> IndexedParallelIterator for IntoIter<T> {
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        let mut folder = consumer.into_folder();
        if let Some(item) = self.opt {
            folder = folder.consume(item);
        }
        folder.complete()
    }

    fn len(&self) -> usize {
        match self.opt {
            Some(_) => 1,
            None => 0,
        }
    }

    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(OptionProducer { opt: self.opt })
    }
}

/// Parallel iterator over an immutable reference to an option
#[derive(Debug)]
pub struct Iter<'a, T: Sync + 'a> {
    inner: IntoIter<&'a T>,
}

impl<'a, T: Sync> Clone for Iter<'a, T> {
    fn clone(&self) -> Self {
        Iter { inner: self.inner.clone() }
    }
}

impl<'a, T: Sync> IntoParallelIterator for &'a Option<T> {
    type Item = &'a T;
    type Iter = Iter<'a, T>;

    fn into_par_iter(self) -> Self::Iter {
        Iter { inner: self.as_ref().into_par_iter() }
    }
}

delegate_indexed_iterator!{
    Iter<'a, T> => &'a T,
    impl<'a, T: Sync + 'a>
}

/// Parallel iterator over a mutable reference to an option
#[derive(Debug)]
pub struct IterMut<'a, T: Send + 'a> {
    inner: IntoIter<&'a mut T>,
}

impl<'a, T: Send> IntoParallelIterator for &'a mut Option<T> {
    type Item = &'a mut T;
    type Iter = IterMut<'a, T>;

    fn into_par_iter(self) -> Self::Iter {
        IterMut { inner: self.as_mut().into_par_iter() }
    }
}

delegate_indexed_iterator!{
    IterMut<'a, T> => &'a mut T,
    impl<'a, T: Send + 'a>
}

/// Private producer for an option
struct OptionProducer<T: Send> {
    opt: Option<T>,
}

impl<T: Send> Producer for OptionProducer<T> {
    type Item = T;
    type IntoIter = std::option::IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        self.opt.into_iter()
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        debug_assert!(index <= 1);
        let none = OptionProducer { opt: None };
        if index == 0 {
            (none, self)
        } else {
            (self, none)
        }
    }
}

/// Collect an arbitrary `Option`-wrapped collection.
///
/// If any item is `None`, then all previous items collected are discarded,
/// and it returns only `None`.
impl<'a, C, T> FromParallelIterator<Option<T>> for Option<C>
    where C: FromParallelIterator<T>,
          T: Send
{
    fn from_par_iter<I>(par_iter: I) -> Self
        where I: IntoParallelIterator<Item = Option<T>>
    {
        let found_none = AtomicBool::new(false);
        let collection = par_iter
            .into_par_iter()
            .inspect(|item| if item.is_none() {
                         found_none.store(true, Ordering::Relaxed);
                     })
            .while_some()
            .collect();

        if found_none.load(Ordering::Relaxed) {
            None
        } else {
            Some(collection)
        }
    }
}
<commit_msg>make requested changes to option<commit_after>//! This module contains the parallel iterator types for options
//! (`Option<T>`). You will rarely need to interact with it directly
//! unless you have need to name one of the iterator types.

use iter::*;
use iter::plumbing::*;
use std;
use std::sync::atomic::{AtomicBool, Ordering};

/// A parallel iterator over the value in [`Some`] variant of an [`Option`].
///
/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none.
///
/// This `struct` is created by the [`par_iter_mut`] function.
///
/// [`Option`]: https://doc.rust-lang.org/std/option/enum.Option.html
/// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
/// [`into_par_iter`]: ../iter/trait.IntoParallelIterator.html#tymethod.into_par_iter
#[derive(Debug, Clone)]
pub struct IntoIter<T: Send> {
    opt: Option<T>,
}

impl<T: Send> IntoParallelIterator for Option<T> {
    type Item = T;
    type Iter = IntoIter<T>;

    fn into_par_iter(self) -> Self::Iter {
        IntoIter { opt: self }
    }
}

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

    fn drive_unindexed<C>(self, consumer: C) -> C::Result
        where C: UnindexedConsumer<Self::Item>
    {
        self.drive(consumer)
    }

    fn opt_len(&self) -> Option<usize> {
        Some(self.len())
    }
}

impl<T: Send> IndexedParallelIterator for IntoIter<T> {
    fn drive<C>(self, consumer: C) -> C::Result
        where C: Consumer<Self::Item>
    {
        let mut folder = consumer.into_folder();
        if let Some(item) = self.opt {
            folder = folder.consume(item);
        }
        folder.complete()
    }

    fn len(&self) -> usize {
        match self.opt {
            Some(_) => 1,
            None => 0,
        }
    }

    fn with_producer<CB>(self, callback: CB) -> CB::Output
        where CB: ProducerCallback<Self::Item>
    {
        callback.callback(OptionProducer { opt: self.opt })
    }
}

/// A parallel iterator over a reference to the [`Some`] variant of an [`Option`].
///
/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none.
///
/// This `struct` is created by the [`par_iter`] function.
///
/// [`Option`]: https://doc.rust-lang.org/std/option/enum.Option.html
/// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
/// [`par_iter`]: ../iter/trait.IntoParallelRefIterator.html#tymethod.par_iter
#[derive(Debug)]
pub struct Iter<'a, T: Sync + 'a> {
    inner: IntoIter<&'a T>,
}

impl<'a, T: Sync> Clone for Iter<'a, T> {
    fn clone(&self) -> Self {
        Iter { inner: self.inner.clone() }
    }
}

impl<'a, T: Sync> IntoParallelIterator for &'a Option<T> {
    type Item = &'a T;
    type Iter = Iter<'a, T>;

    fn into_par_iter(self) -> Self::Iter {
        Iter { inner: self.as_ref().into_par_iter() }
    }
}

delegate_indexed_iterator!{
    Iter<'a, T> => &'a T,
    impl<'a, T: Sync + 'a>
}

/// A parallel iterator over a mutable reference to the [`Some`] variant of an [`Option`].
///
/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none.
///
/// This `struct` is created by the [`par_iter_mut`] function.
///
/// [`Option`]: https://doc.rust-lang.org/std/option/enum.Option.html
/// [`Some`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.Some
/// [`par_iter_mut`]: ../iter/trait.IntoParallelRefMutIterator.html#tymethod.par_iter_mut
#[derive(Debug)]
pub struct IterMut<'a, T: Send + 'a> {
    inner: IntoIter<&'a mut T>,
}

impl<'a, T: Send> IntoParallelIterator for &'a mut Option<T> {
    type Item = &'a mut T;
    type Iter = IterMut<'a, T>;

    fn into_par_iter(self) -> Self::Iter {
        IterMut { inner: self.as_mut().into_par_iter() }
    }
}

delegate_indexed_iterator!{
    IterMut<'a, T> => &'a mut T,
    impl<'a, T: Send + 'a>
}

/// Private producer for an option
struct OptionProducer<T: Send> {
    opt: Option<T>,
}

impl<T: Send> Producer for OptionProducer<T> {
    type Item = T;
    type IntoIter = std::option::IntoIter<T>;

    fn into_iter(self) -> Self::IntoIter {
        self.opt.into_iter()
    }

    fn split_at(self, index: usize) -> (Self, Self) {
        debug_assert!(index <= 1);
        let none = OptionProducer { opt: None };
        if index == 0 {
            (none, self)
        } else {
            (self, none)
        }
    }
}

/// Collect an arbitrary `Option`-wrapped collection.
///
/// If any item is `None`, then all previous items collected are discarded,
/// and it returns only `None`.
impl<'a, C, T> FromParallelIterator<Option<T>> for Option<C>
    where C: FromParallelIterator<T>,
          T: Send
{
    fn from_par_iter<I>(par_iter: I) -> Self
        where I: IntoParallelIterator<Item = Option<T>>
    {
        let found_none = AtomicBool::new(false);
        let collection = par_iter
            .into_par_iter()
            .inspect(|item| if item.is_none() {
                         found_none.store(true, Ordering::Relaxed);
                     })
            .while_some()
            .collect();

        if found_none.load(Ordering::Relaxed) {
            None
        } else {
            Some(collection)
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi;

use sass_sys::{self, Sass_Output_Style};

use bindings::ptr::Unique;

use options::OutputStyle;

/// The internal options we will pass to libsass
#[derive(Debug)]
pub struct SassOptions {
    pub raw: Unique<sass_sys::Sass_Options>
}

impl SassOptions {
    pub fn set_output_style(&mut self, style: OutputStyle) {
        let style = match style {
            OutputStyle::Nested => Sass_Output_Style::SASS_STYLE_NESTED,
            OutputStyle::Expanded => Sass_Output_Style::SASS_STYLE_EXPANDED,
            OutputStyle::Compact => Sass_Output_Style::SASS_STYLE_COMPACT,
            OutputStyle::Compressed => Sass_Output_Style::SASS_STYLE_COMPRESSED,
        };

        unsafe {
            sass_sys::sass_option_set_output_style(self.raw.get_mut(), style);
        }
    }

    pub fn set_precision(&mut self, precision: usize) {
        unsafe {
            sass_sys::sass_option_set_precision(self.raw.get_mut(), precision as i32);
        }
    }

    pub fn set_is_indented_syntax(&mut self) {
        unsafe {
            sass_sys::sass_option_set_is_indented_syntax_src(self.raw.get_mut(), true);
        }
    }

    pub fn set_include_path(&mut self, paths: Vec<String>) {
        let include_path = if cfg!(windows) {
            paths.join(";")
        } else {
            paths.join(",")
        };
        let c_str = ffi::CString::new(include_path).unwrap();
        let ptr = c_str.into_raw();
        unsafe {
            sass_sys::sass_option_set_include_path(self.raw.get_mut(), ptr)
        }
        let _ = ffi::CString::from_raw(ptr);
    }
}
<commit_msg>Fix unsafe call<commit_after>use std::ffi;

use sass_sys::{self, Sass_Output_Style};

use bindings::ptr::Unique;

use options::OutputStyle;

/// The internal options we will pass to libsass
#[derive(Debug)]
pub struct SassOptions {
    pub raw: Unique<sass_sys::Sass_Options>
}

impl SassOptions {
    pub fn set_output_style(&mut self, style: OutputStyle) {
        let style = match style {
            OutputStyle::Nested => Sass_Output_Style::SASS_STYLE_NESTED,
            OutputStyle::Expanded => Sass_Output_Style::SASS_STYLE_EXPANDED,
            OutputStyle::Compact => Sass_Output_Style::SASS_STYLE_COMPACT,
            OutputStyle::Compressed => Sass_Output_Style::SASS_STYLE_COMPRESSED,
        };

        unsafe {
            sass_sys::sass_option_set_output_style(self.raw.get_mut(), style);
        }
    }

    pub fn set_precision(&mut self, precision: usize) {
        unsafe {
            sass_sys::sass_option_set_precision(self.raw.get_mut(), precision as i32);
        }
    }

    pub fn set_is_indented_syntax(&mut self) {
        unsafe {
            sass_sys::sass_option_set_is_indented_syntax_src(self.raw.get_mut(), true);
        }
    }

    pub fn set_include_path(&mut self, paths: Vec<String>) {
        let include_path = if cfg!(windows) {
            paths.join(";")
        } else {
            paths.join(",")
        };
        let c_str = ffi::CString::new(include_path).unwrap();
        let ptr = c_str.into_raw();
        unsafe {
            sass_sys::sass_option_set_include_path(self.raw.get_mut(), ptr);
            let _ = ffi::CString::from_raw(ptr);
        }
    }
}
<|endoftext|>


<commit_before>//! Runs rustfmt on the repository.

use crate::Build;
use build_helper::{output, t};
use ignore::WalkBuilder;
use std::path::Path;
use std::process::Command;

fn rustfmt(src: &Path, rustfmt: &Path, path: &Path, check: bool) {
    let mut cmd = Command::new(&rustfmt);
    // avoid the submodule config paths from coming into play,
    // we only allow a single global config for the workspace for now
    cmd.arg("--config-path").arg(&src.canonicalize().unwrap());
    cmd.arg("--edition").arg("2018");
    cmd.arg("--unstable-features");
    cmd.arg("--skip-children");
    if check {
        cmd.arg("--check");
    }
    cmd.arg(&path);
    let cmd_debug = format!("{:?}", cmd);
    let status = cmd.status().expect("executing rustfmt");
    if !status.success() {
        eprintln!(
            "Running `{}` failed.\nIf you're running `tidy`, \
            try again with `--bless` flag. Or, you just want to format \
            code, run `./x.py fmt` instead.",
            cmd_debug,
        );
        std::process::exit(1);
    }
}

#[derive(serde::Deserialize)]
struct RustfmtConfig {
    ignore: Vec<String>,
}

pub fn format(build: &Build, check: bool) {
    let mut builder = ignore::types::TypesBuilder::new();
    builder.add_defaults();
    builder.select("rust");
    let matcher = builder.build().unwrap();
    let rustfmt_config = build.src.join("rustfmt.toml");
    if !rustfmt_config.exists() {
        eprintln!("Not running formatting checks; rustfmt.toml does not exist.");
        eprintln!("This may happen in distributed tarballs.");
        return;
    }
    let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
    let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
    let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
    for ignore in rustfmt_config.ignore {
        ignore_fmt.add(&format!("!{}", ignore)).expect(&ignore);
    }
    let untracked_paths_output = output(
        Command::new("git").arg("status").arg("--porcelain").arg("--untracked-files=normal"),
    );
    let untracked_paths = untracked_paths_output
        .lines()
        .filter(|entry| entry.starts_with("??"))
        .map(|entry| entry.split(" ").nth(1).expect("every git status entry should list a path"));
    for untracked_path in untracked_paths {
        eprintln!("skip untracked path {} during rustfmt invocations", untracked_path);
        ignore_fmt.add(&format!("!{}", untracked_path)).expect(&untracked_path);
    }
    let ignore_fmt = ignore_fmt.build().unwrap();

    let rustfmt_path = build.config.initial_rustfmt.as_ref().unwrap_or_else(|| {
        eprintln!("./x.py fmt is not supported on this channel");
        std::process::exit(1);
    });
    let src = build.src.clone();
    let walker = WalkBuilder::new(&build.src).types(matcher).overrides(ignore_fmt).build_parallel();
    walker.run(|| {
        let src = src.clone();
        let rustfmt_path = rustfmt_path.clone();
        Box::new(move |entry| {
            let entry = t!(entry);
            if entry.file_type().map_or(false, |t| t.is_file()) {
                rustfmt(&src, &rustfmt_path, &entry.path(), check);
            }
            ignore::WalkState::Continue
        })
    });
}
<commit_msg>Tidy: fix running rustfmt twice<commit_after>//! Runs rustfmt on the repository.

use crate::Build;
use build_helper::{output, t};
use ignore::WalkBuilder;
use std::path::Path;
use std::process::Command;

fn rustfmt(src: &Path, rustfmt: &Path, path: &Path, check: bool) {
    let mut cmd = Command::new(&rustfmt);
    // avoid the submodule config paths from coming into play,
    // we only allow a single global config for the workspace for now
    cmd.arg("--config-path").arg(&src.canonicalize().unwrap());
    cmd.arg("--edition").arg("2018");
    cmd.arg("--unstable-features");
    cmd.arg("--skip-children");
    if check {
        cmd.arg("--check");
    }
    cmd.arg(&path);
    let cmd_debug = format!("{:?}", cmd);
    let status = cmd.status().expect("executing rustfmt");
    if !status.success() {
        eprintln!(
            "Running `{}` failed.\nIf you're running `tidy`, \
            try again with `--bless` flag. Or, you just want to format \
            code, run `./x.py fmt` instead.",
            cmd_debug,
        );
        std::process::exit(1);
    }
}

#[derive(serde::Deserialize)]
struct RustfmtConfig {
    ignore: Vec<String>,
}

pub fn format(build: &Build, check: bool) {
    if build.config.dry_run {
        return;
    }
    let mut builder = ignore::types::TypesBuilder::new();
    builder.add_defaults();
    builder.select("rust");
    let matcher = builder.build().unwrap();
    let rustfmt_config = build.src.join("rustfmt.toml");
    if !rustfmt_config.exists() {
        eprintln!("Not running formatting checks; rustfmt.toml does not exist.");
        eprintln!("This may happen in distributed tarballs.");
        return;
    }
    let rustfmt_config = t!(std::fs::read_to_string(&rustfmt_config));
    let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config));
    let mut ignore_fmt = ignore::overrides::OverrideBuilder::new(&build.src);
    for ignore in rustfmt_config.ignore {
        ignore_fmt.add(&format!("!{}", ignore)).expect(&ignore);
    }
    let untracked_paths_output = output(
        Command::new("git").arg("status").arg("--porcelain").arg("--untracked-files=normal"),
    );
    let untracked_paths = untracked_paths_output
        .lines()
        .filter(|entry| entry.starts_with("??"))
        .map(|entry| entry.split(" ").nth(1).expect("every git status entry should list a path"));
    for untracked_path in untracked_paths {
        eprintln!("skip untracked path {} during rustfmt invocations", untracked_path);
        ignore_fmt.add(&format!("!{}", untracked_path)).expect(&untracked_path);
    }
    let ignore_fmt = ignore_fmt.build().unwrap();

    let rustfmt_path = build.config.initial_rustfmt.as_ref().unwrap_or_else(|| {
        eprintln!("./x.py fmt is not supported on this channel");
        std::process::exit(1);
    });
    let src = build.src.clone();
    let walker = WalkBuilder::new(&build.src).types(matcher).overrides(ignore_fmt).build_parallel();
    walker.run(|| {
        let src = src.clone();
        let rustfmt_path = rustfmt_path.clone();
        Box::new(move |entry| {
            let entry = t!(entry);
            if entry.file_type().map_or(false, |t| t.is_file()) {
                rustfmt(&src, &rustfmt_path, &entry.path(), check);
            }
            ignore::WalkState::Continue
        })
    });
}
<|endoftext|>


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

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};
use std::fs::{self, File};
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;

use build_helper::output;

use Build;

struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    fn new() -> Self {
        Self {
            cache: HashMap::new(),
            path: env::var_os("PATH").unwrap_or_default()
        }
    }

    fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.as_ref().into();
        let path = self.path.clone();
        self.cache.entry(cmd.clone()).or_insert_with(|| {
            for path in env::split_paths(&path) {
                let target = path.join(&cmd);
                let mut cmd_alt = cmd.clone();
                cmd_alt.push(".exe");
                if target.is_file() || // some/path/git
                target.with_extension("exe").exists() || // some/path/git.exe
                target.join(&cmd_alt).exists() { // some/path/git/git.exe
                    return Some(target);
                }
            }
            None
        }).clone()
    }

    fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains("\"") {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.hosts.iter()
        .filter_map(|host| build.config.target_config.get(host))
        .any(|config| config.llvm_config.is_none());
    if building_llvm || build.config.sanitizers {
        cmd_finder.must_have("cmake");
    }

    // Ninja is currently only used for LLVM itself.
    if building_llvm {
        if build.config.ninja {
            // Some Linux distros rename `ninja` to `ninja-build`.
            // CMake can work with either binary name.
            if cmd_finder.maybe_have("ninja-build").is_none() {
                cmd_finder.must_have("ninja");
            }
        }

        // If ninja isn't enabled but we're building for MSVC then we try
        // doubly hard to enable it. It was realized in #43767 that the msbuild
        // CMake generator for MSVC doesn't respect configuration options like
        // disabling LLVM assertions, which can often be quite important!
        //
        // In these cases we automatically enable Ninja if we find it in the
        // environment.
        if !build.config.ninja && build.config.build.contains("msvc") {
            if cmd_finder.maybe_have("ninja").is_some() {
                build.config.ninja = true;
            }
        }
    }

    build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| cmd_finder.maybe_have("python2.7"))
        .or_else(|| cmd_finder.maybe_have("python2"))
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        cmd_finder.must_have(build.cc(*target));
        if let Some(ar) = build.ar(*target) {
            cmd_finder.must_have(ar);
        }
    }

    for host in &build.hosts {
        cmd_finder.must_have(build.cxx(*host).unwrap());

        // The msvc hosts don't use jemalloc, turn it off globally to
        // avoid packaging the dummy liballoc_jemalloc on that platform.
        if host.contains("msvc") {
            build.config.use_jemalloc = false;
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(build.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("FileCheck executable {:?} does not exist", filecheck);
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") &&
           !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        if target.contains("-none-") {
            if build.no_std(*target).is_none() {
                let target = build.config.target_config.entry(target.clone())
                    .or_insert(Default::default());

                target.no_std = true;
            }

            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(target.clone())
                                 .or_insert(Default::default());
                target.musl_root = Some("/usr".into());
            }
            match build.musl_root(*target) {
                Some(root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap_or_else(|| {
                       panic!("{:?} failed {:?}", cmd, output)
                   }).to_string()
        })
    };
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let mut stage0 = String::new();
        t!(t!(File::open(build.src.join("src/stage0.txt")))
            .read_to_string(&mut stage0));
        if stage0.contains("\ndev:") {
            panic!("bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!");
        }
    }
}
<commit_msg>Don't look for cc/cxx when testing with bogus targets<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};
use std::fs::{self, File};
use std::io::Read;
use std::path::PathBuf;
use std::process::Command;

use build_helper::output;

use Build;

struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    fn new() -> Self {
        Self {
            cache: HashMap::new(),
            path: env::var_os("PATH").unwrap_or_default()
        }
    }

    fn maybe_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.as_ref().into();
        let path = self.path.clone();
        self.cache.entry(cmd.clone()).or_insert_with(|| {
            for path in env::split_paths(&path) {
                let target = path.join(&cmd);
                let mut cmd_alt = cmd.clone();
                cmd_alt.push(".exe");
                if target.is_file() || // some/path/git
                target.with_extension("exe").exists() || // some/path/git.exe
                target.join(&cmd_alt).exists() { // some/path/git/git.exe
                    return Some(target);
                }
            }
            None
        }).clone()
    }

    fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains("\"") {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.hosts.iter()
        .filter_map(|host| build.config.target_config.get(host))
        .any(|config| config.llvm_config.is_none());
    if building_llvm || build.config.sanitizers {
        cmd_finder.must_have("cmake");
    }

    // Ninja is currently only used for LLVM itself.
    if building_llvm {
        if build.config.ninja {
            // Some Linux distros rename `ninja` to `ninja-build`.
            // CMake can work with either binary name.
            if cmd_finder.maybe_have("ninja-build").is_none() {
                cmd_finder.must_have("ninja");
            }
        }

        // If ninja isn't enabled but we're building for MSVC then we try
        // doubly hard to enable it. It was realized in #43767 that the msbuild
        // CMake generator for MSVC doesn't respect configuration options like
        // disabling LLVM assertions, which can often be quite important!
        //
        // In these cases we automatically enable Ninja if we find it in the
        // environment.
        if !build.config.ninja && build.config.build.contains("msvc") {
            if cmd_finder.maybe_have("ninja").is_some() {
                build.config.ninja = true;
            }
        }
    }

    build.config.python = build.config.python.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| cmd_finder.maybe_have("python2.7"))
        .or_else(|| cmd_finder.maybe_have("python2"))
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build.config.nodejs.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.gdb = build.config.gdb.take().map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }

        // The msvc hosts don't use jemalloc, turn it off globally to
        // avoid packaging the dummy liballoc_jemalloc on that platform.
        if host.contains("msvc") {
            build.config.use_jemalloc = false;
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(build.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("FileCheck executable {:?} does not exist", filecheck);
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") &&
           !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        if target.contains("-none-") {
            if build.no_std(*target).is_none() {
                let target = build.config.target_config.entry(target.clone())
                    .or_insert(Default::default());

                target.no_std = true;
            }

            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(target.clone())
                                 .or_insert(Default::default());
                target.musl_root = Some("/usr".into());
            }
            match build.musl_root(*target) {
                Some(root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap_or_else(|| {
                       panic!("{:?} failed {:?}", cmd, output)
                   }).to_string()
        })
    };
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let mut stage0 = String::new();
        t!(t!(File::open(build.src.join("src/stage0.txt")))
            .read_to_string(&mut stage0));
        if stage0.contains("\ndev:") {
            panic!("bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!");
        }
    }
}
<|endoftext|>