<commit_before>use crate::ProgressBar;
use rayon::iter::{
    plumbing::Consumer, plumbing::Folder, plumbing::UnindexedConsumer, IndexedParallelIterator,
    ParallelIterator,
};
use std::convert::TryInto;
use std::sync::{Arc, Mutex};

pub struct ParProgressBarIter<T> {
    it: T,
    progress: Arc<Mutex<ProgressBar>>,
}

/// Wraps a Rayon parallel iterator.
///
/// See [`ProgressIterator`](trait.ProgressIterator.html) for method
/// documentation.
pub trait ParallelProgressIterator
where
    Self: Sized,
{
    /// Wrap an iterator with a custom progress bar.
    fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self>;

    /// Wrap an iterator with an explicit element count.
    fn progress_count(self, len: u64) -> ParProgressBarIter<Self> {
        self.progress_with(ProgressBar::new(len))
    }
}

pub trait IndexedParallelProgressIterator
where
    Self: Sized,
{
    fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self>;

    fn progress_count(self, len: u64) -> ParProgressBarIter<Self> {
        self.progress_with(ProgressBar::new(len))
    }

    fn progress(self) -> ParProgressBarIter<Self> {
        self.progress_count(0)
    }
}

impl<S: Send, T: ParallelIterator<Item = S>> ParallelProgressIterator for T {
    fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self> {
        ParProgressBarIter {
            it: self,
            progress: Arc::new(Mutex::new(progress)),
        }
    }
}

impl<S: Send, T: IndexedParallelIterator<Item = S>> IndexedParallelProgressIterator for T {
    fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self> {
        ParProgressBarIter {
            it: self,
            progress: Arc::new(Mutex::new(progress)),
        }
    }

    fn progress(self) -> ParProgressBarIter<Self> {
        let len = self.len().try_into().unwrap();
        IndexedParallelProgressIterator::progress_count(self, len)
    }
}

struct ProgressConsumer<C> {
    base: C,
    progress: Arc<Mutex<ProgressBar>>,
}

impl<C> ProgressConsumer<C> {
    fn new(base: C, progress: Arc<Mutex<ProgressBar>>) -> Self {
        ProgressConsumer { base, progress }
    }
}

impl<T, C: Consumer<T>> Consumer<T> for ProgressConsumer<C> {
    type Folder = ProgressFolder<C::Folder>;
    type Reducer = C::Reducer;
    type Result = C::Result;

    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
        let (left, right, reducer) = self.base.split_at(index);
        (
            ProgressConsumer::new(left, self.progress.clone()),
            ProgressConsumer::new(right, self.progress.clone()),
            reducer,
        )
    }

    fn into_folder(self) -> Self::Folder {
        ProgressFolder {
            base: self.base.into_folder(),
            progress: self.progress.clone(),
        }
    }

    fn full(&self) -> bool {
        self.base.full()
    }
}

impl<T, C: UnindexedConsumer<T>> UnindexedConsumer<T> for ProgressConsumer<C> {
    fn split_off_left(&self) -> Self {
        ProgressConsumer::new(self.base.split_off_left(), self.progress.clone())
    }

    fn to_reducer(&self) -> Self::Reducer {
        self.base.to_reducer()
    }
}

struct ProgressFolder<C> {
    base: C,
    progress: Arc<Mutex<ProgressBar>>,
}

impl<T, C: Folder<T>> Folder<T> for ProgressFolder<C> {
    type Result = C::Result;

    fn consume(self, item: T) -> Self {
        self.progress.lock().unwrap().inc(1);
        ProgressFolder {
            base: self.base.consume(item),
            progress: self.progress,
        }
    }

    fn complete(self) -> C::Result {
        self.base.complete()
    }

    fn full(&self) -> bool {
        self.base.full()
    }
}

impl<S: Send, T: ParallelIterator<Item = S>> ParallelIterator for ParProgressBarIter<T> {
    type Item = S;

    fn drive_unindexed<C: UnindexedConsumer<Self::Item>>(self, consumer: C) -> C::Result {
        let consumer1 = ProgressConsumer::new(consumer, self.progress.clone());
        self.it.drive_unindexed(consumer1)
    }
}

#[cfg(test)]
mod test {
    use super::{ParProgressBarIter, ParallelProgressIterator};
    use crate::progress::ProgressBar;
    use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

    #[test]
    fn it_can_wrap_a_parallel_iterator() {
        let v = vec![1, 2, 3];
        let wrap = |it: ParProgressBarIter<_>| {
            assert_eq!(it.map(|x| x * 2).collect::<Vec<_>>(), vec![2, 4, 6]);
        };

        wrap(v.par_iter().progress_count(3));
        wrap({
            let pb = ProgressBar::new(v.len() as u64);
            v.par_iter().progress_with(pb)
        });
    }
}
<commit_msg>Remove useless Mutex from ParProgressBarIter<commit_after>use crate::ProgressBar;
use rayon::iter::{
    plumbing::Consumer, plumbing::Folder, plumbing::UnindexedConsumer, IndexedParallelIterator,
    ParallelIterator,
};
use std::convert::TryInto;

pub struct ParProgressBarIter<T> {
    it: T,
    progress: ProgressBar,
}

/// Wraps a Rayon parallel iterator.
///
/// See [`ProgressIterator`](trait.ProgressIterator.html) for method
/// documentation.
pub trait ParallelProgressIterator
where
    Self: Sized,
{
    /// Wrap an iterator with a custom progress bar.
    fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self>;

    /// Wrap an iterator with an explicit element count.
    fn progress_count(self, len: u64) -> ParProgressBarIter<Self> {
        self.progress_with(ProgressBar::new(len))
    }
}

pub trait IndexedParallelProgressIterator
where
    Self: Sized,
{
    fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self>;

    fn progress_count(self, len: u64) -> ParProgressBarIter<Self> {
        self.progress_with(ProgressBar::new(len))
    }

    fn progress(self) -> ParProgressBarIter<Self> {
        self.progress_count(0)
    }
}

impl<S: Send, T: ParallelIterator<Item = S>> ParallelProgressIterator for T {
    fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self> {
        ParProgressBarIter { it: self, progress }
    }
}

impl<S: Send, T: IndexedParallelIterator<Item = S>> IndexedParallelProgressIterator for T {
    fn progress_with(self, progress: ProgressBar) -> ParProgressBarIter<Self> {
        ParProgressBarIter { it: self, progress }
    }

    fn progress(self) -> ParProgressBarIter<Self> {
        let len = self.len().try_into().unwrap();
        IndexedParallelProgressIterator::progress_count(self, len)
    }
}

struct ProgressConsumer<C> {
    base: C,
    progress: ProgressBar,
}

impl<C> ProgressConsumer<C> {
    fn new(base: C, progress: ProgressBar) -> Self {
        ProgressConsumer { base, progress }
    }
}

impl<T, C: Consumer<T>> Consumer<T> for ProgressConsumer<C> {
    type Folder = ProgressFolder<C::Folder>;
    type Reducer = C::Reducer;
    type Result = C::Result;

    fn split_at(self, index: usize) -> (Self, Self, Self::Reducer) {
        let (left, right, reducer) = self.base.split_at(index);
        (
            ProgressConsumer::new(left, self.progress.clone()),
            ProgressConsumer::new(right, self.progress),
            reducer,
        )
    }

    fn into_folder(self) -> Self::Folder {
        ProgressFolder {
            base: self.base.into_folder(),
            progress: self.progress,
        }
    }

    fn full(&self) -> bool {
        self.base.full()
    }
}

impl<T, C: UnindexedConsumer<T>> UnindexedConsumer<T> for ProgressConsumer<C> {
    fn split_off_left(&self) -> Self {
        ProgressConsumer::new(self.base.split_off_left(), self.progress.clone())
    }

    fn to_reducer(&self) -> Self::Reducer {
        self.base.to_reducer()
    }
}

struct ProgressFolder<C> {
    base: C,
    progress: ProgressBar,
}

impl<T, C: Folder<T>> Folder<T> for ProgressFolder<C> {
    type Result = C::Result;

    fn consume(self, item: T) -> Self {
        self.progress.inc(1);
        ProgressFolder {
            base: self.base.consume(item),
            progress: self.progress,
        }
    }

    fn complete(self) -> C::Result {
        self.base.complete()
    }

    fn full(&self) -> bool {
        self.base.full()
    }
}

impl<S: Send, T: ParallelIterator<Item = S>> ParallelIterator for ParProgressBarIter<T> {
    type Item = S;

    fn drive_unindexed<C: UnindexedConsumer<Self::Item>>(self, consumer: C) -> C::Result {
        let consumer1 = ProgressConsumer::new(consumer, self.progress.clone());
        self.it.drive_unindexed(consumer1)
    }
}

#[cfg(test)]
mod test {
    use super::{ParProgressBarIter, ParallelProgressIterator};
    use crate::progress::ProgressBar;
    use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

    #[test]
    fn it_can_wrap_a_parallel_iterator() {
        let v = vec![1, 2, 3];
        let wrap = |it: ParProgressBarIter<_>| {
            assert_eq!(it.map(|x| x * 2).collect::<Vec<_>>(), vec![2, 4, 6]);
        };

        wrap(v.par_iter().progress_count(3));
        wrap({
            let pb = ProgressBar::new(v.len() as u64);
            v.par_iter().progress_with(pb)
        });
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::os::unix::io::RawFd;
use libc::{self, c_int, c_void, c_ulong, pid_t};
use {Errno, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
bitflags!{
    flags CloneFlags: c_int {
        const CLONE_VM             = libc::CLONE_VM,
        const CLONE_FS             = libc::CLONE_FS,
        const CLONE_FILES          = libc::CLONE_FILES,
        const CLONE_SIGHAND        = libc::CLONE_SIGHAND,
        const CLONE_PTRACE         = libc::CLONE_PTRACE,
        const CLONE_VFORK          = libc::CLONE_VFORK,
        const CLONE_PARENT         = libc::CLONE_PARENT,
        const CLONE_THREAD         = libc::CLONE_THREAD,
        const CLONE_NEWNS          = libc::CLONE_NEWNS,
        const CLONE_SYSVSEM        = libc::CLONE_SYSVSEM,
        const CLONE_SETTLS         = libc::CLONE_SETTLS,
        const CLONE_PARENT_SETTID  = libc::CLONE_PARENT_SETTID,
        const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
        const CLONE_DETACHED       = libc::CLONE_DETACHED,
        const CLONE_UNTRACED       = libc::CLONE_UNTRACED,
        const CLONE_CHILD_SETTID   = libc::CLONE_CHILD_SETTID,
        // TODO: Once, we use a version containing
        // https://github.com/rust-lang-nursery/libc/pull/147
        // get rid of the casts.
        const CLONE_NEWUTS         = libc::CLONE_NEWUTS as c_int,
        const CLONE_NEWIPC         = libc::CLONE_NEWIPC as c_int,
        const CLONE_NEWUSER        = libc::CLONE_NEWUSER as c_int,
        const CLONE_NEWPID         = libc::CLONE_NEWPID as c_int,
        const CLONE_NEWNET         = libc::CLONE_NEWNET as c_int,
        const CLONE_IO             = libc::CLONE_IO as c_int,
    }
}

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:          usize = 1024;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: c_int,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: c_int) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: c_int) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback), ptr as *mut c_void, flags.bits(), &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<commit_msg>Cast function item to function pointer in order to appease compiler.<commit_after>use std::mem;
use std::os::unix::io::RawFd;
use libc::{self, c_int, c_void, c_ulong, pid_t};
use {Errno, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
bitflags!{
    flags CloneFlags: c_int {
        const CLONE_VM             = libc::CLONE_VM,
        const CLONE_FS             = libc::CLONE_FS,
        const CLONE_FILES          = libc::CLONE_FILES,
        const CLONE_SIGHAND        = libc::CLONE_SIGHAND,
        const CLONE_PTRACE         = libc::CLONE_PTRACE,
        const CLONE_VFORK          = libc::CLONE_VFORK,
        const CLONE_PARENT         = libc::CLONE_PARENT,
        const CLONE_THREAD         = libc::CLONE_THREAD,
        const CLONE_NEWNS          = libc::CLONE_NEWNS,
        const CLONE_SYSVSEM        = libc::CLONE_SYSVSEM,
        const CLONE_SETTLS         = libc::CLONE_SETTLS,
        const CLONE_PARENT_SETTID  = libc::CLONE_PARENT_SETTID,
        const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
        const CLONE_DETACHED       = libc::CLONE_DETACHED,
        const CLONE_UNTRACED       = libc::CLONE_UNTRACED,
        const CLONE_CHILD_SETTID   = libc::CLONE_CHILD_SETTID,
        // TODO: Once, we use a version containing
        // https://github.com/rust-lang-nursery/libc/pull/147
        // get rid of the casts.
        const CLONE_NEWUTS         = libc::CLONE_NEWUTS as c_int,
        const CLONE_NEWIPC         = libc::CLONE_NEWIPC as c_int,
        const CLONE_NEWUSER        = libc::CLONE_NEWUSER as c_int,
        const CLONE_NEWPID         = libc::CLONE_NEWPID as c_int,
        const CLONE_NEWNET         = libc::CLONE_NEWNET as c_int,
        const CLONE_IO             = libc::CLONE_IO as c_int,
    }
}

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "android"))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(any(target_arch = "arm", target_arch = "mips"), target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:          usize = 1024;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: c_int,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: c_int) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: c_int) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback as extern "C" fn(*mut Box<::std::ops::FnMut() -> isize>) -> i32),
                   ptr as *mut c_void,
                   flags.bits(),
                   &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<|endoftext|>


<commit_before>extern crate rusql;
#[cfg(not(feature = "no_readline"))]
extern crate readline;

#[cfg(not(feature = "no_readline"))]
use readline::readline;
use rusql::{rusql_exec, Rusql};

#[cfg(feature = "no_readline")]
use std::io;

#[cfg(feature = "no_readline")]
fn readline(prompt: &str) -> Option<String> {
    print!("{}", prompt);

    io::stdin().read_line().ok()
}

pub fn main() {
    let mut db = Rusql::new();
    loop {
        let mut input = readline("rusql> ").unwrap();

        while !input.as_slice().trim_right().ends_with(";")
                && !input.as_slice().trim_left().starts_with(".") {

            let continuation = readline("  ...> ").unwrap();

            input.push(' ');
            input.push_str(continuation.as_slice());
        }

        match input.as_slice() {
            ".make_foo" => {
                rusql_exec(&mut db, "CREATE TABLE Foo(Id INTEGER, Name TEXT);
                                     INSERT INTO Foo VALUES
                                            (1, \"Foo1\"), (2, \"Foo2\"), (3, \"Foo3\");
                                     CREATE TABLE Qux(QuxId INTEGER PRIMARY KEY, Nick TEXT);
                                     INSERT INTO Qux(Nick) VALUES
                                            (\"Bar1\"), (\"Bar2\"), (\"Bar3\");",
                           |_, _| ());
            }
            _ => {
                if let Some(results) = rusql_exec(&mut db, input.as_slice(), |_, _| {}) {
                    print!("{}", results);
                }
            }
        }
    }
}
<commit_msg>Update for readline<commit_after>extern crate rusql;
#[cfg(not(feature = "no_readline"))]
extern crate readline;

#[cfg(not(feature = "no_readline"))]
use readline::{readline, add_history};
use rusql::{rusql_exec, Rusql};

#[cfg(feature = "no_readline")]
use std::io;

#[cfg(feature = "no_readline")]
fn rl(prompt: &str) -> String {
    print!("{}", prompt);

    io::stdin().read_line().ok().unwrap()
}

#[cfg(not(feature = "no_readline"))]
fn rl(prompt: &str) -> String {
    let res = readline(prompt).unwrap();
    add_history(res.as_slice());

    res
}

pub fn main() {
    let mut db = Rusql::new();
    loop {
        let mut input = rl("rusql> ");

        while !input.as_slice().trim_right().ends_with(";")
                && !input.as_slice().trim_left().starts_with(".") {

            let continuation = rl("  ...> ");

            input.push(' ');
            input.push_str(continuation.as_slice());
        }

        match input.as_slice() {
            ".make_foo" => {
                rusql_exec(&mut db, "CREATE TABLE Foo(Id INTEGER, Name TEXT);
                                     INSERT INTO Foo VALUES
                                            (1, \"Foo1\"), (2, \"Foo2\"), (3, \"Foo3\");
                                     CREATE TABLE Qux(QuxId INTEGER PRIMARY KEY, Nick TEXT);
                                     INSERT INTO Qux(Nick) VALUES
                                            (\"Bar1\"), (\"Bar2\"), (\"Bar3\");",
                           |_, _| ());
            }
            _ => {
                if let Some(results) = rusql_exec(&mut db, input.as_slice(), |_, _| {}) {
                    print!("{}", results);
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Gomez Guillaume
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fs::{File, OpenOptions};
use std::io::{self, BufRead, Write, Read};
use std::process::exit;
use std::ops::Deref;
use utils::join;

use types::{
    EventInfo,
    EventType,
    ParseResult,
    TypeStruct,
    Type,
    MOD_COMMENT,
    FILE_COMMENT,
    FILE,
    OUTPUT_COMMENT_FILE,
};

fn move_to(words: &[&str], it: &mut usize, limit: &str, line: &mut usize) {
    while (*it + 1) < words.len() && limit.contains(words[*it + 1]) == false {
        if words[*it] == "\n" {
            *line += 1;
        }
        *it += 1;
    }
    if words[*it] == "\n" {
        *line += 1;
    }
}

fn move_until(words: &[&str], it: &mut usize, limit: &str, line: &mut usize) {
    while (*it + 1) < words.len() && limit != words[*it] {
        if words[*it] == "\n" {
            *line += 1;
        }
        *it += 1;
    }
}

fn get_impl(words: &[&str], it: &mut usize, line: &mut usize) -> Vec<String> {
    let mut v = vec!();

    while (*it + 1) < words.len() {
        if words[*it] == "\n" {
            *line += 1;
        }
        if words[(*it + 1)] == "{" || words[(*it + 1)] == ";" {
            break;
        }
        *it += 1;
        v.push(words[*it].to_owned());
    }
    v
}

pub fn add_to_type_scope(current: &Option<TypeStruct>, e: &Option<TypeStruct>) -> Option<TypeStruct> {
    match current {
        &Some(ref c) => {
            match e {
                &Some(ref t) => {
                    let mut tmp = t.clone();
                    tmp.parent = Some(Box::new(c.clone()));
                    Some(tmp)
                }
                &None => {
                    let mut tmp = TypeStruct::empty();
                    tmp.parent = Some(Box::new(c.clone()));
                    Some(tmp)
                }
            }
        },
        &None => match e {
            &Some(ref t) => Some(t.clone()),
            &None => None,
        }
    }
}

pub fn type_out_scope(current: &Option<TypeStruct>) -> Option<TypeStruct> {
    match current {
        &Some(ref c) => match c.parent {
            Some(ref p) => Some(p.deref().clone()),
            None => None,
        },
        &None => None,
    }
}

fn get_mod<F: Write>(current: &Option<TypeStruct>, out_file: &mut F) -> bool {
    match *current {
        Some(ref t) => {
            if t.ty != Type::Mod {
                println!("Mod/File comments cannot be put here!");
                false
            } else {
                writeln!(out_file, "{}{}", MOD_COMMENT, t).unwrap();
                true
            }
        }
        None => true,
    }
}

pub fn build_event_list(path: &str) -> io::Result<ParseResult> {
    match File::open(path) {
        Ok(mut f) => {
            let mut b_content = String::new();
            f.read_to_string(&mut b_content).unwrap();
            let content = b_content.replace("{", " { ")
                                   .replace("}", " } ")
                                   .replace("///", "/// ")
                                   .replace("//!", "//! ")
                                   .replace("/*!", "/*! ")
                                   .replace(":", " : ")
                                   .replace(" :  : ", "::")
                                   .replace("*/", " */")
                                   .replace("\n", " \n ")
                                   .replace("!(", " !! (")
                                   .replace(",", ", ")
                                   .replace("(", " (");
            let b_content : Vec<String> = b_content.split('\n').map(|s| s.to_owned()).collect();
            let words : Vec<&str> = content.split(' ').filter(|s| s.len() > 0).collect();
            let mut it = 0;
            let mut line = 0;
            let mut event_list = vec!();
            let mut comment_lines = vec!();

            while it < words.len() {
                match words[it] {
                    "///" => {
                        comment_lines.push(line);
                        event_list.push(EventInfo::new(line, EventType::Comment(b_content[line].to_owned())));
                        move_to(&words, &mut it, "\n", &mut line);
                    }
                    "//!" => {
                        comment_lines.push(line);
                        event_list.push(EventInfo::new(line, EventType::FileComment(b_content[line].to_owned())));
                        if line + 1 < b_content.len() && b_content[line + 1].len() < 1 {
                            comment_lines.push(line + 1);
                            event_list.push(EventInfo::new(line, EventType::FileComment("".to_owned())));
                        }
                        move_to(&words, &mut it, "\n", &mut line);
                    }
                    "/*!" => {
                        let mark = line;
                        move_until(&words, &mut it, "*/", &mut line);
                        for pos in mark..line {
                            comment_lines.push(pos);
                            event_list.push(EventInfo::new(line, EventType::FileComment(b_content[pos].to_owned())));
                        }
                        comment_lines.push(line);
                        let mut removed = false;
                        if line + 1 < b_content.len() && b_content[line + 1].len() < 1 {
                            comment_lines.push(line + 1);
                            removed = true;
                        }
                        event_list.push(EventInfo::new(line, EventType::FileComment("*/".to_owned())));
                        if removed {
                            event_list.push(EventInfo::new(line, EventType::FileComment("".to_owned())));
                        }
                    }
                    "use" | "mod" => {
                        let mut name = words[it + 1].to_owned();
                        let ty = words[it];

                        if line + 1 < b_content.len() && b_content[line].ends_with("::{") {
                            move_to(&words, &mut it, "\n", &mut line);
                            name.push_str(&format!("{}", b_content[line + 1].trim()));
                        }
                        event_list.push(EventInfo::new(line, EventType::Type(TypeStruct::new(Type::from(ty), &name))));
                    }
                    "struct" | "fn" | "enum" | "const" | "static" | "type" | "trait" | "macro_rules!" => {
                        event_list.push(EventInfo::new(line, EventType::Type(TypeStruct::new(Type::from(words[it]), words[it + 1]))));
                        it += 1;
                    }
                    "!!" => {
                        event_list.push(EventInfo::new(line,
                            EventType::Type(TypeStruct::new(Type::from("macro"), &format!("{}!{}", words[it - 1], words[it + 1])))));
                        it += 1;
                    }
                    "impl" => {
                        event_list.push(EventInfo::new(line,
                            EventType::Type(TypeStruct::new(Type::Impl, &join(&get_impl(&words, &mut it, &mut line), " ")))));
                    }
                    "{" => {
                        event_list.push(EventInfo::new(line, EventType::InScope));
                    }
                    "}" => {
                        event_list.push(EventInfo::new(line, EventType::OutScope));
                    }
                    "\n" => {
                        line += 1;
                    }
                    s if s.starts_with("#[") || s.starts_with("#![") => {
                        while words[it + 1] != "\n" {
                            it += 1;
                        }
                    }
                    _ => {
                        event_list.push(EventInfo::new(line, EventType::Type(TypeStruct::new(Type::Unknown, words[it]))));
                    }
                }
                it += 1;
            }
            Ok(ParseResult { event_list : event_list,
                             comment_lines : comment_lines,
                             original_content : b_content,
                           })
        },
        Err(e) => Err(e),
    }
}

pub fn strip_comments<F: Write>(path: &str, out_file: &mut F) {
    match build_event_list(path) {
        Ok(parse_result) => {
            if parse_result.comment_lines.len() < 1 {
                return;
            }
            writeln!(out_file, "{}{}", FILE, path).unwrap();
            let mut current : Option<TypeStruct> = None;
            let mut waiting_type : Option<TypeStruct> = None;
            let mut it = 0;

            while it < parse_result.event_list.len() {
                match parse_result.event_list[it].event {
                    EventType::Type(ref t) => {
                        if t.ty != Type::Unknown {
                            waiting_type = Some(t.clone());
                        }
                    }
                    EventType::InScope => {
                        current = add_to_type_scope(&current, &waiting_type);
                        waiting_type = None;
                    }
                    EventType::OutScope => {
                        current = type_out_scope(&current);
                        waiting_type = None;
                    }
                    EventType::FileComment(ref c) => {
                        // first, we need to find if it belongs to a mod
                        if get_mod(&current, out_file) == false {
                            exit(1);
                        }
                        it += 1;
                        let mut comments = format!("{}{}\n", FILE_COMMENT, c);
                        while match parse_result.event_list[it].event {
                            EventType::FileComment(ref c) => {
                                comments.push_str(&format!("{}{}\n", FILE_COMMENT, c));
                                true
                            }
                            _ => false,
                        } {
                            it += 1;
                        }
                        write!(out_file, "{}", comments).unwrap();
                        continue;
                    }
                    EventType::Comment(ref c) => {
                        let mut comments = format!("{}\n", c);

                        it += 1;
                        while it < parse_result.event_list.len() &&
                              match parse_result.event_list[it].event {
                            EventType::Comment(ref c) => {
                                comments.push_str(&format!("{}\n", c));
                                true
                            }
                            EventType::Type(_) => {
                                false
                            }
                            _ => panic!("Doc comments cannot be written everywhere"),
                        } {
                            it += 1;
                        }
                        if it >= parse_result.event_list.len() {
                            continue;
                        }
                        while match parse_result.event_list[it].event {
                            EventType::Type(ref t) => {
                                match t.ty {
                                    Type::Unknown => {
                                        match current {
                                            Some(ref cur) => {
                                                if cur.ty == Type::Enum || cur.ty == Type::Struct || cur.ty == Type::Use {
                                                    if t.name == "pub" {
                                                        true
                                                    } else {
                                                        let mut copy = t.clone();
                                                        copy.ty = Type::Variant;
                                                        let tmp = add_to_type_scope(&current, &Some(copy));
                                                        write!(out_file, "{}{}\n{}", MOD_COMMENT, tmp.unwrap(), comments).unwrap();
                                                        false
                                                    }
                                                } else {
                                                    if t.name == "pub" {
                                                        true
                                                    } else {
                                                        false
                                                    }
                                                }
                                            }
                                            None => {
                                                if t.name == "pub" {
                                                    true
                                                } else {
                                                    false
                                                }
                                            },
                                        }
                                    },
                                    _ => {
                                        let tmp = add_to_type_scope(&current, &Some(t.clone()));
                                        write!(out_file, "{}{}\n{}", MOD_COMMENT, tmp.unwrap(), comments).unwrap();
                                        false
                                    }
                                }
                            }
                            _ => panic!("An item was expected for this comment: {}", comments),
                        } {
                            it += 1;
                        }
                        continue;
                    }
                }
                it += 1;
            }
            // we now remove doc comments from original file
            remove_comments(path, &parse_result.comment_lines, parse_result.original_content);
        }
        Err(e) => {
            println!("Unable to open \"{}\": {}", path, e);
        }
    }
}

fn remove_comments(path: &str, to_remove: &[usize], mut o_content: Vec<String>) {
    match OpenOptions::new().write(true).create(true).truncate(true).open(path) {
        Ok(mut f) => {
            let mut decal = 0;

            for line in to_remove {
                o_content.remove(line - decal);
                decal += 1;
            }
            write!(f, "{}", o_content.join("\n")).unwrap();
        }
        Err(e) => {
            println!("Cannot open '{}': {}", path, e);
        }
    }
}
<commit_msg>Remove one warning<commit_after>// Copyright 2015 Gomez Guillaume
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fs::{File, OpenOptions};
use std::io::{self, BufRead, Write, Read};
use std::process::exit;
use std::ops::Deref;
use utils::join;

use types::{
    EventInfo,
    EventType,
    ParseResult,
    TypeStruct,
    Type,
    MOD_COMMENT,
    FILE_COMMENT,
    FILE,
};

fn move_to(words: &[&str], it: &mut usize, limit: &str, line: &mut usize) {
    while (*it + 1) < words.len() && limit.contains(words[*it + 1]) == false {
        if words[*it] == "\n" {
            *line += 1;
        }
        *it += 1;
    }
    if words[*it] == "\n" {
        *line += 1;
    }
}

fn move_until(words: &[&str], it: &mut usize, limit: &str, line: &mut usize) {
    while (*it + 1) < words.len() && limit != words[*it] {
        if words[*it] == "\n" {
            *line += 1;
        }
        *it += 1;
    }
}

fn get_impl(words: &[&str], it: &mut usize, line: &mut usize) -> Vec<String> {
    let mut v = vec!();

    while (*it + 1) < words.len() {
        if words[*it] == "\n" {
            *line += 1;
        }
        if words[(*it + 1)] == "{" || words[(*it + 1)] == ";" {
            break;
        }
        *it += 1;
        v.push(words[*it].to_owned());
    }
    v
}

pub fn add_to_type_scope(current: &Option<TypeStruct>, e: &Option<TypeStruct>) -> Option<TypeStruct> {
    match current {
        &Some(ref c) => {
            match e {
                &Some(ref t) => {
                    let mut tmp = t.clone();
                    tmp.parent = Some(Box::new(c.clone()));
                    Some(tmp)
                }
                &None => {
                    let mut tmp = TypeStruct::empty();
                    tmp.parent = Some(Box::new(c.clone()));
                    Some(tmp)
                }
            }
        },
        &None => match e {
            &Some(ref t) => Some(t.clone()),
            &None => None,
        }
    }
}

pub fn type_out_scope(current: &Option<TypeStruct>) -> Option<TypeStruct> {
    match current {
        &Some(ref c) => match c.parent {
            Some(ref p) => Some(p.deref().clone()),
            None => None,
        },
        &None => None,
    }
}

fn get_mod<F: Write>(current: &Option<TypeStruct>, out_file: &mut F) -> bool {
    match *current {
        Some(ref t) => {
            if t.ty != Type::Mod {
                println!("Mod/File comments cannot be put here!");
                false
            } else {
                writeln!(out_file, "{}{}", MOD_COMMENT, t).unwrap();
                true
            }
        }
        None => true,
    }
}

pub fn build_event_list(path: &str) -> io::Result<ParseResult> {
    match File::open(path) {
        Ok(mut f) => {
            let mut b_content = String::new();
            f.read_to_string(&mut b_content).unwrap();
            let content = b_content.replace("{", " { ")
                                   .replace("}", " } ")
                                   .replace("///", "/// ")
                                   .replace("//!", "//! ")
                                   .replace("/*!", "/*! ")
                                   .replace(":", " : ")
                                   .replace(" :  : ", "::")
                                   .replace("*/", " */")
                                   .replace("\n", " \n ")
                                   .replace("!(", " !! (")
                                   .replace(",", ", ")
                                   .replace("(", " (");
            let b_content : Vec<String> = b_content.split('\n').map(|s| s.to_owned()).collect();
            let words : Vec<&str> = content.split(' ').filter(|s| s.len() > 0).collect();
            let mut it = 0;
            let mut line = 0;
            let mut event_list = vec!();
            let mut comment_lines = vec!();

            while it < words.len() {
                match words[it] {
                    "///" => {
                        comment_lines.push(line);
                        event_list.push(EventInfo::new(line, EventType::Comment(b_content[line].to_owned())));
                        move_to(&words, &mut it, "\n", &mut line);
                    }
                    "//!" => {
                        comment_lines.push(line);
                        event_list.push(EventInfo::new(line, EventType::FileComment(b_content[line].to_owned())));
                        if line + 1 < b_content.len() && b_content[line + 1].len() < 1 {
                            comment_lines.push(line + 1);
                            event_list.push(EventInfo::new(line, EventType::FileComment("".to_owned())));
                        }
                        move_to(&words, &mut it, "\n", &mut line);
                    }
                    "/*!" => {
                        let mark = line;
                        move_until(&words, &mut it, "*/", &mut line);
                        for pos in mark..line {
                            comment_lines.push(pos);
                            event_list.push(EventInfo::new(line, EventType::FileComment(b_content[pos].to_owned())));
                        }
                        comment_lines.push(line);
                        let mut removed = false;
                        if line + 1 < b_content.len() && b_content[line + 1].len() < 1 {
                            comment_lines.push(line + 1);
                            removed = true;
                        }
                        event_list.push(EventInfo::new(line, EventType::FileComment("*/".to_owned())));
                        if removed {
                            event_list.push(EventInfo::new(line, EventType::FileComment("".to_owned())));
                        }
                    }
                    "use" | "mod" => {
                        let mut name = words[it + 1].to_owned();
                        let ty = words[it];

                        if line + 1 < b_content.len() && b_content[line].ends_with("::{") {
                            move_to(&words, &mut it, "\n", &mut line);
                            name.push_str(&format!("{}", b_content[line + 1].trim()));
                        }
                        event_list.push(EventInfo::new(line, EventType::Type(TypeStruct::new(Type::from(ty), &name))));
                    }
                    "struct" | "fn" | "enum" | "const" | "static" | "type" | "trait" | "macro_rules!" => {
                        event_list.push(EventInfo::new(line, EventType::Type(TypeStruct::new(Type::from(words[it]), words[it + 1]))));
                        it += 1;
                    }
                    "!!" => {
                        event_list.push(EventInfo::new(line,
                            EventType::Type(TypeStruct::new(Type::from("macro"), &format!("{}!{}", words[it - 1], words[it + 1])))));
                        it += 1;
                    }
                    "impl" => {
                        event_list.push(EventInfo::new(line,
                            EventType::Type(TypeStruct::new(Type::Impl, &join(&get_impl(&words, &mut it, &mut line), " ")))));
                    }
                    "{" => {
                        event_list.push(EventInfo::new(line, EventType::InScope));
                    }
                    "}" => {
                        event_list.push(EventInfo::new(line, EventType::OutScope));
                    }
                    "\n" => {
                        line += 1;
                    }
                    s if s.starts_with("#[") || s.starts_with("#![") => {
                        while words[it + 1] != "\n" {
                            it += 1;
                        }
                    }
                    _ => {
                        event_list.push(EventInfo::new(line, EventType::Type(TypeStruct::new(Type::Unknown, words[it]))));
                    }
                }
                it += 1;
            }
            Ok(ParseResult { event_list : event_list,
                             comment_lines : comment_lines,
                             original_content : b_content,
                           })
        },
        Err(e) => Err(e),
    }
}

pub fn strip_comments<F: Write>(path: &str, out_file: &mut F) {
    match build_event_list(path) {
        Ok(parse_result) => {
            if parse_result.comment_lines.len() < 1 {
                return;
            }
            writeln!(out_file, "{}{}", FILE, path).unwrap();
            let mut current : Option<TypeStruct> = None;
            let mut waiting_type : Option<TypeStruct> = None;
            let mut it = 0;

            while it < parse_result.event_list.len() {
                match parse_result.event_list[it].event {
                    EventType::Type(ref t) => {
                        if t.ty != Type::Unknown {
                            waiting_type = Some(t.clone());
                        }
                    }
                    EventType::InScope => {
                        current = add_to_type_scope(&current, &waiting_type);
                        waiting_type = None;
                    }
                    EventType::OutScope => {
                        current = type_out_scope(&current);
                        waiting_type = None;
                    }
                    EventType::FileComment(ref c) => {
                        // first, we need to find if it belongs to a mod
                        if get_mod(&current, out_file) == false {
                            exit(1);
                        }
                        it += 1;
                        let mut comments = format!("{}{}\n", FILE_COMMENT, c);
                        while match parse_result.event_list[it].event {
                            EventType::FileComment(ref c) => {
                                comments.push_str(&format!("{}{}\n", FILE_COMMENT, c));
                                true
                            }
                            _ => false,
                        } {
                            it += 1;
                        }
                        write!(out_file, "{}", comments).unwrap();
                        continue;
                    }
                    EventType::Comment(ref c) => {
                        let mut comments = format!("{}\n", c);

                        it += 1;
                        while it < parse_result.event_list.len() &&
                              match parse_result.event_list[it].event {
                            EventType::Comment(ref c) => {
                                comments.push_str(&format!("{}\n", c));
                                true
                            }
                            EventType::Type(_) => {
                                false
                            }
                            _ => panic!("Doc comments cannot be written everywhere"),
                        } {
                            it += 1;
                        }
                        if it >= parse_result.event_list.len() {
                            continue;
                        }
                        while match parse_result.event_list[it].event {
                            EventType::Type(ref t) => {
                                match t.ty {
                                    Type::Unknown => {
                                        match current {
                                            Some(ref cur) => {
                                                if cur.ty == Type::Enum || cur.ty == Type::Struct || cur.ty == Type::Use {
                                                    if t.name == "pub" {
                                                        true
                                                    } else {
                                                        let mut copy = t.clone();
                                                        copy.ty = Type::Variant;
                                                        let tmp = add_to_type_scope(&current, &Some(copy));
                                                        write!(out_file, "{}{}\n{}", MOD_COMMENT, tmp.unwrap(), comments).unwrap();
                                                        false
                                                    }
                                                } else {
                                                    if t.name == "pub" {
                                                        true
                                                    } else {
                                                        false
                                                    }
                                                }
                                            }
                                            None => {
                                                if t.name == "pub" {
                                                    true
                                                } else {
                                                    false
                                                }
                                            },
                                        }
                                    },
                                    _ => {
                                        let tmp = add_to_type_scope(&current, &Some(t.clone()));
                                        write!(out_file, "{}{}\n{}", MOD_COMMENT, tmp.unwrap(), comments).unwrap();
                                        false
                                    }
                                }
                            }
                            _ => panic!("An item was expected for this comment: {}", comments),
                        } {
                            it += 1;
                        }
                        continue;
                    }
                }
                it += 1;
            }
            // we now remove doc comments from original file
            remove_comments(path, &parse_result.comment_lines, parse_result.original_content);
        }
        Err(e) => {
            println!("Unable to open \"{}\": {}", path, e);
        }
    }
}

fn remove_comments(path: &str, to_remove: &[usize], mut o_content: Vec<String>) {
    match OpenOptions::new().write(true).create(true).truncate(true).open(path) {
        Ok(mut f) => {
            let mut decal = 0;

            for line in to_remove {
                o_content.remove(line - decal);
                decal += 1;
            }
            write!(f, "{}", o_content.join("\n")).unwrap();
        }
        Err(e) => {
            println!("Cannot open '{}': {}", path, e);
        }
    }
}
<|endoftext|>


<commit_before>use config::{parse_config, Benchmark, Config};
use Commit;
use git2;
use Push;
use repo::Workspace;

use std::collections::HashMap;
use std::io;
use std::path::Path;
use std::process::{Command, ExitStatus, Output};
use std::str;

/// `(val, percentage_change)`
#[derive(Debug, Clone)]
pub enum BenchmarkResult<T> {
    Improvement(T, f64),
    Regression(T, f64),
    Neutral(T, f64),
}

#[derive(Debug, Clone)]
pub struct TastingResult {
    pub branch: Option<String>,
    pub commit: Commit,
    pub build: bool,
    pub test: bool,
    pub bench: bool,
    pub results: Option<Vec<(Benchmark, ExitStatus, HashMap<String, BenchmarkResult<f64>>)>>,
}

fn run_benchmark(workdir: &str, cfg: &Config, bench: &Benchmark, timeout: Option<u64>) -> Output {
    let mut cmd = if cfg.version.is_none() || cfg.version.unwrap() < 2 {
        // older taster configs assume an implied "cargo" prefix on each benchmark command
        match timeout {
            None => {
                let mut cmd = Command::new("cargo");
                cmd.arg(&bench.cmd);
                cmd
            }
            Some(timeout) => {
                let mut cmd = Command::new("timeout");
                cmd.arg("-k")
                    .arg(&format!("{}s", timeout + 30))
                    .arg(&format!("{}s", timeout))
                    .arg("cargo")
                    .arg(&bench.cmd);
                cmd
            }
        }
    } else {
        // from taster config version 2, we no longer assume an implicit "cargo" prefix on
        // benchmark commands
        match timeout {
            None => Command::new(&bench.cmd),
            Some(timeout) => {
                let mut cmd = Command::new("timeout");
                cmd.arg("-k")
                    .arg(&format!("{}s", timeout + 30))
                    .arg(&format!("{}s", timeout))
                    .arg(&bench.cmd);
                cmd
            }
        }
    };

    cmd.current_dir(workdir)
        .env("RUST_BACKTRACE", "1")
        .args(bench.args.as_slice());

    cmd.output()
        .expect(&format!("Failed to execute benchmark '{}'!", bench.name))
}

fn write_output(output: &Output, commit_id: git2::Oid, name: &str) {
    use std::fs::File;
    use std::io::Write;

    let mut stdout_file =
        File::create(&format!("{}-{}-stdout.log", commit_id, name)).expect(&format!(
            "Failed to create stdout log file for '{}' at commit '{}'.",
            name,
            commit_id
        ));
    stdout_file
        .write_all(output.stdout.as_slice())
        .expect("Failed to write output to stdout log file!");
    let mut stderr_file =
        File::create(&format!("{}-{}-stderr.log", commit_id, name)).expect(&format!(
            "Failed to create stderr log file for '{}' at commit '{}'.",
            name,
            commit_id
        ));
    stderr_file
        .write_all(output.stderr.as_slice())
        .expect("Failed to write output to stderr log file!");
}

fn benchmark(
    workdir: &str,
    cfg: &Config,
    bench: &Benchmark,
    commit_id: git2::Oid,
    previous_result: Option<&HashMap<String, BenchmarkResult<f64>>>,
    timeout: Option<u64>,
) -> (ExitStatus, HashMap<String, BenchmarkResult<f64>>) {
    // Run the benchmark and collect its output
    let output = run_benchmark(workdir, cfg, bench, timeout);
    write_output(&output, commit_id, &bench.name);

    let lines = str::from_utf8(output.stdout.as_slice())
        .unwrap()
        .lines()
        .chain(str::from_utf8(output.stderr.as_slice()).unwrap().lines());
    let mut res = HashMap::new();

    // Don't try parsing the output if we didn't succeed
    if !output.status.success() {
        return (output.status, res);
    }

    // Success, so let's look for the results
    for l in lines {
        for (i, regex) in bench.result_expr.iter().enumerate() {
            for cap in regex.captures_iter(l) {
                let (metric, value) = if cap.len() > 2 {
                    (String::from(cap.at(1).unwrap()), cap.at(2))
                } else {
                    (format!("{}", i), cap.at(1))
                };
                let bm_name = format!("{}/{}", bench.name, &metric);
                if let Some(c) = value {
                    use std::str::FromStr;
                    let val = match f64::from_str(&c) {
                        Ok(f) => f,
                        Err(_) => {
                            println!(
                                "failed to parse value '{}' for {} into f64 number, ignoring",
                                c,
                                bm_name
                            );
                            continue;
                        }
                    };
                    let new_result = match previous_result {
                        None => BenchmarkResult::Improvement(val, 0.0),
                        Some(prev_res) => {
                            let old_val = match prev_res.get(&bm_name) {
                                None => val,
                                Some(pv) => match *pv {
                                    BenchmarkResult::Improvement(v, _) => v,
                                    BenchmarkResult::Regression(v, _) => v,
                                    BenchmarkResult::Neutral(v, _) => v,
                                },
                            };
                            let new_result = if bench.lower_is_better {
                                if val >= old_val * (1.0 + bench.regression_threshold) {
                                    BenchmarkResult::Regression(val, (val / old_val) - 1.0)
                                } else if val < old_val * (1.0 - bench.improvement_threshold) {
                                    BenchmarkResult::Improvement(val, (val / old_val) - 1.0)
                                } else {
                                    BenchmarkResult::Neutral(val, (val / old_val) - 1.0)
                                }
                            } else {
                                if val >= old_val * (1.0 + bench.improvement_threshold) {
                                    BenchmarkResult::Improvement(val, (val / old_val) - 1.0)
                                } else if val < old_val * (1.0 - bench.regression_threshold) {
                                    BenchmarkResult::Regression(val, (val / old_val) - 1.0)
                                } else {
                                    BenchmarkResult::Neutral(val, (val / old_val) - 1.0)
                                }
                            };
                            new_result
                        }
                    };
                    res.insert(bm_name, new_result);
                }
            }
        }
    }
    (output.status, res)
}

fn build(workdir: &str) -> Output {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("build")
        .arg("--release")
        .env("RUST_BACKTRACE", "1")
        .output()
        .expect("Failed to execute 'cargo build'!")
}

pub fn taste_commit(
    ws: &Workspace,
    history: &mut HashMap<String, HashMap<String, HashMap<String, BenchmarkResult<f64>>>>,
    push: &Push,
    commit: &Commit,
    def_improvement_threshold: f64,
    def_regression_threshold: f64,
    timeout: Option<u64>,
) -> Result<(Option<Config>, TastingResult), String> {
    println!("Tasting commit {}", commit.id);
    ws.checkout_commit(&commit.id)?;

    let branch = match push.push_ref {
        None => None,
        Some(ref pr) => match pr.rfind("/") {
            None => None,
            Some(i) => Some(String::from(&pr[i + 1..])),
        },
    };

    let do_update = !Path::new(&format!("{}/Cargo.lock", ws.path)).exists();

    let build_success = {
        let update_success = if do_update {
            println!("running 'cargo update'");
            let update_output = update(&ws.path);
            if !update_output.status.success() {
                println!("update failed: output status is {:?}", update_output.status);
            }
            update_output.status.success()
        } else {
            // nothing to do, always succeeds
            true
        };

        let build_output = build(&ws.path);
        write_output(&build_output, commit.id, "build");
        if !build_output.status.success() {
            println!("build failed: output status is {:?}", build_output.status);
        }

        update_success && build_output.status.success()
    };

    let test_output = test(&ws.path, timeout);
    write_output(&test_output, commit.id, "test");

    if !test_output.status.success() {
        println!("tests failed: output status is {:?}", test_output.status);
    }

    let cfg = match parse_config(
        Path::new(&format!("{}/taster.toml", ws.path)),
        def_improvement_threshold,
        def_regression_threshold,
    ) {
        Ok(c) => c,
        Err(e) => match e.kind() {
            io::ErrorKind::NotFound => {
                println!(
                    "Skipping commit {} which doesn't have a Taster config.",
                    commit.id
                );
                return Ok((
                    None,
                    TastingResult {
                        branch: branch,
                        commit: commit.clone(),
                        build: build_success,
                        test: test_output.status.success(),
                        bench: false,
                        results: None,
                    },
                ));
            }
            io::ErrorKind::InvalidInput => {
                println!(
                    "Skipping commit {} which has an invalid Taster config.",
                    commit.id
                );
                return Ok((
                    None,
                    TastingResult {
                        branch: branch,
                        commit: commit.clone(),
                        build: build_success,
                        test: test_output.status.success(),
                        bench: false,
                        results: None,
                    },
                ));
            }
            _ => unimplemented!(),
        },
    };

    let bench_results =
        match branch {
            Some(ref branch) => {
                let branch_history = history.entry(branch.clone()).or_insert(HashMap::new());
                cfg.benchmarks
                .iter()
                .map(|b| {
                    let (status, res) =
                        benchmark(&ws.path, &cfg, b, commit.id, branch_history.get(&b.name),
                                  timeout);
                    branch_history.insert(b.name.clone(), res.clone());
                    (b.clone(), status, res)
                })
                .collect::<Vec<(Benchmark, ExitStatus, HashMap<String, BenchmarkResult<f64>>)>>()
            }
            None => cfg.benchmarks
                .iter()
                .map(|b| {
                    let (status, res) = benchmark(&ws.path, &cfg, b, commit.id, None, timeout);
                    (b.clone(), status, res)
                })
                .collect::<Vec<(Benchmark, ExitStatus, HashMap<String, BenchmarkResult<f64>>)>>(),
        };
    let bench_success = bench_results.iter().all(|x| x.1.success());

    Ok((
        Some(cfg),
        TastingResult {
            branch: branch,
            commit: commit.clone(),
            build: build_success,
            test: test_output.status.success(),
            bench: bench_success,
            results: Some(bench_results),
        },
    ))
}

fn test(workdir: &str, timeout: Option<u64>) -> Output {
    let mut cmd = match timeout {
        None => {
            let mut cmd = Command::new("cargo");
            cmd.arg("test");
            cmd
        }
        Some(timeout) => {
            let mut cmd = Command::new("timeout");
            cmd.arg("-k")
                .arg(&format!("{}s", timeout + 30))
                .arg(&format!("{}s", timeout))
                .arg("cargo")
                .arg("test");
            cmd
        }
    };
    cmd.current_dir(workdir)
        .env("RUST_BACKTRACE", "1")
        .env("RUST_TEST_THREADS", "1")
        .output()
        .expect("Failed to execute 'cargo test'!")
}

fn update(workdir: &str) -> Output {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("update")
        .output()
        .expect("Failed to execute 'cargo update'!")
}
<commit_msg>rustfmt<commit_after>use config::{parse_config, Benchmark, Config};
use Commit;
use git2;
use Push;
use repo::Workspace;

use std::collections::HashMap;
use std::io;
use std::path::Path;
use std::process::{Command, ExitStatus, Output};
use std::str;

/// `(val, percentage_change)`
#[derive(Debug, Clone)]
pub enum BenchmarkResult<T> {
    Improvement(T, f64),
    Regression(T, f64),
    Neutral(T, f64),
}

#[derive(Debug, Clone)]
pub struct TastingResult {
    pub branch: Option<String>,
    pub commit: Commit,
    pub build: bool,
    pub test: bool,
    pub bench: bool,
    pub results: Option<Vec<(Benchmark, ExitStatus, HashMap<String, BenchmarkResult<f64>>)>>,
}

fn run_benchmark(workdir: &str, cfg: &Config, bench: &Benchmark, timeout: Option<u64>) -> Output {
    let mut cmd = if cfg.version.is_none() || cfg.version.unwrap() < 2 {
        // older taster configs assume an implied "cargo" prefix on each benchmark command
        match timeout {
            None => {
                let mut cmd = Command::new("cargo");
                cmd.arg(&bench.cmd);
                cmd
            }
            Some(timeout) => {
                let mut cmd = Command::new("timeout");
                cmd.arg("-k")
                    .arg(&format!("{}s", timeout + 30))
                    .arg(&format!("{}s", timeout))
                    .arg("cargo")
                    .arg(&bench.cmd);
                cmd
            }
        }
    } else {
        // from taster config version 2, we no longer assume an implicit "cargo" prefix on
        // benchmark commands
        match timeout {
            None => Command::new(&bench.cmd),
            Some(timeout) => {
                let mut cmd = Command::new("timeout");
                cmd.arg("-k")
                    .arg(&format!("{}s", timeout + 30))
                    .arg(&format!("{}s", timeout))
                    .arg(&bench.cmd);
                cmd
            }
        }
    };

    cmd.current_dir(workdir)
        .env("RUST_BACKTRACE", "1")
        .args(bench.args.as_slice());

    cmd.output()
        .expect(&format!("Failed to execute benchmark '{}'!", bench.name))
}

fn write_output(output: &Output, commit_id: git2::Oid, name: &str) {
    use std::fs::File;
    use std::io::Write;

    let mut stdout_file =
        File::create(&format!("{}-{}-stdout.log", commit_id, name)).expect(&format!(
            "Failed to create stdout log file for '{}' at commit '{}'.",
            name, commit_id
        ));
    stdout_file
        .write_all(output.stdout.as_slice())
        .expect("Failed to write output to stdout log file!");
    let mut stderr_file =
        File::create(&format!("{}-{}-stderr.log", commit_id, name)).expect(&format!(
            "Failed to create stderr log file for '{}' at commit '{}'.",
            name, commit_id
        ));
    stderr_file
        .write_all(output.stderr.as_slice())
        .expect("Failed to write output to stderr log file!");
}

fn benchmark(
    workdir: &str,
    cfg: &Config,
    bench: &Benchmark,
    commit_id: git2::Oid,
    previous_result: Option<&HashMap<String, BenchmarkResult<f64>>>,
    timeout: Option<u64>,
) -> (ExitStatus, HashMap<String, BenchmarkResult<f64>>) {
    // Run the benchmark and collect its output
    let output = run_benchmark(workdir, cfg, bench, timeout);
    write_output(&output, commit_id, &bench.name);

    let lines = str::from_utf8(output.stdout.as_slice())
        .unwrap()
        .lines()
        .chain(str::from_utf8(output.stderr.as_slice()).unwrap().lines());
    let mut res = HashMap::new();

    // Don't try parsing the output if we didn't succeed
    if !output.status.success() {
        return (output.status, res);
    }

    // Success, so let's look for the results
    for l in lines {
        for (i, regex) in bench.result_expr.iter().enumerate() {
            for cap in regex.captures_iter(l) {
                let (metric, value) = if cap.len() > 2 {
                    (String::from(cap.at(1).unwrap()), cap.at(2))
                } else {
                    (format!("{}", i), cap.at(1))
                };
                let bm_name = format!("{}/{}", bench.name, &metric);
                if let Some(c) = value {
                    use std::str::FromStr;
                    let val = match f64::from_str(&c) {
                        Ok(f) => f,
                        Err(_) => {
                            println!(
                                "failed to parse value '{}' for {} into f64 number, ignoring",
                                c, bm_name
                            );
                            continue;
                        }
                    };
                    let new_result = match previous_result {
                        None => BenchmarkResult::Improvement(val, 0.0),
                        Some(prev_res) => {
                            let old_val = match prev_res.get(&bm_name) {
                                None => val,
                                Some(pv) => match *pv {
                                    BenchmarkResult::Improvement(v, _) => v,
                                    BenchmarkResult::Regression(v, _) => v,
                                    BenchmarkResult::Neutral(v, _) => v,
                                },
                            };
                            let new_result = if bench.lower_is_better {
                                if val >= old_val * (1.0 + bench.regression_threshold) {
                                    BenchmarkResult::Regression(val, (val / old_val) - 1.0)
                                } else if val < old_val * (1.0 - bench.improvement_threshold) {
                                    BenchmarkResult::Improvement(val, (val / old_val) - 1.0)
                                } else {
                                    BenchmarkResult::Neutral(val, (val / old_val) - 1.0)
                                }
                            } else {
                                if val >= old_val * (1.0 + bench.improvement_threshold) {
                                    BenchmarkResult::Improvement(val, (val / old_val) - 1.0)
                                } else if val < old_val * (1.0 - bench.regression_threshold) {
                                    BenchmarkResult::Regression(val, (val / old_val) - 1.0)
                                } else {
                                    BenchmarkResult::Neutral(val, (val / old_val) - 1.0)
                                }
                            };
                            new_result
                        }
                    };
                    res.insert(bm_name, new_result);
                }
            }
        }
    }
    (output.status, res)
}

fn build(workdir: &str) -> Output {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("build")
        .arg("--release")
        .env("RUST_BACKTRACE", "1")
        .output()
        .expect("Failed to execute 'cargo build'!")
}

pub fn taste_commit(
    ws: &Workspace,
    history: &mut HashMap<String, HashMap<String, HashMap<String, BenchmarkResult<f64>>>>,
    push: &Push,
    commit: &Commit,
    def_improvement_threshold: f64,
    def_regression_threshold: f64,
    timeout: Option<u64>,
) -> Result<(Option<Config>, TastingResult), String> {
    println!("Tasting commit {}", commit.id);
    ws.checkout_commit(&commit.id)?;

    let branch = match push.push_ref {
        None => None,
        Some(ref pr) => match pr.rfind("/") {
            None => None,
            Some(i) => Some(String::from(&pr[i + 1..])),
        },
    };

    let do_update = !Path::new(&format!("{}/Cargo.lock", ws.path)).exists();

    let build_success = {
        let update_success = if do_update {
            println!("running 'cargo update'");
            let update_output = update(&ws.path);
            if !update_output.status.success() {
                println!("update failed: output status is {:?}", update_output.status);
            }
            update_output.status.success()
        } else {
            // nothing to do, always succeeds
            true
        };

        let build_output = build(&ws.path);
        write_output(&build_output, commit.id, "build");
        if !build_output.status.success() {
            println!("build failed: output status is {:?}", build_output.status);
        }

        update_success && build_output.status.success()
    };

    let test_output = test(&ws.path, timeout);
    write_output(&test_output, commit.id, "test");

    if !test_output.status.success() {
        println!("tests failed: output status is {:?}", test_output.status);
    }

    let cfg = match parse_config(
        Path::new(&format!("{}/taster.toml", ws.path)),
        def_improvement_threshold,
        def_regression_threshold,
    ) {
        Ok(c) => c,
        Err(e) => match e.kind() {
            io::ErrorKind::NotFound => {
                println!(
                    "Skipping commit {} which doesn't have a Taster config.",
                    commit.id
                );
                return Ok((
                    None,
                    TastingResult {
                        branch: branch,
                        commit: commit.clone(),
                        build: build_success,
                        test: test_output.status.success(),
                        bench: false,
                        results: None,
                    },
                ));
            }
            io::ErrorKind::InvalidInput => {
                println!(
                    "Skipping commit {} which has an invalid Taster config.",
                    commit.id
                );
                return Ok((
                    None,
                    TastingResult {
                        branch: branch,
                        commit: commit.clone(),
                        build: build_success,
                        test: test_output.status.success(),
                        bench: false,
                        results: None,
                    },
                ));
            }
            _ => unimplemented!(),
        },
    };

    let bench_results =
        match branch {
            Some(ref branch) => {
                let branch_history = history.entry(branch.clone()).or_insert(HashMap::new());
                cfg.benchmarks
                .iter()
                .map(|b| {
                    let (status, res) =
                        benchmark(&ws.path, &cfg, b, commit.id, branch_history.get(&b.name),
                                  timeout);
                    branch_history.insert(b.name.clone(), res.clone());
                    (b.clone(), status, res)
                })
                .collect::<Vec<(Benchmark, ExitStatus, HashMap<String, BenchmarkResult<f64>>)>>()
            }
            None => cfg.benchmarks
                .iter()
                .map(|b| {
                    let (status, res) = benchmark(&ws.path, &cfg, b, commit.id, None, timeout);
                    (b.clone(), status, res)
                })
                .collect::<Vec<(Benchmark, ExitStatus, HashMap<String, BenchmarkResult<f64>>)>>(),
        };
    let bench_success = bench_results.iter().all(|x| x.1.success());

    Ok((
        Some(cfg),
        TastingResult {
            branch: branch,
            commit: commit.clone(),
            build: build_success,
            test: test_output.status.success(),
            bench: bench_success,
            results: Some(bench_results),
        },
    ))
}

fn test(workdir: &str, timeout: Option<u64>) -> Output {
    let mut cmd = match timeout {
        None => {
            let mut cmd = Command::new("cargo");
            cmd.arg("test");
            cmd
        }
        Some(timeout) => {
            let mut cmd = Command::new("timeout");
            cmd.arg("-k")
                .arg(&format!("{}s", timeout + 30))
                .arg(&format!("{}s", timeout))
                .arg("cargo")
                .arg("test");
            cmd
        }
    };
    cmd.current_dir(workdir)
        .env("RUST_BACKTRACE", "1")
        .env("RUST_TEST_THREADS", "1")
        .output()
        .expect("Failed to execute 'cargo test'!")
}

fn update(workdir: &str) -> Output {
    Command::new("cargo")
        .current_dir(workdir)
        .arg("update")
        .output()
        .expect("Failed to execute 'cargo update'!")
}
<|endoftext|>


<commit_before>
pub struct Timer {
	priv divider: u8,
	priv counter: u8,
	priv modulo: u8,
	priv control: u8,
	priv internalcnt: uint,
	interrupt: u8,
}

impl Timer {
	pub fn new() -> Timer {
		Timer {
			divider: 0,
			counter: 0,
			modulo: 0,
			control: 0,
			internalcnt: 0,
			interrupt: 0,
		}
	}

	pub fn rb(&self, a: u16) -> u8 {
		match a {
			0xFF04 => self.divider,
			0xFF05 => self.counter,
			0xFF06 => self.modulo,
			0xFF07 => self.control,
			_ => fail!("Timer does not handler read {:4X}", a),
		}
	}

	pub fn wb(&mut self, a: u16, v: u8) {
		match a {
			0xFF04 => { self.divider = 0; },
			0xFF05 => { self.counter = v; },
			0xFF06 => { self.modulo = v; },
			0xFF07 => { self.control = v; },
			_ => fail!("Timer does not handler write {:4X}", a),
		};
	}

	pub fn step(&mut self, mut ticks: uint) {
		let step = match self.control & 0x03 {
			0 => 256,
			1 => 4,
			2 => 16,
			3 => 64,
			_ => { fail!("There is something very very wrong..."); },
		};

		self.internalcnt %= 256;

		while ticks > 0 {
			ticks -= 1;
			self.internalcnt += 1;
			if self.internalcnt % 64 == 0 { self.divider += 1; };
			if self.control & 0x04 == 0 { continue; };
			if self.internalcnt % step == 0 {
				self.counter += 1;
				if self.counter == 0 {
					self.counter = self.modulo;
					self.interrupt |= 0x04;
				}
			}
		};
	}
}

<commit_msg>Updated Timer logic<commit_after>
pub struct Timer {
	priv divider: u8,
	priv counter: u8,
	priv modulo: u8,
	priv enabled: bool,
	priv step: uint,
	priv internalcnt: uint,
	priv internaldiv: uint,
	interrupt: u8,
}

impl Timer {
	pub fn new() -> Timer {
		Timer {
			divider: 0,
			counter: 0,
			modulo: 0,
			enabled: true,
			step: 256,
			internalcnt: 0,
			internaldiv: 0,
			interrupt: 0,
		}
	}

	pub fn rb(&self, a: u16) -> u8 {
		match a {
			0xFF04 => self.divider,
			0xFF05 => self.counter,
			0xFF06 => self.modulo,
			0xFF07 => {
				(if self.enabled { 0x4 } else { 0 }) |
				(match self.step { 4 => 1, 16 => 2, 64 => 3, _ => 0 })
			}
			_ => fail!("Timer does not handler read {:4X}", a),
		}
	}

	pub fn wb(&mut self, a: u16, v: u8) {
		match a {
			0xFF04 => { self.divider = 0; },
			0xFF05 => { self.counter = v; },
			0xFF06 => { self.modulo = v; },
			0xFF07 => {
				self.enabled = v & 0x4 == 0x4;
				self.step = match v & 0x3 { 1 => 4, 2 => 16, 3 => 64, _ => 256 };
			},
			_ => fail!("Timer does not handler write {:4X}", a),
		};
	}

	pub fn cycle(&mut self, ticks: uint) {
		self.internaldiv += ticks;
		while self.internaldiv >= 64 {
			self.divider += 1;
			self.internaldiv -= 64;
		}

		if self.enabled {
			self.internalcnt += ticks;

			while self.internalcnt >= self.step {
				self.counter += 1;
				if self.counter == 0 {
					self.counter = self.modulo;
					self.interrupt |= 0x04;
				}
				self.internalcnt -= self.step;
			}
		}
	}
}

<|endoftext|>


<commit_before>use std::collections::HashMap;

#[derive(Serialize, Deserialize, Debug)]
pub struct Account {
    #[serde(default)]
    pub short_name: String,

    #[serde(default)]
    pub author_name: String,

    #[serde(default)]
    pub author_url: String,

    #[serde(default)]
    pub access_token: String,

    #[serde(default)]
    pub auth_url: String,

    #[serde(default)]
    pub page_count: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct CreateAccountResponse {
    pub ok: bool,
    pub result: Account,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EditAccountResponse {
    pub ok: bool,
    pub result: Account,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Page {
    pub path: String,
    pub url: String,
    pub title: String,
    pub description: String,

    #[serde(default)]
    pub author_name: String,

    #[serde(default)]
    pub author_url: String,

    #[serde(default)]
    pub image_url: String,

    #[serde(default)]
    pub content: Vec<Node>,
    pub views: i32,

    #[serde(default)]
    pub can_edit: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PageList {
    pub total_count: i32,
    pub pages: Vec<Page>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PageViews {
    pub views: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Node {}

#[derive(Serialize, Deserialize, Debug)]
pub struct NodeElement {
    pub tag: String,

    #[serde(default)]
    pub attrs: HashMap<String, String>,

    #[serde(default)]
    pub children: Vec<Node>,
}
<commit_msg>implemented Default trait for Account struct<commit_after>use std::default::Default;
use std::collections::HashMap;

#[derive(Serialize, Deserialize, Debug)]
pub struct Account {
    #[serde(default)]
    pub short_name: String,

    #[serde(default)]
    pub author_name: String,

    #[serde(default)]
    pub author_url: String,

    #[serde(default)]
    pub access_token: String,

    #[serde(default)]
    pub auth_url: String,

    #[serde(default)]
    pub page_count: i32,
}

impl Default for Account {
    fn default() -> Self {
        Account {
            short_name: String::new(),
            author_name: String::new(),
            author_url: String::new(),
            access_token: String::new(),
            auth_url: String::new(),
            page_count: 0,
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct CreateAccountResponse {
    pub ok: bool,
    pub result: Account,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct EditAccountResponse {
    pub ok: bool,
    pub result: Account,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Page {
    pub path: String,
    pub url: String,
    pub title: String,
    pub description: String,

    #[serde(default)]
    pub author_name: String,

    #[serde(default)]
    pub author_url: String,

    #[serde(default)]
    pub image_url: String,

    #[serde(default)]
    pub content: Vec<Node>,
    pub views: i32,

    #[serde(default)]
    pub can_edit: bool,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PageList {
    pub total_count: i32,
    pub pages: Vec<Page>,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct PageViews {
    pub views: i32,
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Node {}

#[derive(Serialize, Deserialize, Debug)]
pub struct NodeElement {
    pub tag: String,

    #[serde(default)]
    pub attrs: HashMap<String, String>,

    #[serde(default)]
    pub children: Vec<Node>,
}
<|endoftext|>


<commit_before>#![doc(html_root_url = "https://urschrei.github.io/lonlat_bng/")]
//! This module provides utilities to the conversions module
use conversions::MIN_X_SHIFT;
use conversions::MIN_Y_SHIFT;
use conversions::MIN_Z_SHIFT;

use std;
use std::fmt;
use ostn02_phf::ostn02_lookup;

/// Bounds checking for input values
pub fn check<T>(to_check: T, bounds: (T, T)) -> Result<T, ()>
    where T: std::cmp::PartialOrd + fmt::Display + Copy
{
    match to_check {
        to_check if bounds.0 <= to_check && to_check <= bounds.1 => Ok(to_check),
        _ => Err(()),
    }
}

// TODO Herbie's going to have a field day with this
/// Round Easting, Northing, and Orthometric height to the nearest millimetre
pub fn round_to_nearest_mm(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
    let new_x = (x * 1000.).round() as f64 / 1000.;
    let new_y = (y * 1000.).round() as f64 / 1000.;
    let new_z = (z * 1000.).round() as f64 / 1000.;
    (new_x, new_y, new_z)
}

// TODO Herbie's going to have a field day with this
/// Round a float to nine decimal places
pub fn round_to_eight(x: f64, y: f64) -> (f64, f64) {
    let new_x = (x * 100000000.).round() as f64 / 100000000.;
    let new_y = (y * 100000000.).round() as f64 / 100000000.;
    (new_x, new_y)
}

// Try to get OSTN02 shift parameters, and calculate offsets
pub fn get_ostn_ref(x: &i32, y: &i32) -> Result<(f64, f64, f64), ()> {
    let key = format!("{:03x}{:03x}", y, x);
    // some or None, so try! this
    let lookup = ostn02_lookup(&*key);
    let intermediate = lookup.ok_or(());
    let result = intermediate.unwrap();
    Ok((result.0 as f64 / 1000. + MIN_X_SHIFT,
        result.1 as f64 / 1000. + MIN_Y_SHIFT,
        result.2 as f64 / 1000. + MIN_Z_SHIFT))

}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
pub fn ostn02_shifts(x: &f64, y: &f64) -> Result<(f64, f64, f64), ()> {
    let e_index = (*x / 1000.) as i32;
    let n_index = (*y / 1000.) as i32;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index * 1000;
    let y0 = n_index * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!
    let s0: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 0), &(n_index + 0)));
    let s1: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 0)));
    let s2: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 0), &(n_index + 1)));
    let s3: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 1)));

    // offset within square
    let dx = *x - (x0 as f64);
    let dy = *y - (y0 as f64);

    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0.0 + f1 * s1.0 + f2 * s2.0 + f3 * s3.0;
    let sn = f0 * s0.1 + f1 * s1.1 + f2 * s2.1 + f3 * s3.1;
    let sg = f0 * s0.2 + f1 * s1.2 + f2 * s2.2 + f3 * s3.2;

    Ok(round_to_nearest_mm(se, sn, sg))

}

#[cfg(test)]
mod tests {
    use super::get_ostn_ref;
    use super::ostn02_shifts;
    use super::check;

    #[test]
    // original coordinates are 651307.003, 313255.686
    fn test_ostn_hashmap_retrieval() {
        let eastings = 651;
        let northings = 313;
        let expected = (102.775, -78.244, 44.252);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    fn test_ostn02_shift_incorporation() {
        // these are the input values and corrections on p20-21
        let eastings = 651307.003;
        let northings = 313255.686;
        let expected = (102.789, -78.238, 44.244);
        assert_eq!(expected, ostn02_shifts(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_min_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // below min_lon
        check(&-6.379881, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_min_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // below min lat
        check(&49.871158, (&min_lat, &max_lat)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // above max lon
        check(&1.768961, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // above max lat
        check(&55.811742, (&min_lat, &max_lat)).unwrap();
    }

}
<commit_msg>try! the converted Option result from the shift retrieval function<commit_after>#![doc(html_root_url = "https://urschrei.github.io/lonlat_bng/")]
//! This module provides utilities to the conversions module
use conversions::MIN_X_SHIFT;
use conversions::MIN_Y_SHIFT;
use conversions::MIN_Z_SHIFT;

use std;
use std::fmt;
use ostn02_phf::ostn02_lookup;

/// Bounds checking for input values
pub fn check<T>(to_check: T, bounds: (T, T)) -> Result<T, ()>
    where T: std::cmp::PartialOrd + fmt::Display + Copy
{
    match to_check {
        to_check if bounds.0 <= to_check && to_check <= bounds.1 => Ok(to_check),
        _ => Err(()),
    }
}

// TODO Herbie's going to have a field day with this
/// Round Easting, Northing, and Orthometric height to the nearest millimetre
pub fn round_to_nearest_mm(x: f64, y: f64, z: f64) -> (f64, f64, f64) {
    let new_x = (x * 1000.).round() as f64 / 1000.;
    let new_y = (y * 1000.).round() as f64 / 1000.;
    let new_z = (z * 1000.).round() as f64 / 1000.;
    (new_x, new_y, new_z)
}

// TODO Herbie's going to have a field day with this
/// Round a float to nine decimal places
pub fn round_to_eight(x: f64, y: f64) -> (f64, f64) {
    let new_x = (x * 100000000.).round() as f64 / 100000000.;
    let new_y = (y * 100000000.).round() as f64 / 100000000.;
    (new_x, new_y)
}

// Try to get OSTN02 shift parameters, and calculate offsets
pub fn get_ostn_ref(x: &i32, y: &i32) -> Result<(f64, f64, f64), ()> {
    let key = format!("{:03x}{:03x}", y, x);
    // some or None, so try! this
    let result = try!(ostn02_lookup(&*key).ok_or(()));
    Ok((result.0 as f64 / 1000. + MIN_X_SHIFT,
        result.1 as f64 / 1000. + MIN_Y_SHIFT,
        result.2 as f64 / 1000. + MIN_Z_SHIFT))

}

// Input values must be valid ETRS89 grid references
// See p20 of the transformation user guide at
// https://www.ordnancesurvey.co.uk/business-and-government/help-and-support/navigation-technology/os-net/formats-for-developers.html
pub fn ostn02_shifts(x: &f64, y: &f64) -> Result<(f64, f64, f64), ()> {
    let e_index = (*x / 1000.) as i32;
    let n_index = (*y / 1000.) as i32;

    // eastings and northings of the south-west corner of the cell
    let x0 = e_index * 1000;
    let y0 = n_index * 1000;

    // The easting, northing and geoid shifts for the four corners of the cell
    // any of these could be Err, so use try!
    let s0: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 0), &(n_index + 0)));
    let s1: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 0)));
    let s2: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 0), &(n_index + 1)));
    let s3: (f64, f64, f64) = try!(get_ostn_ref(&(e_index + 1), &(n_index + 1)));

    // offset within square
    let dx = *x - (x0 as f64);
    let dy = *y - (y0 as f64);

    let t = dx / 1000.;
    let u = dy / 1000.;

    let f0 = (1. - t as f64) * (1. - u as f64);
    let f1 = t as f64 * (1. - u as f64);
    let f2 = (1. - t as f64) * u as f64;
    let f3 = t as f64 * u as f64;

    // bilinear interpolation, to obtain the actual shifts
    let se = f0 * s0.0 + f1 * s1.0 + f2 * s2.0 + f3 * s3.0;
    let sn = f0 * s0.1 + f1 * s1.1 + f2 * s2.1 + f3 * s3.1;
    let sg = f0 * s0.2 + f1 * s1.2 + f2 * s2.2 + f3 * s3.2;

    Ok(round_to_nearest_mm(se, sn, sg))

}

#[cfg(test)]
mod tests {
    use super::get_ostn_ref;
    use super::ostn02_shifts;
    use super::check;

    #[test]
    // original coordinates are 651307.003, 313255.686
    fn test_ostn_hashmap_retrieval() {
        let eastings = 651;
        let northings = 313;
        let expected = (102.775, -78.244, 44.252);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_failed_ostn_hashmap_retrieval() {
        // we're try!ing this in the shift calculation function, so an Err is fine
        let eastings = 999;
        let northings = 999;
        let expected = (1., 1., 1.);
        assert_eq!(expected, get_ostn_ref(&eastings, &northings).unwrap());
    }

    #[test]
    fn test_ostn02_shift_incorporation() {
        // these are the input values and corrections on p20-21
        let eastings = 651307.003;
        let northings = 313255.686;
        let expected = (102.789, -78.238, 44.244);
        assert_eq!(expected, ostn02_shifts(&eastings, &northings).unwrap());
    }

    #[test]
    #[should_panic]
    fn test_min_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // below min_lon
        check(&-6.379881, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_min_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // below min lat
        check(&49.871158, (&min_lat, &max_lat)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lon_extents() {
        let max_lon = 1.768960;
        let min_lon = -6.379880;
        // above max lon
        check(&1.768961, (&min_lon, &max_lon)).unwrap();
    }

    #[test]
    #[should_panic]
    fn test_max_lat_extents() {
        let max_lat = 55.811741;
        let min_lat = 49.871159;
        // above max lat
        check(&55.811742, (&min_lat, &max_lat)).unwrap();
    }

}
<|endoftext|>