<commit_before>use std::cell::UnsafeCell;
use std::io;
#[cfg(target_os = "linux")]
use std::os::unix::io::AsRawFd;
#[cfg(target_os = "linux")]
use std::convert::From;
use std::sync::Arc;
use std::thread;
#[cfg(target_os = "linux")]
use std::mem;

use coroutine::{State, Handle, Coroutine};

use mio::{EventLoop, Evented, Handler, Token, ReadHint, Interest, PollOpt};
use mio::util::Slab;
#[cfg(target_os = "linux")]
use mio::Io;

use mio::util::BoundedQueue;

use scheduler::Scheduler;

thread_local!(static PROCESSOR: UnsafeCell<Processor> = UnsafeCell::new(Processor::new()));

pub struct Processor {
    event_loop: EventLoop<IoHandler>,
    work_queue: Arc<BoundedQueue<Handle>>,
    handler: IoHandler,
}

impl Processor {
    pub fn new() -> Processor {
        Processor {
            event_loop: EventLoop::new().unwrap(),
            work_queue: Scheduler::get().get_queue(),
            handler: IoHandler::new(),
        }
    }

    pub fn current() -> &'static mut Processor {
        PROCESSOR.with(|p| unsafe { &mut *p.get() })
    }

    pub fn schedule(&mut self) -> io::Result<()> {
        loop {
            if self.handler.slabs.count() != 0 {
                try!(self.event_loop.run_once(&mut self.handler));
            }

            match self.work_queue.pop() {
                Some(hdl) => {
                    match hdl.resume() {
                        Ok(State::Suspended) => {
                            Scheduler::ready(hdl);
                        },
                        Ok(State::Finished) | Ok(State::Panicked) => {
                            Scheduler::finished(hdl);
                        },
                        Ok(State::Blocked) => (),
                        Ok(..) => unreachable!(),
                        Err(err) => {
                            error!("Coroutine resume failed, {:?}", err);
                            Scheduler::finished(hdl);
                        }
                    }
                },
                None => {
                    if Scheduler::get().work_count() == 0 {
                        break;
                    }
                    if self.handler.slabs.count() == 0 {
                        thread::sleep_ms(100);
                    }
                }
            }
        }

        Ok(())
    }
}

const MAX_TOKEN_NUM: usize = 102400;
impl IoHandler {
    fn new() -> IoHandler {
        IoHandler {
            slabs: Slab::new(MAX_TOKEN_NUM),
        }
    }
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
impl Processor {
    pub fn wait_event<E: Evented + AsRawFd>(&mut self, fd: &E, interest: Interest) -> io::Result<()> {
        let token = self.handler.slabs.insert((Coroutine::current().clone(), From::from(fd.as_raw_fd()))).unwrap();
        try!(self.event_loop.register_opt(fd, token, interest,
                                         PollOpt::level()|PollOpt::oneshot()));

        debug!("wait_event: Blocked current Coroutine ...; token={:?}", token);
        Coroutine::block();
        debug!("wait_event: Waked up; token={:?}", token);

        Ok(())
    }
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
struct IoHandler {
    slabs: Slab<(Handle, Io)>,
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
impl Handler for IoHandler {
    type Timeout = ();
    type Message = ();

    fn writable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {

        debug!("In writable, token {:?}", token);

        match self.slabs.remove(token) {
            Some((hdl, fd)) => {
                // Linux EPoll needs to explicit EPOLL_CTL_DEL the fd
                event_loop.deregister(&fd).unwrap();
                mem::forget(fd);
                Scheduler::ready(hdl);
            },
            None => {
                warn!("No coroutine is waiting on writable {:?}", token);
            }
        }

    }

    fn readable(&mut self, event_loop: &mut EventLoop<Self>, token: Token, hint: ReadHint) {

        debug!("In readable, token {:?}, hint {:?}", token, hint);

        match self.slabs.remove(token) {
            Some((hdl, fd)) => {
                // Linux EPoll needs to explicit EPOLL_CTL_DEL the fd
                event_loop.deregister(&fd).unwrap();
                mem::forget(fd);
                Scheduler::ready(hdl);
            },
            None => {
                warn!("No coroutine is waiting on readable {:?}", token);
            }
        }

    }
}

#[cfg(any(target_os = "macos",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "openbsd"))]
impl Processor {
    pub fn wait_event<E: Evented>(&mut self, fd: &E, interest: Interest) -> io::Result<()> {
        let token = self.handler.slabs.insert(Coroutine::current().clone()).unwrap();
        try!(self.event_loop.register_opt(fd, token, interest,
                                         PollOpt::level()|PollOpt::oneshot()));

        debug!("wait_event: Blocked current Coroutine ...; token={:?}", token);
        Coroutine::block();
        debug!("wait_event: Waked up; token={:?}", token);

        Ok(())
    }
}

#[cfg(any(target_os = "macos",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "openbsd"))]
struct IoHandler {
    slabs: Slab<Handle>,
}

#[cfg(any(target_os = "macos",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "openbsd"))]
impl Handler for IoHandler {
    type Timeout = ();
    type Message = ();

    fn writable(&mut self, _: &mut EventLoop<Self>, token: Token) {

        debug!("In writable, token {:?}", token);

        match self.slabs.remove(token) {
            Some(hdl) => {
                Scheduler::ready(hdl);
            },
            None => {
                warn!("No coroutine is waiting on writable {:?}", token);
            }
        }

    }

    fn readable(&mut self, _: &mut EventLoop<Self>, token: Token, hint: ReadHint) {

        debug!("In readable, token {:?}, hint {:?}", token, hint);

        match self.slabs.remove(token) {
            Some(hdl) => {
                Scheduler::ready(hdl);
            },
            None => {
                warn!("No coroutine is waiting on readable {:?}", token);
            }
        }

    }
}
<commit_msg>use edge trigger<commit_after>use std::cell::UnsafeCell;
use std::io;
#[cfg(target_os = "linux")]
use std::os::unix::io::AsRawFd;
#[cfg(target_os = "linux")]
use std::convert::From;
use std::sync::Arc;
use std::thread;
#[cfg(target_os = "linux")]
use std::mem;

use coroutine::{State, Handle, Coroutine};

use mio::{EventLoop, Evented, Handler, Token, ReadHint, Interest, PollOpt};
use mio::util::Slab;
#[cfg(target_os = "linux")]
use mio::Io;

use mio::util::BoundedQueue;

use scheduler::Scheduler;

thread_local!(static PROCESSOR: UnsafeCell<Processor> = UnsafeCell::new(Processor::new()));

pub struct Processor {
    event_loop: EventLoop<IoHandler>,
    work_queue: Arc<BoundedQueue<Handle>>,
    handler: IoHandler,
}

impl Processor {
    pub fn new() -> Processor {
        Processor {
            event_loop: EventLoop::new().unwrap(),
            work_queue: Scheduler::get().get_queue(),
            handler: IoHandler::new(),
        }
    }

    pub fn current() -> &'static mut Processor {
        PROCESSOR.with(|p| unsafe { &mut *p.get() })
    }

    pub fn schedule(&mut self) -> io::Result<()> {
        loop {
            if self.handler.slabs.count() != 0 {
                try!(self.event_loop.run_once(&mut self.handler));
            }

            match self.work_queue.pop() {
                Some(hdl) => {
                    match hdl.resume() {
                        Ok(State::Suspended) => {
                            Scheduler::ready(hdl);
                        },
                        Ok(State::Finished) | Ok(State::Panicked) => {
                            Scheduler::finished(hdl);
                        },
                        Ok(State::Blocked) => (),
                        Ok(..) => unreachable!(),
                        Err(err) => {
                            error!("Coroutine resume failed, {:?}", err);
                            Scheduler::finished(hdl);
                        }
                    }
                },
                None => {
                    if Scheduler::get().work_count() == 0 {
                        break;
                    }
                    if self.handler.slabs.count() == 0 {
                        thread::sleep_ms(100);
                    }
                }
            }
        }

        Ok(())
    }
}

const MAX_TOKEN_NUM: usize = 102400;
impl IoHandler {
    fn new() -> IoHandler {
        IoHandler {
            slabs: Slab::new(MAX_TOKEN_NUM),
        }
    }
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
impl Processor {
    pub fn wait_event<E: Evented + AsRawFd>(&mut self, fd: &E, interest: Interest) -> io::Result<()> {
        let token = self.handler.slabs.insert((Coroutine::current().clone(), From::from(fd.as_raw_fd()))).unwrap();
        try!(self.event_loop.register_opt(fd, token, interest,
                                          PollOpt::edge()|PollOpt::oneshot()));

        debug!("wait_event: Blocked current Coroutine ...; token={:?}", token);
        Coroutine::block();
        debug!("wait_event: Waked up; token={:?}", token);

        Ok(())
    }
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
struct IoHandler {
    slabs: Slab<(Handle, Io)>,
}

#[cfg(any(target_os = "linux",
          target_os = "android"))]
impl Handler for IoHandler {
    type Timeout = ();
    type Message = ();

    fn writable(&mut self, event_loop: &mut EventLoop<Self>, token: Token) {

        debug!("In writable, token {:?}", token);

        match self.slabs.remove(token) {
            Some((hdl, fd)) => {
                // Linux EPoll needs to explicit EPOLL_CTL_DEL the fd
                event_loop.deregister(&fd).unwrap();
                mem::forget(fd);
                Scheduler::ready(hdl);
            },
            None => {
                warn!("No coroutine is waiting on writable {:?}", token);
            }
        }

    }

    fn readable(&mut self, event_loop: &mut EventLoop<Self>, token: Token, hint: ReadHint) {

        debug!("In readable, token {:?}, hint {:?}", token, hint);

        match self.slabs.remove(token) {
            Some((hdl, fd)) => {
                // Linux EPoll needs to explicit EPOLL_CTL_DEL the fd
                event_loop.deregister(&fd).unwrap();
                mem::forget(fd);
                Scheduler::ready(hdl);
            },
            None => {
                warn!("No coroutine is waiting on readable {:?}", token);
            }
        }

    }
}

#[cfg(any(target_os = "macos",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "openbsd"))]
impl Processor {
    pub fn wait_event<E: Evented>(&mut self, fd: &E, interest: Interest) -> io::Result<()> {
        let token = self.handler.slabs.insert(Coroutine::current().clone()).unwrap();
        try!(self.event_loop.register_opt(fd, token, interest,
                                          PollOpt::edge()|PollOpt::oneshot()));

        debug!("wait_event: Blocked current Coroutine ...; token={:?}", token);
        Coroutine::block();
        debug!("wait_event: Waked up; token={:?}", token);

        Ok(())
    }
}

#[cfg(any(target_os = "macos",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "openbsd"))]
struct IoHandler {
    slabs: Slab<Handle>,
}

#[cfg(any(target_os = "macos",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "openbsd"))]
impl Handler for IoHandler {
    type Timeout = ();
    type Message = ();

    fn writable(&mut self, _: &mut EventLoop<Self>, token: Token) {

        debug!("In writable, token {:?}", token);

        match self.slabs.remove(token) {
            Some(hdl) => {
                Scheduler::ready(hdl);
            },
            None => {
                warn!("No coroutine is waiting on writable {:?}", token);
            }
        }

    }

    fn readable(&mut self, _: &mut EventLoop<Self>, token: Token, hint: ReadHint) {

        debug!("In readable, token {:?}, hint {:?}", token, hint);

        match self.slabs.remove(token) {
            Some(hdl) => {
                Scheduler::ready(hdl);
            },
            None => {
                warn!("No coroutine is waiting on readable {:?}", token);
            }
        }

    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

#![feature(phase)]
#![feature(macro_rules)]
#![feature(associated_types)]

#[cfg(target_os = "android")]
#[phase(plugin, link)]
extern crate android_glue;

extern crate libc;
extern crate cgmath;
extern crate "zoc_gl" as gl;
extern crate serialize;
extern crate glutin;

mod mesh;
mod core_map;
mod geom;
mod camera;
mod visualizer;
mod visualizer_types;
mod shader;
mod core_types;
mod core_misc;
mod zgl;
mod dir;

pub fn main() {
    let mut visualizer = visualizer::Visualizer::new();
    while visualizer.is_running() {
        visualizer.tick();
    }
}

#[cfg(target_os = "android")]
#[no_mangle]
pub fn rust_android_main(app: *mut()) {
    android_glue::android_main2(app, move|| main());
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/lib.rs: Removed unneeded '#![feature(macro_rules)]'<commit_after>// See LICENSE file for copyright and license details.

#![feature(phase)]
#![feature(associated_types)]

#[cfg(target_os = "android")]
#[phase(plugin, link)]
extern crate android_glue;

extern crate libc;
extern crate cgmath;
extern crate "zoc_gl" as gl;
extern crate serialize;
extern crate glutin;

mod mesh;
mod core_map;
mod geom;
mod camera;
mod visualizer;
mod visualizer_types;
mod shader;
mod core_types;
mod core_misc;
mod zgl;
mod dir;

pub fn main() {
    let mut visualizer = visualizer::Visualizer::new();
    while visualizer.is_running() {
        visualizer.tick();
    }
}

#[cfg(target_os = "android")]
#[no_mangle]
pub fn rust_android_main(app: *mut()) {
    android_glue::android_main2(app, move|| main());
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>pub mod grid;
pub mod engine;
pub mod life;
pub mod repr;

pub mod traits {

    use std::collections::HashMap;

    use repr::GridRepr;

    pub trait Cell {
        fn step<'a, I>(&'a self, neighbors: I) -> Self
            where I: Iterator<Item=Option<&'a Self>>;
        fn repr(&self, meta: &mut HashMap<&str, &str>);
        fn from_repr(&mut self, meta: &HashMap<&str, &str>);
    }

    pub trait Grid {
        fn step(&mut self);
        fn repr(&self) -> &GridRepr;
        fn from_repr<'a: 'b, 'b>(&'a mut self, &GridRepr<'b>);
    }

    pub trait ReprConsumer {
        fn consume(&mut self, repr: &GridRepr);
    }

    pub trait Engine {
        fn run_times(&mut self, times: i64);
    }

    pub trait Parallel: Sized {
        fn into_parts(self) -> Vec<Self>;
    }
}

<commit_msg>Unused (by now) trait.<commit_after>pub mod grid;
pub mod engine;
pub mod life;
pub mod repr;

pub mod traits {

    use std::collections::HashMap;

    use repr::GridRepr;

    pub trait Cell {
        fn step<'a, I>(&'a self, neighbors: I) -> Self
            where I: Iterator<Item=Option<&'a Self>>;
        fn repr(&self, meta: &mut HashMap<&str, &str>);
        fn from_repr(&mut self, meta: &HashMap<&str, &str>);
    }

    pub trait Grid {
        fn step(&mut self);
        fn repr(&self) -> &GridRepr;
        fn from_repr<'a: 'b, 'b>(&'a mut self, &GridRepr<'b>);
    }

    pub trait ReprConsumer {
        fn consume(&mut self, repr: &GridRepr);
    }

    pub trait Engine {
        fn run_times(&mut self, times: i64);
    }
}

<|endoftext|>


<commit_before>//! This crate is a Rust port of Google's high-performance [SwissTable] hash
//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap`
//! and `HashSet` types.
//!
//! The original C++ version of [SwissTable] can be found [here], and this
//! [CppCon talk] gives an overview of how the algorithm works.
//!
//! [SwissTable]: https://abseil.io/blog/20180927-swisstables
//! [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h
//! [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4

#![no_std]
#![cfg_attr(
    feature = "nightly",
    feature(
        test,
        core_intrinsics,
        dropck_eyepatch,
        min_specialization,
        extend_one,
    )
)]
#![allow(
    clippy::doc_markdown,
    clippy::module_name_repetitions,
    clippy::must_use_candidate,
    clippy::option_if_let_else
)]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]

#[cfg(test)]
#[macro_use]
extern crate std;

#[cfg_attr(test, macro_use)]
extern crate alloc;

#[cfg(feature = "nightly")]
#[cfg(doctest)]
doc_comment::doctest!("../README.md");

#[macro_use]
mod macros;

#[cfg(feature = "raw")]
/// Experimental and unsafe `RawTable` API. This module is only available if the
/// `raw` feature is enabled.
pub mod raw {
    // The RawTable API is still experimental and is not properly documented yet.
    #[allow(missing_docs)]
    #[path = "mod.rs"]
    mod inner;
    pub use inner::*;

    #[cfg(feature = "rayon")]
    pub mod rayon {
        pub use crate::external_trait_impls::rayon::raw::*;
    }
}
#[cfg(not(feature = "raw"))]
mod raw;

mod external_trait_impls;
mod map;
#[cfg(feature = "rustc-internal-api")]
mod rustc_entry;
mod scopeguard;
mod set;

pub mod hash_map {
    //! A hash map implemented with quadratic probing and SIMD lookup.
    pub use crate::map::*;

    #[cfg(feature = "rustc-internal-api")]
    pub use crate::rustc_entry::*;

    #[cfg(feature = "rayon")]
    /// [rayon]-based parallel iterator types for hash maps.
    /// You will rarely need to interact with it directly unless you have need
    /// to name one of the iterator types.
    ///
    /// [rayon]: https://docs.rs/rayon/1.0/rayon
    pub mod rayon {
        pub use crate::external_trait_impls::rayon::map::*;
    }
}
pub mod hash_set {
    //! A hash set implemented as a `HashMap` where the value is `()`.
    pub use crate::set::*;

    #[cfg(feature = "rayon")]
    /// [rayon]-based parallel iterator types for hash sets.
    /// You will rarely need to interact with it directly unless you have need
    /// to name one of the iterator types.
    ///
    /// [rayon]: https://docs.rs/rayon/1.0/rayon
    pub mod rayon {
        pub use crate::external_trait_impls::rayon::set::*;
    }
}

pub use crate::map::HashMap;
pub use crate::set::HashSet;

/// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TryReserveError {
    /// Error due to the computed capacity exceeding the collection's maximum
    /// (usually `isize::MAX` bytes).
    CapacityOverflow,

    /// The memory allocator returned an error
    AllocError {
        /// The layout of the allocation request that failed.
        layout: alloc::alloc::Layout,
    },
}
<commit_msg>rustfmt<commit_after>//! This crate is a Rust port of Google's high-performance [SwissTable] hash
//! map, adapted to make it a drop-in replacement for Rust's standard `HashMap`
//! and `HashSet` types.
//!
//! The original C++ version of [SwissTable] can be found [here], and this
//! [CppCon talk] gives an overview of how the algorithm works.
//!
//! [SwissTable]: https://abseil.io/blog/20180927-swisstables
//! [here]: https://github.com/abseil/abseil-cpp/blob/master/absl/container/internal/raw_hash_set.h
//! [CppCon talk]: https://www.youtube.com/watch?v=ncHmEUmJZf4

#![no_std]
#![cfg_attr(
    feature = "nightly",
    feature(test, core_intrinsics, dropck_eyepatch, min_specialization, extend_one)
)]
#![allow(
    clippy::doc_markdown,
    clippy::module_name_repetitions,
    clippy::must_use_candidate,
    clippy::option_if_let_else
)]
#![warn(missing_docs)]
#![warn(rust_2018_idioms)]

#[cfg(test)]
#[macro_use]
extern crate std;

#[cfg_attr(test, macro_use)]
extern crate alloc;

#[cfg(feature = "nightly")]
#[cfg(doctest)]
doc_comment::doctest!("../README.md");

#[macro_use]
mod macros;

#[cfg(feature = "raw")]
/// Experimental and unsafe `RawTable` API. This module is only available if the
/// `raw` feature is enabled.
pub mod raw {
    // The RawTable API is still experimental and is not properly documented yet.
    #[allow(missing_docs)]
    #[path = "mod.rs"]
    mod inner;
    pub use inner::*;

    #[cfg(feature = "rayon")]
    pub mod rayon {
        pub use crate::external_trait_impls::rayon::raw::*;
    }
}
#[cfg(not(feature = "raw"))]
mod raw;

mod external_trait_impls;
mod map;
#[cfg(feature = "rustc-internal-api")]
mod rustc_entry;
mod scopeguard;
mod set;

pub mod hash_map {
    //! A hash map implemented with quadratic probing and SIMD lookup.
    pub use crate::map::*;

    #[cfg(feature = "rustc-internal-api")]
    pub use crate::rustc_entry::*;

    #[cfg(feature = "rayon")]
    /// [rayon]-based parallel iterator types for hash maps.
    /// You will rarely need to interact with it directly unless you have need
    /// to name one of the iterator types.
    ///
    /// [rayon]: https://docs.rs/rayon/1.0/rayon
    pub mod rayon {
        pub use crate::external_trait_impls::rayon::map::*;
    }
}
pub mod hash_set {
    //! A hash set implemented as a `HashMap` where the value is `()`.
    pub use crate::set::*;

    #[cfg(feature = "rayon")]
    /// [rayon]-based parallel iterator types for hash sets.
    /// You will rarely need to interact with it directly unless you have need
    /// to name one of the iterator types.
    ///
    /// [rayon]: https://docs.rs/rayon/1.0/rayon
    pub mod rayon {
        pub use crate::external_trait_impls::rayon::set::*;
    }
}

pub use crate::map::HashMap;
pub use crate::set::HashSet;

/// The error type for `try_reserve` methods.
#[derive(Clone, PartialEq, Eq, Debug)]
pub enum TryReserveError {
    /// Error due to the computed capacity exceeding the collection's maximum
    /// (usually `isize::MAX` bytes).
    CapacityOverflow,

    /// The memory allocator returned an error
    AllocError {
        /// The layout of the allocation request that failed.
        layout: alloc::alloc::Layout,
    },
}
<|endoftext|>


<commit_before>//! Checked arithmetic.
//!
//! The Checked struct allows you to perform checked arithmetic without an overabundance of
//! .checked_* calls.
//! # Examples
//! ```
//! use checked::Checked;
//!
//! let x = Checked::from(1_000_u32);
//! let y = Checked::from(1_000_000_u32);
//!
//! assert_eq!(x * 1_000, y);
//! assert_eq!(1_000_000 * y, Checked::from(None));
//! assert_eq!(x << 3, Checked::<u32>::from(8_000));
//! ```

mod num;
pub use num::Checked;

#[cfg(test)]
mod tests;
<commit_msg>add lots more examples<commit_after>//! Checked arithmetic.
//!
//! The Checked struct allows you to perform checked arithmetic without an overabundance of
//! .checked_* calls.
//! # Examples
//! ```
//! use checked::Checked;
//!
//! let x = Checked::from(1_000_u32);
//! let y = Checked::from(1_000_000_u32);
//!
//! assert_eq!(x * 1_000, y);
//! assert_eq!(1_000_000 * y, Checked::from(None));
//! assert_eq!(x << 3, Checked::<u32>::from(8_000));
//! ```
//!
//! All the basic arithmetic operations are implemented.
//! ```
//! assert_eq!(Checked::<u8>::from(5) + Checked::<u8>::from(6), Checked::<u8>::from(11));
//! assert_eq!(Checked::<u8>::from(5) - Checked::<u8>::from(6), Checked::<u8>::from(None));
//! assert_eq!(Checked::<u8>::from(5) * Checked::<u8>::from(6), Checked::<u8>::from(30));
//! assert_eq!(Checked::<u8>::from(5) / Checked::<u8>::from(6), Checked::<u8>::from(0));
//! assert_eq!(- Checked::<u8>::from(6), Checked::<u8>::from(None));
//! assert_eq!(Checked::<u8>::from(5) % Checked::<u8>::from(6), Checked::<u8>::from(5));
//! ```
//!
//! Including bitwise operations.
//! ```
//! assert_eq!(Checked::<u8>::from(5) & Checked::<u8>::from(6), Checked::<u8>::from(4));
//! assert_eq!(Checked::<u8>::from(5) | Checked::<u8>::from(6), Checked::<u8>::from(7));
//! assert_eq!(Checked::<u8>::from(5) ^ Checked::<u8>::from(6), Checked::<u8>::from(3));
//! assert_eq!(! Checked::<u8>::from(6), Checked::<u8>::from(249));
//! assert_eq!(Checked::<u8>::from(5) << Checked::<u32>::from(5), Checked::<u8>::from(160));
//! assert_eq!(Checked::<u8>::from(160) >> Checked::<u32>::from(5), Checked::<u8>::from(5));
//! ```
//!
//! Ord is implemented, and the overflow state is considered less than everything
//! (may change this in the future)
//! ```
//! assert!(Checked::from(1_000_u32) <= Checked::from(10_000_u32));
//! assert!(!(Checked::from(1_000_u32) <= Checked::from(None)));
//! assert!((Checked::from(None) <= Checked::from(1_000_u32)));
//! ```

mod num;
pub use num::Checked;

#[cfg(test)]
mod tests;
<|endoftext|>


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

#[cfg(not(target_os = "windows"))]
pub use self::windows::shell_escape;

mod windows {
    use std::borrow::Cow;

    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        panic!()
    }
}

#[cfg(target_os = "windows")]
pub use self::other::shell_escape;

mod other {
    use std::borrow::Cow;

    static SHELL_SPECIAL: &'static str = r#" \$'"`!"#;

    #[cfg(not(target_os = "windows"))]
    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        let escape_char = '\\';
        // check if string needs to be escaped
        let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char));
        if clean {
            return s
        }
        let mut es = String::with_capacity(s.len());
        for ch in s.chars() {
            if SHELL_SPECIAL.contains(ch) {
                es.push(escape_char);
            }
            es.push(ch)
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#"linker=gcc\ -L/foo\ -Wl,bar"#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"'!\$`\\\n "#.into()),
                                r#"\'\!\\\$\`\\\\\\n\ "#);
    }
}
<commit_msg>Shell Escape for Windows<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[cfg(target_os = "windows")]
pub use self::windows::shell_escape;

#[cfg(any(test, target_os = "windows"))]
mod windows {
    use std::borrow::Cow;

    static NEED_QUOTING: &'static str = r#" ""#;
    const ESCAPE_CHAR: char = '\\';
    const QUOTE_CHAR: char = '"';
    const BACKSLASH: char = '\\';
    const SLASH: char = '/';

    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    ///
    /// Escape double quotes and spaces by wrapping the string in double quotes.
    ///
    /// Turn all backslashes into forward slashes.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        // check if string needs to be escaped
        let mut needs_quoting = false;
        let mut needs_slashes = false;
        for ch in s.chars() {
            if NEED_QUOTING.contains(ch) {
                needs_quoting = true;
            } else if ch == BACKSLASH {
                needs_slashes = true;
            }
        }
        if !needs_quoting && !needs_slashes {
            return s
        }
        let mut es = String::with_capacity(s.len());
        if needs_quoting {
            es.push(QUOTE_CHAR);
        }
        for ch in s.chars() {
            match ch {
                BACKSLASH => { es.push(SLASH); continue }
                QUOTE_CHAR => es.push(ESCAPE_CHAR),
                _ => {}
            }
            es.push(ch)
        }
        if needs_quoting {
            es.push(QUOTE_CHAR);
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#""linker=gcc -L/foo -Wl,bar""#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#""--features=\"default\"""#);
        assert_eq!(shell_escape(r#"\path\to\my documents\"#.into()),
                                r#""/path/to/my documents/""#);
    }
}

#[cfg(not(target_os = "windows"))]
pub use self::other::shell_escape;

#[cfg(any(test, not(target_os = "windows")))]
mod other {
    use std::borrow::Cow;

    static SHELL_SPECIAL: &'static str = r#" \$'"`!"#;

    #[cfg(not(target_os = "windows"))]
    /// Escape characters that may have special meaning in a shell,
    /// including spaces.
    pub fn shell_escape(s: Cow<str>) -> Cow<str> {
        let escape_char = '\\';
        // check if string needs to be escaped
        let clean = SHELL_SPECIAL.chars().all(|sp_char| !s.contains(sp_char));
        if clean {
            return s
        }
        let mut es = String::with_capacity(s.len());
        for ch in s.chars() {
            if SHELL_SPECIAL.contains(ch) {
                es.push(escape_char);
            }
            es.push(ch)
        }
        es.into()
    }

    #[test]
    fn test_shell_escape() {
        assert_eq!(shell_escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
        assert_eq!(shell_escape("linker=gcc -L/foo -Wl,bar".into()),
                                r#"linker=gcc\ -L/foo\ -Wl,bar"#);
        assert_eq!(shell_escape(r#"--features="default""#.into()),
                                r#"--features=\"default\""#);
        assert_eq!(shell_escape(r#"'!\$`\\\n "#.into()),
                                r#"\'\!\\\$\`\\\\\\n\ "#);
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
use std::os::unix::net::{UnixDatagram, UnixStream};

use libc::{c_void, iovec};

use data_model::VolatileSlice;

use {Result, Error};

// These functions are implemented in C because each of them requires complicated setup with CMSG
// macros. These macros are part of the system headers and are required to be used for portability
// reasons. In practice, the control message ABI can't change but using them is much easier and less
// error prone than trying to port these macros to rust.
extern "C" {
    fn scm_cmsg_buffer_len(fd_count: usize) -> usize;
    fn scm_sendmsg(fd: RawFd,
                   outv: *const iovec,
                   outv_count: usize,
                   cmsg_buffer: *mut u8,
                   fds: *const RawFd,
                   fd_count: usize)
                   -> isize;
    fn scm_recvmsg(fd: RawFd,
                   outv: *mut iovec,
                   outv_count: usize,
                   cmsg_buffer: *mut u8,
                   fds: *mut RawFd,
                   fd_count: *mut usize)
                   -> isize;
}

fn cmsg_buffer_len(fd_count: usize) -> usize {
    // Safe because this function has no side effects, touches no pointers, and never fails.
    unsafe { scm_cmsg_buffer_len(fd_count) }
}

/// Trait for file descriptors can send and receive socket control messages via `sendmsg` and
/// `recvmsg`.
pub trait ScmSocket {
    /// Gets the file descriptor of this socket.
    fn socket_fd(&self) -> RawFd;
}

impl ScmSocket for UnixDatagram {
    fn socket_fd(&self) -> RawFd {
        self.as_raw_fd()
    }
}

impl ScmSocket for UnixStream {
    fn socket_fd(&self) -> RawFd {
        self.as_raw_fd()
    }
}

/// Trait for types that can be converted into an `iovec` that can be referenced by a syscall for
/// the lifetime of this object.
///
/// This trait is unsafe because interfaces that use this trait depend on the base pointer and size
/// being accurate.
pub unsafe trait IntoIovec {
    /// Gets the base pointer of this `iovec`.
    fn as_ptr(&self) -> *const c_void;

    /// Gets the size in bytes of this `iovec`.
    fn size(&self) -> usize;
}

// Safe because this slice can not have another mutable reference and it's pointer and size are
// guaranteed to be valid.
unsafe impl<'a> IntoIovec for &'a [u8] {
    fn as_ptr(&self) -> *const c_void {
        self.as_ref().as_ptr() as *const c_void
    }

    fn size(&self) -> usize {
        self.len()
    }
}

// Safe because volatile slices are only ever accessed with other volatile interfaces and the
// pointer and size are guaranteed to be accurate.
unsafe impl<'a> IntoIovec for VolatileSlice<'a> {
    fn as_ptr(&self) -> *const c_void {
        self.as_ptr() as *const c_void
    }

    fn size(&self) -> usize {
        self.size() as usize
    }
}

/// Used to send and receive messages with file descriptors on sockets that accept control messages
/// (e.g. Unix domain sockets).
pub struct Scm {
    cmsg_buffer: Vec<u8>,
    vecs: Vec<iovec>,
    fds: Vec<RawFd>,
}

impl Scm {
    /// Constructs a new Scm object with pre-allocated structures.
    ///
    /// # Arguments
    ///
    /// * `fd_count` - The maximum number of files that can be received per `recv` call.
    pub fn new(fd_count: usize) -> Scm {
        Scm {
            cmsg_buffer: Vec::with_capacity(cmsg_buffer_len(fd_count)),
            vecs: Vec::new(),
            fds: vec![-1; fd_count],
        }
    }

    /// Sends the given data and file descriptors over the given `socket`.
    ///
    /// On success, returns the number of bytes sent.
    ///
    /// # Arguments
    ///
    /// * `socket` - A socket that supports socket control messages.
    /// * `bufs` - A list of buffers to send on the `socket`.
    /// * `fds` - A list of file descriptors to be sent.
    pub fn send<T: ScmSocket, D: IntoIovec>(&mut self,
                              socket: &T,
                              bufs: &[D],
                              fds: &[RawFd])
                              -> Result<usize> {
        let cmsg_buf_len = cmsg_buffer_len(fds.len());
        self.cmsg_buffer.reserve(cmsg_buf_len);
        self.vecs.clear();
        for ref buf in bufs {
            self.vecs
                .push(iovec {
                    iov_base: buf.as_ptr() as *mut c_void,
                    iov_len: buf.size(),
              });
        }
        let write_count = unsafe {
            // Safe because we are giving scm_sendmsg only valid pointers and lengths and we check
            // the return value.
            self.cmsg_buffer.set_len(cmsg_buf_len);
            scm_sendmsg(socket.socket_fd(),
                        self.vecs.as_ptr(),
                        self.vecs.len(),
                        self.cmsg_buffer.as_mut_ptr(),
                        fds.as_ptr(),
                        fds.len())
        };

        if write_count < 0 {
            Err(Error::new(write_count as i32))
        } else {
            Ok(write_count as usize)
        }
    }

    /// Receives data and file descriptors from the given `socket` into the list of buffers.
    ///
    /// On success, returns the number of bytes received.
    ///
    /// # Arguments
    ///
    /// * `socket` - A socket that supports socket control messages.
    /// * `bufs` - A list of buffers to receive data from the `socket`. The `recvmsg` call fills
    ///            these directly.
    /// * `files` - A vector of `File`s to put the received file descriptors into. This vector is
    ///             not cleared and will have at most `fd_count` (specified in `Scm::new`) `File`s
    ///             added to it.
    pub fn recv<T: ScmSocket>(&mut self,
                              socket: &T,
                              bufs: &mut [&mut [u8]],
                              files: &mut Vec<File>)
                              -> Result<usize> {
        let cmsg_buf_len = cmsg_buffer_len(files.len());
        self.cmsg_buffer.reserve(cmsg_buf_len);
        self.vecs.clear();
        for buf in bufs {
            self.vecs
                .push(iovec {
                          iov_base: buf.as_mut_ptr() as *mut c_void,
                          iov_len: buf.len(),
                      });
        }
        let mut fd_count = self.fds.len();
        let read_count = unsafe {
            // Safe because we are giving scm_recvmsg only valid pointers and lengths and we check
            // the return value.
            self.cmsg_buffer.set_len(cmsg_buf_len);
            scm_recvmsg(socket.socket_fd(),
                        self.vecs.as_mut_ptr(),
                        self.vecs.len(),
                        self.cmsg_buffer.as_mut_ptr(),
                        self.fds.as_mut_ptr(),
                        &mut fd_count as *mut usize)
        };

        if read_count < 0 {
            Err(Error::new(read_count as i32))
        } else {
            // Safe because we have unqiue ownership of each fd we wrap with File.
            for &fd in &self.fds[0..fd_count] {
                files.push(unsafe { File::from_raw_fd(fd) });
            }
            Ok(read_count as usize)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::io::Write;
    use std::mem::size_of;
    use std::os::raw::c_long;
    use std::os::unix::net::UnixDatagram;
    use std::slice::from_raw_parts;

    use libc::cmsghdr;

    use EventFd;

    #[test]
    fn buffer_len() {
        assert_eq!(cmsg_buffer_len(0), size_of::<cmsghdr>());
        assert_eq!(cmsg_buffer_len(1),
                   size_of::<cmsghdr>() + size_of::<c_long>());
        if size_of::<RawFd>() == 4 {
            assert_eq!(cmsg_buffer_len(2),
                       size_of::<cmsghdr>() + size_of::<c_long>());
            assert_eq!(cmsg_buffer_len(3),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 2);
            assert_eq!(cmsg_buffer_len(4),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 2);
        } else if size_of::<RawFd>() == 8 {
            assert_eq!(cmsg_buffer_len(2),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 2);
            assert_eq!(cmsg_buffer_len(3),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 3);
            assert_eq!(cmsg_buffer_len(4),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 4);
        }
    }

    #[test]
    fn send_recv_no_fd() {
        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");

        let mut scm = Scm::new(1);
        let write_count = scm.send(&s1,
                                   [[1u8, 1, 2].as_ref(), [21, 34, 55].as_ref()].as_ref(),
                                   &[])
            .expect("failed to send data");

        assert_eq!(write_count, 6);

        let mut buf1 = [0; 3];
        let mut buf2 = [0; 3];
        let mut bufs = [buf1.as_mut(), buf2.as_mut()];
        let mut files = Vec::new();
        let read_count = scm.recv(&s2, &mut bufs[..], &mut files)
            .expect("failed to recv data");

        assert_eq!(read_count, 6);
        assert!(files.is_empty());
        assert_eq!(bufs[0], [1, 1, 2]);
        assert_eq!(bufs[1], [21, 34, 55]);
    }

    #[test]
    fn send_recv_only_fd() {
        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");

        let mut scm = Scm::new(1);
        let evt = EventFd::new().expect("failed to create eventfd");
        let write_count = scm.send(&s1, &[[].as_ref()], &[evt.as_raw_fd()])
            .expect("failed to send fd");

        assert_eq!(write_count, 0);

        let mut files = Vec::new();
        let read_count = scm.recv(&s2, &mut [&mut []], &mut files)
            .expect("failed to recv fd");

        assert_eq!(read_count, 0);
        assert_eq!(files.len(), 1);
        assert!(files[0].as_raw_fd() >= 0);
        assert_ne!(files[0].as_raw_fd(), s1.as_raw_fd());
        assert_ne!(files[0].as_raw_fd(), s2.as_raw_fd());
        assert_ne!(files[0].as_raw_fd(), evt.as_raw_fd());

        files[0]
            .write(unsafe { from_raw_parts(&1203u64 as *const u64 as *const u8, 8) })
            .expect("failed to write to sent fd");

        assert_eq!(evt.read().expect("failed to read from eventfd"), 1203);
    }

    #[test]
    fn send_recv_with_fd() {
        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");

        let mut scm = Scm::new(1);
        let evt = EventFd::new().expect("failed to create eventfd");
        let write_count = scm.send(&s1, &[[237].as_ref()], &[evt.as_raw_fd()])
            .expect("failed to send fd");

        assert_eq!(write_count, 1);

        let mut files = Vec::new();
        let mut buf = [0u8];
        let read_count = scm.recv(&s2, &mut [&mut buf], &mut files)
            .expect("failed to recv fd");

        assert_eq!(read_count, 1);
        assert_eq!(buf[0], 237);
        assert_eq!(files.len(), 1);
        assert!(files[0].as_raw_fd() >= 0);
        assert_ne!(files[0].as_raw_fd(), s1.as_raw_fd());
        assert_ne!(files[0].as_raw_fd(), s2.as_raw_fd());
        assert_ne!(files[0].as_raw_fd(), evt.as_raw_fd());

        files[0]
            .write(unsafe { from_raw_parts(&1203u64 as *const u64 as *const u8, 8) })
            .expect("failed to write to sent fd");

        assert_eq!(evt.read().expect("failed to read from eventfd"), 1203);
    }
}
<commit_msg>sys_util: properly convert errors in sock_ctrl_msg<commit_after>// Copyright 2017 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::fs::File;
use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
use std::os::unix::net::{UnixDatagram, UnixStream};

use libc::{c_void, iovec};

use data_model::VolatileSlice;

use {Result, Error};

// These functions are implemented in C because each of them requires complicated setup with CMSG
// macros. These macros are part of the system headers and are required to be used for portability
// reasons. In practice, the control message ABI can't change but using them is much easier and less
// error prone than trying to port these macros to rust.
extern "C" {
    fn scm_cmsg_buffer_len(fd_count: usize) -> usize;
    fn scm_sendmsg(fd: RawFd,
                   outv: *const iovec,
                   outv_count: usize,
                   cmsg_buffer: *mut u8,
                   fds: *const RawFd,
                   fd_count: usize)
                   -> isize;
    fn scm_recvmsg(fd: RawFd,
                   outv: *mut iovec,
                   outv_count: usize,
                   cmsg_buffer: *mut u8,
                   fds: *mut RawFd,
                   fd_count: *mut usize)
                   -> isize;
}

fn cmsg_buffer_len(fd_count: usize) -> usize {
    // Safe because this function has no side effects, touches no pointers, and never fails.
    unsafe { scm_cmsg_buffer_len(fd_count) }
}

/// Trait for file descriptors can send and receive socket control messages via `sendmsg` and
/// `recvmsg`.
pub trait ScmSocket {
    /// Gets the file descriptor of this socket.
    fn socket_fd(&self) -> RawFd;
}

impl ScmSocket for UnixDatagram {
    fn socket_fd(&self) -> RawFd {
        self.as_raw_fd()
    }
}

impl ScmSocket for UnixStream {
    fn socket_fd(&self) -> RawFd {
        self.as_raw_fd()
    }
}

/// Trait for types that can be converted into an `iovec` that can be referenced by a syscall for
/// the lifetime of this object.
///
/// This trait is unsafe because interfaces that use this trait depend on the base pointer and size
/// being accurate.
pub unsafe trait IntoIovec {
    /// Gets the base pointer of this `iovec`.
    fn as_ptr(&self) -> *const c_void;

    /// Gets the size in bytes of this `iovec`.
    fn size(&self) -> usize;
}

// Safe because this slice can not have another mutable reference and it's pointer and size are
// guaranteed to be valid.
unsafe impl<'a> IntoIovec for &'a [u8] {
    fn as_ptr(&self) -> *const c_void {
        self.as_ref().as_ptr() as *const c_void
    }

    fn size(&self) -> usize {
        self.len()
    }
}

// Safe because volatile slices are only ever accessed with other volatile interfaces and the
// pointer and size are guaranteed to be accurate.
unsafe impl<'a> IntoIovec for VolatileSlice<'a> {
    fn as_ptr(&self) -> *const c_void {
        self.as_ptr() as *const c_void
    }

    fn size(&self) -> usize {
        self.size() as usize
    }
}

/// Used to send and receive messages with file descriptors on sockets that accept control messages
/// (e.g. Unix domain sockets).
pub struct Scm {
    cmsg_buffer: Vec<u8>,
    vecs: Vec<iovec>,
    fds: Vec<RawFd>,
}

impl Scm {
    /// Constructs a new Scm object with pre-allocated structures.
    ///
    /// # Arguments
    ///
    /// * `fd_count` - The maximum number of files that can be received per `recv` call.
    pub fn new(fd_count: usize) -> Scm {
        Scm {
            cmsg_buffer: Vec::with_capacity(cmsg_buffer_len(fd_count)),
            vecs: Vec::new(),
            fds: vec![-1; fd_count],
        }
    }

    /// Sends the given data and file descriptors over the given `socket`.
    ///
    /// On success, returns the number of bytes sent.
    ///
    /// # Arguments
    ///
    /// * `socket` - A socket that supports socket control messages.
    /// * `bufs` - A list of buffers to send on the `socket`.
    /// * `fds` - A list of file descriptors to be sent.
    pub fn send<T: ScmSocket, D: IntoIovec>(&mut self,
                              socket: &T,
                              bufs: &[D],
                              fds: &[RawFd])
                              -> Result<usize> {
        let cmsg_buf_len = cmsg_buffer_len(fds.len());
        self.cmsg_buffer.reserve(cmsg_buf_len);
        self.vecs.clear();
        for ref buf in bufs {
            self.vecs
                .push(iovec {
                    iov_base: buf.as_ptr() as *mut c_void,
                    iov_len: buf.size(),
              });
        }
        let write_count = unsafe {
            // Safe because we are giving scm_sendmsg only valid pointers and lengths and we check
            // the return value.
            self.cmsg_buffer.set_len(cmsg_buf_len);
            scm_sendmsg(socket.socket_fd(),
                        self.vecs.as_ptr(),
                        self.vecs.len(),
                        self.cmsg_buffer.as_mut_ptr(),
                        fds.as_ptr(),
                        fds.len())
        };

        if write_count < 0 {
            Err(Error::new(-write_count as i32))
        } else {
            Ok(write_count as usize)
        }
    }

    /// Receives data and file descriptors from the given `socket` into the list of buffers.
    ///
    /// On success, returns the number of bytes received.
    ///
    /// # Arguments
    ///
    /// * `socket` - A socket that supports socket control messages.
    /// * `bufs` - A list of buffers to receive data from the `socket`. The `recvmsg` call fills
    ///            these directly.
    /// * `files` - A vector of `File`s to put the received file descriptors into. This vector is
    ///             not cleared and will have at most `fd_count` (specified in `Scm::new`) `File`s
    ///             added to it.
    pub fn recv<T: ScmSocket>(&mut self,
                              socket: &T,
                              bufs: &mut [&mut [u8]],
                              files: &mut Vec<File>)
                              -> Result<usize> {
        let cmsg_buf_len = cmsg_buffer_len(files.len());
        self.cmsg_buffer.reserve(cmsg_buf_len);
        self.vecs.clear();
        for buf in bufs {
            self.vecs
                .push(iovec {
                          iov_base: buf.as_mut_ptr() as *mut c_void,
                          iov_len: buf.len(),
                      });
        }
        let mut fd_count = self.fds.len();
        let read_count = unsafe {
            // Safe because we are giving scm_recvmsg only valid pointers and lengths and we check
            // the return value.
            self.cmsg_buffer.set_len(cmsg_buf_len);
            scm_recvmsg(socket.socket_fd(),
                        self.vecs.as_mut_ptr(),
                        self.vecs.len(),
                        self.cmsg_buffer.as_mut_ptr(),
                        self.fds.as_mut_ptr(),
                        &mut fd_count as *mut usize)
        };

        if read_count < 0 {
            Err(Error::new(-read_count as i32))
        } else {
            // Safe because we have unqiue ownership of each fd we wrap with File.
            for &fd in &self.fds[0..fd_count] {
                files.push(unsafe { File::from_raw_fd(fd) });
            }
            Ok(read_count as usize)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use std::io::Write;
    use std::mem::size_of;
    use std::os::raw::c_long;
    use std::os::unix::net::UnixDatagram;
    use std::slice::from_raw_parts;

    use libc::cmsghdr;

    use EventFd;

    #[test]
    fn buffer_len() {
        assert_eq!(cmsg_buffer_len(0), size_of::<cmsghdr>());
        assert_eq!(cmsg_buffer_len(1),
                   size_of::<cmsghdr>() + size_of::<c_long>());
        if size_of::<RawFd>() == 4 {
            assert_eq!(cmsg_buffer_len(2),
                       size_of::<cmsghdr>() + size_of::<c_long>());
            assert_eq!(cmsg_buffer_len(3),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 2);
            assert_eq!(cmsg_buffer_len(4),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 2);
        } else if size_of::<RawFd>() == 8 {
            assert_eq!(cmsg_buffer_len(2),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 2);
            assert_eq!(cmsg_buffer_len(3),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 3);
            assert_eq!(cmsg_buffer_len(4),
                       size_of::<cmsghdr>() + size_of::<c_long>() * 4);
        }
    }

    #[test]
    fn send_recv_no_fd() {
        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");

        let mut scm = Scm::new(1);
        let write_count = scm.send(&s1,
                                   [[1u8, 1, 2].as_ref(), [21, 34, 55].as_ref()].as_ref(),
                                   &[])
            .expect("failed to send data");

        assert_eq!(write_count, 6);

        let mut buf1 = [0; 3];
        let mut buf2 = [0; 3];
        let mut bufs = [buf1.as_mut(), buf2.as_mut()];
        let mut files = Vec::new();
        let read_count = scm.recv(&s2, &mut bufs[..], &mut files)
            .expect("failed to recv data");

        assert_eq!(read_count, 6);
        assert!(files.is_empty());
        assert_eq!(bufs[0], [1, 1, 2]);
        assert_eq!(bufs[1], [21, 34, 55]);
    }

    #[test]
    fn send_recv_only_fd() {
        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");

        let mut scm = Scm::new(1);
        let evt = EventFd::new().expect("failed to create eventfd");
        let write_count = scm.send(&s1, &[[].as_ref()], &[evt.as_raw_fd()])
            .expect("failed to send fd");

        assert_eq!(write_count, 0);

        let mut files = Vec::new();
        let read_count = scm.recv(&s2, &mut [&mut []], &mut files)
            .expect("failed to recv fd");

        assert_eq!(read_count, 0);
        assert_eq!(files.len(), 1);
        assert!(files[0].as_raw_fd() >= 0);
        assert_ne!(files[0].as_raw_fd(), s1.as_raw_fd());
        assert_ne!(files[0].as_raw_fd(), s2.as_raw_fd());
        assert_ne!(files[0].as_raw_fd(), evt.as_raw_fd());

        files[0]
            .write(unsafe { from_raw_parts(&1203u64 as *const u64 as *const u8, 8) })
            .expect("failed to write to sent fd");

        assert_eq!(evt.read().expect("failed to read from eventfd"), 1203);
    }

    #[test]
    fn send_recv_with_fd() {
        let (s1, s2) = UnixDatagram::pair().expect("failed to create socket pair");

        let mut scm = Scm::new(1);
        let evt = EventFd::new().expect("failed to create eventfd");
        let write_count = scm.send(&s1, &[[237].as_ref()], &[evt.as_raw_fd()])
            .expect("failed to send fd");

        assert_eq!(write_count, 1);

        let mut files = Vec::new();
        let mut buf = [0u8];
        let read_count = scm.recv(&s2, &mut [&mut buf], &mut files)
            .expect("failed to recv fd");

        assert_eq!(read_count, 1);
        assert_eq!(buf[0], 237);
        assert_eq!(files.len(), 1);
        assert!(files[0].as_raw_fd() >= 0);
        assert_ne!(files[0].as_raw_fd(), s1.as_raw_fd());
        assert_ne!(files[0].as_raw_fd(), s2.as_raw_fd());
        assert_ne!(files[0].as_raw_fd(), evt.as_raw_fd());

        files[0]
            .write(unsafe { from_raw_parts(&1203u64 as *const u64 as *const u8, 8) })
            .expect("failed to write to sent fd");

        assert_eq!(evt.read().expect("failed to read from eventfd"), 1203);
    }
}
<|endoftext|>


<commit_before>// lib.rs
// Copyright 2016 Alexander Altman
//
// 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.

pub struct Papamū {
  board: [[Position; 10]; 10],
}
<commit_msg>stuff<commit_after>// lib.rs
// Copyright 2016 Alexander Altman
//
// 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::ops::Index;

#[derive(Clone,Copy,PartialEq,Eq,Debug)]
pub enum Position {
  White,
  Black,
  Empty,
}

impl Position {
  pub fn is_occupied(&self) -> bool {
    self != &Position::Empty
  }

  pub fn is_empty(&self) -> bool {
    self == &Position::Empty
  }

  pub fn is_white(&self) -> bool {
    self == &Position::White
  }

  pub fn is_black(&self) -> bool {
    self == &Position::Black
  }
}

#[derive(Clone,Copy,PartialEq,Eq,Debug)]
pub struct Papamu {
  board: [[Position; 10]; 10],
}

impl Default for Papamu {
  fn default() -> Self {
    let mut board = [[Position::White; 10]; 10];
    for x in 0..9 {
      for y in 0..9 {
        if (x + y) % 2 == 0 {
          board[x][y] = Position::Black;
        }
      }
    }
    Papamu {
      board: board,
    }
  }
}

impl Index<(u8, u8)> for Papamu {
  type Output = Position;

  fn index(&self, (x, y): (u8, u8)) -> &Position {
    assert!(x >= 1);
    assert!(x <= 10);
    assert!(y >= 1);
    assert!(y <= 10);
    &self.board[(x - 1) as usize][(y - 1) as usize]
  }
}
<|endoftext|>


<commit_before>//! This is a small crate for the [AnyBar](https://github.com/tonsky/AnyBar).
//!
//! # Examples
//! The functioning of this crate is pretty simple. These are the most use cases:
//!
//! ## Using the default port
//! ```
//! # use anybar::*;
//! // create a new AnyBar instance connected to the default port
//! let bar = Anybar::default();
//!
//! // set the color
//! bar.set_color(Color::Red);
//! ```
//!
//! ## Using a separate port
//! ```
//! # use anybar::*;
//! // Anybar::new() takes the Anybar port as parameter
//! let custom_bar = Anybar::new(1708);
//! custom_bar.set_color(Color::Exclamation);
//! ```
//!
//! ## Additional information
//! ```
//! # use anybar::*;
//! let bar = Anybar::default();
//!
//! // after instantiation, the last color is None
//! assert!(bar.color.is_none());
//!
//! bar.set_color(Color::Red);
//! // the last color now contains a value
//! // assert_eq!(bar.color.unwrap(), Color::Red);
//! ```
//!
//! Note that the value of `bar.color` does not necessarily represent the real color
//! displayed at the moment, depending on whether you have something or someone else messing
//! with your AnyBar simultaneously.
//!
//! # Note
//! The AnyBar itself does not provide any information on whether the sent command was executed
//! successfully, so the lib will only panic if it was not able to bind a UDP socket.
//!

use std::net;

/// The Anybar handle.
pub struct Anybar {
    /// The UDP Port the Anybar is connected to
    pub port: u16,
    /// The last color that has been set.
    ///
    /// When no color has been set yet, color is `None`.
    pub color: Option<Color>,
}

/// The different colors supported by AnyBar.
pub enum Color {
    /// White dot
    White,
    /// Red dot
    Red,
    /// Orange dot
    Orange,
    /// Yellow dot
    Yellow,
    /// Green dot
    Green,
    /// Cyan dot
    Cyan,
    /// Blue dot
    Blue,
    /// Purple dot
    Purple,
    /// Black dot; Has a white frame in _dark_ mode
    Black,
    /// Question mark
    Question,
    /// White exclamation mark on red ground
    Exclamation,
}

impl Anybar {
    /// Create a new Anybar instance, connected to the given UDP port.
    ///
    /// `port` may be any port between 0 and 6553.
    pub fn new(port: u16) -> Anybar {
        //TODO check if port is valid
        Anybar{port:port, color:None}
    }

    fn parse_color(color: Color) -> Vec<u8> {
        use Color::*;
        let col = match color {
            White       => "white",
            Red         => "red",
            Orange      => "orange",
            Yellow      => "yellow",
            Green       => "green",
            Cyan        => "cyan",
            Blue        => "blue",
            Purple      => "purple",
            Black       => "black",
            Question    => "question",
            Exclamation => "exclamation",
        };

        let mut parsed: Vec<u8> = Vec::new();
        parsed.extend(col.as_bytes()
                         .iter());
        parsed
    }

    fn socket(ip: &str, port: u16) -> net::UdpSocket {
        match net::UdpSocket::bind((ip, port)) {
            Ok(sock) => sock,
            Err(err) => panic!("Could not bind: {}", err),
        }
    }

    /// Set a new color.
    pub fn set_color(&self, color: Color) {
        let message = Anybar::parse_color(color);

        let socket = Anybar::socket("127.0.0.1", 0);
        let _ = socket.send_to(&message, ("127.0.0.1", self.port));
        drop(socket);
    }
}

/// Instanciates the default AnyBar, connected to the Port `1738`.
///
/// ```
/// # use anybar::*;
/// let bar = Anybar::default();
/// assert_eq!(bar.port, 1738);
/// ```
impl Default for Anybar {
    fn default() -> Anybar {
        Anybar{port:1738, color:None}
    }
}
<commit_msg>Check if port is in range<commit_after>//! This is a small crate for the [AnyBar](https://github.com/tonsky/AnyBar).
//!
//! # Examples
//! The functioning of this crate is pretty simple. These are the most use cases:
//!
//! ## Using the default port
//! ```
//! # use anybar::*;
//! // create a new AnyBar instance connected to the default port
//! let bar = Anybar::default();
//!
//! // set the color
//! bar.set_color(Color::Red);
//! ```
//!
//! ## Using a separate port
//! ```
//! # use anybar::*;
//! // Anybar::new() takes the Anybar port as parameter
//! let custom_bar = Anybar::new(1708);
//! custom_bar.set_color(Color::Exclamation);
//! ```
//!
//! ## Additional information
//! ```
//! # use anybar::*;
//! let bar = Anybar::default();
//!
//! // after instantiation, the last color is None
//! assert!(bar.color.is_none());
//!
//! bar.set_color(Color::Red);
//! // the last color now contains a value
//! // assert_eq!(bar.color.unwrap(), Color::Red);
//! ```
//!
//! Note that the value of `bar.color` does not necessarily represent the real color
//! displayed at the moment, depending on whether you have something or someone else messing
//! with your AnyBar simultaneously.
//!
//! # Note
//! The AnyBar itself does not provide any information on whether the sent command was executed
//! successfully, so the lib will only panic if it was not able to bind a UDP socket.
//!

use std::net;

/// The Anybar handle.
pub struct Anybar {
    /// The UDP Port the Anybar is connected to
    pub port: u16,
    /// The last color that has been set.
    ///
    /// When no color has been set yet, color is `None`.
    pub color: Option<Color>,
}

/// The different colors supported by AnyBar.
pub enum Color {
    /// White dot
    White,
    /// Red dot
    Red,
    /// Orange dot
    Orange,
    /// Yellow dot
    Yellow,
    /// Green dot
    Green,
    /// Cyan dot
    Cyan,
    /// Blue dot
    Blue,
    /// Purple dot
    Purple,
    /// Black dot; Has a white frame in _dark_ mode
    Black,
    /// Question mark
    Question,
    /// White exclamation mark on red ground
    Exclamation,
}

impl Anybar {
    /// Create a new Anybar instance, connected to the given UDP port.
    ///
    /// `port` may be any port between 0 and 6553.
    ///
    /// # Panics
    /// Panics if the port has a non-valid value outside of the range between 0 and 6553.
    ///
    /// # Examples
    ///
    /// ```
    /// # use anybar::*;
    /// let custom_bar = Anybar::new(1708);
    ///
    /// assert_eq!(custom_bar.port, 1708);
    /// ```
    pub fn new(port: u16) -> Anybar {
        if port > 6553 {
            panic!("The port {} is not between 0 and 6553!", port);
        }
        Anybar{port:port, color:None}
    }

    fn parse_color(color: Color) -> Vec<u8> {
        use Color::*;
        let col = match color {
            White       => "white",
            Red         => "red",
            Orange      => "orange",
            Yellow      => "yellow",
            Green       => "green",
            Cyan        => "cyan",
            Blue        => "blue",
            Purple      => "purple",
            Black       => "black",
            Question    => "question",
            Exclamation => "exclamation",
        };

        let mut parsed: Vec<u8> = Vec::new();
        parsed.extend(col.as_bytes()
                         .iter());
        parsed
    }

    fn socket(ip: &str, port: u16) -> net::UdpSocket {
        match net::UdpSocket::bind((ip, port)) {
            Ok(sock) => sock,
            Err(err) => panic!("Could not bind: {}", err),
        }
    }

    /// Set a new color.
    pub fn set_color(&self, color: Color) {
        let message = Anybar::parse_color(color);

        let socket = Anybar::socket("127.0.0.1", 0);
        let _ = socket.send_to(&message, ("127.0.0.1", self.port));
        drop(socket);
    }
}

/// Instanciates the default AnyBar, connected to the Port `1738`.
///
/// ```
/// # use anybar::*;
/// let bar = Anybar::default();
/// assert_eq!(bar.port, 1738);
/// ```
impl Default for Anybar {
    fn default() -> Anybar {
        Anybar{port:1738, color:None}
    }
}
<|endoftext|>


<commit_before>use crate::config::*;
use crate::errors::*;
use crate::ptrace_control::*;
use crate::statemachine::*;
use crate::test_loader::*;
use crate::traces::*;
use cargo::core::{compiler::CompileMode, Package, Shell, Workspace};
use cargo::ops;
use cargo::ops::{CompileOptions, CompileFilter, Packages, CleanOptions, clean, compile, TestOptions};
use cargo::util::{homedir, Config as CargoConfig};
use log::{debug, info, trace, warn};
use nix::unistd::*;
use std::env;
use std::ffi::CString;
use std::path::{Path, PathBuf};

pub mod breakpoint;
pub mod config;
pub mod errors;
pub mod report;
mod source_analysis;
mod statemachine;
pub mod test_loader;
pub mod traces;

/// Should be unnecessary with a future nix crate release.
mod personality;
mod ptrace_control;

static DOCTEST_FOLDER: &str = "target/doctests";

pub fn run(config: &Config) -> Result<(), RunError> {
    let (tracemap, ret) = launch_tarpaulin(config)?;
    report_coverage(config, &tracemap)?;

    if ret == 0 {
        Ok(())
    } else {
        Err(RunError::TestFailed)
    }
}

/// Launches tarpaulin with the given configuration.
pub fn launch_tarpaulin(config: &Config) -> Result<(TraceMap, i32), RunError> {
    setup_environment(&config);
    cargo::core::enable_nightly_features();
    let cwd = match config.manifest.parent() {
        Some(p) => p.to_path_buf(),
        None => PathBuf::new(),
    };
    let home = match homedir(&cwd) {
        Some(h) => h,
        None => {
            warn!("Warning failed to find home directory.");
            PathBuf::new()
        }
    };
    let mut cargo_config = CargoConfig::new(Shell::new(), cwd, home);
    let flag_quiet = if config.verbose { None } else { Some(true) };

    // This shouldn't fail so no checking the error.
    let _ = cargo_config.configure(0u32, flag_quiet, &None, false, false, &None, &[]);

    let workspace = Workspace::new(config.manifest.as_path(), &cargo_config)
        .map_err(|e| RunError::Manifest(e.to_string()))?;

    let mut compile_options = get_compile_options(&config, &cargo_config)?;

    info!("Running Tarpaulin");

    if config.force_clean {
        debug!("Cleaning project");
        // Clean isn't expected to fail and if it does it likely won't have an effect
        let clean_opt = CleanOptions {
            config: &cargo_config,
            spec: vec![],
            target: None,
            release: false,
            doc: false,
        };
        let _ = clean(&workspace, &clean_opt);
    }
    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    info!("Building project");
    for copt in compile_options.drain(..) {
        let run_result = match copt.build_config.mode {
            CompileMode::Test => run_tests(&workspace, copt, config),
            CompileMode::Doctest => run_doctests(&workspace, copt, config),
            e => {
                debug!("Internal tarpaulin error. Unsupported compile mode {:?}", e);
                Err(RunError::Internal)
            },
        }?;
        result.merge(&run_result.0);
        return_code |= run_result.1;
    }
    Ok((result, return_code))
}

fn run_tests(workspace: &Workspace, compile_options: CompileOptions, config: &Config) -> Result<(TraceMap, i32), RunError> {
    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    let compilation = compile(&workspace, &compile_options);
    match compilation {
        Ok(comp) => {
            for &(ref package, _, ref name, ref path) in &comp.tests {
                debug!("Processing {}", name);
                if let Some(res) =
                    get_test_coverage(&workspace, package, path.as_path(), config, false)?
                {
                    result.merge(&res.0);
                    return_code |= res.1;
                }
                if config.run_ignored {
                    if let Some(res) =
                        get_test_coverage(&workspace, package, path.as_path(), config, true)?
                    {
                        result.merge(&res.0);
                        return_code |= res.1;
                    }
                }
            }
            result.dedup();
            Ok((result, return_code))
        }
        Err(e) => return Err(RunError::TestCompile(e.to_string())),
    }
}

fn run_doctests(workspace: &Workspace,
                compile_options: CompileOptions,
                config: &Config) -> Result<(TraceMap, i32), RunError> {

    let opts = TestOptions {
        no_run: false,
        no_fail_fast: false,
        compile_opts: compile_options,
    };
    let _ = ops::run_tests(workspace, &opts, &[]);

    // go over all the doc tests and run them.
    let doctest_dir = match config.manifest.parent() {
        Some(p) => p.join(DOCTEST_FOLDER),
        None => PathBuf::from(DOCTEST_FOLDER)
    };
    unimplemented!()
}

fn get_compile_options<'a>(config: &Config,
                       cargo_config: &'a CargoConfig) -> Result<Vec<CompileOptions<'a>>, RunError> {
    let mut result = Vec::new();
    for run_type in &config.run_types {
        let mut copt = CompileOptions::new(cargo_config, (*run_type).into())
            .map_err(|e| RunError::Cargo(e.to_string()))?;
        if run_type == &RunType::Tests {
            if let CompileFilter::Default { ref mut required_features_filterable } = copt.filter
            {
                *required_features_filterable = true;
            }
        } else if run_type == &RunType::Doctests {
            copt.filter = CompileFilter::new(true, vec![], false, vec![], false, vec![], false, vec![], false, false);
        }

        copt.features = config.features.clone();
        copt.all_features = config.all_features;
        copt.no_default_features = config.no_default_features;
        copt.build_config.release = config.release;
        copt.spec = match Packages::from_flags(
            config.all,
            config.exclude.clone(),
            config.packages.clone(),
        ) {
            Ok(spec) => spec,
            Err(e) => {
                return Err(RunError::Packages(e.to_string()));
            }
        };
        result.push(copt);
    }
    Ok(result)
}

fn setup_environment(config: &Config) {
    let rustflags = "RUSTFLAGS";
    let mut value =
        " -C relocation-model=dynamic-no-pic -C link-dead-code -C opt-level=0 -C debuginfo=2 "
            .to_string();
    if config.release {
        value = format!("{}-C debug-assertions=off ", value);
    }
    if let Ok(vtemp) = env::var(rustflags) {
        value.push_str(vtemp.as_ref());
    }
    env::set_var(rustflags, value);
    // doesn't matter if we don't use it
    let rustdoc = "RUSTDOCFLAGS";
    let mut value = format!("--persist-doctests {} -Z unstable-options ", DOCTEST_FOLDER);
    if let Ok(vtemp) = env::var(rustdoc) {
        value.push_str(vtemp.as_ref());
    }
    env::set_var(rustdoc, value);
}

fn accumulate_lines(
    (mut acc, mut group): (Vec<String>, Vec<u64>),
    next: u64,
) -> (Vec<String>, Vec<u64>) {
    if let Some(last) = group.last().cloned() {
        if next == last + 1 {
            group.push(next);
            (acc, group)
        } else {
            match (group.first(), group.last()) {
                (Some(first), Some(last)) if first == last => {
                    acc.push(format!("{}", first));
                }
                (Some(first), Some(last)) => {
                    acc.push(format!("{}-{}", first, last));
                }
                (Some(_), None) | (None, _) => (),
            };
            (acc, vec![next])
        }
    } else {
        group.push(next);
        (acc, group)
    }
}

/// Reports the test coverage using the users preferred method. See config.rs
/// or help text for details.
pub fn report_coverage(config: &Config, result: &TraceMap) -> Result<(), RunError> {
    if !result.is_empty() {
        info!("Coverage Results:");
        if config.verbose {
            println!("|| Uncovered Lines:");
            for (ref key, ref value) in result.iter() {
                let path = config.strip_project_path(key);
                let mut uncovered_lines = vec![];
                for v in value.iter() {
                    match v.stats {
                        traces::CoverageStat::Line(count) if count == 0 => {
                            uncovered_lines.push(v.line);
                        }
                        _ => (),
                    }
                }
                uncovered_lines.sort();
                let (groups, last_group) = uncovered_lines
                    .into_iter()
                    .fold((vec![], vec![]), accumulate_lines);
                let (groups, _) = accumulate_lines((groups, last_group), u64::max_value());
                if !groups.is_empty() {
                    println!("|| {}: {}", path.display(), groups.join(", "));
                }
            }
        }
        println!("|| Tested/Total Lines:");
        for file in result.files() {
            let path = config.strip_project_path(file);
            println!(
                "|| {}: {}/{}",
                path.display(),
                result.covered_in_path(&file),
                result.coverable_in_path(&file)
            );
        }
        let percent = result.coverage_percentage() * 100.0f64;
        // Put file filtering here
        println!(
            "|| \n{:.2}% coverage, {}/{} lines covered",
            percent,
            result.total_covered(),
            result.total_coverable()
        );
        if config.is_coveralls() {
            report::coveralls::export(result, config)?;
            info!("Coverage data sent");
        }

        for g in &config.generate {
            match *g {
                OutputFile::Xml => {
                    report::cobertura::report(result, config).map_err(|e| RunError::XML(e))?;
                }
                OutputFile::Html => {
                    report::html::export(result, config)?;
                }
                _ => {
                    return Err(RunError::OutFormat(
                        "Format currently unsupported".to_string(),
                    ));
                }
            }
        }

        Ok(())
    } else {
        Err(RunError::CovReport(
            "No coverage results collected.".to_string(),
        ))
    }
}

/// Returns the coverage statistics for a test executable in the given workspace
pub fn get_test_coverage(
    project: &Workspace,
    package: &Package,
    test: &Path,
    config: &Config,
    ignored: bool,
) -> Result<Option<(TraceMap, i32)>, RunError> {
    if !test.exists() {
        return Ok(None);
    }
    match fork() {
        Ok(ForkResult::Parent { child }) => match collect_coverage(project, test, child, config) {
            Ok(t) => Ok(Some(t)),
            Err(e) => Err(RunError::TestCoverage(e.to_string())),
        },
        Ok(ForkResult::Child) => {
            info!("Launching test");
            execute_test(test, package, ignored, config)?;
            Ok(None)
        }
        Err(err) => Err(RunError::TestCoverage(format!(
            "Failed to run test {}, Error: {}",
            test.display(),
            err.to_string()
        ))),
    }
}

/// Collects the coverage data from the launched test
fn collect_coverage(
    project: &Workspace,
    test_path: &Path,
    test: Pid,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    let mut ret_code = 0;
    let mut traces = generate_tracemap(project, test_path, config)?;
    {
        trace!("Test PID is {}", test);
        let (mut state, mut data) = create_state_machine(test, &mut traces, config);
        loop {
            state = state.step(&mut data, config)?;
            if state.is_finished() {
                if let TestState::End(i) = state {
                    ret_code = i;
                }
                break;
            }
        }
    }
    Ok((traces, ret_code))
}

/// Launches the test executable
fn execute_test(
    test: &Path,
    package: &Package,
    ignored: bool,
    config: &Config,
) -> Result<(), RunError> {
    let exec_path = CString::new(test.to_str().unwrap()).unwrap();
    match personality::disable_aslr() {
        Ok(_) => {}
        Err(e) => return Err(RunError::TestRuntime(format!("ASLR disable failed: {}", e))),
    }
    match request_trace() {
        Ok(_) => {}
        Err(e) => return Err(RunError::Trace(e.to_string())),
    }
    info!("running {}", test.display());
    if let Some(parent) = package.manifest_path().parent() {
        let _ = env::set_current_dir(parent);
    }

    let mut envars: Vec<CString> = vec![CString::new("RUST_TEST_THREADS=1").unwrap()];
    for (key, value) in env::vars() {
        let mut temp = String::new();
        temp.push_str(key.as_str());
        temp.push('=');
        temp.push_str(value.as_str());
        envars.push(CString::new(temp).unwrap());
    }
    let mut argv = if ignored {
        vec![exec_path.clone(), CString::new("--ignored").unwrap()]
    } else {
        vec![exec_path.clone()]
    };
    if config.verbose {
        envars.push(CString::new("RUST_BACKTRACE=1").unwrap());
    } else {
        argv.push(CString::new("--quiet").unwrap());
    }
    for s in &config.varargs {
        argv.push(CString::new(s.as_bytes()).unwrap_or_default());
    }
    execve(&exec_path, &argv, envars.as_slice()).unwrap();

    Ok(())
}
<commit_msg>Now runs the doctests but hits pie based errors.<commit_after>use crate::config::*;
use crate::errors::*;
use crate::ptrace_control::*;
use crate::statemachine::*;
use crate::test_loader::*;
use crate::traces::*;
use cargo::core::{compiler::CompileMode, Package, Shell, Workspace};
use cargo::ops;
use cargo::ops::{CompileOptions, CompileFilter, Packages, CleanOptions, clean, compile, TestOptions};
use cargo::util::{homedir, Config as CargoConfig};
use log::{debug, info, trace, warn};
use nix::unistd::*;
use std::env;
use std::ffi::CString;
use std::path::{Path, PathBuf};
use walkdir::WalkDir;

pub mod breakpoint;
pub mod config;
pub mod errors;
pub mod report;
mod source_analysis;
mod statemachine;
pub mod test_loader;
pub mod traces;

/// Should be unnecessary with a future nix crate release.
mod personality;
mod ptrace_control;

static DOCTEST_FOLDER: &str = "target/doctests";

pub fn run(config: &Config) -> Result<(), RunError> {
    let (tracemap, ret) = launch_tarpaulin(config)?;
    report_coverage(config, &tracemap)?;

    if ret == 0 {
        Ok(())
    } else {
        Err(RunError::TestFailed)
    }
}

/// Launches tarpaulin with the given configuration.
pub fn launch_tarpaulin(config: &Config) -> Result<(TraceMap, i32), RunError> {
    setup_environment(&config);
    cargo::core::enable_nightly_features();
    let cwd = match config.manifest.parent() {
        Some(p) => p.to_path_buf(),
        None => PathBuf::new(),
    };
    let home = match homedir(&cwd) {
        Some(h) => h,
        None => {
            warn!("Warning failed to find home directory.");
            PathBuf::new()
        }
    };
    let mut cargo_config = CargoConfig::new(Shell::new(), cwd, home);
    let flag_quiet = if config.verbose { None } else { Some(true) };

    // This shouldn't fail so no checking the error.
    let _ = cargo_config.configure(0u32, flag_quiet, &None, false, false, &None, &[]);

    let workspace = Workspace::new(config.manifest.as_path(), &cargo_config)
        .map_err(|e| RunError::Manifest(e.to_string()))?;

    let mut compile_options = get_compile_options(&config, &cargo_config)?;

    info!("Running Tarpaulin");

    if config.force_clean {
        debug!("Cleaning project");
        // Clean isn't expected to fail and if it does it likely won't have an effect
        let clean_opt = CleanOptions {
            config: &cargo_config,
            spec: vec![],
            target: None,
            release: false,
            doc: false,
        };
        let _ = clean(&workspace, &clean_opt);
    }
    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    info!("Building project");
    for copt in compile_options.drain(..) {
        let run_result = match copt.build_config.mode {
            CompileMode::Test => run_tests(&workspace, copt, config),
            CompileMode::Doctest => run_doctests(&workspace, copt, config),
            e => {
                debug!("Internal tarpaulin error. Unsupported compile mode {:?}", e);
                Err(RunError::Internal)
            },
        }?;
        result.merge(&run_result.0);
        return_code |= run_result.1;
    }
    Ok((result, return_code))
}

fn run_tests(workspace: &Workspace, compile_options: CompileOptions, config: &Config) -> Result<(TraceMap, i32), RunError> {
    let mut result = TraceMap::new();
    let mut return_code = 0i32;
    let compilation = compile(&workspace, &compile_options);
    match compilation {
        Ok(comp) => {
            for &(ref package, _, ref name, ref path) in &comp.tests {
                debug!("Processing {}", name);
                if let Some(res) =
                    get_test_coverage(&workspace, Some(package), path.as_path(), config, false)?
                {
                    result.merge(&res.0);
                    return_code |= res.1;
                }
                if config.run_ignored {
                    if let Some(res) =
                        get_test_coverage(&workspace, Some(package), path.as_path(), config, true)?
                    {
                        result.merge(&res.0);
                        return_code |= res.1;
                    }
                }
            }
            result.dedup();
            Ok((result, return_code))
        }
        Err(e) => return Err(RunError::TestCompile(e.to_string())),
    }
}

fn run_doctests(workspace: &Workspace,
                compile_options: CompileOptions,
                config: &Config) -> Result<(TraceMap, i32), RunError> {
    let mut result = TraceMap::new();
    let mut return_code = 0i32;

    let opts = TestOptions {
        no_run: false,
        no_fail_fast: false,
        compile_opts: compile_options,
    };
    let _ = ops::run_tests(workspace, &opts, &[]);

    // go over all the doc tests and run them.
    let doctest_dir = match config.manifest.parent() {
        Some(p) => p.join(DOCTEST_FOLDER),
        None => PathBuf::from(DOCTEST_FOLDER)
    };
    let walker = WalkDir::new(&doctest_dir).into_iter();
    for dt in walker.filter_map(|e| e.ok()).filter(|e| e.file_type().is_file()) {
        trace!("Processing {}", config.strip_project_path(dt.path()).display());
        if let Some(res) = get_test_coverage(&workspace, None, dt.path(), config, false)?
        {
            result.merge(&res.0);
            return_code |= res.1;
        }

    }
    Ok((result, return_code))
}

fn get_compile_options<'a>(config: &Config,
                       cargo_config: &'a CargoConfig) -> Result<Vec<CompileOptions<'a>>, RunError> {
    let mut result = Vec::new();
    for run_type in &config.run_types {
        let mut copt = CompileOptions::new(cargo_config, (*run_type).into())
            .map_err(|e| RunError::Cargo(e.to_string()))?;
        if run_type == &RunType::Tests {
            if let CompileFilter::Default { ref mut required_features_filterable } = copt.filter
            {
                *required_features_filterable = true;
            }
        } else if run_type == &RunType::Doctests {
            copt.filter = CompileFilter::new(true, vec![], false, vec![], false, vec![], false, vec![], false, false);
        }

        copt.features = config.features.clone();
        copt.all_features = config.all_features;
        copt.no_default_features = config.no_default_features;
        copt.build_config.release = config.release;
        copt.spec = match Packages::from_flags(
            config.all,
            config.exclude.clone(),
            config.packages.clone(),
        ) {
            Ok(spec) => spec,
            Err(e) => {
                return Err(RunError::Packages(e.to_string()));
            }
        };
        result.push(copt);
    }
    Ok(result)
}

fn setup_environment(config: &Config) {
    let rustflags = "RUSTFLAGS";
    let mut value =
        " -C relocation-model=dynamic-no-pic -C link-dead-code -C opt-level=0 -C debuginfo=2 "
            .to_string();
    if config.release {
        value = format!("{}-C debug-assertions=off ", value);
    }
    if let Ok(vtemp) = env::var(rustflags) {
        value.push_str(vtemp.as_ref());
    }
    env::set_var(rustflags, value);
    // doesn't matter if we don't use it
    let rustdoc = "RUSTDOCFLAGS";
    let mut value = format!("--persist-doctests {} -Z unstable-options ", DOCTEST_FOLDER);
    if let Ok(vtemp) = env::var(rustdoc) {
        value.push_str(vtemp.as_ref());
    }
    env::set_var(rustdoc, value);
}

fn accumulate_lines(
    (mut acc, mut group): (Vec<String>, Vec<u64>),
    next: u64,
) -> (Vec<String>, Vec<u64>) {
    if let Some(last) = group.last().cloned() {
        if next == last + 1 {
            group.push(next);
            (acc, group)
        } else {
            match (group.first(), group.last()) {
                (Some(first), Some(last)) if first == last => {
                    acc.push(format!("{}", first));
                }
                (Some(first), Some(last)) => {
                    acc.push(format!("{}-{}", first, last));
                }
                (Some(_), None) | (None, _) => (),
            };
            (acc, vec![next])
        }
    } else {
        group.push(next);
        (acc, group)
    }
}

/// Reports the test coverage using the users preferred method. See config.rs
/// or help text for details.
pub fn report_coverage(config: &Config, result: &TraceMap) -> Result<(), RunError> {
    if !result.is_empty() {
        info!("Coverage Results:");
        if config.verbose {
            println!("|| Uncovered Lines:");
            for (ref key, ref value) in result.iter() {
                let path = config.strip_project_path(key);
                let mut uncovered_lines = vec![];
                for v in value.iter() {
                    match v.stats {
                        traces::CoverageStat::Line(count) if count == 0 => {
                            uncovered_lines.push(v.line);
                        }
                        _ => (),
                    }
                }
                uncovered_lines.sort();
                let (groups, last_group) = uncovered_lines
                    .into_iter()
                    .fold((vec![], vec![]), accumulate_lines);
                let (groups, _) = accumulate_lines((groups, last_group), u64::max_value());
                if !groups.is_empty() {
                    println!("|| {}: {}", path.display(), groups.join(", "));
                }
            }
        }
        println!("|| Tested/Total Lines:");
        for file in result.files() {
            let path = config.strip_project_path(file);
            println!(
                "|| {}: {}/{}",
                path.display(),
                result.covered_in_path(&file),
                result.coverable_in_path(&file)
            );
        }
        let percent = result.coverage_percentage() * 100.0f64;
        // Put file filtering here
        println!(
            "|| \n{:.2}% coverage, {}/{} lines covered",
            percent,
            result.total_covered(),
            result.total_coverable()
        );
        if config.is_coveralls() {
            report::coveralls::export(result, config)?;
            info!("Coverage data sent");
        }

        for g in &config.generate {
            match *g {
                OutputFile::Xml => {
                    report::cobertura::report(result, config).map_err(|e| RunError::XML(e))?;
                }
                OutputFile::Html => {
                    report::html::export(result, config)?;
                }
                _ => {
                    return Err(RunError::OutFormat(
                        "Format currently unsupported".to_string(),
                    ));
                }
            }
        }

        Ok(())
    } else {
        Err(RunError::CovReport(
            "No coverage results collected.".to_string(),
        ))
    }
}

/// Returns the coverage statistics for a test executable in the given workspace
pub fn get_test_coverage(
    project: &Workspace,
    package: Option<&Package>,
    test: &Path,
    config: &Config,
    ignored: bool,
) -> Result<Option<(TraceMap, i32)>, RunError> {
    if !test.exists() {
        return Ok(None);
    }
    match fork() {
        Ok(ForkResult::Parent { child }) => match collect_coverage(project, test, child, config) {
            Ok(t) => Ok(Some(t)),
            Err(e) => Err(RunError::TestCoverage(e.to_string())),
        },
        Ok(ForkResult::Child) => {
            info!("Launching test");
            execute_test(test, package, ignored, config)?;
            Ok(None)
        }
        Err(err) => Err(RunError::TestCoverage(format!(
            "Failed to run test {}, Error: {}",
            test.display(),
            err.to_string()
        ))),
    }
}

/// Collects the coverage data from the launched test
fn collect_coverage(
    project: &Workspace,
    test_path: &Path,
    test: Pid,
    config: &Config,
) -> Result<(TraceMap, i32), RunError> {
    let mut ret_code = 0;
    let mut traces = generate_tracemap(project, test_path, config)?;
    {
        trace!("Test PID is {}", test);
        let (mut state, mut data) = create_state_machine(test, &mut traces, config);
        loop {
            state = state.step(&mut data, config)?;
            if state.is_finished() {
                if let TestState::End(i) = state {
                    ret_code = i;
                }
                break;
            }
        }
    }
    Ok((traces, ret_code))
}

/// Launches the test executable
fn execute_test(
    test: &Path,
    package: Option<&Package>,
    ignored: bool,
    config: &Config,
) -> Result<(), RunError> {
    let exec_path = CString::new(test.to_str().unwrap()).unwrap();
    match personality::disable_aslr() {
        Ok(_) => {}
        Err(e) => return Err(RunError::TestRuntime(format!("ASLR disable failed: {}", e))),
    }
    match request_trace() {
        Ok(_) => {}
        Err(e) => return Err(RunError::Trace(e.to_string())),
    }
    info!("running {}", test.display());
    if let Some(pack) = package {
        if let Some(parent) = pack.manifest_path().parent() {
            let _ = env::set_current_dir(parent);
        }
    }

    let mut envars: Vec<CString> = vec![CString::new("RUST_TEST_THREADS=1").unwrap()];
    for (key, value) in env::vars() {
        let mut temp = String::new();
        temp.push_str(key.as_str());
        temp.push('=');
        temp.push_str(value.as_str());
        envars.push(CString::new(temp).unwrap());
    }
    let mut argv = if ignored {
        vec![exec_path.clone(), CString::new("--ignored").unwrap()]
    } else {
        vec![exec_path.clone()]
    };
    if config.verbose {
        envars.push(CString::new("RUST_BACKTRACE=1").unwrap());
    } else {
        argv.push(CString::new("--quiet").unwrap());
    }
    for s in &config.varargs {
        argv.push(CString::new(s.as_bytes()).unwrap_or_default());
    }
    execve(&exec_path, &argv, envars.as_slice()).unwrap();

    Ok(())
}
<|endoftext|>