<commit_before>// Copyright 2012-2014 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.

//! A very simple bit-vector that serves the needs of `primal`.

extern crate hamming;

use std::cmp::{self, Ordering};
use std::fmt;
use std::hash;
use std::ops::Index;

const BITS: usize = 64;

static TRUE: bool = true;
static FALSE: bool = false;

/// The bitvector type.
pub struct BitVec {
    /// Internal representation of the bit vector
    storage: Vec<u64>,
    /// The number of valid bits in the internal representation
    nbits: usize
}

impl Index<usize> for BitVec {
    type Output = bool;

    #[inline]
    fn index(&self, i: usize) -> &bool {
        if self.get(i).expect("index out of bounds") {
            &TRUE
        } else {
            &FALSE
        }
    }
}

impl BitVec {
    /// An operation might screw up the unused bits in the last block of the
    /// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up.
    fn fix_last_block(&mut self) {
        let extra_bits = self.len() % BITS;
        if extra_bits > 0 {
            let mask = (1 << extra_bits) - 1;
            let storage_len = self.storage.len();
            self.storage[storage_len - 1] &= mask;
        }
    }

    /// Creates an empty `BitVec`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    /// let mut bv = BitVec::new();
    /// ```
    pub fn new() -> BitVec {
        BitVec { storage: Vec::new(), nbits: 0 }
    }

    pub fn from_u64s(data: Vec<u64>, bits: usize) -> BitVec {
        assert!(bits <= data.len() * 64);
        let mut ret = BitVec { storage: data, nbits: bits };
        ret.fix_last_block();
        ret
    }
    #[inline]
    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
        unsafe {
            std::slice::from_raw_parts_mut(self.storage.as_mut_ptr() as *mut _,
                                           (self.nbits + 7) / 8)
        }
    }
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts(self.storage.as_ptr() as *const _,
                                       (self.nbits + 7) / 8)
        }
    }

    #[inline]
    pub fn as_u64s(&self) -> &[u64] {
        &self.storage
    }

    /// Count the number of ones for the bits up to but not including
    /// the `bit`th bit.
    pub fn count_ones_before(&self, bit: usize) -> usize {
        assert!(bit <= self.nbits);
        let (byte, bit) = (bit / 8, bit % 8);
        let mask = (1 << bit) - 1;

        let bytes = self.as_bytes();

        hamming::weight(&bytes[..byte]) as usize
            + bytes.get(byte).map_or(0, |b| (b & mask).count_ones() as usize)
    }

    /// Find the index of the `n`th (0-indexed) set bit.
    pub fn find_nth_bit(&self, mut n: usize) -> Option<usize> {
        n += 1;
        let all_bytes = self.as_bytes();
        let mut bytes = all_bytes;

        while bytes.len() > 240 {
            let ix = bytes.len() / 2;
            let (first, second) = bytes.split_at(ix);

            let count = hamming::weight(first) as usize;
            match count.cmp(&n) {
                Ordering::Equal | Ordering::Greater => {
                    bytes = first;
                }
                Ordering::Less => {
                    n -= count;
                    bytes = second;
                }
            }
        }

        let mut byte_idx = bytes.as_ptr() as usize - all_bytes.as_ptr() as usize;

        let mut b = 0;
        for &b_ in bytes {
            let count = b_.count_ones() as usize;
            if count >= n {
                b = b_;
                break
            }

            byte_idx += 1;
            n -= count
        }
        if b == 0 {
            None
        } else {
            // clear the bottom n-1 set bits, so that the lowest one
            // is the one we care about
            for _ in 1..n {
                b = b & (b - 1);
            }
            assert!(b != 0);

            Some(byte_idx * 8 + b.trailing_zeros() as usize)
        }
    }

    /// Creates a `BitVec` that holds `nbits` elements, setting each element
    /// to `bit`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let mut bv = BitVec::from_elem(10, false);
    /// assert_eq!(bv.len(), 10);
    /// for x in bv.iter() {
    ///     assert_eq!(x, false);
    /// }
    /// ```
    pub fn from_elem(nbits: usize, bit: bool) -> BitVec {
        use std::ptr;

        let nblocks = nbits.checked_add(BITS - 1).expect("capacity overflow") / BITS;
        let mut out_vec = Vec::with_capacity(nblocks);

        unsafe {
            out_vec.set_len(nblocks);
            ptr::write_bytes(out_vec.as_mut_ptr(), if bit { !0 } else { 0 }, nblocks);
        }

        let mut bit_vec = BitVec {
            storage: out_vec,
            nbits: nbits,
        };

        bit_vec.fix_last_block();
        bit_vec
    }

    /// Retrieves the value at index `i`, or `None` if the index is out of bounds.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let bv = BitVec::from_bytes(&[0b01100000]);
    /// assert_eq!(bv.get(0), Some(false));
    /// assert_eq!(bv.get(1), Some(true));
    /// assert_eq!(bv.get(100), None);
    ///
    /// // Can also use array indexing
    /// assert_eq!(bv[1], true);
    /// ```
    #[inline]
    pub fn get(&self, i: usize) -> Option<bool> {
        if i >= self.nbits {
            return None;
        }
        let w = i / BITS;
        let b = i % BITS;
        self.storage.get(w).map(|&block|
            (block & (1 << b)) != 0
        )
    }

    /// Sets the value of a bit at an index `i`.
    ///
    /// # Panics
    ///
    /// Panics if `i` is out of bounds.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let mut bv = BitVec::from_elem(5, false);
    /// bv.set(3, true);
    /// assert_eq!(bv[3], true);
    /// ```
    #[inline]
    pub fn set(&mut self, i: usize, x: bool) {
        assert!(i < self.nbits);
        unsafe {
            self.set_unchecked(i, x)
        }
    }

    #[inline]
    pub unsafe fn set_unchecked(&mut self, i: usize, x: bool) {
        //
        let w = i / BITS;
        let b = i % BITS;
        let flag = 1 << b;
        let ptr = self.storage.get_unchecked_mut(w);
        let val = if x { *ptr | flag } else { *ptr & !flag };
        *ptr = val;
    }

    /// Sets all bits to 1.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let before = 0b01100000;
    /// let after  = 0b11111111;
    ///
    /// let mut bv = BitVec::from_bytes(&[before]);
    /// bv.set_all();
    /// assert_eq!(bv, BitVec::from_bytes(&[after]));
    /// ```
    #[inline]
    pub fn set_all(&mut self) {
        for w in &mut self.storage { *w = !0; }
        self.fix_last_block();
    }

    /// Returns an iterator over the elements of the vector in order.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]);
    /// assert_eq!(bv.iter().filter(|x| *x).count(), 7);
    /// ```
    #[inline]
    pub fn iter(&self) -> Iter {
        Iter { bit_vec: self, next_idx: 0, end_idx: self.nbits }
    }

    /// Returns the total number of bits in this vector
    #[inline]
    pub fn len(&self) -> usize { self.nbits }

    /// Returns true if there are no bits in this vector
    #[inline]
    pub fn is_empty(&self) -> bool { self.len() == 0 }

    /// Clears all bits in this vector.
    #[inline]
    pub fn clear(&mut self) {
        for w in &mut self.storage { *w = 0; }
    }
}

impl Default for BitVec {
    #[inline]
    fn default() -> BitVec { BitVec::new() }
}
impl Clone for BitVec {
    #[inline]
    fn clone(&self) -> BitVec {
        BitVec { storage: self.storage.clone(), nbits: self.nbits }
    }

    #[inline]
    fn clone_from(&mut self, source: &BitVec) {
        self.nbits = source.nbits;
        self.storage.clone_from(&source.storage);
    }
}

impl fmt::Debug for BitVec {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        for bit in self {
            try!(write!(fmt, "{}", if bit { 1 } else { 0 }));
        }
        Ok(())
    }
}

impl hash::Hash for BitVec {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.nbits.hash(state);
        for elem in self.storage.iter().cloned() {
            elem.hash(state);
        }
    }
}

impl cmp::PartialEq for BitVec {
    #[inline]
    fn eq(&self, other: &BitVec) -> bool {
        if self.nbits != other.nbits {
            return false;
        }
        self.storage.iter().cloned().zip(other.storage.iter().cloned()).all(|(w1, w2)| w1 == w2)
    }
}

impl cmp::Eq for BitVec {}

/// An iterator for `BitVec`.
#[derive(Clone)]
pub struct Iter<'a> {
    bit_vec: &'a BitVec,
    next_idx: usize,
    end_idx: usize,
}

impl<'a> Iterator for Iter<'a> {
    type Item = bool;

    #[inline]
    fn next(&mut self) -> Option<bool> {
        if self.next_idx != self.end_idx {
            let idx = self.next_idx;
            self.next_idx += 1;
            Some(self.bit_vec[idx])
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let rem = self.end_idx - self.next_idx;
        (rem, Some(rem))
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<bool> {
        if self.next_idx != self.end_idx {
            self.end_idx -= 1;
            Some(self.bit_vec[self.end_idx])
        } else {
            None
        }
    }
}

impl<'a> ExactSizeIterator for Iter<'a> {}

impl<'a> IntoIterator for &'a BitVec {
    type Item = bool;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

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

    #[test]
    fn count_ones_before() {
        let len = 10000;

        let ones = BitVec::from_elem(len, true);
        let zeros = BitVec::from_elem(len, false);
        let mut halves = zeros.clone();
        for i in 0..len / 2 {
            halves.set(i * 2, true);
        }
        for i in 0..len + 1 {
            assert_eq!(ones.count_ones_before(i), i);
            assert_eq!(zeros.count_ones_before(i), 0);
            assert_eq!(halves.count_ones_before(i), (i + 1) / 2);
        }
    }

    #[test]
    fn find_nth_bit() {
        let len = 5000;

        let ones = BitVec::from_elem(len, true);
        let mut halves = BitVec::from_elem(len * 2, false);
        for i in 0..len {
            halves.set(i * 2, true);
        }
        for i in 0..len {
            assert_eq!(ones.find_nth_bit(i), Some(i));
            assert_eq!(halves.find_nth_bit(i), Some(i * 2));
        }
        assert_eq!(ones.find_nth_bit(len + 1), None);
        assert_eq!(halves.find_nth_bit(len + 1), None);

        assert_eq!(BitVec::new().find_nth_bit(0), None);
        assert_eq!(BitVec::from_elem(len, false).find_nth_bit(0), None);
    }
}
<commit_msg>Make vec initialisation safe<commit_after>// Copyright 2012-2014 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.

//! A very simple bit-vector that serves the needs of `primal`.

extern crate hamming;

use std::cmp::{self, Ordering};
use std::fmt;
use std::hash;
use std::ops::Index;

const BITS: usize = 64;

static TRUE: bool = true;
static FALSE: bool = false;

/// The bitvector type.
pub struct BitVec {
    /// Internal representation of the bit vector
    storage: Vec<u64>,
    /// The number of valid bits in the internal representation
    nbits: usize
}

impl Index<usize> for BitVec {
    type Output = bool;

    #[inline]
    fn index(&self, i: usize) -> &bool {
        if self.get(i).expect("index out of bounds") {
            &TRUE
        } else {
            &FALSE
        }
    }
}

impl BitVec {
    /// An operation might screw up the unused bits in the last block of the
    /// `BitVec`. As per (3), it's assumed to be all 0s. This method fixes it up.
    fn fix_last_block(&mut self) {
        let extra_bits = self.len() % BITS;
        if extra_bits > 0 {
            let mask = (1 << extra_bits) - 1;
            let storage_len = self.storage.len();
            self.storage[storage_len - 1] &= mask;
        }
    }

    /// Creates an empty `BitVec`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    /// let mut bv = BitVec::new();
    /// ```
    pub fn new() -> BitVec {
        BitVec { storage: Vec::new(), nbits: 0 }
    }

    pub fn from_u64s(data: Vec<u64>, bits: usize) -> BitVec {
        assert!(bits <= data.len() * 64);
        let mut ret = BitVec { storage: data, nbits: bits };
        ret.fix_last_block();
        ret
    }
    #[inline]
    pub fn as_bytes_mut(&mut self) -> &mut [u8] {
        unsafe {
            std::slice::from_raw_parts_mut(self.storage.as_mut_ptr() as *mut _,
                                           (self.nbits + 7) / 8)
        }
    }
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        unsafe {
            std::slice::from_raw_parts(self.storage.as_ptr() as *const _,
                                       (self.nbits + 7) / 8)
        }
    }

    #[inline]
    pub fn as_u64s(&self) -> &[u64] {
        &self.storage
    }

    /// Count the number of ones for the bits up to but not including
    /// the `bit`th bit.
    pub fn count_ones_before(&self, bit: usize) -> usize {
        assert!(bit <= self.nbits);
        let (byte, bit) = (bit / 8, bit % 8);
        let mask = (1 << bit) - 1;

        let bytes = self.as_bytes();

        hamming::weight(&bytes[..byte]) as usize
            + bytes.get(byte).map_or(0, |b| (b & mask).count_ones() as usize)
    }

    /// Find the index of the `n`th (0-indexed) set bit.
    pub fn find_nth_bit(&self, mut n: usize) -> Option<usize> {
        n += 1;
        let all_bytes = self.as_bytes();
        let mut bytes = all_bytes;

        while bytes.len() > 240 {
            let ix = bytes.len() / 2;
            let (first, second) = bytes.split_at(ix);

            let count = hamming::weight(first) as usize;
            match count.cmp(&n) {
                Ordering::Equal | Ordering::Greater => {
                    bytes = first;
                }
                Ordering::Less => {
                    n -= count;
                    bytes = second;
                }
            }
        }

        let mut byte_idx = bytes.as_ptr() as usize - all_bytes.as_ptr() as usize;

        let mut b = 0;
        for &b_ in bytes {
            let count = b_.count_ones() as usize;
            if count >= n {
                b = b_;
                break
            }

            byte_idx += 1;
            n -= count
        }
        if b == 0 {
            None
        } else {
            // clear the bottom n-1 set bits, so that the lowest one
            // is the one we care about
            for _ in 1..n {
                b = b & (b - 1);
            }
            assert!(b != 0);

            Some(byte_idx * 8 + b.trailing_zeros() as usize)
        }
    }

    /// Creates a `BitVec` that holds `nbits` elements, setting each element
    /// to `bit`.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let mut bv = BitVec::from_elem(10, false);
    /// assert_eq!(bv.len(), 10);
    /// for x in bv.iter() {
    ///     assert_eq!(x, false);
    /// }
    /// ```
    pub fn from_elem(nbits: usize, bit: bool) -> BitVec {
        let nblocks = nbits.checked_add(BITS - 1).expect("capacity overflow") / BITS;
        let out_vec = vec![if bit { !0 } else { 0 }; nblocks];

        let mut bit_vec = BitVec {
            storage: out_vec,
            nbits: nbits,
        };

        bit_vec.fix_last_block();
        bit_vec
    }

    /// Retrieves the value at index `i`, or `None` if the index is out of bounds.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let bv = BitVec::from_bytes(&[0b01100000]);
    /// assert_eq!(bv.get(0), Some(false));
    /// assert_eq!(bv.get(1), Some(true));
    /// assert_eq!(bv.get(100), None);
    ///
    /// // Can also use array indexing
    /// assert_eq!(bv[1], true);
    /// ```
    #[inline]
    pub fn get(&self, i: usize) -> Option<bool> {
        if i >= self.nbits {
            return None;
        }
        let w = i / BITS;
        let b = i % BITS;
        self.storage.get(w).map(|&block|
            (block & (1 << b)) != 0
        )
    }

    /// Sets the value of a bit at an index `i`.
    ///
    /// # Panics
    ///
    /// Panics if `i` is out of bounds.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let mut bv = BitVec::from_elem(5, false);
    /// bv.set(3, true);
    /// assert_eq!(bv[3], true);
    /// ```
    #[inline]
    pub fn set(&mut self, i: usize, x: bool) {
        assert!(i < self.nbits);
        unsafe {
            self.set_unchecked(i, x)
        }
    }

    #[inline]
    pub unsafe fn set_unchecked(&mut self, i: usize, x: bool) {
        //
        let w = i / BITS;
        let b = i % BITS;
        let flag = 1 << b;
        let ptr = self.storage.get_unchecked_mut(w);
        let val = if x { *ptr | flag } else { *ptr & !flag };
        *ptr = val;
    }

    /// Sets all bits to 1.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let before = 0b01100000;
    /// let after  = 0b11111111;
    ///
    /// let mut bv = BitVec::from_bytes(&[before]);
    /// bv.set_all();
    /// assert_eq!(bv, BitVec::from_bytes(&[after]));
    /// ```
    #[inline]
    pub fn set_all(&mut self) {
        for w in &mut self.storage { *w = !0; }
        self.fix_last_block();
    }

    /// Returns an iterator over the elements of the vector in order.
    ///
    /// # Examples
    ///
    /// ```ignore
    /// use std::collections::BitVec;
    ///
    /// let bv = BitVec::from_bytes(&[0b01110100, 0b10010010]);
    /// assert_eq!(bv.iter().filter(|x| *x).count(), 7);
    /// ```
    #[inline]
    pub fn iter(&self) -> Iter {
        Iter { bit_vec: self, next_idx: 0, end_idx: self.nbits }
    }

    /// Returns the total number of bits in this vector
    #[inline]
    pub fn len(&self) -> usize { self.nbits }

    /// Returns true if there are no bits in this vector
    #[inline]
    pub fn is_empty(&self) -> bool { self.len() == 0 }

    /// Clears all bits in this vector.
    #[inline]
    pub fn clear(&mut self) {
        for w in &mut self.storage { *w = 0; }
    }
}

impl Default for BitVec {
    #[inline]
    fn default() -> BitVec { BitVec::new() }
}
impl Clone for BitVec {
    #[inline]
    fn clone(&self) -> BitVec {
        BitVec { storage: self.storage.clone(), nbits: self.nbits }
    }

    #[inline]
    fn clone_from(&mut self, source: &BitVec) {
        self.nbits = source.nbits;
        self.storage.clone_from(&source.storage);
    }
}

impl fmt::Debug for BitVec {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        for bit in self {
            try!(write!(fmt, "{}", if bit { 1 } else { 0 }));
        }
        Ok(())
    }
}

impl hash::Hash for BitVec {
    fn hash<H: hash::Hasher>(&self, state: &mut H) {
        self.nbits.hash(state);
        for elem in self.storage.iter().cloned() {
            elem.hash(state);
        }
    }
}

impl cmp::PartialEq for BitVec {
    #[inline]
    fn eq(&self, other: &BitVec) -> bool {
        if self.nbits != other.nbits {
            return false;
        }
        self.storage.iter().cloned().zip(other.storage.iter().cloned()).all(|(w1, w2)| w1 == w2)
    }
}

impl cmp::Eq for BitVec {}

/// An iterator for `BitVec`.
#[derive(Clone)]
pub struct Iter<'a> {
    bit_vec: &'a BitVec,
    next_idx: usize,
    end_idx: usize,
}

impl<'a> Iterator for Iter<'a> {
    type Item = bool;

    #[inline]
    fn next(&mut self) -> Option<bool> {
        if self.next_idx != self.end_idx {
            let idx = self.next_idx;
            self.next_idx += 1;
            Some(self.bit_vec[idx])
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let rem = self.end_idx - self.next_idx;
        (rem, Some(rem))
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    #[inline]
    fn next_back(&mut self) -> Option<bool> {
        if self.next_idx != self.end_idx {
            self.end_idx -= 1;
            Some(self.bit_vec[self.end_idx])
        } else {
            None
        }
    }
}

impl<'a> ExactSizeIterator for Iter<'a> {}

impl<'a> IntoIterator for &'a BitVec {
    type Item = bool;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

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

    #[test]
    fn count_ones_before() {
        let len = 10000;

        let ones = BitVec::from_elem(len, true);
        let zeros = BitVec::from_elem(len, false);
        let mut halves = zeros.clone();
        for i in 0..len / 2 {
            halves.set(i * 2, true);
        }
        for i in 0..len + 1 {
            assert_eq!(ones.count_ones_before(i), i);
            assert_eq!(zeros.count_ones_before(i), 0);
            assert_eq!(halves.count_ones_before(i), (i + 1) / 2);
        }
    }

    #[test]
    fn find_nth_bit() {
        let len = 5000;

        let ones = BitVec::from_elem(len, true);
        let mut halves = BitVec::from_elem(len * 2, false);
        for i in 0..len {
            halves.set(i * 2, true);
        }
        for i in 0..len {
            assert_eq!(ones.find_nth_bit(i), Some(i));
            assert_eq!(halves.find_nth_bit(i), Some(i * 2));
        }
        assert_eq!(ones.find_nth_bit(len + 1), None);
        assert_eq!(halves.find_nth_bit(len + 1), None);

        assert_eq!(BitVec::new().find_nth_bit(0), None);
        assert_eq!(BitVec::from_elem(len, false).find_nth_bit(0), None);
    }
}
<|endoftext|>


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

//! Memory profiling functions.

use libc::{c_char,c_int,c_void,size_t};
use std::borrow::ToOwned;
use std::ffi::CString;
use std::old_io::timer::sleep;
#[cfg(target_os="linux")]
use std::old_io::File;
use std::mem::size_of;
use std::ptr::null_mut;
use std::sync::mpsc::{Sender, channel, Receiver};
use std::time::duration::Duration;
use task::spawn_named;
#[cfg(target_os="macos")]
use task_info::task_basic_info::{virtual_size,resident_size};

pub struct MemoryProfilerChan(pub Sender<MemoryProfilerMsg>);

impl MemoryProfilerChan {
    pub fn send(&self, msg: MemoryProfilerMsg) {
        let MemoryProfilerChan(ref c) = *self;
        c.send(msg).unwrap();
    }
}

pub enum MemoryProfilerMsg {
    /// Message used to force print the memory profiling metrics.
    Print,
    /// Tells the memory profiler to shut down.
    Exit,
}

pub struct MemoryProfiler {
    pub port: Receiver<MemoryProfilerMsg>,
}

impl MemoryProfiler {
    pub fn create(period: Option<f64>) -> MemoryProfilerChan {
        let (chan, port) = channel();
        match period {
            Some(period) => {
                let period = Duration::milliseconds((period * 1000f64) as i64);
                let chan = chan.clone();
                spawn_named("Memory profiler timer".to_owned(), move || {
                    loop {
                        sleep(period);
                        if chan.send(MemoryProfilerMsg::Print).is_err() {
                            break;
                        }
                    }
                });
                // Spawn the memory profiler.
                spawn_named("Memory profiler".to_owned(), move || {
                    let memory_profiler = MemoryProfiler::new(port);
                    memory_profiler.start();
                });
            }
            None => {
                // No-op to handle messages when the memory profiler is
                // inactive.
                spawn_named("Memory profiler".to_owned(), move || {
                    loop {
                        match port.recv() {
                            Err(_) | Ok(MemoryProfilerMsg::Exit) => break,
                            _ => {}
                        }
                    }
                });
            }
        }

        MemoryProfilerChan(chan)
    }

    pub fn new(port: Receiver<MemoryProfilerMsg>) -> MemoryProfiler {
        MemoryProfiler {
            port: port
        }
    }

    pub fn start(&self) {
        loop {
            match self.port.recv() {
               Ok(msg) => {
                   if !self.handle_msg(msg) {
                       break
                   }
               }
               _ => break
            }
        }
    }

    fn handle_msg(&self, msg: MemoryProfilerMsg) -> bool {
        match msg {
            MemoryProfilerMsg::Print => {
                self.handle_print_msg();
                true
            },
            MemoryProfilerMsg::Exit => false
        }
    }

    fn print_measurement(path: &str, nbytes: Option<u64>) {
        match nbytes {
            Some(nbytes) => {
                let mebi = 1024f64 * 1024f64;
                println!("{:12.2}: {}", (nbytes as f64) / mebi, path);
            }
            None => {
                println!("{:>12}: {}", "???", path);
            }
        }
    }

    fn handle_print_msg(&self) {
        println!("{:12}: {}", "_size (MiB)_", "_category_");

        // Virtual and physical memory usage, as reported by the OS.
        MemoryProfiler::print_measurement("vsize", get_vsize());
        MemoryProfiler::print_measurement("resident", get_resident());

        for seg in get_resident_segments().iter() {
            MemoryProfiler::print_measurement(seg.0.as_slice(), Some(seg.1));
        }

        // Total number of bytes allocated by the application on the system
        // heap.
        MemoryProfiler::print_measurement("system-heap-allocated",
                                          get_system_heap_allocated());

        // The descriptions of the following jemalloc measurements are taken
        // directly from the jemalloc documentation.

        // "Total number of bytes allocated by the application."
        MemoryProfiler::print_measurement("jemalloc-heap-allocated",
                                          get_jemalloc_stat("stats.allocated"));

        // "Total number of bytes in active pages allocated by the application.
        // This is a multiple of the page size, and greater than or equal to
        // |stats.allocated|."
        MemoryProfiler::print_measurement("jemalloc-heap-active",
                                          get_jemalloc_stat("stats.active"));

        // "Total number of bytes in chunks mapped on behalf of the application.
        // This is a multiple of the chunk size, and is at least as large as
        // |stats.active|. This does not include inactive chunks."
        MemoryProfiler::print_measurement("jemalloc-heap-mapped",
                                          get_jemalloc_stat("stats.mapped"));

        println!("");
    }
}

#[cfg(target_os="linux")]
extern {
    fn mallinfo() -> struct_mallinfo;
}

#[cfg(target_os="linux")]
#[repr(C)]
pub struct struct_mallinfo {
    arena:    c_int,
    ordblks:  c_int,
    smblks:   c_int,
    hblks:    c_int,
    hblkhd:   c_int,
    usmblks:  c_int,
    fsmblks:  c_int,
    uordblks: c_int,
    fordblks: c_int,
    keepcost: c_int,
}

#[cfg(target_os="linux")]
fn get_system_heap_allocated() -> Option<u64> {
    let mut info: struct_mallinfo;
    unsafe {
        info = mallinfo();
    }
    // The documentation in the glibc man page makes it sound like |uordblks|
    // would suffice, but that only gets the small allocations that are put in
    // the brk heap. We need |hblkhd| as well to get the larger allocations
    // that are mmapped.
    Some((info.hblkhd + info.uordblks) as u64)
}

#[cfg(not(target_os="linux"))]
fn get_system_heap_allocated() -> Option<u64> {
    None
}

extern {
    fn je_mallctl(name: *const c_char, oldp: *mut c_void, oldlenp: *mut size_t,
                  newp: *mut c_void, newlen: size_t) -> c_int;
}

fn get_jemalloc_stat(value_name: &str) -> Option<u64> {
    // Before we request the measurement of interest, we first send an "epoch"
    // request. Without that jemalloc gives cached statistics(!) which can be
    // highly inaccurate.
    let epoch_name = "epoch";
    let epoch_c_name = CString::from_slice(epoch_name.as_bytes());
    let mut epoch: u64 = 0;
    let epoch_ptr = &mut epoch as *mut _ as *mut c_void;
    let mut epoch_len = size_of::<u64>() as size_t;

    let value_c_name = CString::from_slice(value_name.as_bytes());
    let mut value: size_t = 0;
    let value_ptr = &mut value as *mut _ as *mut c_void;
    let mut value_len = size_of::<size_t>() as size_t;

    // Using the same values for the `old` and `new` parameters is enough
    // to get the statistics updated.
    let rv = unsafe {
        je_mallctl(epoch_c_name.as_ptr(), epoch_ptr, &mut epoch_len, epoch_ptr,
                   epoch_len)
    };
    if rv != 0 {
        return None;
    }

    let rv = unsafe {
        je_mallctl(value_c_name.as_ptr(), value_ptr, &mut value_len,
                   null_mut(), 0)
    };
    if rv != 0 {
        return None;
    }

    Some(value as u64)
}

// Like std::macros::try!, but for Option<>.
macro_rules! option_try(
    ($e:expr) => (match $e { Some(e) => e, None => return None })
);

#[cfg(target_os="linux")]
fn get_proc_self_statm_field(field: usize) -> Option<u64> {
    let mut f = File::open(&Path::new("/proc/self/statm"));
    match f.read_to_string() {
        Ok(contents) => {
            let s = option_try!(contents.as_slice().words().nth(field));
            let npages = option_try!(s.parse::<u64>().ok());
            Some(npages * (::std::env::page_size() as u64))
        }
        Err(_) => None
    }
}

#[cfg(target_os="linux")]
fn get_vsize() -> Option<u64> {
    get_proc_self_statm_field(0)
}

#[cfg(target_os="linux")]
fn get_resident() -> Option<u64> {
    get_proc_self_statm_field(1)
}

#[cfg(target_os="macos")]
fn get_vsize() -> Option<u64> {
    virtual_size()
}

#[cfg(target_os="macos")]
fn get_resident() -> Option<u64> {
    resident_size()
}

#[cfg(not(any(target_os="linux", target_os = "macos")))]
fn get_vsize() -> Option<u64> {
    None
}

#[cfg(not(any(target_os="linux", target_os = "macos")))]
fn get_resident() -> Option<u64> {
    None
}

#[cfg(target_os="linux")]
fn get_resident_segments() -> Vec<(String, u64)> {
    use regex::Regex;
    use std::collections::HashMap;
    use std::collections::hash_map::Entry;

    // The first line of an entry in /proc/<pid>/smaps looks just like an entry
    // in /proc/<pid>/maps:
    //
    //   address           perms offset  dev   inode  pathname
    //   02366000-025d8000 rw-p 00000000 00:00 0      [heap]
    //
    // Each of the following lines contains a key and a value, separated
    // by ": ", where the key does not contain either of those characters.
    // For example:
    //
    //   Rss:           132 kB

    let path = Path::new("/proc/self/smaps");
    let mut f = ::std::old_io::BufferedReader::new(File::open(&path));

    let seg_re = Regex::new(
        r"^[:xdigit:]+-[:xdigit:]+ (....) [:xdigit:]+ [:xdigit:]+:[:xdigit:]+ \d+ +(.*)").unwrap();
    let rss_re = Regex::new(r"^Rss: +(\d+) kB").unwrap();

    // We record each segment's resident size.
    let mut seg_map: HashMap<String, u64> = HashMap::new();

    #[derive(PartialEq)]
    enum LookingFor { Segment, Rss }
    let mut looking_for = LookingFor::Segment;

    let mut curr_seg_name = String::new();

    // Parse the file.
    for line in f.lines() {
        let line = match line {
            Ok(line) => line,
            Err(_) => continue,
        };
        if looking_for == LookingFor::Segment {
            // Look for a segment info line.
            let cap = match seg_re.captures(line.as_slice()) {
                Some(cap) => cap,
                None => continue,
            };
            let perms = cap.at(1).unwrap();
            let pathname = cap.at(2).unwrap();

            // Construct the segment name from its pathname and permissions.
            curr_seg_name.clear();
            curr_seg_name.push_str("- ");
            if pathname == "" || pathname.starts_with("[stack:") {
                // Anonymous memory. Entries marked with "[stack:nnn]"
                // look like thread stacks but they may include other
                // anonymous mappings, so we can't trust them and just
                // treat them as entirely anonymous.
                curr_seg_name.push_str("anonymous");
            } else {
                curr_seg_name.push_str(pathname);
            }
            curr_seg_name.push_str(" (");
            curr_seg_name.push_str(perms);
            curr_seg_name.push_str(")");

            looking_for = LookingFor::Rss;
        } else {
            // Look for an "Rss:" line.
            let cap = match rss_re.captures(line.as_slice()) {
                Some(cap) => cap,
                None => continue,
            };
            let rss = cap.at(1).unwrap().parse::<u64>().unwrap() * 1024;

            if rss > 0 {
                // Aggregate small segments into "- other".
                let seg_name = if rss < 512 * 1024 {
                    "- other".to_owned()
                } else {
                    curr_seg_name.clone()
                };
                match seg_map.entry(seg_name) {
                    Entry::Vacant(entry) => { entry.insert(rss); },
                    Entry::Occupied(mut entry) => *entry.get_mut() += rss,
                }
            }

            looking_for = LookingFor::Segment;
        }
    }

    let mut segs: Vec<(String, u64)> = seg_map.into_iter().collect();

    // Get the total and add it to the vector. Note that this total differs
    // from the "resident" measurement obtained via /proc/<pid>/statm in
    // get_resident(). It's unclear why this difference occurs; for some
    // processes the measurements match, but for Servo they do not.
    let total = segs.iter().fold(0u64, |total, &(_, size)| total + size);
    segs.push(("resident-according-to-smaps".to_owned(), total));

    // Sort by size; the total will be first.
    segs.sort_by(|&(_, rss1), &(_, rss2)| rss2.cmp(&rss1));

    segs
}

#[cfg(not(target_os="linux"))]
fn get_resident_segments() -> Vec<(String, u64)> {
    vec![]
}

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

//! Memory profiling functions.

use libc::{c_char,c_int,c_void,size_t};
use std::borrow::ToOwned;
use std::ffi::CString;
use std::iter::AdditiveIterator;
use std::old_io::timer::sleep;
#[cfg(target_os="linux")]
use std::old_io::File;
use std::mem::size_of;
use std::ptr::null_mut;
use std::sync::mpsc::{Sender, channel, Receiver};
use std::time::duration::Duration;
use task::spawn_named;
#[cfg(target_os="macos")]
use task_info::task_basic_info::{virtual_size,resident_size};

pub struct MemoryProfilerChan(pub Sender<MemoryProfilerMsg>);

impl MemoryProfilerChan {
    pub fn send(&self, msg: MemoryProfilerMsg) {
        let MemoryProfilerChan(ref c) = *self;
        c.send(msg).unwrap();
    }
}

pub enum MemoryProfilerMsg {
    /// Message used to force print the memory profiling metrics.
    Print,
    /// Tells the memory profiler to shut down.
    Exit,
}

pub struct MemoryProfiler {
    pub port: Receiver<MemoryProfilerMsg>,
}

impl MemoryProfiler {
    pub fn create(period: Option<f64>) -> MemoryProfilerChan {
        let (chan, port) = channel();
        match period {
            Some(period) => {
                let period = Duration::milliseconds((period * 1000f64) as i64);
                let chan = chan.clone();
                spawn_named("Memory profiler timer".to_owned(), move || {
                    loop {
                        sleep(period);
                        if chan.send(MemoryProfilerMsg::Print).is_err() {
                            break;
                        }
                    }
                });
                // Spawn the memory profiler.
                spawn_named("Memory profiler".to_owned(), move || {
                    let memory_profiler = MemoryProfiler::new(port);
                    memory_profiler.start();
                });
            }
            None => {
                // No-op to handle messages when the memory profiler is
                // inactive.
                spawn_named("Memory profiler".to_owned(), move || {
                    loop {
                        match port.recv() {
                            Err(_) | Ok(MemoryProfilerMsg::Exit) => break,
                            _ => {}
                        }
                    }
                });
            }
        }

        MemoryProfilerChan(chan)
    }

    pub fn new(port: Receiver<MemoryProfilerMsg>) -> MemoryProfiler {
        MemoryProfiler {
            port: port
        }
    }

    pub fn start(&self) {
        loop {
            match self.port.recv() {
               Ok(msg) => {
                   if !self.handle_msg(msg) {
                       break
                   }
               }
               _ => break
            }
        }
    }

    fn handle_msg(&self, msg: MemoryProfilerMsg) -> bool {
        match msg {
            MemoryProfilerMsg::Print => {
                self.handle_print_msg();
                true
            },
            MemoryProfilerMsg::Exit => false
        }
    }

    fn print_measurement(path: &str, nbytes: Option<u64>) {
        match nbytes {
            Some(nbytes) => {
                let mebi = 1024f64 * 1024f64;
                println!("{:12.2}: {}", (nbytes as f64) / mebi, path);
            }
            None => {
                println!("{:>12}: {}", "???", path);
            }
        }
    }

    fn handle_print_msg(&self) {
        println!("{:12}: {}", "_size (MiB)_", "_category_");

        // Virtual and physical memory usage, as reported by the OS.
        MemoryProfiler::print_measurement("vsize", get_vsize());
        MemoryProfiler::print_measurement("resident", get_resident());

        for seg in get_resident_segments().iter() {
            MemoryProfiler::print_measurement(seg.0.as_slice(), Some(seg.1));
        }

        // Total number of bytes allocated by the application on the system
        // heap.
        MemoryProfiler::print_measurement("system-heap-allocated",
                                          get_system_heap_allocated());

        // The descriptions of the following jemalloc measurements are taken
        // directly from the jemalloc documentation.

        // "Total number of bytes allocated by the application."
        MemoryProfiler::print_measurement("jemalloc-heap-allocated",
                                          get_jemalloc_stat("stats.allocated"));

        // "Total number of bytes in active pages allocated by the application.
        // This is a multiple of the page size, and greater than or equal to
        // |stats.allocated|."
        MemoryProfiler::print_measurement("jemalloc-heap-active",
                                          get_jemalloc_stat("stats.active"));

        // "Total number of bytes in chunks mapped on behalf of the application.
        // This is a multiple of the chunk size, and is at least as large as
        // |stats.active|. This does not include inactive chunks."
        MemoryProfiler::print_measurement("jemalloc-heap-mapped",
                                          get_jemalloc_stat("stats.mapped"));

        println!("");
    }
}

#[cfg(target_os="linux")]
extern {
    fn mallinfo() -> struct_mallinfo;
}

#[cfg(target_os="linux")]
#[repr(C)]
pub struct struct_mallinfo {
    arena:    c_int,
    ordblks:  c_int,
    smblks:   c_int,
    hblks:    c_int,
    hblkhd:   c_int,
    usmblks:  c_int,
    fsmblks:  c_int,
    uordblks: c_int,
    fordblks: c_int,
    keepcost: c_int,
}

#[cfg(target_os="linux")]
fn get_system_heap_allocated() -> Option<u64> {
    let mut info: struct_mallinfo;
    unsafe {
        info = mallinfo();
    }
    // The documentation in the glibc man page makes it sound like |uordblks|
    // would suffice, but that only gets the small allocations that are put in
    // the brk heap. We need |hblkhd| as well to get the larger allocations
    // that are mmapped.
    Some((info.hblkhd + info.uordblks) as u64)
}

#[cfg(not(target_os="linux"))]
fn get_system_heap_allocated() -> Option<u64> {
    None
}

extern {
    fn je_mallctl(name: *const c_char, oldp: *mut c_void, oldlenp: *mut size_t,
                  newp: *mut c_void, newlen: size_t) -> c_int;
}

fn get_jemalloc_stat(value_name: &str) -> Option<u64> {
    // Before we request the measurement of interest, we first send an "epoch"
    // request. Without that jemalloc gives cached statistics(!) which can be
    // highly inaccurate.
    let epoch_name = "epoch";
    let epoch_c_name = CString::from_slice(epoch_name.as_bytes());
    let mut epoch: u64 = 0;
    let epoch_ptr = &mut epoch as *mut _ as *mut c_void;
    let mut epoch_len = size_of::<u64>() as size_t;

    let value_c_name = CString::from_slice(value_name.as_bytes());
    let mut value: size_t = 0;
    let value_ptr = &mut value as *mut _ as *mut c_void;
    let mut value_len = size_of::<size_t>() as size_t;

    // Using the same values for the `old` and `new` parameters is enough
    // to get the statistics updated.
    let rv = unsafe {
        je_mallctl(epoch_c_name.as_ptr(), epoch_ptr, &mut epoch_len, epoch_ptr,
                   epoch_len)
    };
    if rv != 0 {
        return None;
    }

    let rv = unsafe {
        je_mallctl(value_c_name.as_ptr(), value_ptr, &mut value_len,
                   null_mut(), 0)
    };
    if rv != 0 {
        return None;
    }

    Some(value as u64)
}

// Like std::macros::try!, but for Option<>.
macro_rules! option_try(
    ($e:expr) => (match $e { Some(e) => e, None => return None })
);

#[cfg(target_os="linux")]
fn get_proc_self_statm_field(field: usize) -> Option<u64> {
    let mut f = File::open(&Path::new("/proc/self/statm"));
    match f.read_to_string() {
        Ok(contents) => {
            let s = option_try!(contents.as_slice().words().nth(field));
            let npages = option_try!(s.parse::<u64>().ok());
            Some(npages * (::std::env::page_size() as u64))
        }
        Err(_) => None
    }
}

#[cfg(target_os="linux")]
fn get_vsize() -> Option<u64> {
    get_proc_self_statm_field(0)
}

#[cfg(target_os="linux")]
fn get_resident() -> Option<u64> {
    get_proc_self_statm_field(1)
}

#[cfg(target_os="macos")]
fn get_vsize() -> Option<u64> {
    virtual_size()
}

#[cfg(target_os="macos")]
fn get_resident() -> Option<u64> {
    resident_size()
}

#[cfg(not(any(target_os="linux", target_os = "macos")))]
fn get_vsize() -> Option<u64> {
    None
}

#[cfg(not(any(target_os="linux", target_os = "macos")))]
fn get_resident() -> Option<u64> {
    None
}

#[cfg(target_os="linux")]
fn get_resident_segments() -> Vec<(String, u64)> {
    use regex::Regex;
    use std::collections::HashMap;
    use std::collections::hash_map::Entry;

    // The first line of an entry in /proc/<pid>/smaps looks just like an entry
    // in /proc/<pid>/maps:
    //
    //   address           perms offset  dev   inode  pathname
    //   02366000-025d8000 rw-p 00000000 00:00 0      [heap]
    //
    // Each of the following lines contains a key and a value, separated
    // by ": ", where the key does not contain either of those characters.
    // For example:
    //
    //   Rss:           132 kB

    let path = Path::new("/proc/self/smaps");
    let mut f = ::std::old_io::BufferedReader::new(File::open(&path));

    let seg_re = Regex::new(
        r"^[:xdigit:]+-[:xdigit:]+ (....) [:xdigit:]+ [:xdigit:]+:[:xdigit:]+ \d+ +(.*)").unwrap();
    let rss_re = Regex::new(r"^Rss: +(\d+) kB").unwrap();

    // We record each segment's resident size.
    let mut seg_map: HashMap<String, u64> = HashMap::new();

    #[derive(PartialEq)]
    enum LookingFor { Segment, Rss }
    let mut looking_for = LookingFor::Segment;

    let mut curr_seg_name = String::new();

    // Parse the file.
    for line in f.lines() {
        let line = match line {
            Ok(line) => line,
            Err(_) => continue,
        };
        if looking_for == LookingFor::Segment {
            // Look for a segment info line.
            let cap = match seg_re.captures(line.as_slice()) {
                Some(cap) => cap,
                None => continue,
            };
            let perms = cap.at(1).unwrap();
            let pathname = cap.at(2).unwrap();

            // Construct the segment name from its pathname and permissions.
            curr_seg_name.clear();
            curr_seg_name.push_str("- ");
            if pathname == "" || pathname.starts_with("[stack:") {
                // Anonymous memory. Entries marked with "[stack:nnn]"
                // look like thread stacks but they may include other
                // anonymous mappings, so we can't trust them and just
                // treat them as entirely anonymous.
                curr_seg_name.push_str("anonymous");
            } else {
                curr_seg_name.push_str(pathname);
            }
            curr_seg_name.push_str(" (");
            curr_seg_name.push_str(perms);
            curr_seg_name.push_str(")");

            looking_for = LookingFor::Rss;
        } else {
            // Look for an "Rss:" line.
            let cap = match rss_re.captures(line.as_slice()) {
                Some(cap) => cap,
                None => continue,
            };
            let rss = cap.at(1).unwrap().parse::<u64>().unwrap() * 1024;

            if rss > 0 {
                // Aggregate small segments into "- other".
                let seg_name = if rss < 512 * 1024 {
                    "- other".to_owned()
                } else {
                    curr_seg_name.clone()
                };
                match seg_map.entry(seg_name) {
                    Entry::Vacant(entry) => { entry.insert(rss); },
                    Entry::Occupied(mut entry) => *entry.get_mut() += rss,
                }
            }

            looking_for = LookingFor::Segment;
        }
    }

    let mut segs: Vec<(String, u64)> = seg_map.into_iter().collect();

    // Get the total and add it to the vector. Note that this total differs
    // from the "resident" measurement obtained via /proc/<pid>/statm in
    // get_resident(). It's unclear why this difference occurs; for some
    // processes the measurements match, but for Servo they do not.
    let total = segs.iter().map(|&(_, size)| size).sum();
    segs.push(("resident-according-to-smaps".to_owned(), total));

    // Sort by size; the total will be first.
    segs.sort_by(|&(_, rss1), &(_, rss2)| rss2.cmp(&rss1));

    segs
}

#[cfg(not(target_os="linux"))]
fn get_resident_segments() -> Vec<(String, u64)> {
    vec![]
}

<|endoftext|>


<commit_before>//! An echo server that just writes back everything that's written to it.

extern crate futures;
extern crate futures_io;
extern crate futures_mio;

use std::env;
use std::net::SocketAddr;

use futures::Future;
use futures::stream::Stream;
use futures_io::{copy, TaskIo};

fn main() {
    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    // Create the event loop that will drive this server
    let mut l = futures_mio::Loop::new().unwrap();

    // Create a TCP listener which will listen for incoming connections
    let server = l.handle().tcp_listen(&addr);

    let done = server.and_then(move |socket| {
        // Once we've got the TCP listener, inform that we have it
        println!("Listening on: {}", addr);

        // Pull out the stream of incoming connections and then for each new
        // one spin up a new task copying data. We put the `socket` into a
        // `Arc` structure which then allows us to share it across the
        // read/write halves with a small shim.
        //
        // Finally we use the `io::copy` future to copy all data from the
        // reading half onto the writing half.
        socket.incoming().for_each(|(socket, addr)| {
            let socket = futures::lazy(|| futures::finished(TaskIo::new(socket)));
            let pair = socket.map(|s| s.split());
            let amt = pair.and_then(|(reader, writer)| copy(reader, writer));

            // Once all that is done we print out how much we wrote, and then
            // critically we *forget* this future which allows it to run
            // concurrently with other connections.
            amt.map(move |amt| {
                println!("wrote {} bytes to {}", amt, addr)
            }).forget();

            Ok(())
        })
    });
    l.run(done).unwrap();
}
<commit_msg>update comment and simplify echo example<commit_after>//! An echo server that just writes back everything that's written to it.

extern crate futures;
extern crate futures_io;
extern crate futures_mio;

use std::env;
use std::net::SocketAddr;

use futures::Future;
use futures::stream::Stream;
use futures_io::{copy, TaskIo};

fn main() {
    let addr = env::args().nth(1).unwrap_or("127.0.0.1:8080".to_string());
    let addr = addr.parse::<SocketAddr>().unwrap();

    // Create the event loop that will drive this server
    let mut l = futures_mio::Loop::new().unwrap();

    // Create a TCP listener which will listen for incoming connections
    let server = l.handle().tcp_listen(&addr);

    let done = server.and_then(move |socket| {
        // Once we've got the TCP listener, inform that we have it
        println!("Listening on: {}", addr);

        // Pull out the stream of incoming connections and then for each new
        // one spin up a new task copying data.
        //
        // We use the `io::copy` future to copy all data from the
        // reading half onto the writing half.
        socket.incoming().for_each(|(socket, addr)| {
            let (reader, writer) = TaskIo::new(socket).split();
            let amt = copy(reader, writer);

            // Once all that is done we print out how much we wrote, and then
            // critically we *forget* this future which allows it to run
            // concurrently with other connections.
            amt.map(move |amt| {
                println!("wrote {} bytes to {}", amt, addr)
            }).forget();

            Ok(())
        })
    });
    l.run(done).unwrap();
}
<|endoftext|>


<commit_before>use ::log::warn;
use ::nix::{
    sys::signal::{self, Signal},
    unistd::Pid,
};
use psutil::process::{processes, Process};

/// Get all children of a specific process
pub fn get_children(pid: i32) -> Vec<Process> {
    let all_processes = match processes() {
        Err(error) => {
            warn!("Failed to get full process list: {}", error);
            return;
        }
        Ok(processes) => processes,
    };
    all_processes
        .into_iter()
        .filter(|result| result.is_ok())
        .map(|result| result.unwrap())
        .filter(|process| {
            if let Ok(ppid) = process.ppid() {
                if let Some(ppid) = ppid {
                    return ppid as i32 == pid;
                }
            }
            false
        })
        .collect()
}

/// Send a signal to a list of processes
pub fn send_signal_to_processes(processes: Vec<Process>, signal: Signal) {
    for process in processes {
        let pid = Pid::from_raw(process.pid() as i32);

        // Process is no longer alive, skip this.
        if !process.is_running() {
            continue;
        }

        if let Err(error) = signal::kill(pid, signal) {
            warn!(
                "Failed send signal {:?} to Pid {}: {:?}",
                signal,
                process.pid(),
                error
            );
        }
    }
}

/// A small helper to send a signal to all direct child processes of a specific task.
pub fn send_signal_to_children(pid: i32, signal: Signal) {
    send_signal_to_processes(get_children(pid), signal);
}
<commit_msg>Finally fix macos process handling again<commit_after>use ::log::warn;
use ::nix::{
    sys::signal::{self, Signal},
    unistd::Pid,
};
use psutil::process::{processes, Process};

/// Get all children of a specific process
pub fn get_children(pid: i32) -> Vec<Process> {
    let all_processes = match processes() {
        Err(error) => {
            warn!("Failed to get full process list: {}", error);
            return Vec::new();
        }
        Ok(processes) => processes,
    };
    all_processes
        .into_iter()
        .filter(|result| result.is_ok())
        .map(|result| result.unwrap())
        .filter(|process| {
            if let Ok(ppid) = process.ppid() {
                if let Some(ppid) = ppid {
                    return ppid as i32 == pid;
                }
            }
            false
        })
        .collect()
}

/// Send a signal to a list of processes
pub fn send_signal_to_processes(processes: Vec<Process>, signal: Signal) {
    for process in processes {
        let pid = Pid::from_raw(process.pid() as i32);

        // Process is no longer alive, skip this.
        if !process.is_running() {
            continue;
        }

        if let Err(error) = signal::kill(pid, signal) {
            warn!(
                "Failed send signal {:?} to Pid {}: {:?}",
                signal,
                process.pid(),
                error
            );
        }
    }
}

/// A small helper to send a signal to all direct child processes of a specific task.
pub fn send_signal_to_children(pid: i32, signal: Signal) {
    send_signal_to_processes(get_children(pid), signal);
}
<|endoftext|>


<commit_before>#![cfg_attr(feature = "nightlytests", feature(try_from))]

#[macro_use]
extern crate derive_builder;

#[allow(unused_imports)]
mod struct_level {
    #[cfg(feature = "nightlytests")]
    use std::convert::TryFrom;

    use std::net::{IpAddr, AddrParseError};
    use std::str::FromStr;
    use std::string::ToString;

    #[derive(Debug, Clone, PartialEq)]
    pub struct MyAddr(IpAddr);

    impl From<IpAddr> for MyAddr {
        fn from(v: IpAddr) -> Self {
            MyAddr(v)
        }
    }

    #[cfg(feature = "nightlytests")]
    impl<'a> TryFrom<&'a str> for MyAddr {
        type Err = AddrParseError;

        fn try_from(v: &str) -> Result<Self, Self::Err> {
            Ok(MyAddr(v.parse()?))
        }
    }

    #[derive(Debug, PartialEq, Builder)]
    #[builder(try_setter, setter(into))]
    struct Lorem {
        pub source: MyAddr,
        pub dest: MyAddr,
    }

    #[derive(Debug, PartialEq, Builder)]
    #[builder(try_setter, setter(into, prefix = "set"))]
    struct Ipsum {
        pub source: MyAddr
    }

    // Allow dead code here since the test that uses this depends on the try_setter feature.
    #[cfg_attr(not(feature = "nightlytests"), allow(dead_code))]
    fn exact_helper() -> Result<Lorem, String> {
        LoremBuilder::default()
            .source(IpAddr::from_str("1.2.3.4").unwrap())
            .dest(IpAddr::from_str("0.0.0.0").unwrap())
            .build()
    }

    #[cfg(feature = "nightlytests")]
    fn try_helper() -> Result<Lorem, String> {
        LoremBuilder::default()
            .try_source("1.2.3.4").map_err(|e| e.to_string())?
            .try_dest("0.0.0.0").map_err(|e| e.to_string())?
            .build()
    }

    #[test]
    fn infallible_set() {
        let _ = LoremBuilder::default()
            .source(IpAddr::from_str("1.2.3.4").unwrap())
            .dest(IpAddr::from_str("0.0.0.0").unwrap())
            .build();
    }

    #[test]
    #[cfg(feature = "nightlytests")]
    fn fallible_set() {
        let mut builder = LoremBuilder::default();
        let try_result = builder.try_source("1.2.3.4");
        let built = try_result.expect("Passed well-formed address")
            .dest(IpAddr::from_str("0.0.0.0").unwrap())
            .build()
            .unwrap();
        assert_eq!(built, exact_helper().unwrap());
    }

    #[test]
    #[cfg(feature = "nightlytests")]
    fn with_helper() {
        assert_eq!(exact_helper().unwrap(), try_helper().unwrap());
    }

    #[test]
    #[cfg(feature = "nightlytests")]
    fn renamed() {
        IpsumBuilder::default()
            .try_set_source("0.0.0.0")
            .unwrap()
            .build()
            .expect("All fields were provided");
    }
}<commit_msg>Made the entire try_setter test dependent on nightly.<commit_after>#![cfg_attr(feature = "nightlytests", feature(try_from))]

#[macro_use]
extern crate derive_builder;

#[cfg(feature = "nightlytests")]
#[allow(unused_imports)]
mod struct_level {
    #[cfg(feature = "nightlytests")]
    use std::convert::TryFrom;

    use std::net::{IpAddr, AddrParseError};
    use std::str::FromStr;
    use std::string::ToString;

    #[derive(Debug, Clone, PartialEq)]
    pub struct MyAddr(IpAddr);

    impl From<IpAddr> for MyAddr {
        fn from(v: IpAddr) -> Self {
            MyAddr(v)
        }
    }

    #[cfg(feature = "nightlytests")]
    impl<'a> TryFrom<&'a str> for MyAddr {
        type Err = AddrParseError;

        fn try_from(v: &str) -> Result<Self, Self::Err> {
            Ok(MyAddr(v.parse()?))
        }
    }

    #[derive(Debug, PartialEq, Builder)]
    #[builder(try_setter, setter(into))]
    struct Lorem {
        pub source: MyAddr,
        pub dest: MyAddr,
    }

    #[derive(Debug, PartialEq, Builder)]
    #[builder(try_setter, setter(into, prefix = "set"))]
    struct Ipsum {
        pub source: MyAddr
    }

    fn exact_helper() -> Result<Lorem, String> {
        LoremBuilder::default()
            .source(IpAddr::from_str("1.2.3.4").unwrap())
            .dest(IpAddr::from_str("0.0.0.0").unwrap())
            .build()
    }

    #[cfg(feature = "nightlytests")]
    fn try_helper() -> Result<Lorem, String> {
        LoremBuilder::default()
            .try_source("1.2.3.4").map_err(|e| e.to_string())?
            .try_dest("0.0.0.0").map_err(|e| e.to_string())?
            .build()
    }

    #[test]
    fn infallible_set() {
        let _ = LoremBuilder::default()
            .source(IpAddr::from_str("1.2.3.4").unwrap())
            .dest(IpAddr::from_str("0.0.0.0").unwrap())
            .build();
    }

    #[test]
    #[cfg(feature = "nightlytests")]
    fn fallible_set() {
        let mut builder = LoremBuilder::default();
        let try_result = builder.try_source("1.2.3.4");
        let built = try_result.expect("Passed well-formed address")
            .dest(IpAddr::from_str("0.0.0.0").unwrap())
            .build()
            .unwrap();
        assert_eq!(built, exact_helper().unwrap());
    }

    #[test]
    #[cfg(feature = "nightlytests")]
    fn with_helper() {
        assert_eq!(exact_helper().unwrap(), try_helper().unwrap());
    }

    #[test]
    #[cfg(feature = "nightlytests")]
    fn renamed() {
        IpsumBuilder::default()
            .try_set_source("0.0.0.0")
            .unwrap()
            .build()
            .expect("All fields were provided");
    }
}<|endoftext|>


<commit_before>use std::{
    cell::{Cell, RefCell},
    fs,
    path::{Path, PathBuf},
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use flexi_logger::Logger;
use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
use lsp_types::{
    notification::DidOpenTextDocument,
    request::{Request, Shutdown},
    DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
    notification::{Notification, ShowMessage},
};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use thread_worker::Worker;
use test_utils::{parse_fixture, find_mismatch};

use ra_lsp_server::{
    main_loop, req,
    InitializationOptions,
};

pub struct Project<'a> {
    fixture: &'a str,
    tmp_dir: Option<TempDir>,
    roots: Vec<PathBuf>,
}

impl<'a> Project<'a> {
    pub fn with_fixture(fixture: &str) -> Project {
        Project { fixture, tmp_dir: None, roots: vec![] }
    }

    pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
        self.tmp_dir = Some(tmp_dir);
        self
    }

    pub fn root(mut self, path: &str) -> Project<'a> {
        self.roots.push(path.into());
        self
    }

    pub fn server(self) -> Server {
        let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            let _ = Logger::with_env_or_str(crate::LOG).start().unwrap();
            ra_prof::set_filter(if crate::PROFILE.is_empty() {
                ra_prof::Filter::disabled()
            } else {
                ra_prof::Filter::from_spec(&crate::PROFILE)
            });
        });

        let mut paths = vec![];

        for entry in parse_fixture(self.fixture) {
            let path = tmp_dir.path().join(entry.meta);
            fs::create_dir_all(path.parent().unwrap()).unwrap();
            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
            paths.push((path, entry.text));
        }

        let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect();

        Server::new(tmp_dir, roots, paths)
    }
}

pub fn project(fixture: &str) -> Server {
    Project::with_fixture(fixture).server()
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<RawMessage>>,
    dir: TempDir,
    worker: Worker<RawMessage, RawMessage>,
}

impl Server {
    fn new(dir: TempDir, roots: Vec<PathBuf>, files: Vec<(PathBuf, String)>) -> Server {
        let path = dir.path().to_path_buf();

        let roots = if roots.is_empty() { vec![path] } else { roots };

        let worker = Worker::<RawMessage, RawMessage>::spawn(
            "test server",
            128,
            move |mut msg_receiver, mut msg_sender| {
                main_loop(
                    roots,
                    InitializationOptions::default(),
                    &mut msg_receiver,
                    &mut msg_sender,
                )
                .unwrap()
            },
        );
        let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };

        for (path, text) in files {
            res.send_notification(RawNotification::new::<DidOpenTextDocument>(
                &DidOpenTextDocumentParams {
                    text_document: TextDocumentItem {
                        uri: Url::from_file_path(path).unwrap(),
                        language_id: "rust".to_string(),
                        version: 0,
                        text,
                    },
                },
            ))
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn notification<N>(&self, params: N::Params)
    where
        N: Notification,
        N::Params: Serialize,
    {
        let r = RawNotification::new::<N>(&params);
        self.send_notification(r)
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        if let Some((expected_part, actual_part)) = find_mismatch(&expected_resp, &actual) {
            panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            );
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = RawRequest::new::<R>(id, &params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: RawRequest) -> Value {
        let id = r.id;
        self.worker.sender().send(RawMessage::Request(r)).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
                RawMessage::Notification(_) => (),
                RawMessage::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_until_workspace_is_loaded(&self) {
        self.wait_for_message_cond(1, &|msg: &RawMessage| match msg {
            RawMessage::Notification(n) if n.method == ShowMessage::METHOD => {
                let msg = n.clone().cast::<req::ShowMessage>().unwrap();
                msg.message.starts_with("workspace loaded")
            }
            _ => false,
        })
    }
    fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&RawMessage) -> bool) {
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if cond(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if cond(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<RawMessage> {
        recv_timeout(&self.worker.receiver()).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: RawNotification) {
        self.worker.sender().send(RawMessage::Notification(not)).unwrap();
    }

    pub fn path(&self) -> &Path {
        self.dir.path()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.send_request::<Shutdown>(());
    }
}

fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
    let timeout = Duration::from_secs(120);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<commit_msg>Fix clippy::unnecessary_mut_passed<commit_after>use std::{
    cell::{Cell, RefCell},
    fs,
    path::{Path, PathBuf},
    sync::Once,
    time::Duration,
};

use crossbeam_channel::{after, select, Receiver};
use flexi_logger::Logger;
use gen_lsp_server::{RawMessage, RawNotification, RawRequest};
use lsp_types::{
    notification::DidOpenTextDocument,
    request::{Request, Shutdown},
    DidOpenTextDocumentParams, TextDocumentIdentifier, TextDocumentItem, Url,
    notification::{Notification, ShowMessage},
};
use serde::Serialize;
use serde_json::{to_string_pretty, Value};
use tempfile::TempDir;
use thread_worker::Worker;
use test_utils::{parse_fixture, find_mismatch};

use ra_lsp_server::{
    main_loop, req,
    InitializationOptions,
};

pub struct Project<'a> {
    fixture: &'a str,
    tmp_dir: Option<TempDir>,
    roots: Vec<PathBuf>,
}

impl<'a> Project<'a> {
    pub fn with_fixture(fixture: &str) -> Project {
        Project { fixture, tmp_dir: None, roots: vec![] }
    }

    pub fn tmp_dir(mut self, tmp_dir: TempDir) -> Project<'a> {
        self.tmp_dir = Some(tmp_dir);
        self
    }

    pub fn root(mut self, path: &str) -> Project<'a> {
        self.roots.push(path.into());
        self
    }

    pub fn server(self) -> Server {
        let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
        static INIT: Once = Once::new();
        INIT.call_once(|| {
            let _ = Logger::with_env_or_str(crate::LOG).start().unwrap();
            ra_prof::set_filter(if crate::PROFILE.is_empty() {
                ra_prof::Filter::disabled()
            } else {
                ra_prof::Filter::from_spec(&crate::PROFILE)
            });
        });

        let mut paths = vec![];

        for entry in parse_fixture(self.fixture) {
            let path = tmp_dir.path().join(entry.meta);
            fs::create_dir_all(path.parent().unwrap()).unwrap();
            fs::write(path.as_path(), entry.text.as_bytes()).unwrap();
            paths.push((path, entry.text));
        }

        let roots = self.roots.into_iter().map(|root| tmp_dir.path().join(root)).collect();

        Server::new(tmp_dir, roots, paths)
    }
}

pub fn project(fixture: &str) -> Server {
    Project::with_fixture(fixture).server()
}

pub struct Server {
    req_id: Cell<u64>,
    messages: RefCell<Vec<RawMessage>>,
    dir: TempDir,
    worker: Worker<RawMessage, RawMessage>,
}

impl Server {
    fn new(dir: TempDir, roots: Vec<PathBuf>, files: Vec<(PathBuf, String)>) -> Server {
        let path = dir.path().to_path_buf();

        let roots = if roots.is_empty() { vec![path] } else { roots };

        let worker = Worker::<RawMessage, RawMessage>::spawn(
            "test server",
            128,
            move |mut msg_receiver, mut msg_sender| {
                main_loop(roots, InitializationOptions::default(), &msg_receiver, &msg_sender)
                    .unwrap()
            },
        );
        let res = Server { req_id: Cell::new(1), dir, messages: Default::default(), worker };

        for (path, text) in files {
            res.send_notification(RawNotification::new::<DidOpenTextDocument>(
                &DidOpenTextDocumentParams {
                    text_document: TextDocumentItem {
                        uri: Url::from_file_path(path).unwrap(),
                        language_id: "rust".to_string(),
                        version: 0,
                        text,
                    },
                },
            ))
        }
        res
    }

    pub fn doc_id(&self, rel_path: &str) -> TextDocumentIdentifier {
        let path = self.dir.path().join(rel_path);
        TextDocumentIdentifier { uri: Url::from_file_path(path).unwrap() }
    }

    pub fn notification<N>(&self, params: N::Params)
    where
        N: Notification,
        N::Params: Serialize,
    {
        let r = RawNotification::new::<N>(&params);
        self.send_notification(r)
    }

    pub fn request<R>(&self, params: R::Params, expected_resp: Value)
    where
        R: Request,
        R::Params: Serialize,
    {
        let actual = self.send_request::<R>(params);
        if let Some((expected_part, actual_part)) = find_mismatch(&expected_resp, &actual) {
            panic!(
                "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
                to_string_pretty(&expected_resp).unwrap(),
                to_string_pretty(&actual).unwrap(),
                to_string_pretty(expected_part).unwrap(),
                to_string_pretty(actual_part).unwrap(),
            );
        }
    }

    pub fn send_request<R>(&self, params: R::Params) -> Value
    where
        R: Request,
        R::Params: Serialize,
    {
        let id = self.req_id.get();
        self.req_id.set(id + 1);

        let r = RawRequest::new::<R>(id, &params);
        self.send_request_(r)
    }
    fn send_request_(&self, r: RawRequest) -> Value {
        let id = r.id;
        self.worker.sender().send(RawMessage::Request(r)).unwrap();
        while let Some(msg) = self.recv() {
            match msg {
                RawMessage::Request(req) => panic!("unexpected request: {:?}", req),
                RawMessage::Notification(_) => (),
                RawMessage::Response(res) => {
                    assert_eq!(res.id, id);
                    if let Some(err) = res.error {
                        panic!("error response: {:#?}", err);
                    }
                    return res.result.unwrap();
                }
            }
        }
        panic!("no response");
    }
    pub fn wait_until_workspace_is_loaded(&self) {
        self.wait_for_message_cond(1, &|msg: &RawMessage| match msg {
            RawMessage::Notification(n) if n.method == ShowMessage::METHOD => {
                let msg = n.clone().cast::<req::ShowMessage>().unwrap();
                msg.message.starts_with("workspace loaded")
            }
            _ => false,
        })
    }
    fn wait_for_message_cond(&self, n: usize, cond: &dyn Fn(&RawMessage) -> bool) {
        let mut total = 0;
        for msg in self.messages.borrow().iter() {
            if cond(msg) {
                total += 1
            }
        }
        while total < n {
            let msg = self.recv().expect("no response");
            if cond(&msg) {
                total += 1;
            }
        }
    }
    fn recv(&self) -> Option<RawMessage> {
        recv_timeout(&self.worker.receiver()).map(|msg| {
            self.messages.borrow_mut().push(msg.clone());
            msg
        })
    }
    fn send_notification(&self, not: RawNotification) {
        self.worker.sender().send(RawMessage::Notification(not)).unwrap();
    }

    pub fn path(&self) -> &Path {
        self.dir.path()
    }
}

impl Drop for Server {
    fn drop(&mut self) {
        self.send_request::<Shutdown>(());
    }
}

fn recv_timeout(receiver: &Receiver<RawMessage>) -> Option<RawMessage> {
    let timeout = Duration::from_secs(120);
    select! {
        recv(receiver) -> msg => msg.ok(),
        recv(after(timeout)) -> _ => panic!("timed out"),
    }
}
<|endoftext|>


<commit_before>//! Generator configurations specific for each Qt module.

use crate::detect_signals_and_slots::detect_signals_and_slots;
use crate::doc_parser::{parse_docs, set_crate_root_doc};
use crate::slot_wrappers::add_slot_wrappers;
use crate::versions;
use log::info;
use qt_ritual_common::{all_crate_names, get_full_build_config, lib_dependencies, lib_folder_name};
use ritual::config::CrateProperties;
use ritual::config::{Config, GlobalConfig};
use ritual_common::cpp_build_config::CppLibraryType;
use ritual_common::cpp_build_config::{CppBuildConfigData, CppBuildPaths};
use ritual_common::errors::{bail, format_err, Result, ResultExt};
use ritual_common::file_utils::repo_dir_path;
use ritual_common::target;
use ritual_common::toml;
use std::path::{Path, PathBuf};

mod _3d;
mod charts;
mod core;
mod gui;
mod widgets;

use self::_3d::{
    core_3d_config, extras_3d_config, input_3d_config, logic_3d_config, render_3d_config,
};
use self::{charts::charts_config, core::core_config, gui::gui_config, widgets::widgets_config};
use std::env;

pub const MOQT_INSTALL_DIR_ENV_VAR_NAME: &str = "MOQT_INSTALL_DIR";
pub const MOQT_TEMPLATE_DIR_ENV_VAR_NAME: &str = "MOQT_TEMPLATE_DIR";

fn empty_config(_config: &mut Config) -> Result<()> {
    Ok(())
}

/// Executes the generator for a single Qt module with given configuration.
pub fn create_config(crate_name: &str, qmake_path: Option<&str>) -> Result<Config> {
    info!("Preparing generator config for crate: {}", crate_name);
    let mut crate_properties = CrateProperties::new(crate_name, versions::QT_OUTPUT_CRATES_VERSION);
    let mut custom_fields = toml::value::Table::new();
    let mut package_data = toml::value::Table::new();
    package_data.insert(
        "authors".to_string(),
        toml::Value::Array(vec![toml::Value::String(
            "Pavel Strakhov <ri@idzaaus.org>".to_string(),
        )]),
    );
    let description = format!("Bindings for {} C++ library", lib_folder_name(crate_name));
    package_data.insert("description".to_string(), toml::Value::String(description));
    let doc_url = format!("https://rust-qt.github.io/rustdoc/qt/{}", &crate_name);
    package_data.insert("documentation".to_string(), toml::Value::String(doc_url));
    package_data.insert(
        "repository".to_string(),
        toml::Value::String("https://github.com/rust-qt/ritual".to_string()),
    );
    package_data.insert(
        "license".to_string(),
        toml::Value::String("MIT OR Apache-2.0".to_string()),
    );
    package_data.insert(
        "keywords".to_string(),
        toml::Value::Array(vec![
            toml::Value::String("gui".to_string()),
            toml::Value::String("ffi".to_string()),
            toml::Value::String("qt".to_string()),
            toml::Value::String("ritual".to_string()),
        ]),
    );
    package_data.insert(
        "categories".to_string(),
        toml::Value::Array(vec![
            toml::Value::String("external-ffi-bindings".to_string()),
            toml::Value::String("gui".to_string()),
        ]),
    );

    custom_fields.insert("package".to_string(), toml::Value::Table(package_data));
    crate_properties.set_custom_fields(custom_fields);
    let mut config = if crate_name.starts_with("moqt_") {
        let mut config = Config::new(crate_properties);
        let moqt_path =
            PathBuf::from(env::var(MOQT_INSTALL_DIR_ENV_VAR_NAME).with_context(|_| {
                format_err!("{} env var is missing", MOQT_INSTALL_DIR_ENV_VAR_NAME)
            })?);

        config.add_include_directive(format!("{}.h", crate_name));
        let include_path = moqt_path.join("include");
        if !include_path.exists() {
            bail!("Path does not exist: {}", include_path.display());
        }
        let lib_path = moqt_path.join("lib");
        if !lib_path.exists() {
            bail!("Path does not exist: {}", lib_path.display());
        }
        let sublib_include_path = include_path.join(crate_name);
        if !sublib_include_path.exists() {
            bail!("Path does not exist: {}", sublib_include_path.display());
        }
        {
            let mut paths = CppBuildPaths::new();
            paths.add_include_path(&sublib_include_path);
            paths.add_lib_path(&lib_path);

            for &lib in lib_dependencies(crate_name)? {
                let dep_include_path = include_path.join(lib);
                if !dep_include_path.exists() {
                    bail!("Path does not exist: {}", dep_include_path.display());
                }
                paths.add_include_path(&dep_include_path);
            }
            config.set_cpp_build_paths(paths);
        }
        config.add_target_include_path(&sublib_include_path);

        {
            let mut data = CppBuildConfigData::new();
            data.add_linked_lib(crate_name);
            for &lib in lib_dependencies(crate_name)? {
                data.add_linked_lib(lib);
            }
            data.set_library_type(CppLibraryType::Shared);
            config
                .cpp_build_config_mut()
                .add(target::Condition::True, data);
        }
        {
            let mut data = CppBuildConfigData::new();
            data.add_compiler_flag("-fPIC");
            data.add_compiler_flag("-std=gnu++11");
            config
                .cpp_build_config_mut()
                .add(target::Condition::Env(target::Env::Msvc).negate(), data);
        }
        if target::current_env() == target::Env::Msvc {
            config.add_cpp_parser_argument("-std=c++14");
        } else {
            config.add_cpp_parser_argument("-std=gnu++11");
        }

        let template_path =
            PathBuf::from(env::var(MOQT_TEMPLATE_DIR_ENV_VAR_NAME).with_context(|_| {
                format_err!("{} env var is missing", MOQT_TEMPLATE_DIR_ENV_VAR_NAME)
            })?);
        config.set_crate_template_path(template_path.join(&crate_name));

        let steps = config.processing_steps_mut();
        let crate_name_clone = crate_name.to_string();
        steps.add_after(&["cpp_parser"], "qt_doc_parser", move |data| {
            parse_docs(data, &crate_name_clone, &Path::new("."))
        })?;

        config
    } else {
        crate_properties.remove_default_build_dependencies();
        crate_properties.add_build_dependency(
            "qt_ritual_build",
            versions::QT_RITUAL_BUILD_VERSION,
            Some(repo_dir_path("qt_ritual_build")?),
        );

        let mut config = Config::new(crate_properties);

        let qt_config = get_full_build_config(crate_name, qmake_path)?;
        config.set_cpp_build_config(qt_config.cpp_build_config);
        config.set_cpp_build_paths(qt_config.cpp_build_paths);

        config.add_target_include_path(&qt_config.installation_data.lib_include_path);
        config.set_cpp_lib_version(qt_config.installation_data.qt_version.as_str());
        // TODO: does parsing work on MacOS without adding "-F"?

        config.add_include_directive(&lib_folder_name(crate_name));

        // DEBUG!
        //config.add_include_directive("QObject");
        //config.add_include_directive("QMetaObject");

        // TODO: allow to override parser flags
        config.add_cpp_parser_arguments(vec!["-fPIC", "-fcxx-exceptions"]);

        if target::current_env() == target::Env::Msvc {
            config.add_cpp_parser_argument("-std=c++14");
        } else {
            config.add_cpp_parser_argument("-std=gnu++11");
        }
        //config.add_cpp_parser_blocked_name(CppName::from_one_part("qt_check_for_QGADGET_macro"));

        let steps = config.processing_steps_mut();
        let crate_name_clone = crate_name.to_string();
        let docs_path = qt_config.installation_data.docs_path.clone();

        steps.add_after(&["cpp_parser"], "qt_doc_parser", move |data| {
            parse_docs(data, &crate_name_clone, &docs_path)
        })?;

        config
            .set_crate_template_path(repo_dir_path("qt_ritual/crate_templates")?.join(&crate_name));

        config
    };

    config.add_after_cpp_parser_hook(detect_signals_and_slots);

    let steps = config.processing_steps_mut();
    for cpp_parser_stage in &["cpp_parser", "cpp_parser_stage2"] {
        steps.add_after(&[cpp_parser_stage], "add_slot_wrappers", add_slot_wrappers)?;
    }

    steps.add_after(
        &["rust_generator"],
        "set_crate_root_doc",
        set_crate_root_doc,
    )?;

    let lib_config = match crate_name {
        "qt_core" => core_config,
        "qt_gui" => gui_config,
        "qt_widgets" => widgets_config,
        "qt_3d_core" => core_3d_config,
        "qt_3d_render" => render_3d_config,
        "qt_3d_input" => input_3d_config,
        "qt_3d_logic" => logic_3d_config,
        "qt_3d_extras" => extras_3d_config,
        "qt_ui_tools" => empty_config,
        "qt_charts" => charts_config,
        "qt_qml" => empty_config,
        "moqt_core" => core_config,
        "moqt_gui" => gui_config,
        _ => bail!("Unknown crate name: {}", crate_name),
    };
    lib_config(&mut config)?;

    config.set_dependent_cpp_crates(
        lib_dependencies(crate_name)?
            .iter()
            .map(|s| s.to_string())
            .collect(),
    );
    Ok(config)
}

pub fn global_config() -> GlobalConfig {
    let mut config = GlobalConfig::new();
    config.set_all_crate_names(all_crate_names().iter().map(|s| s.to_string()).collect());
    config.set_create_config_hook(|crate_name| create_config(crate_name, None));
    config
}
<commit_msg>add todo about set_library_type<commit_after>//! Generator configurations specific for each Qt module.

use crate::detect_signals_and_slots::detect_signals_and_slots;
use crate::doc_parser::{parse_docs, set_crate_root_doc};
use crate::slot_wrappers::add_slot_wrappers;
use crate::versions;
use log::info;
use qt_ritual_common::{all_crate_names, get_full_build_config, lib_dependencies, lib_folder_name};
use ritual::config::CrateProperties;
use ritual::config::{Config, GlobalConfig};
use ritual_common::cpp_build_config::CppLibraryType;
use ritual_common::cpp_build_config::{CppBuildConfigData, CppBuildPaths};
use ritual_common::errors::{bail, format_err, Result, ResultExt};
use ritual_common::file_utils::repo_dir_path;
use ritual_common::target;
use ritual_common::toml;
use std::path::{Path, PathBuf};

mod _3d;
mod charts;
mod core;
mod gui;
mod widgets;

use self::_3d::{
    core_3d_config, extras_3d_config, input_3d_config, logic_3d_config, render_3d_config,
};
use self::{charts::charts_config, core::core_config, gui::gui_config, widgets::widgets_config};
use std::env;

pub const MOQT_INSTALL_DIR_ENV_VAR_NAME: &str = "MOQT_INSTALL_DIR";
pub const MOQT_TEMPLATE_DIR_ENV_VAR_NAME: &str = "MOQT_TEMPLATE_DIR";

fn empty_config(_config: &mut Config) -> Result<()> {
    Ok(())
}

/// Executes the generator for a single Qt module with given configuration.
pub fn create_config(crate_name: &str, qmake_path: Option<&str>) -> Result<Config> {
    info!("Preparing generator config for crate: {}", crate_name);
    let mut crate_properties = CrateProperties::new(crate_name, versions::QT_OUTPUT_CRATES_VERSION);
    let mut custom_fields = toml::value::Table::new();
    let mut package_data = toml::value::Table::new();
    package_data.insert(
        "authors".to_string(),
        toml::Value::Array(vec![toml::Value::String(
            "Pavel Strakhov <ri@idzaaus.org>".to_string(),
        )]),
    );
    let description = format!("Bindings for {} C++ library", lib_folder_name(crate_name));
    package_data.insert("description".to_string(), toml::Value::String(description));
    let doc_url = format!("https://rust-qt.github.io/rustdoc/qt/{}", &crate_name);
    package_data.insert("documentation".to_string(), toml::Value::String(doc_url));
    package_data.insert(
        "repository".to_string(),
        toml::Value::String("https://github.com/rust-qt/ritual".to_string()),
    );
    package_data.insert(
        "license".to_string(),
        toml::Value::String("MIT OR Apache-2.0".to_string()),
    );
    package_data.insert(
        "keywords".to_string(),
        toml::Value::Array(vec![
            toml::Value::String("gui".to_string()),
            toml::Value::String("ffi".to_string()),
            toml::Value::String("qt".to_string()),
            toml::Value::String("ritual".to_string()),
        ]),
    );
    package_data.insert(
        "categories".to_string(),
        toml::Value::Array(vec![
            toml::Value::String("external-ffi-bindings".to_string()),
            toml::Value::String("gui".to_string()),
        ]),
    );

    custom_fields.insert("package".to_string(), toml::Value::Table(package_data));
    crate_properties.set_custom_fields(custom_fields);
    let mut config = if crate_name.starts_with("moqt_") {
        let mut config = Config::new(crate_properties);
        let moqt_path =
            PathBuf::from(env::var(MOQT_INSTALL_DIR_ENV_VAR_NAME).with_context(|_| {
                format_err!("{} env var is missing", MOQT_INSTALL_DIR_ENV_VAR_NAME)
            })?);

        config.add_include_directive(format!("{}.h", crate_name));
        let include_path = moqt_path.join("include");
        if !include_path.exists() {
            bail!("Path does not exist: {}", include_path.display());
        }
        let lib_path = moqt_path.join("lib");
        if !lib_path.exists() {
            bail!("Path does not exist: {}", lib_path.display());
        }
        let sublib_include_path = include_path.join(crate_name);
        if !sublib_include_path.exists() {
            bail!("Path does not exist: {}", sublib_include_path.display());
        }
        {
            let mut paths = CppBuildPaths::new();
            paths.add_include_path(&sublib_include_path);
            paths.add_lib_path(&lib_path);

            for &lib in lib_dependencies(crate_name)? {
                let dep_include_path = include_path.join(lib);
                if !dep_include_path.exists() {
                    bail!("Path does not exist: {}", dep_include_path.display());
                }
                paths.add_include_path(&dep_include_path);
            }
            config.set_cpp_build_paths(paths);
        }
        config.add_target_include_path(&sublib_include_path);

        {
            let mut data = CppBuildConfigData::new();
            data.add_linked_lib(crate_name);
            for &lib in lib_dependencies(crate_name)? {
                data.add_linked_lib(lib);
            }
            // TODO: why shared for moqt?
            data.set_library_type(CppLibraryType::Shared);
            config
                .cpp_build_config_mut()
                .add(target::Condition::True, data);
        }
        {
            let mut data = CppBuildConfigData::new();
            data.add_compiler_flag("-fPIC");
            data.add_compiler_flag("-std=gnu++11");
            config
                .cpp_build_config_mut()
                .add(target::Condition::Env(target::Env::Msvc).negate(), data);
        }
        if target::current_env() == target::Env::Msvc {
            config.add_cpp_parser_argument("-std=c++14");
        } else {
            config.add_cpp_parser_argument("-std=gnu++11");
        }

        let template_path =
            PathBuf::from(env::var(MOQT_TEMPLATE_DIR_ENV_VAR_NAME).with_context(|_| {
                format_err!("{} env var is missing", MOQT_TEMPLATE_DIR_ENV_VAR_NAME)
            })?);
        config.set_crate_template_path(template_path.join(&crate_name));

        let steps = config.processing_steps_mut();
        let crate_name_clone = crate_name.to_string();
        steps.add_after(&["cpp_parser"], "qt_doc_parser", move |data| {
            parse_docs(data, &crate_name_clone, &Path::new("."))
        })?;

        config
    } else {
        crate_properties.remove_default_build_dependencies();
        crate_properties.add_build_dependency(
            "qt_ritual_build",
            versions::QT_RITUAL_BUILD_VERSION,
            Some(repo_dir_path("qt_ritual_build")?),
        );

        let mut config = Config::new(crate_properties);

        let qt_config = get_full_build_config(crate_name, qmake_path)?;
        config.set_cpp_build_config(qt_config.cpp_build_config);
        config.set_cpp_build_paths(qt_config.cpp_build_paths);

        config.add_target_include_path(&qt_config.installation_data.lib_include_path);
        config.set_cpp_lib_version(qt_config.installation_data.qt_version.as_str());
        // TODO: does parsing work on MacOS without adding "-F"?

        config.add_include_directive(&lib_folder_name(crate_name));

        // DEBUG!
        //config.add_include_directive("QObject");
        //config.add_include_directive("QMetaObject");

        // TODO: allow to override parser flags
        config.add_cpp_parser_arguments(vec!["-fPIC", "-fcxx-exceptions"]);

        if target::current_env() == target::Env::Msvc {
            config.add_cpp_parser_argument("-std=c++14");
        } else {
            config.add_cpp_parser_argument("-std=gnu++11");
        }
        //config.add_cpp_parser_blocked_name(CppName::from_one_part("qt_check_for_QGADGET_macro"));

        let steps = config.processing_steps_mut();
        let crate_name_clone = crate_name.to_string();
        let docs_path = qt_config.installation_data.docs_path.clone();

        steps.add_after(&["cpp_parser"], "qt_doc_parser", move |data| {
            parse_docs(data, &crate_name_clone, &docs_path)
        })?;

        config
            .set_crate_template_path(repo_dir_path("qt_ritual/crate_templates")?.join(&crate_name));

        config
    };

    config.add_after_cpp_parser_hook(detect_signals_and_slots);

    let steps = config.processing_steps_mut();
    for cpp_parser_stage in &["cpp_parser", "cpp_parser_stage2"] {
        steps.add_after(&[cpp_parser_stage], "add_slot_wrappers", add_slot_wrappers)?;
    }

    steps.add_after(
        &["rust_generator"],
        "set_crate_root_doc",
        set_crate_root_doc,
    )?;

    let lib_config = match crate_name {
        "qt_core" => core_config,
        "qt_gui" => gui_config,
        "qt_widgets" => widgets_config,
        "qt_3d_core" => core_3d_config,
        "qt_3d_render" => render_3d_config,
        "qt_3d_input" => input_3d_config,
        "qt_3d_logic" => logic_3d_config,
        "qt_3d_extras" => extras_3d_config,
        "qt_ui_tools" => empty_config,
        "qt_charts" => charts_config,
        "qt_qml" => empty_config,
        "moqt_core" => core_config,
        "moqt_gui" => gui_config,
        _ => bail!("Unknown crate name: {}", crate_name),
    };
    lib_config(&mut config)?;

    config.set_dependent_cpp_crates(
        lib_dependencies(crate_name)?
            .iter()
            .map(|s| s.to_string())
            .collect(),
    );
    Ok(config)
}

pub fn global_config() -> GlobalConfig {
    let mut config = GlobalConfig::new();
    config.set_all_crate_names(all_crate_names().iter().map(|s| s.to_string()).collect());
    config.set_create_config_hook(|crate_name| create_config(crate_name, None));
    config
}
<|endoftext|>


<commit_before>extern crate robin_core;

extern crate nom;

#[cfg(test)]
mod parser_tests {
    use nom::IResult;

    use robin_core::parser;

    #[test]
    fn it_works() {
        assert_eq!(parser::abcd_parser(b"abcd"), IResult::Done(&b""[..], &b"abcd"[..]))
    }
}<commit_msg>Add simple hexadecimal tests<commit_after>extern crate robin_core;

extern crate nom;

#[cfg(test)]
mod parser_tests {
    use nom::IResult;

    use robin_core::parser;

    #[test]
    fn parse_a_single_hex_digit() {
        assert_eq!(parser::hex_digits_literal(b"0x1"), IResult::Done(&b""[..], 1.0));
    }

    #[test]
    fn parse_a_multiple_hex_digit() {
        assert_eq!(parser::hex_digits_literal(b"0x1AB"), IResult::Done(&b""[..], 427.0));
    }
}<|endoftext|>


<commit_before>use std::io;
use std::str::FromStr;

struct VM {
	stack: Vec<Operator>,
}

impl VM {
	fn pop(&self, ret: &mut Operator) {
		let mut transfer = move |op: Operator| op;
		ret = transfer(self.stack.pop().expect("gg reinstall"));
	}

	fn push(&self, op: Operator) {
		self.stack.push(op);
	}
}

enum Operator {
	//stack
	Dup,
	Drop,
	Swap,
	Over,
	Rot,

	//debug
	Print,

	//math
	Add,
	Subtract,
	Multiply,
	Divide,
	Mod,
	And,
	Or,
	Xor,
	Lshift,
	Rshift,
	Abs,
	Max,
	Min,
	Invert,
	Negate,

	//custom
	Define,

	//values and custom calls
	Value(i32),
	Other,
}

fn parse(s: &str) -> Operator {
	match s {
		//stack operations:
		"dup" => Operator::Dup,
		"drop" => Operator::Drop,
		"swap" => Operator::Swap,
		"over" => Operator::Over,
		"rot" => Operator::Rot,

		//debug operations:
		"." => Operator::Print,

		//math operations:
		"+" => Operator::Add,
		"-" => Operator::Subtract,
		"*" => Operator::Multiply,
		"/" => Operator::Divide,
		"mod" => Operator::Mod,
		"and" => Operator::And,
		"or" => Operator::Or,
		"xor" => Operator::Xor,
		"lshift" => Operator::Lshift,
		"<<" => Operator::Lshift,
		"rshift" => Operator::Rshift,
		">>" => Operator::Rshift,
		"abs" => Operator::Abs,
		"max" => Operator::Max,
		"min" => Operator::Min,
		"invert" => Operator::Invert,
		"negate" => Operator::Negate,

		//custom definitions
		":" => Operator::Define,

		//value or custom operator
		x => {
			let y: Option<i32> = FromStr::from_str(x).ok();
			match y{
				Some(i) => Operator::Value(i),
				None => Operator::Other,
			}
		},
	}
}

fn process(s: String) {
	for o in s.split(" "){
		let b = parse(o.trim());
		println!("{}",match b {
			Operator::Add => "addition!",
			Operator::Subtract => "subtraction!",
			Operator::Value(_) => "value!",
			_ => "other!",
		});
	}
}

fn main() {

	let mut x = io::stdin();
	let vm = VM {stack: vec![Operator::Print]};

	loop{
		let mut y: String = "".to_string();
		let _ = x.read_line(&mut y);

	    process(y);
	}
}
<commit_msg>mutable trait for the vm struct (maybe works)<commit_after>use std::io;
use std::str::FromStr;

struct VM {
	stack: Vec<Operator>,
}

impl VM {
	fn pop <'a> (&'a mut self, ret: &mut Operator) {
		*ret = self.stack.pop().expect("gg reinstall");
	}

	fn push <'a> (&'a mut self, op: Operator) {
		self.stack.push(op);
	}
}

enum Operator {
	//stack
	Dup,
	Drop,
	Swap,
	Over,
	Rot,

	//debug
	Print,

	//math
	Add,
	Subtract,
	Multiply,
	Divide,
	Mod,
	And,
	Or,
	Xor,
	Lshift,
	Rshift,
	Abs,
	Max,
	Min,
	Invert,
	Negate,

	//custom
	Define,

	//values and custom calls
	Value(i32),
	Other,
}

fn parse(s: &str) -> Operator {
	match s {
		//stack operations:
		"dup" => Operator::Dup,
		"drop" => Operator::Drop,
		"swap" => Operator::Swap,
		"over" => Operator::Over,
		"rot" => Operator::Rot,

		//debug operations:
		"." => Operator::Print,

		//math operations:
		"+" => Operator::Add,
		"-" => Operator::Subtract,
		"*" => Operator::Multiply,
		"/" => Operator::Divide,
		"mod" => Operator::Mod,
		"and" => Operator::And,
		"or" => Operator::Or,
		"xor" => Operator::Xor,
		"lshift" => Operator::Lshift,
		"<<" => Operator::Lshift,
		"rshift" => Operator::Rshift,
		">>" => Operator::Rshift,
		"abs" => Operator::Abs,
		"max" => Operator::Max,
		"min" => Operator::Min,
		"invert" => Operator::Invert,
		"negate" => Operator::Negate,

		//custom definitions
		":" => Operator::Define,

		//value or custom operator
		x => {
			let y: Option<i32> = FromStr::from_str(x).ok();
			match y{
				Some(i) => Operator::Value(i),
				None => Operator::Other,
			}
		},
	}
}

fn process(s: String) {
	for o in s.split(" "){
		let b = parse(o.trim());
		println!("{}",match b {
			Operator::Add => "addition!",
			Operator::Subtract => "subtraction!",
			Operator::Value(_) => "value!",
			_ => "other!",
		});
	}
}

fn main() {

	let mut x = io::stdin();
	let mut vm = VM {stack: vec![Operator::Print]};

	loop{
		let mut y: String = "".to_string();
		let _ = x.read_line(&mut y);

	    process(y);
	}
}
<|endoftext|>