<commit_before>use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};
use std::io::{Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions, create_dir_all};

/// `LazyFile` type
///
/// A lazy file is either absent, but a path to it is available, or it is present.
#[derive(Debug)]
pub enum LazyFile {
    Absent(PathBuf),
    File(File)
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    if let Some(parent) = p.as_ref().parent() {
        debug!("Implicitely creating directory: {:?}", parent);
        if let Err(e) = create_dir_all(parent) {
            return Err(e);
        }
    }
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

impl LazyFile {

    /**
     * Get the mutable file behind a LazyFile object
     */
    pub fn get_file_mut(&mut self) -> Result<&mut File, SE> {
        debug!("Getting lazy file: {:?}", self);
        let file = match *self {
            LazyFile::File(ref mut f) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                f.seek(SeekFrom::Start(0))
                    .map_err_into(SEK::FileNotCreated)
                    .map(|_| f)
            },
            LazyFile::Absent(ref p) => try!(open_file(p).map_err_into(SEK::FileNotFound)),
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }

    /**
     * Create a file out of this LazyFile object
     */
    pub fn create_file(&mut self) -> Result<&mut File, SE> {
        debug!("Creating lazy file: {:?}", self);
        let file = match *self {
            LazyFile::File(ref mut f) => return Ok(f),
            LazyFile::Absent(ref p) => try!(create_file(p).map_err_into(SEK::FileNotFound)),
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }
}

#[cfg(test)]
mod test {
    use super::LazyFile;
    use std::io::{Read, Write};
    use std::path::PathBuf;
    use tempdir::TempDir;

    fn get_dir() -> TempDir {
        TempDir::new("test-image").unwrap()
    }

    #[test]
    fn lazy_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test1");
        let mut lf = LazyFile::Absent(path);

        write!(lf.create_file().unwrap(), "Hello World").unwrap();
        dir.close().unwrap();
    }

    #[test]
    fn lazy_file_with_file() {
        let dir = get_dir();
        let mut path = PathBuf::from(dir.path());
        path.set_file_name("test2");
        let mut lf = LazyFile::Absent(path.clone());

        {
            let mut file = lf.create_file().unwrap();

            file.write(b"Hello World").unwrap();
            file.sync_all().unwrap();
        }

        {
            let mut file = lf.get_file_mut().unwrap();
            let mut s = Vec::new();
            file.read_to_end(&mut s).unwrap();
            assert_eq!(s, "Hello World".to_string().into_bytes());
        }

        dir.close().unwrap();
    }
}
<commit_msg>Comment out tests<commit_after>use error::{MapErrInto, StoreError as SE, StoreErrorKind as SEK};
use std::io::{Seek, SeekFrom};
use std::path::{Path, PathBuf};
use std::fs::{File, OpenOptions, create_dir_all};

/// `LazyFile` type
///
/// A lazy file is either absent, but a path to it is available, or it is present.
#[derive(Debug)]
pub enum LazyFile {
    Absent(PathBuf),
    File(File)
}

fn open_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    OpenOptions::new().write(true).read(true).open(p)
}

fn create_file<A: AsRef<Path>>(p: A) -> ::std::io::Result<File> {
    if let Some(parent) = p.as_ref().parent() {
        debug!("Implicitely creating directory: {:?}", parent);
        if let Err(e) = create_dir_all(parent) {
            return Err(e);
        }
    }
    OpenOptions::new().write(true).read(true).create(true).open(p)
}

impl LazyFile {

    /**
     * Get the mutable file behind a LazyFile object
     */
    pub fn get_file_mut(&mut self) -> Result<&mut File, SE> {
        debug!("Getting lazy file: {:?}", self);
        let file = match *self {
            LazyFile::File(ref mut f) => return {
                // We seek to the beginning of the file since we expect each
                // access to the file to be in a different context
                f.seek(SeekFrom::Start(0))
                    .map_err_into(SEK::FileNotCreated)
                    .map(|_| f)
            },
            LazyFile::Absent(ref p) => try!(open_file(p).map_err_into(SEK::FileNotFound)),
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }

    /**
     * Create a file out of this LazyFile object
     */
    pub fn create_file(&mut self) -> Result<&mut File, SE> {
        debug!("Creating lazy file: {:?}", self);
        let file = match *self {
            LazyFile::File(ref mut f) => return Ok(f),
            LazyFile::Absent(ref p) => try!(create_file(p).map_err_into(SEK::FileNotFound)),
        };
        *self = LazyFile::File(file);
        if let LazyFile::File(ref mut f) = *self {
            return Ok(f);
        }
        unreachable!()
    }
}

#[cfg(test)]
mod test {
    // use super::LazyFile;
    // use std::io::{Read, Write};
    // use std::path::PathBuf;
    // use tempdir::TempDir;

    // fn get_dir() -> TempDir {
    //     TempDir::new("test-image").unwrap()
    // }

    // #[test]
    // fn lazy_file() {
    //     let dir = get_dir();
    //     let mut path = PathBuf::from(dir.path());
    //     path.set_file_name("test1");
    //     let mut lf = LazyFile::Absent(path);

    //     write!(lf.create_file().unwrap(), "Hello World").unwrap();
    //     dir.close().unwrap();
    // }

    // #[test]
    // fn lazy_file_with_file() {
    //     let dir = get_dir();
    //     let mut path = PathBuf::from(dir.path());
    //     path.set_file_name("test2");
    //     let mut lf = LazyFile::Absent(path.clone());

    //     {
    //         let mut file = lf.create_file().unwrap();

    //         file.write(b"Hello World").unwrap();
    //         file.sync_all().unwrap();
    //     }

    //     {
    //         let mut file = lf.get_file_mut().unwrap();
    //         let mut s = Vec::new();
    //         file.read_to_end(&mut s).unwrap();
    //         assert_eq!(s, "Hello World".to_string().into_bytes());
    //     }

    //     dir.close().unwrap();
    // }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Communicating with the running kernel using devicemapper.

#[allow(dead_code, non_camel_case_types)]
mod dm_ioctl;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufRead};
use std::os::unix::io::AsRawFd;
use std::mem;
use std::slice;
use std::slice::bytes::copy_memory;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::BTreeSet;

use byteorder::{LittleEndian, ByteOrder};

use nix::sys::ioctl;

use dm::dm_ioctl as dmi;
use lv::LV;
use vg::VG;
use util::align_to;
use pv::Device;

const DM_IOCTL: u8 = 0xfd;
const DM_CTL_PATH: &'static str= "/dev/mapper/control";

const DM_VERSION_MAJOR: u32 = 4;
const DM_VERSION_MINOR: u32 = 30;
const DM_VERSION_PATCHLEVEL: u32 = 0;

/// Context needed for communicating with devicemapper.
pub struct DM<'a> {
    file: File,
    vg: &'a VG,
}

impl <'a> DM<'a> {
    /// Create a new context for communicating about a given VG with DM.
    pub fn new(vg: &'a VG) -> io::Result<Self> {
        Ok(DM {
            file: try!(File::open(DM_CTL_PATH)),
            vg: vg,
        })
    }

    /// Determine if a major number is a major number used by DM.
    pub fn is_dm_major(major: u32) -> bool {
        let mut set = BTreeSet::new();

        let f = File::open("/proc/devices")
            .ok().expect("Could not open /proc/devices");

        let reader = BufReader::new(f);

        for line in reader.lines()
            .filter_map(|x| x.ok())
            .skip_while(|x| x != "Block devices:")
            .skip(1) {
                let spl: Vec<_> = line.split_whitespace().collect();

                if spl[1] == "device-mapper" {
                    set.insert(spl[0].parse::<u32>().unwrap());
                }
            }

        set.contains(&major)
    }

    fn initialize_hdr(hdr: &mut dmi::Struct_dm_ioctl) -> () {
        hdr.version[0] = DM_VERSION_MAJOR;
        hdr.version[1] = DM_VERSION_MINOR;
        hdr.version[2] = DM_VERSION_PATCHLEVEL;

        hdr.data_start = mem::size_of::<dmi::Struct_dm_ioctl>() as u32;
    }

    fn hdr_set_name(hdr: &mut dmi::Struct_dm_ioctl, name: &[u8]) -> () {
        let name_dest: &mut [u8; 128] = unsafe { mem::transmute(&mut hdr.name) };
        copy_memory(name, &mut name_dest[..]);
    }

    fn hdr_set_uuid(hdr: &mut dmi::Struct_dm_ioctl, uuid: &[u8]) -> () {
        let uuid_dest: &mut [u8; 129] = unsafe { mem::transmute(&mut hdr.uuid) };
        copy_memory(uuid, &mut uuid_dest[..]);
    }

    /// Devicemapper version information: Major, Minor, and patchlevel versions.
    pub fn get_version(&self) -> io::Result<(u32, u32, u32)> {

        let mut hdr: dmi::Struct_dm_ioctl = Default::default();
        hdr.version[0] = DM_VERSION_MAJOR;
        hdr.version[1] = DM_VERSION_MINOR;
        hdr.version[2] = DM_VERSION_PATCHLEVEL;

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_VERSION_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => {},
        };

        Ok((hdr.version[0], hdr.version[1], hdr.version[2]))
    }

    /// Returns a list of tuples containing DM device names and their major/minor
    /// device numbers.
    pub fn list_devices(&self) -> io::Result<Vec<(String, Device)>> {
        let mut buf = [0u8; 16 * 1024];
        let mut hdr: &mut dmi::Struct_dm_ioctl = unsafe {mem::transmute(&mut buf)};

        Self::initialize_hdr(&mut hdr);
        hdr.data_size = buf.len() as u32;

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_LIST_DEVICES_CMD as u8, buf.len());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut buf) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => {},
        };

        let mut devs = Vec::new();
        if (hdr.data_size - hdr.data_start as u32) != 0 {
            let mut result = &buf[hdr.data_start as usize..];

            loop {
                let slc = slice_to_null(&result[12..]).expect("Bad data from ioctl");
                let devno = LittleEndian::read_u64(&result[..8]);
                devs.push((String::from_utf8_lossy(slc).into_owned(), Device::from(devno)));

                let next = LittleEndian::read_u32(&result[8..12]);
                if next == 0 { break }

                result = &result[next as usize..];
            }
        }

        Ok(devs)
    }

    fn create_device(&self, lv: &mut LV) -> io::Result<()> {
        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        Self::hdr_set_name(&mut hdr, lv.name.as_bytes());
        // TODO: concat uuid or something?
        //Self::hdr_set_uuid(&mut hdr, lv.uuid);
        hdr.data_size = hdr.data_start;

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_DEV_CREATE_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => { }
        };

        lv.device = Some(Device::from(hdr.dev));

        Ok(())
    }

    fn load_device(&self, lv: &LV) -> io::Result<()> {
        let sectors_per_extent = self.vg.extent_size;
        let mut targs = Vec::new();

        // Construct targets first, since we need to know how many & size
        // before initializing the header.
        for seg in &lv.segments {
            for &(ref pvname, ref loc) in &seg.stripes {
                let err = || Error::new(Other, "dm load_device error");
                let pv = try!(self.vg.pvs.get(pvname).ok_or(err()));

                let mut targ: dmi::Struct_dm_target_spec = Default::default();
                targ.sector_start = seg.start_extent * sectors_per_extent;
                targ.length = seg.extent_count * sectors_per_extent;
                targ.status = 0;

                let mut dst: &mut [u8] = unsafe {
                    mem::transmute(&mut targ.target_type[..])
                };
                copy_memory(seg.ty.as_bytes(), &mut dst);

                let mut params = Vec::new();
                // TODO: only works for linear
                params.extend(
                    format!("{}:{} {}",
                            pv.device.major,
                            pv.device.minor,
                            (loc * sectors_per_extent) + pv.pe_start).as_bytes());

                let pad_bytes = align_to(
                    params.len() + 1usize, 8usize) - params.len();
                params.extend(vec![0; pad_bytes]);

                targ.next = (mem::size_of::<dmi::Struct_dm_target_spec>()
                           + params.len()) as u32;

                targs.push((targ, params));
            }
        }

        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        Self::hdr_set_name(&mut hdr, lv.name.as_bytes());

        hdr.data_start = mem::size_of::<dmi::Struct_dm_ioctl>() as u32;
        hdr.data_size = hdr.data_start + targs.iter()
            .map(|&(t, _)| t.next)
            .sum::<u32>();
        hdr.target_count = targs.len() as u32;

        // Flatten into buf
        let mut buf: Vec<u8> = Vec::with_capacity(hdr.data_size as usize);
        unsafe {
            let ptr: *mut u8 = mem::transmute(&mut hdr);
            let slc = slice::from_raw_parts(ptr, hdr.data_start as usize);
            buf.extend(slc);
        }

        for (targ, param) in targs {
            unsafe {
                let ptr: *mut u8 = mem::transmute(&targ);
                let slc = slice::from_raw_parts(
                    ptr, mem::size_of::<dmi::Struct_dm_target_spec>());
                buf.extend(slc);
            }

            buf.extend(&param);
        }

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_TABLE_LOAD_CMD as u8, buf.len());

        match unsafe { ioctl::read_into_ptr(self.file.as_raw_fd(), op, buf.as_mut_ptr()) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => Ok(())
        }
    }

    fn resume_device(&self, lv: &LV) -> io::Result<()> {
        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        hdr.data_size = hdr.data_start;
        Self::hdr_set_name(&mut hdr, lv.name.as_bytes());

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_DEV_SUSPEND_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => Ok(())
        }
    }

    /// Activate a Logical Volume.
    ///
    /// Also populates the LV's device field.
    pub fn activate_device(&self, lv: &mut LV) -> io::Result<()> {

        // TODO: name/uuid mangle?

        try!(self.create_device(lv));

        try!(self.load_device(lv));

        self.resume_device(lv)
    }

    /// Remove a Logical Volume.
    // UNTESTED
    pub fn remove_device(&self, lv: LV) -> io::Result<()> {
        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        hdr.data_size = hdr.data_start;
        Self::hdr_set_name(&mut hdr, lv.name.as_bytes());

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_DEV_REMOVE_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => Ok(())
        }

    }
}

//
// Return up to the first \0, or None
//
fn slice_to_null(slc: &[u8]) -> Option<&[u8]> {
    for (i, c) in slc.iter().enumerate() {
        if *c == b'\0' { return Some(&slc[..i]) };
    }
    None
}
<commit_msg>Fix DM::hdr_set_name and hdr_set_name to have proper format<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

//! Communicating with the running kernel using devicemapper.

#[allow(dead_code, non_camel_case_types)]
mod dm_ioctl;

use std::fs::File;
use std::io;
use std::io::{BufReader, BufRead};
use std::os::unix::io::AsRawFd;
use std::mem;
use std::slice;
use std::slice::bytes::copy_memory;
use std::io::Error;
use std::io::ErrorKind::Other;
use std::collections::BTreeSet;

use byteorder::{LittleEndian, ByteOrder};

use nix::sys::ioctl;

use dm::dm_ioctl as dmi;
use lv::LV;
use vg::VG;
use util::align_to;
use pv::Device;

const DM_IOCTL: u8 = 0xfd;
const DM_CTL_PATH: &'static str= "/dev/mapper/control";

const DM_VERSION_MAJOR: u32 = 4;
const DM_VERSION_MINOR: u32 = 30;
const DM_VERSION_PATCHLEVEL: u32 = 0;

/// Context needed for communicating with devicemapper.
pub struct DM<'a> {
    file: File,
    vg: &'a VG,
}

impl <'a> DM<'a> {
    /// Create a new context for communicating about a given VG with DM.
    pub fn new(vg: &'a VG) -> io::Result<Self> {
        Ok(DM {
            file: try!(File::open(DM_CTL_PATH)),
            vg: vg,
        })
    }

    /// Determine if a major number is a major number used by DM.
    pub fn is_dm_major(major: u32) -> bool {
        let mut set = BTreeSet::new();

        let f = File::open("/proc/devices")
            .ok().expect("Could not open /proc/devices");

        let reader = BufReader::new(f);

        for line in reader.lines()
            .filter_map(|x| x.ok())
            .skip_while(|x| x != "Block devices:")
            .skip(1) {
                let spl: Vec<_> = line.split_whitespace().collect();

                if spl[1] == "device-mapper" {
                    set.insert(spl[0].parse::<u32>().unwrap());
                }
            }

        set.contains(&major)
    }

    fn initialize_hdr(hdr: &mut dmi::Struct_dm_ioctl) -> () {
        hdr.version[0] = DM_VERSION_MAJOR;
        hdr.version[1] = DM_VERSION_MINOR;
        hdr.version[2] = DM_VERSION_PATCHLEVEL;

        hdr.data_start = mem::size_of::<dmi::Struct_dm_ioctl>() as u32;
    }

    fn hdr_set_name(hdr: &mut dmi::Struct_dm_ioctl, vg_name: &str, lv_name: &str) -> () {
        let name = format!("{}-{}", vg_name.replace("-", "--"),
                           lv_name.replace("-", "--"));
        let name_dest: &mut [u8; 128] = unsafe { mem::transmute(&mut hdr.name) };
        copy_memory(name.as_bytes(), &mut name_dest[..]);
    }

    fn hdr_set_uuid(hdr: &mut dmi::Struct_dm_ioctl, vg_uuid: &str, lv_uuid: &str) -> () {
        let uuid = format!("LVM-{}{}", vg_uuid.replace("-", ""), lv_uuid.replace("-", ""));
        let uuid_dest: &mut [u8; 129] = unsafe { mem::transmute(&mut hdr.uuid) };
        copy_memory(uuid.as_bytes(), &mut uuid_dest[..]);
    }

    /// Devicemapper version information: Major, Minor, and patchlevel versions.
    pub fn get_version(&self) -> io::Result<(u32, u32, u32)> {

        let mut hdr: dmi::Struct_dm_ioctl = Default::default();
        hdr.version[0] = DM_VERSION_MAJOR;
        hdr.version[1] = DM_VERSION_MINOR;
        hdr.version[2] = DM_VERSION_PATCHLEVEL;

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_VERSION_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => {},
        };

        Ok((hdr.version[0], hdr.version[1], hdr.version[2]))
    }

    /// Returns a list of tuples containing DM device names and their major/minor
    /// device numbers.
    pub fn list_devices(&self) -> io::Result<Vec<(String, Device)>> {
        let mut buf = [0u8; 16 * 1024];
        let mut hdr: &mut dmi::Struct_dm_ioctl = unsafe {mem::transmute(&mut buf)};

        Self::initialize_hdr(&mut hdr);
        hdr.data_size = buf.len() as u32;

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_LIST_DEVICES_CMD as u8, buf.len());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut buf) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => {},
        };

        let mut devs = Vec::new();
        if (hdr.data_size - hdr.data_start as u32) != 0 {
            let mut result = &buf[hdr.data_start as usize..];

            loop {
                let slc = slice_to_null(&result[12..]).expect("Bad data from ioctl");
                let devno = LittleEndian::read_u64(&result[..8]);
                devs.push((String::from_utf8_lossy(slc).into_owned(), Device::from(devno)));

                let next = LittleEndian::read_u32(&result[8..12]);
                if next == 0 { break }

                result = &result[next as usize..];
            }
        }

        Ok(devs)
    }

    fn create_device(&self, lv: &mut LV) -> io::Result<()> {
        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        Self::hdr_set_name(&mut hdr, &self.vg.name, &lv.name);
        Self::hdr_set_uuid(&mut hdr, &self.vg.id, &lv.id);
        hdr.data_size = hdr.data_start;

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_DEV_CREATE_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => { }
        };

        lv.device = Some(Device::from(hdr.dev));

        Ok(())
    }

    fn load_device(&self, lv: &LV) -> io::Result<()> {
        let sectors_per_extent = self.vg.extent_size;
        let mut targs = Vec::new();

        // Construct targets first, since we need to know how many & size
        // before initializing the header.
        for seg in &lv.segments {
            for &(ref pvname, ref loc) in &seg.stripes {
                let err = || Error::new(Other, "dm load_device error");
                let pv = try!(self.vg.pvs.get(pvname).ok_or(err()));

                let mut targ: dmi::Struct_dm_target_spec = Default::default();
                targ.sector_start = seg.start_extent * sectors_per_extent;
                targ.length = seg.extent_count * sectors_per_extent;
                targ.status = 0;

                let mut dst: &mut [u8] = unsafe {
                    mem::transmute(&mut targ.target_type[..])
                };
                copy_memory(seg.ty.as_bytes(), &mut dst);

                let mut params = Vec::new();
                // TODO: only works for linear
                params.extend(
                    format!("{}:{} {}",
                            pv.device.major,
                            pv.device.minor,
                            (loc * sectors_per_extent) + pv.pe_start).as_bytes());

                let pad_bytes = align_to(
                    params.len() + 1usize, 8usize) - params.len();
                params.extend(vec![0; pad_bytes]);

                targ.next = (mem::size_of::<dmi::Struct_dm_target_spec>()
                           + params.len()) as u32;

                targs.push((targ, params));
            }
        }

        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        Self::hdr_set_name(&mut hdr, &self.vg.name, &lv.name);

        hdr.data_start = mem::size_of::<dmi::Struct_dm_ioctl>() as u32;
        hdr.data_size = hdr.data_start + targs.iter()
            .map(|&(t, _)| t.next)
            .sum::<u32>();
        hdr.target_count = targs.len() as u32;

        // Flatten into buf
        let mut buf: Vec<u8> = Vec::with_capacity(hdr.data_size as usize);
        unsafe {
            let ptr: *mut u8 = mem::transmute(&mut hdr);
            let slc = slice::from_raw_parts(ptr, hdr.data_start as usize);
            buf.extend(slc);
        }

        for (targ, param) in targs {
            unsafe {
                let ptr: *mut u8 = mem::transmute(&targ);
                let slc = slice::from_raw_parts(
                    ptr, mem::size_of::<dmi::Struct_dm_target_spec>());
                buf.extend(slc);
            }

            buf.extend(&param);
        }

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_TABLE_LOAD_CMD as u8, buf.len());

        match unsafe { ioctl::read_into_ptr(self.file.as_raw_fd(), op, buf.as_mut_ptr()) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => Ok(())
        }
    }

    fn suspend_device(&self, lv: &LV) -> io::Result<()> {
        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        hdr.data_size = hdr.data_start;
        Self::hdr_set_name(&mut hdr, &self.vg.name, &lv.name);
        hdr.flags = DM_SUSPEND_FLAG;

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_DEV_SUSPEND_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => Ok(())
        }
    }

    fn resume_device(&self, lv: &LV) -> io::Result<()> {
        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        hdr.data_size = hdr.data_start;
        Self::hdr_set_name(&mut hdr, &self.vg.name, &lv.name);
        // DM_SUSPEND_FLAG not set = resume

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_DEV_SUSPEND_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => Ok(())
        }
    }

    /// Activate a Logical Volume.
    ///
    /// Also populates the LV's device field.
    pub fn activate_device(&self, lv: &mut LV) -> io::Result<()> {

        // TODO: name/uuid mangle?

        try!(self.create_device(lv));

        try!(self.load_device(lv));

        self.resume_device(lv)
    }

    /// Remove a Logical Volume.
    // UNTESTED
    pub fn remove_device(&self, lv: LV) -> io::Result<()> {
        let mut hdr: dmi::Struct_dm_ioctl = Default::default();

        Self::initialize_hdr(&mut hdr);
        hdr.data_size = hdr.data_start;
        Self::hdr_set_name(&mut hdr, lv.name.as_bytes());

        let op = ioctl::op_read_write(DM_IOCTL, dmi::DM_DEV_REMOVE_CMD as u8,
                                      mem::size_of::<dmi::Struct_dm_ioctl>());

        match unsafe { ioctl::read_into(self.file.as_raw_fd(), op, &mut hdr) } {
            Err(_) => return Err((io::Error::last_os_error())),
            _ => Ok(())
        }

    }
}

//
// Return up to the first \0, or None
//
fn slice_to_null(slc: &[u8]) -> Option<&[u8]> {
    for (i, c) in slc.iter().enumerate() {
        if *c == b'\0' { return Some(&slc[..i]) };
    }
    None
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![feature(result_map_or)]
#![feature(rustc_private)]

// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_interface;

use rustc_interface::interface;
use rustc_tools_util::*;

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

mod lintlist;

/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a>(
    args: impl IntoIterator<Item = &'a String>,
    find_arg: &str,
    pred: impl Fn(&str) -> bool,
) -> Option<&'a str> {
    let mut args = args.into_iter().map(String::as_str);

    while let Some(arg) = args.next() {
        let arg: Vec<_> = arg.splitn(2, '=').collect();
        if arg.get(0) != Some(&find_arg) {
            continue;
        }

        let value = arg.get(1).cloned().or_else(|| args.next());
        if value.as_ref().map_or(false, |p| pred(p)) {
            return value;
        }
    }
    None
}

#[test]
fn test_arg_value() {
    let args: Vec<_> = ["--bar=bar", "--foobar", "123", "--foo"]
        .iter()
        .map(std::string::ToString::to_string)
        .collect();

    assert_eq!(arg_value(None, "--foobar", |_| true), None);
    assert_eq!(arg_value(&args, "--bar", |_| false), None);
    assert_eq!(arg_value(&args, "--bar", |_| true), Some("bar"));
    assert_eq!(arg_value(&args, "--bar", |p| p == "bar"), Some("bar"));
    assert_eq!(arg_value(&args, "--bar", |p| p == "foo"), None);
    assert_eq!(arg_value(&args, "--foobar", |p| p == "foo"), None);
    assert_eq!(arg_value(&args, "--foobar", |p| p == "123"), Some("123"));
    assert_eq!(arg_value(&args, "--foo", |_| true), None);
}

#[allow(clippy::too_many_lines)]

struct ClippyCallbacks;

impl rustc_driver::Callbacks for ClippyCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
        let previous = config.register_lints.take();
        config.register_lints = Some(Box::new(move |sess, mut lint_store| {
            // technically we're ~guaranteed that this is none but might as well call anything that
            // is there already. Certainly it can't hurt.
            if let Some(previous) = &previous {
                (previous)(sess, lint_store);
            }

            let conf = clippy_lints::read_conf(&[], &sess);
            clippy_lints::register_plugins(&mut lint_store, &sess, &conf);
            clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf);
            clippy_lints::register_renamed(&mut lint_store);
        }));

        // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
        // run on the unoptimized MIR. On the other hand this results in some false negatives. If
        // MIR passes can be enabled / disabled separately, we should figure out, what passes to
        // use for Clippy.
        config.opts.debugging_opts.mir_opt_level = 0;
    }
}

#[allow(clippy::find_map, clippy::filter_map)]
fn describe_lints() {
    use lintlist::*;
    use std::collections::HashSet;

    println!(
        "
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny <foo> and all attempts to override)

"
    );

    let lint_level = |lint: &Lint| {
        LINT_LEVELS
            .iter()
            .find(|level_mapping| level_mapping.0 == lint.group)
            .map(|(_, level)| match level {
                Level::Allow => "allow",
                Level::Warn => "warn",
                Level::Deny => "deny",
            })
            .unwrap()
    };

    let mut lints: Vec<_> = ALL_LINTS.iter().collect();
    // The sort doesn't case-fold but it's doubtful we care.
    lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name));

    let max_lint_name_len = lints
        .iter()
        .map(|lint| lint.name.len())
        .map(|len| len + "clippy::".len())
        .max()
        .unwrap_or(0);

    let padded = |x: &str| {
        let mut s = " ".repeat(max_lint_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    let scoped = |x: &str| format!("clippy::{}", x);

    let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();

    println!("Lint checks provided by clippy:\n");
    println!("    {}  {:7.7}  meaning", padded("name"), "default");
    println!("    {}  {:7.7}  -------", padded("----"), "-------");

    let print_lints = |lints: &[&Lint]| {
        for lint in lints {
            let name = lint.name.replace("_", "-");
            println!(
                "    {}  {:7.7}  {}",
                padded(&scoped(&name)),
                lint_level(lint),
                lint.desc
            );
        }
        println!("\n");
    };

    print_lints(&lints);

    let max_group_name_len = std::cmp::max(
        "clippy::all".len(),
        lint_groups
            .iter()
            .map(|group| group.len())
            .map(|len| len + "clippy::".len())
            .max()
            .unwrap_or(0),
    );

    let padded_group = |x: &str| {
        let mut s = " ".repeat(max_group_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    println!("Lint groups provided by clippy:\n");
    println!("    {}  sub-lints", padded_group("name"));
    println!("    {}  ---------", padded_group("----"));
    println!("    {}  the set of all clippy lints", padded_group("clippy::all"));

    let print_lint_groups = || {
        for group in lint_groups {
            let name = group.to_lowercase().replace("_", "-");
            let desc = lints
                .iter()
                .filter(|&lint| lint.group == group)
                .map(|lint| lint.name)
                .map(|name| name.replace("_", "-"))
                .collect::<Vec<String>>()
                .join(", ");
            println!("    {}  {}", padded_group(&scoped(&name)), desc);
        }
        println!("\n");
    };

    print_lint_groups();
}

fn display_help() {
    println!(
        "\
Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

You can use tool lints to allow or deny lints from your code, eg.:

    #[allow(clippy::needless_lifetimes)]
"
    );
}

pub fn main() {
    rustc_driver::init_rustc_env_logger();
    rustc_driver::install_ice_hook();
    exit(
        rustc_driver::catch_fatal_errors(move || {
            use std::env;

            if std::env::args().any(|a| a == "--version" || a == "-V") {
                let version_info = rustc_tools_util::get_version_info!();
                println!("{}", version_info);
                exit(0);
            }

            let mut orig_args: Vec<String> = env::args().collect();

            // Get the sysroot, looking from most specific to this invocation to the least:
            // - command line
            // - runtime environment
            //    - SYSROOT
            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
            // - sysroot from rustc in the path
            // - compile-time environment
            let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
            let have_sys_root_arg = sys_root_arg.is_some();
            let sys_root = sys_root_arg
                .map(PathBuf::from)
                .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
                .or_else(|| {
                    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
                    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
                    home.and_then(|home| {
                        toolchain.map(|toolchain| {
                            let mut path = PathBuf::from(home);
                            path.push("toolchains");
                            path.push(toolchain);
                            path
                        })
                    })
                })
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| PathBuf::from(s.trim()))
                })
                .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
                .map(|pb| pb.to_string_lossy().to_string())
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");

            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
            // We're invoking the compiler programmatically, so we ignore this/
            let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());

            if wrapper_mode {
                // we still want to be able to invoke it normally though
                orig_args.remove(1);
            }

            if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
                display_help();
                exit(0);
            }

            let should_describe_lints = || {
                let args: Vec<_> = std::env::args().collect();
                args.windows(2).any(|args| {
                    args[1] == "help"
                        && match args[0].as_str() {
                            "-W" | "-A" | "-D" | "-F" => true,
                            _ => false,
                        }
                })
            };

            if !wrapper_mode && should_describe_lints() {
                describe_lints();
                exit(0);
            }

            // this conditional check for the --sysroot flag is there so users can call
            // `clippy_driver` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if have_sys_root_arg {
                orig_args.clone()
            } else {
                orig_args
                    .clone()
                    .into_iter()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is
            // linted but not built
            let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true")
                || arg_value(&orig_args, "--emit", |val| val.split(',').any(|e| e == "metadata")).is_some();

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
                        if s.is_empty() {
                            None
                        } else {
                            Some(s.to_string())
                        }
                    }));
                }
            }

            let mut clippy = ClippyCallbacks;
            let mut default = rustc_driver::DefaultCallbacks;
            let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
                if clippy_enabled { &mut clippy } else { &mut default };
            let args = args;
            rustc_driver::run_compiler(&args, callbacks, None, None)
        })
        .and_then(|result| result)
        .is_err() as i32,
    )
}
<commit_msg>Auto merge of #4845 - flip1995:clippy_toml_deps, r=phansch<commit_after>#![cfg_attr(feature = "deny-warnings", deny(warnings))]
#![feature(result_map_or)]
#![feature(rustc_private)]

// FIXME: switch to something more ergonomic here, once available.
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
#[allow(unused_extern_crates)]
extern crate rustc_driver;
#[allow(unused_extern_crates)]
extern crate rustc_interface;

use rustc_interface::interface;
use rustc_tools_util::*;

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

mod lintlist;

/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a>(
    args: impl IntoIterator<Item = &'a String>,
    find_arg: &str,
    pred: impl Fn(&str) -> bool,
) -> Option<&'a str> {
    let mut args = args.into_iter().map(String::as_str);

    while let Some(arg) = args.next() {
        let arg: Vec<_> = arg.splitn(2, '=').collect();
        if arg.get(0) != Some(&find_arg) {
            continue;
        }

        let value = arg.get(1).cloned().or_else(|| args.next());
        if value.as_ref().map_or(false, |p| pred(p)) {
            return value;
        }
    }
    None
}

#[test]
fn test_arg_value() {
    let args: Vec<_> = ["--bar=bar", "--foobar", "123", "--foo"]
        .iter()
        .map(std::string::ToString::to_string)
        .collect();

    assert_eq!(arg_value(None, "--foobar", |_| true), None);
    assert_eq!(arg_value(&args, "--bar", |_| false), None);
    assert_eq!(arg_value(&args, "--bar", |_| true), Some("bar"));
    assert_eq!(arg_value(&args, "--bar", |p| p == "bar"), Some("bar"));
    assert_eq!(arg_value(&args, "--bar", |p| p == "foo"), None);
    assert_eq!(arg_value(&args, "--foobar", |p| p == "foo"), None);
    assert_eq!(arg_value(&args, "--foobar", |p| p == "123"), Some("123"));
    assert_eq!(arg_value(&args, "--foo", |_| true), None);
}

#[allow(clippy::too_many_lines)]

struct ClippyCallbacks;

impl rustc_driver::Callbacks for ClippyCallbacks {
    fn config(&mut self, config: &mut interface::Config) {
        let previous = config.register_lints.take();
        config.register_lints = Some(Box::new(move |sess, mut lint_store| {
            // technically we're ~guaranteed that this is none but might as well call anything that
            // is there already. Certainly it can't hurt.
            if let Some(previous) = &previous {
                (previous)(sess, lint_store);
            }

            let conf = clippy_lints::read_conf(&[], &sess);
            clippy_lints::register_plugins(&mut lint_store, &sess, &conf);
            clippy_lints::register_pre_expansion_lints(&mut lint_store, &conf);
            clippy_lints::register_renamed(&mut lint_store);
        }));

        // FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
        // run on the unoptimized MIR. On the other hand this results in some false negatives. If
        // MIR passes can be enabled / disabled separately, we should figure out, what passes to
        // use for Clippy.
        config.opts.debugging_opts.mir_opt_level = 0;
    }
}

#[allow(clippy::find_map, clippy::filter_map)]
fn describe_lints() {
    use lintlist::*;
    use std::collections::HashSet;

    println!(
        "
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny <foo> and all attempts to override)

"
    );

    let lint_level = |lint: &Lint| {
        LINT_LEVELS
            .iter()
            .find(|level_mapping| level_mapping.0 == lint.group)
            .map(|(_, level)| match level {
                Level::Allow => "allow",
                Level::Warn => "warn",
                Level::Deny => "deny",
            })
            .unwrap()
    };

    let mut lints: Vec<_> = ALL_LINTS.iter().collect();
    // The sort doesn't case-fold but it's doubtful we care.
    lints.sort_by_cached_key(|x: &&Lint| (lint_level(x), x.name));

    let max_lint_name_len = lints
        .iter()
        .map(|lint| lint.name.len())
        .map(|len| len + "clippy::".len())
        .max()
        .unwrap_or(0);

    let padded = |x: &str| {
        let mut s = " ".repeat(max_lint_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    let scoped = |x: &str| format!("clippy::{}", x);

    let lint_groups: HashSet<_> = lints.iter().map(|lint| lint.group).collect();

    println!("Lint checks provided by clippy:\n");
    println!("    {}  {:7.7}  meaning", padded("name"), "default");
    println!("    {}  {:7.7}  -------", padded("----"), "-------");

    let print_lints = |lints: &[&Lint]| {
        for lint in lints {
            let name = lint.name.replace("_", "-");
            println!(
                "    {}  {:7.7}  {}",
                padded(&scoped(&name)),
                lint_level(lint),
                lint.desc
            );
        }
        println!("\n");
    };

    print_lints(&lints);

    let max_group_name_len = std::cmp::max(
        "clippy::all".len(),
        lint_groups
            .iter()
            .map(|group| group.len())
            .map(|len| len + "clippy::".len())
            .max()
            .unwrap_or(0),
    );

    let padded_group = |x: &str| {
        let mut s = " ".repeat(max_group_name_len - x.chars().count());
        s.push_str(x);
        s
    };

    println!("Lint groups provided by clippy:\n");
    println!("    {}  sub-lints", padded_group("name"));
    println!("    {}  ---------", padded_group("----"));
    println!("    {}  the set of all clippy lints", padded_group("clippy::all"));

    let print_lint_groups = || {
        for group in lint_groups {
            let name = group.to_lowercase().replace("_", "-");
            let desc = lints
                .iter()
                .filter(|&lint| lint.group == group)
                .map(|lint| lint.name)
                .map(|name| name.replace("_", "-"))
                .collect::<Vec<String>>()
                .join(", ");
            println!("    {}  {}", padded_group(&scoped(&name)), desc);
        }
        println!("\n");
    };

    print_lint_groups();
}

fn display_help() {
    println!(
        "\
Checks a package to catch common mistakes and improve your Rust code.

Usage:
    cargo clippy [options] [--] [<opts>...]

Common options:
    -h, --help               Print this message
    -V, --version            Print version info and exit

Other options are the same as `cargo check`.

To allow or deny a lint from the command line you can use `cargo clippy --`
with:

    -W --warn OPT       Set lint warnings
    -A --allow OPT      Set lint allowed
    -D --deny OPT       Set lint denied
    -F --forbid OPT     Set lint forbidden

You can use tool lints to allow or deny lints from your code, eg.:

    #[allow(clippy::needless_lifetimes)]
"
    );
}

pub fn main() {
    rustc_driver::init_rustc_env_logger();
    rustc_driver::install_ice_hook();
    exit(
        rustc_driver::catch_fatal_errors(move || {
            use std::env;

            if std::env::args().any(|a| a == "--version" || a == "-V") {
                let version_info = rustc_tools_util::get_version_info!();
                println!("{}", version_info);
                exit(0);
            }

            let mut orig_args: Vec<String> = env::args().collect();

            // Get the sysroot, looking from most specific to this invocation to the least:
            // - command line
            // - runtime environment
            //    - SYSROOT
            //    - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
            // - sysroot from rustc in the path
            // - compile-time environment
            let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
            let have_sys_root_arg = sys_root_arg.is_some();
            let sys_root = sys_root_arg
                .map(PathBuf::from)
                .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
                .or_else(|| {
                    let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
                    let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
                    home.and_then(|home| {
                        toolchain.map(|toolchain| {
                            let mut path = PathBuf::from(home);
                            path.push("toolchains");
                            path.push(toolchain);
                            path
                        })
                    })
                })
                .or_else(|| {
                    Command::new("rustc")
                        .arg("--print")
                        .arg("sysroot")
                        .output()
                        .ok()
                        .and_then(|out| String::from_utf8(out.stdout).ok())
                        .map(|s| PathBuf::from(s.trim()))
                })
                .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
                .map(|pb| pb.to_string_lossy().to_string())
                .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");

            // Setting RUSTC_WRAPPER causes Cargo to pass 'rustc' as the first argument.
            // We're invoking the compiler programmatically, so we ignore this/
            let wrapper_mode = orig_args.get(1).map(Path::new).and_then(Path::file_stem) == Some("rustc".as_ref());

            if wrapper_mode {
                // we still want to be able to invoke it normally though
                orig_args.remove(1);
            }

            if !wrapper_mode && (orig_args.iter().any(|a| a == "--help" || a == "-h") || orig_args.len() == 1) {
                display_help();
                exit(0);
            }

            let should_describe_lints = || {
                let args: Vec<_> = std::env::args().collect();
                args.windows(2).any(|args| {
                    args[1] == "help"
                        && match args[0].as_str() {
                            "-W" | "-A" | "-D" | "-F" => true,
                            _ => false,
                        }
                })
            };

            if !wrapper_mode && should_describe_lints() {
                describe_lints();
                exit(0);
            }

            // this conditional check for the --sysroot flag is there so users can call
            // `clippy_driver` directly
            // without having to pass --sysroot or anything
            let mut args: Vec<String> = if have_sys_root_arg {
                orig_args.clone()
            } else {
                orig_args
                    .clone()
                    .into_iter()
                    .chain(Some("--sysroot".to_owned()))
                    .chain(Some(sys_root))
                    .collect()
            };

            // this check ensures that dependencies are built but not linted and the final
            // crate is linted but not built
            let clippy_enabled = env::var("CLIPPY_TESTS").map_or(false, |val| val == "true")
                || arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_none();

            if clippy_enabled {
                args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-clippy""#.to_owned()]);
                if let Ok(extra_args) = env::var("CLIPPY_ARGS") {
                    args.extend(extra_args.split("__CLIPPY_HACKERY__").filter_map(|s| {
                        if s.is_empty() {
                            None
                        } else {
                            Some(s.to_string())
                        }
                    }));
                }
            }

            let mut clippy = ClippyCallbacks;
            let mut default = rustc_driver::DefaultCallbacks;
            let callbacks: &mut (dyn rustc_driver::Callbacks + Send) =
                if clippy_enabled { &mut clippy } else { &mut default };
            let args = args;
            rustc_driver::run_compiler(&args, callbacks, None, None)
        })
        .and_then(|result| result)
        .is_err() as i32,
    )
}
<|endoftext|>


<commit_before> #![allow(dead_code)]

/// Calculates the total energy and virial of a system containing num_particles with coords rx,ry,rz
/// of size l_x, l_y, l_z and given cutoff + corrections
pub fn get_total_energy(rx: &[f64], ry: &[f64], rz: &[f64], num_particles: usize, l_x: f64, l_y: f64, l_z: f64, cutoff_squared: f64, e_corr: f64, e_shift: f64) -> (f64, f64) {
    let mut energy = 0.0;
    let mut virial = 0.0;
    let hl_x = l_x / 2.0;
    let hl_y = l_y / 2.0;
    let hl_z = l_z / 2.0;
    for i in 0..num_particles {
        for j in i+1..num_particles {
            let dist_squared = get_particle_distance_squared(rx[i], ry[i],rz[i],rx[j],ry[j],rz[j], l_x, l_y, l_z, hl_x, hl_y, hl_z);
            if dist_squared < cutoff_squared {
                let (e,v) = eval_pair_energy(dist_squared, e_shift);
                energy += e;
                virial += v;
            }
        }
    }
    energy += num_particles as f64 * e_corr;
    return (energy, virial);
}

/// Calculates the particle energy and virial for particle at p_index in system containing num_particles with coords rx,ry,rz
/// of size l_x, l_y, l_z and given cutoff + corrections
pub fn get_particle_energy(rx: &[f64], ry: &[f64], rz: &[f64], p_index: usize, num_particles: usize, l_x: f64, l_y: f64, l_z: f64, cutoff_squared: f64, e_shift: f64) -> (f64, f64) {
    let mut energy = 0.0;
    let mut virial = 0.0;
    let hl_x = l_x / 2.0;
    let hl_y = l_y / 2.0;
    let hl_z = l_z / 2.0;
    for i in 0..num_particles {
        if i == p_index { continue; }

        let dist_squared = get_particle_distance_squared(rx[i], ry[i], rz[i], rx[p_index], ry[p_index], rz[p_index], l_x, l_y, l_z, hl_x, hl_y, hl_z);
        if dist_squared < cutoff_squared {
            let (e,v) = eval_pair_energy(dist_squared, e_shift);
            energy += e;
            virial += v;
        }
    }
    return (energy, virial);
}

// squared distance between 2 particles regarding the minimum image convention
pub fn get_particle_distance_squared(x1: f64,y1: f64,z1: f64,x2: f64,y2: f64,z2: f64, l_x: f64, l_y: f64, l_z: f64, hl_x: f64, hl_y: f64, hl_z: f64) -> f64 {
    let mut dx = (x1 - x2).abs();
    let mut dy = (y1 - y2).abs();
    let mut dz = (z1 - z2).abs();

    if dx > hl_x { dx -= l_x }
        else if dx < -hl_x { dx += l_x }
    if dy > hl_y { dy -= l_y}
        else if dy < -hl_y{ dy += l_y }
    if dz > hl_z { dz -= l_y }
        else if dz < -hl_z { dz += l_z}
    return dx*dx + dy*dy + dz*dz;
}

// one dimensional distance with applied minimum image convention
pub fn get_distance_with_pbc(x1: f64, x2: f64, length: f64, half_length: f64) -> f64 {
    let mut d = (x1-x2).abs();
    if d > half_length { d -= length }
    else if d < -half_length { d += length }
    return d;
}

#[test]
fn test_get_particle_distance_squared() {
    let (x1, y1, z1) = (0.0, 0.0, 0.0);
    let (x2, y2, z2) = (5.0, 0.0, 0.0);

    // no pbc
    assert!( (get_particle_distance_squared(x1,y1,z1,x2,y2,z2, 20.0, 20.0, 20.0, 10.0, 10.0, 10.0) - 25.0) < 0.00001);

    // with pbc
    assert!( (get_particle_distance_squared(x1,y1,z1,x2,y2,z2, 9.0,9.0,9.0, 4.5,4.5,4.5) - 16.0) < 0.00001, "{}", get_particle_distance_squared(x1,y1,z1,x2,y2,z2, 9.0,9.0,9.0, 4.5,4.5,4.5));

    // PBC edge case
    let (x3, y3, z3) = ( 0.948369102634727,1.4018028642626956,2.6884871697542323);
    let (x4, y4, z4) = ( 0.4924652252404308,0.27903672240586597,1.258265555104697);
    let a = get_particle_distance_squared(x3,y3,z3,x4,y4,z4, 1.418983411970384,1.418983411970384,2.83796682394076,0.709491705985192,0.709491705985192,1.418983411970384);
    let b = get_particle_distance_squared(x4,y4,z4,x3,y3,z3, 1.418983411970384,1.418983411970384,2.83796682394076,0.709491705985192,0.709491705985192,1.418983411970384);
    assert!( (a-b).abs() < 0.0000000001);

    let (x1, y1, z1) = (1.0, 1.0, 1.0);
    let (x2, y2, z2) = (99.0, 99.0, 99.0);
    let dist = get_particle_distance_squared(x1,y1,z1,x2,y2,z2, 100.0, 100.0, 100.0, 50.0, 50.0, 50.0);
    assert!(dist - 12.0 < 0.00001);
}

/// calculate the lj energy and virial between two particles from given square distance
pub fn eval_pair_energy(dist_squared: f64, e_shift: f64) -> (f64, f64) {
    let r6 = ::LJ_SIG/(dist_squared * dist_squared * dist_squared);
    let r62 = r6*r6;
    let energy = 4.0 * ::LJ_EPS * (r62 - r6) - e_shift;
    let virial = 48.0 * ::LJ_EPS * ( r62 - 0.5 * r6 );
    return (energy, virial);
}

#[test]
fn test_eval_pair_energy() {
    let (e,v) = eval_pair_energy(1.0, 0.0);
    assert!( (e - 0.0).abs() < 0.00001, "{}",  e);

    let (e,v) = eval_pair_energy(2.0, 0.0);
    assert!( (e - -0.4375).abs() < 0.00001, "{}",  e);

    let (e,v) = eval_pair_energy(0.5, 0.0);
    assert!( (e - 224.0).abs() < 0.00001, "{}",  e);
}

/// calculate the virial between two particles from given square distance. If energy is required too,
/// see eval_pair_energy which does energy and virial
pub fn eval_virial(distance: f64, lj_eps: f64, lj_sig: f64) -> f64 {
    let r7 = (lj_sig/distance).powi(7);
    let r13 = (lj_sig/distance).powi(13);
    return 24.0 * lj_eps / lj_sig * ( r7-2.0*r13 );
}

#[test]
fn test_eval_virial() {
    let dist = 1.5;
    let result = eval_virial(dist, 1.0, 1.0, 0.0);
    let expected = 1.1580288;
    assert!( (result - expected).abs() < 0.0001, "{}", result );
}
<commit_msg>fixed virial test<commit_after> #![allow(dead_code)]

/// Calculates the total energy and virial of a system containing num_particles with coords rx,ry,rz
/// of size l_x, l_y, l_z and given cutoff + corrections
pub fn get_total_energy(rx: &[f64], ry: &[f64], rz: &[f64], num_particles: usize, l_x: f64, l_y: f64, l_z: f64, cutoff_squared: f64, e_corr: f64, e_shift: f64) -> (f64, f64) {
    let mut energy = 0.0;
    let mut virial = 0.0;
    let hl_x = l_x / 2.0;
    let hl_y = l_y / 2.0;
    let hl_z = l_z / 2.0;
    for i in 0..num_particles {
        for j in i+1..num_particles {
            let dist_squared = get_particle_distance_squared(rx[i], ry[i],rz[i],rx[j],ry[j],rz[j], l_x, l_y, l_z, hl_x, hl_y, hl_z);
            if dist_squared < cutoff_squared {
                let (e,v) = eval_pair_energy(dist_squared, e_shift);
                energy += e;
                virial += v;
            }
        }
    }
    energy += num_particles as f64 * e_corr;
    return (energy, virial);
}

/// Calculates the particle energy and virial for particle at p_index in system containing num_particles with coords rx,ry,rz
/// of size l_x, l_y, l_z and given cutoff + corrections
pub fn get_particle_energy(rx: &[f64], ry: &[f64], rz: &[f64], p_index: usize, num_particles: usize, l_x: f64, l_y: f64, l_z: f64, cutoff_squared: f64, e_shift: f64) -> (f64, f64) {
    let mut energy = 0.0;
    let mut virial = 0.0;
    let hl_x = l_x / 2.0;
    let hl_y = l_y / 2.0;
    let hl_z = l_z / 2.0;
    for i in 0..num_particles {
        if i == p_index { continue; }

        let dist_squared = get_particle_distance_squared(rx[i], ry[i], rz[i], rx[p_index], ry[p_index], rz[p_index], l_x, l_y, l_z, hl_x, hl_y, hl_z);
        if dist_squared < cutoff_squared {
            let (e,v) = eval_pair_energy(dist_squared, e_shift);
            energy += e;
            virial += v;
        }
    }
    return (energy, virial);
}

// squared distance between 2 particles regarding the minimum image convention
pub fn get_particle_distance_squared(x1: f64,y1: f64,z1: f64,x2: f64,y2: f64,z2: f64, l_x: f64, l_y: f64, l_z: f64, hl_x: f64, hl_y: f64, hl_z: f64) -> f64 {
    let mut dx = (x1 - x2).abs();
    let mut dy = (y1 - y2).abs();
    let mut dz = (z1 - z2).abs();

    if dx > hl_x { dx -= l_x }
        else if dx < -hl_x { dx += l_x }
    if dy > hl_y { dy -= l_y}
        else if dy < -hl_y{ dy += l_y }
    if dz > hl_z { dz -= l_y }
        else if dz < -hl_z { dz += l_z}
    return dx*dx + dy*dy + dz*dz;
}

// one dimensional distance with applied minimum image convention
pub fn get_distance_with_pbc(x1: f64, x2: f64, length: f64, half_length: f64) -> f64 {
    let mut d = (x1-x2).abs();
    if d > half_length { d -= length }
    else if d < -half_length { d += length }
    return d;
}

#[test]
fn test_get_particle_distance_squared() {
    let (x1, y1, z1) = (0.0, 0.0, 0.0);
    let (x2, y2, z2) = (5.0, 0.0, 0.0);

    // no pbc
    assert!( (get_particle_distance_squared(x1,y1,z1,x2,y2,z2, 20.0, 20.0, 20.0, 10.0, 10.0, 10.0) - 25.0) < 0.00001);

    // with pbc
    assert!( (get_particle_distance_squared(x1,y1,z1,x2,y2,z2, 9.0,9.0,9.0, 4.5,4.5,4.5) - 16.0) < 0.00001, "{}", get_particle_distance_squared(x1,y1,z1,x2,y2,z2, 9.0,9.0,9.0, 4.5,4.5,4.5));

    // PBC edge case
    let (x3, y3, z3) = ( 0.948369102634727,1.4018028642626956,2.6884871697542323);
    let (x4, y4, z4) = ( 0.4924652252404308,0.27903672240586597,1.258265555104697);
    let a = get_particle_distance_squared(x3,y3,z3,x4,y4,z4, 1.418983411970384,1.418983411970384,2.83796682394076,0.709491705985192,0.709491705985192,1.418983411970384);
    let b = get_particle_distance_squared(x4,y4,z4,x3,y3,z3, 1.418983411970384,1.418983411970384,2.83796682394076,0.709491705985192,0.709491705985192,1.418983411970384);
    assert!( (a-b).abs() < 0.0000000001);

    let (x1, y1, z1) = (1.0, 1.0, 1.0);
    let (x2, y2, z2) = (99.0, 99.0, 99.0);
    let dist = get_particle_distance_squared(x1,y1,z1,x2,y2,z2, 100.0, 100.0, 100.0, 50.0, 50.0, 50.0);
    assert!(dist - 12.0 < 0.00001);
}

/// calculate the lj energy and virial between two particles from given square distance
pub fn eval_pair_energy(dist_squared: f64, e_shift: f64) -> (f64, f64) {
    let r6 = ::LJ_SIG/(dist_squared * dist_squared * dist_squared);
    let r62 = r6*r6;
    let energy = 4.0 * ::LJ_EPS * (r62 - r6) - e_shift;
    let virial = 48.0 * ::LJ_EPS * ( r62 - 0.5 * r6 );
    return (energy, virial);
}

#[test]
fn test_eval_pair_energy() {
    let e = eval_pair_energy(1.0, 0.0).0;
    assert!( (e - 0.0).abs() < 0.00001, "{}",  e);

    let e = eval_pair_energy(2.0, 0.0).0;
    assert!( (e - -0.4375).abs() < 0.00001, "{}",  e);

    let e = eval_pair_energy(0.5, 0.0).0;
    assert!( (e - 224.0).abs() < 0.00001, "{}",  e);
}

/// calculate the virial between two particles from given square distance. If energy is required too,
/// see eval_pair_energy which does energy and virial
pub fn eval_virial(distance: f64, lj_eps: f64, lj_sig: f64) -> f64 {
    let r7 = (lj_sig/distance).powi(7);
    let r13 = (lj_sig/distance).powi(13);
    return 24.0 * lj_eps / lj_sig * ( r7-2.0*r13 );
}

#[test]
fn test_eval_virial() {
    let dist = 1.5;
    let result = eval_virial(dist, 1.0, 1.0);
    let expected = 1.1580288;
    assert!( (result - expected).abs() < 0.0001, "{}", result );
}
<|endoftext|>


<commit_before>use std::{io, error, fmt};

use log;

/// Convenience error which combines possible which could occur while initializing logging.
///
/// Fern does not use this error natively, but functions which set up fern and open log files will
/// often need to return both io::Error and SetLoggerError. This error is for that purpose.
#[derive(Debug)]
pub enum InitError {
    /// IO error.
    Io(io::Error),
    /// The log crate's global logger was already initialized when trying to initialize a logger.
    SetLoggerError(log::SetLoggerError),
}

impl From<io::Error> for InitError {
    fn from(error: io::Error) -> InitError {
        InitError::Io(error)
    }
}

impl From<log::SetLoggerError> for InitError {
    fn from(error: log::SetLoggerError) -> InitError {
        InitError::SetLoggerError(error)
    }
}

impl fmt::Display for InitError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            InitError::Io(ref e) => write!(f, "IO Error initializing logger: {}", e),
            InitError::SetLoggerError(ref e) => write!(f, "logging initialization failed: {}", e),
        }
    }
}

impl error::Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::Io(..) => "IO error while initializing logging",
            InitError::SetLoggerError(..) => "logging system already initialized with different logger",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            InitError::Io(ref e) => Some(e),
            InitError::SetLoggerError(ref e) => Some(e),
        }
    }
}
<commit_msg>Add hyperlinks to InitError documentation.<commit_after>use std::{io, error, fmt};

use log;

/// Convenience error which combines possible which could occur while initializing logging.
///
/// Fern does not use this error natively, but functions which set up fern and open log files will
/// often need to return both [`io::Error`] and [`SetLoggerError`]. This error is for that purpose.
///
/// [`io::Error`]: https://doc.rust-lang.org/std/io/struct.Error.html
/// [`SetLoggerError`]: ../log/struct.SetLoggerError.html
#[derive(Debug)]
pub enum InitError {
    /// IO error.
    Io(io::Error),
    /// The log crate's global logger was already initialized when trying to initialize a logger.
    SetLoggerError(log::SetLoggerError),
}

impl From<io::Error> for InitError {
    fn from(error: io::Error) -> InitError {
        InitError::Io(error)
    }
}

impl From<log::SetLoggerError> for InitError {
    fn from(error: log::SetLoggerError) -> InitError {
        InitError::SetLoggerError(error)
    }
}

impl fmt::Display for InitError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            InitError::Io(ref e) => write!(f, "IO Error initializing logger: {}", e),
            InitError::SetLoggerError(ref e) => write!(f, "logging initialization failed: {}", e),
        }
    }
}

impl error::Error for InitError {
    fn description(&self) -> &str {
        match *self {
            InitError::Io(..) => "IO error while initializing logging",
            InitError::SetLoggerError(..) => "logging system already initialized with different logger",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            InitError::Io(ref e) => Some(e),
            InitError::SetLoggerError(ref e) => Some(e),
        }
    }
}
<|endoftext|>


<commit_before>use conversion::Conversion;
use std::process::Command;
use std::process::Stdio;
use std::ffi::OsStr;
use std::io::Read;

pub fn ffmpeg(con: &Conversion) {
    let mut c = Command::new("ffmpeg");
    c.args(&[
        OsStr::new("-i"),       OsStr::new(&con.source.path),
        OsStr::new("-f"),       OsStr::new("matroska"),
        OsStr::new("-c:v"),     OsStr::new("libx264"),
        OsStr::new("-level"),   OsStr::new("4.1"),
        OsStr::new("-preset"),  OsStr::new("placebo"),
        OsStr::new("-crf"),     OsStr::new("18"),
        OsStr::new("-c:a"),     OsStr::new("opus"),
        OsStr::new("-b:a"),     OsStr::new("192k"),
        OsStr::new("-y"),
        OsStr::new("/dev/null") // c.target.path
    ]);
    c.stderr(Stdio::piped());
    c.stdout(Stdio::null());
    c.stdin(Stdio::null());

    let mut child = c.spawn().unwrap();
    let mut s = String::new();

    child.wait();
    child.stderr.unwrap().read_to_string(&mut s);

    println!("{}", s);

    // let result = c.output().unwrap();
    // let stdout = String::from_utf8(result.stdout).unwrap();
    // let stderr = String::from_utf8(result.stderr).unwrap();
    // let status = result.status.code().unwrap();

    // println!("{}", stderr);
}

<commit_msg>Added some threads for good measure<commit_after>use conversion::Conversion;
use std::process::Command;
use std::process::Stdio;
use std::ffi::OsStr;
use std::io::Read;
use std::thread;

pub fn ffmpeg(con: &Conversion) {
    let mut c = Command::new("ffmpeg");
    c.args(&[
        OsStr::new("-i"),       OsStr::new(&con.source.path),
        OsStr::new("-f"),       OsStr::new("matroska"),
        OsStr::new("-c:v"),     OsStr::new("libx264"),
        OsStr::new("-level"),   OsStr::new("4.1"),
        OsStr::new("-preset"),  OsStr::new("medium"),
        OsStr::new("-crf"),     OsStr::new("18"),
        OsStr::new("-c:a"),     OsStr::new("opus"),
        OsStr::new("-b:a"),     OsStr::new("192k"),
        OsStr::new("-y"),
        OsStr::new("/dev/null") // c.target.path
    ]);
    c.stderr(Stdio::piped());
    c.stdout(Stdio::null());
    c.stdin(Stdio::null());

    let mut child = c.spawn().unwrap();
    if let Some(mut stderr) = child.stderr {
        child.stderr = Some(thread::spawn(move || {
            let mut s = String::new();
            let _bytes = stderr.read_to_string(&mut s);
            println!("{}", s);
            stderr
        }).join().unwrap());
    };

    let _status = child.wait();
}
<|endoftext|>


<commit_before>extern crate num_cpus;

use std;
use std::thread;
use std::sync::mpsc;

pub fn prime_filter(iter_size: usize) -> Vec<bool>{
    if iter_size<100{
        slow_prime_filter(iter_size)
    }else{
        prime_filter_section(0, iter_size)
    }
}

fn case_1(y_sq: usize, iter_size: usize)
    -> Vec<usize> {
    //n_1 = 4x^2 + y^2 === 1 (mod 4)
    let (mut n_1, mut to_next_n_1) = (y_sq, 4);    let mut ret_stack: Vec<usize> = Vec::new();
    loop{
        n_1 += to_next_n_1;
        to_next_n_1 += 8;
        match n_1%60{
            _ if n_1 >= iter_size => break,
            1 | 13 | 17 | 29 | 37 | 41 | 49 | 53 => (),
            _ => continue,
        };

        // println!("1: {}", n_1);
        ret_stack.push(n_1);
    };
    ret_stack
}
fn case_2(y_sq: usize, iter_size: usize)
    -> Vec<usize> {
    //n_2 = 3x^2 + y^2 === 1 (mod 6)
    let (mut n_2, mut to_next_n_2) = (y_sq, 3);
    let mut ret_stack: Vec<usize> = Vec::new();
    loop {
        n_2 += to_next_n_2;
        to_next_n_2 += 6;
        match n_2%60{
            _ if n_2 >= iter_size => break,
            7 | 19 | 31 | 43 => (),
            _ => continue,
        };
        // println!("2: {}", n_2);
        ret_stack.push(n_2);
    };
    ret_stack
}
fn case_3(y_sq: usize, to_next_y_sq: usize, iter_size: usize)
    -> Vec<usize> {
    //n_3 = 3x^2 - y^2 === 11 (mod 12)
    let (mut n_3, mut to_next_n_3) = (2*y_sq, 3*to_next_y_sq);
    let mut ret_stack: Vec<usize> = Vec::new();
    loop {
        n_3 += to_next_n_3;
        to_next_n_3 += 6;
        match n_3%60{
            _ if n_3 >= iter_size => break,
            11 | 23 | 47 | 59 => (),
            _ => continue,
        };
        // println!("3: {}", n_3);
        ret_stack.push(n_3);
    };
    ret_stack
}

fn prime_filter_section(min:usize, max: usize) -> Vec<bool>{
    //Sieve of Atkin
    let num_cpus = num_cpus::get();
    assert!(min<max);
    let mut prime_filter = vec![false; max-min];
    if (min <= 2) & (max > 2) {prime_filter[2-min] = true;}
    if (min <= 3) & (max > 3) {prime_filter[3-min] = true;}
    if (min <= 5) & (max > 5) {prime_filter[5-min] = true;}

    let (mut y_sq, mut to_next_y_sq) = match min {
        0|1 => (1, 3),
        _ => (min*min, 2*min + 1),
    };
    let mut spawned_threads = 0;
    let (tx, rx) = mpsc::channel();
    while y_sq<max {
        if y_sq%2 == 1 {
            spawned_threads += 1;
            let (y_sq, tx) = (y_sq, tx.clone());
            thread::spawn(move || {
                tx.send(case_1(y_sq, max)).unwrap();
            });
        };
        if y_sq%3 == 1 {

            spawned_threads += 1;
            let (y_sq, to_next_y_sq, tx1) = (y_sq, to_next_y_sq, tx.clone());
            thread::spawn(move || {
                tx1.send(case_2(y_sq, max)).unwrap();
            });
            if y_sq*2<max{
                spawned_threads += 1;
                let tx2 = tx.clone();
                thread::spawn(move || {
                    tx2.send(case_3(y_sq, to_next_y_sq, max)).unwrap();
                });
            }
        };
        while{ //Do-while
            y_sq += to_next_y_sq;
            to_next_y_sq += 2;
            y_sq%6 == 0
        } {};
        while spawned_threads>=num_cpus{
            for mes in rx.try_iter(){
                spawned_threads -= 1;
                for flip_i in mes{
                    prime_filter[flip_i - min] ^= true;
                }
            }
        };
    };

    while spawned_threads!=0{
        for mes in rx.try_iter(){
            spawned_threads -= 1;
            for flip_i in mes{
                prime_filter[flip_i - min] ^= true;
            }
        }
    };
    //Eliminate non-squarefree numbers
    let mut n_sq = 49; // 7^2
    let mut next_n_sq = 32; //9^2 - 7^2, skip even numbers.
    while n_sq < max {
        let mut non_sq_free = n_sq;
        while non_sq_free < max {
            if non_sq_free >= min {
                prime_filter[non_sq_free - min] = false;
            }
            while{ //Do-while
                non_sq_free += n_sq + n_sq;
                (non_sq_free%3==0) | (non_sq_free%5==0)
            } {};
        };
        while{ //Do-while
            n_sq += next_n_sq;
            next_n_sq += 8;
            (n_sq%3==0) | (n_sq%5 == 0)
        } {};
    }
    prime_filter
}
#[cfg(test)]
pub fn old_prime_filter(iter_size: usize) -> std::vec::Vec<bool>{
    slow_prime_filter(iter_size)
}

fn slow_prime_filter(iter_size: usize) -> std::vec::Vec<bool>{
    if iter_size < 5 {
         let mut ret = vec![false, false, true, true];
         ret.truncate(iter_size);
         return ret
     }
    let mut prime_filter = vec![true; iter_size];
    prime_filter[0] = false;
    prime_filter[1] = false;
    let mut cur_num = 2;
    'outer: loop{
        for i in (cur_num+1)..iter_size{
            if 0 == i%cur_num { prime_filter[i] = false; }
        }
        cur_num += 1;
        while !prime_filter[cur_num]{
            if cur_num*cur_num > iter_size {
                break 'outer
            }
            cur_num += 1;
        }
    };
    prime_filter
}
<commit_msg>concidering current thread as well<commit_after>extern crate num_cpus;

use std;
use std::thread;
use std::sync::mpsc;

pub fn prime_filter(iter_size: usize) -> Vec<bool>{
    if iter_size<100{
        slow_prime_filter(iter_size)
    }else{
        prime_filter_section(0, iter_size)
    }
}

fn case_1(y_sq: usize, iter_size: usize)
    -> Vec<usize> {
    //n_1 = 4x^2 + y^2 === 1 (mod 4)
    let (mut n_1, mut to_next_n_1) = (y_sq, 4);    let mut ret_stack: Vec<usize> = Vec::new();
    loop{
        n_1 += to_next_n_1;
        to_next_n_1 += 8;
        match n_1%60{
            _ if n_1 >= iter_size => break,
            1 | 13 | 17 | 29 | 37 | 41 | 49 | 53 => (),
            _ => continue,
        };

        // println!("1: {}", n_1);
        ret_stack.push(n_1);
    };
    ret_stack
}
fn case_2(y_sq: usize, iter_size: usize)
    -> Vec<usize> {
    //n_2 = 3x^2 + y^2 === 1 (mod 6)
    let (mut n_2, mut to_next_n_2) = (y_sq, 3);
    let mut ret_stack: Vec<usize> = Vec::new();
    loop {
        n_2 += to_next_n_2;
        to_next_n_2 += 6;
        match n_2%60{
            _ if n_2 >= iter_size => break,
            7 | 19 | 31 | 43 => (),
            _ => continue,
        };
        // println!("2: {}", n_2);
        ret_stack.push(n_2);
    };
    ret_stack
}
fn case_3(y_sq: usize, to_next_y_sq: usize, iter_size: usize)
    -> Vec<usize> {
    //n_3 = 3x^2 - y^2 === 11 (mod 12)
    let (mut n_3, mut to_next_n_3) = (2*y_sq, 3*to_next_y_sq);
    let mut ret_stack: Vec<usize> = Vec::new();
    loop {
        n_3 += to_next_n_3;
        to_next_n_3 += 6;
        match n_3%60{
            _ if n_3 >= iter_size => break,
            11 | 23 | 47 | 59 => (),
            _ => continue,
        };
        // println!("3: {}", n_3);
        ret_stack.push(n_3);
    };
    ret_stack
}

fn prime_filter_section(min:usize, max: usize) -> Vec<bool>{
    //Sieve of Atkin
    let num_cpus = num_cpus::get();
    assert!(min<max);
    let mut prime_filter = vec![false; max-min];
    if (min <= 2) & (max > 2) {prime_filter[2-min] = true;}
    if (min <= 3) & (max > 3) {prime_filter[3-min] = true;}
    if (min <= 5) & (max > 5) {prime_filter[5-min] = true;}

    let (mut y_sq, mut to_next_y_sq) = match min {
        0|1 => (1, 3),
        _ => (min*min, 2*min + 1),
    };
    let mut spawned_threads = 0;
    let (tx, rx) = mpsc::channel();
    while y_sq<max {
        if y_sq%2 == 1 {
            spawned_threads += 1;
            let (y_sq, tx) = (y_sq, tx.clone());
            thread::spawn(move || {
                tx.send(case_1(y_sq, max)).unwrap();
            });
        };
        if y_sq%3 == 1 {

            spawned_threads += 1;
            let (y_sq, to_next_y_sq, tx1) = (y_sq, to_next_y_sq, tx.clone());
            thread::spawn(move || {
                tx1.send(case_2(y_sq, max)).unwrap();
            });
            if y_sq*2<max{
                spawned_threads += 1;
                let tx2 = tx.clone();
                thread::spawn(move || {
                    tx2.send(case_3(y_sq, to_next_y_sq, max)).unwrap();
                });
            }
        };
        while{ //Do-while
            y_sq += to_next_y_sq;
            to_next_y_sq += 2;
            y_sq%6 == 0
        } {};
        while (spawned_threads + 1)>=num_cpus{
            for mes in rx.try_iter(){
                spawned_threads -= 1;
                for flip_i in mes{
                    prime_filter[flip_i - min] ^= true;
                }
            }
        };
    };

    while spawned_threads!=0{
        for mes in rx.try_iter(){
            spawned_threads -= 1;
            for flip_i in mes{
                prime_filter[flip_i - min] ^= true;
            }
        }
    };
    //Eliminate non-squarefree numbers
    let mut n_sq = 49; // 7^2
    let mut next_n_sq = 32; //9^2 - 7^2, skip even numbers.
    while n_sq < max {
        let mut non_sq_free = n_sq;
        while non_sq_free < max {
            if non_sq_free >= min {
                prime_filter[non_sq_free - min] = false;
            }
            while{ //Do-while
                non_sq_free += n_sq + n_sq;
                (non_sq_free%3==0) | (non_sq_free%5==0)
            } {};
        };
        while{ //Do-while
            n_sq += next_n_sq;
            next_n_sq += 8;
            (n_sq%3==0) | (n_sq%5 == 0)
        } {};
    }
    prime_filter
}
#[cfg(test)]
pub fn old_prime_filter(iter_size: usize) -> std::vec::Vec<bool>{
    slow_prime_filter(iter_size)
}

fn slow_prime_filter(iter_size: usize) -> std::vec::Vec<bool>{
    if iter_size < 5 {
         let mut ret = vec![false, false, true, true];
         ret.truncate(iter_size);
         return ret
     }
    let mut prime_filter = vec![true; iter_size];
    prime_filter[0] = false;
    prime_filter[1] = false;
    let mut cur_num = 2;
    'outer: loop{
        for i in (cur_num+1)..iter_size{
            if 0 == i%cur_num { prime_filter[i] = false; }
        }
        cur_num += 1;
        while !prime_filter[cur_num]{
            if cur_num*cur_num > iter_size {
                break 'outer
            }
            cur_num += 1;
        }
    };
    prime_filter
}
<|endoftext|>