<commit_before>use std::ffi::CString;
use std::mem;
use std::ptr;

const STRING_SIZE: usize = 512;

pub struct CFixedString {
    pub local_string: [i8; STRING_SIZE],
    pub heap_string: Option<CString>,
}

impl CFixedString {
    pub fn from_str(name: &str) -> CFixedString {
        unsafe {
            let name_len = name.len();
            if name_len <= STRING_SIZE - 1 {
                let mut handler = CFixedString {
                    local_string: mem::uninitialized(),
                    heap_string: None,
                };

                ptr::copy(name.as_ptr(),
                          handler.local_string.as_mut_ptr() as *mut u8,
                          name_len);
                handler.local_string[name_len] = 0;

                handler
            } else {
                CFixedString {
                    local_string: mem::uninitialized(),
                    heap_string: Some(CString::new(name).unwrap()),
                }
            }
        }
    }

    pub fn as_ptr(&mut self) -> *const i8 {
        if self.heap_string == None {
            self.local_string.as_ptr()
        } else {
            self.heap_string.as_mut().unwrap().as_ptr()
        }
    }
}

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

    fn get_string(handler: &mut CFixedString) -> String {
        unsafe { CStr::from_ptr(handler.as_ptr()).to_string_lossy().into_owned() }
    }

    #[test]
    fn test_empty_handler() {
        let short_string = "";
        let mut t = CFixedString::from_str(short_string);
        assert_eq!(t.heap_string.is_none(), true);
        assert_eq!(get_string(&mut t), short_string);
    }

    #[test]
    fn test_short_1() {
        let short_string = "test_local";
        let mut t = CFixedString::from_str(short_string);
        assert_eq!(t.heap_string.is_none(), true);
        assert_eq!(get_string(&mut t), short_string);
    }

    #[test]
    fn test_short_2() {
        let short_string = "test_local stoheusthsotheost";
        let mut t = CFixedString::from_str(short_string);
        assert_eq!(t.heap_string.is_none(), true);
        assert_eq!(get_string(&mut t), short_string);
    }

    #[test]
    fn test_511() {
        // this string (width 511) buffer should just fit
        let test_511_string = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeuuuuuuuuuuuuu\
                                uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\
                                uuuueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaa\
                                aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoooooooooooooooooooooooooooooo\
                                oooooooooooooooooooooooooooooooooeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\
                                eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeuuuuuuuuuuuuuuuuuuuuuuuuuu\
                                uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuoooooooooooooooooooooooooooooo\
                                oooooooooooooooooooooooooooooooooooooooacd";
        let mut t = CFixedString::from_str(test_511_string);
        assert_eq!(t.heap_string.is_none(), true);
        assert_eq!(get_string(&mut t), test_511_string);
    }

    #[test]
    fn test_512() {
        // this string (width 512) buffer should not fit
        let test_512_string = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeuuuuuuuuuuuuu\
                                uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\
                                uuuueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaa\
                                aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoooooooooooooooooooooooooooooo\
                                oooooooooooooooooooooooooooooooooeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\
                                eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeuuuuuuuuuuuuuuuuuuuuuuuuuu\
                                uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuoooooooooooooooooooooooooooooo\
                                oooooooooooooooooooooooooooooooooooooooabcd";
        let mut t = CFixedString::from_str(test_512_string);
        assert_eq!(t.heap_string.is_some(), true);
        assert_eq!(get_string(&mut t), test_512_string);
    }

    #[test]
    fn test_513() {
        // this string (width 513) buffer should not fit
        let test_513_string = "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeuuuuuuuuuuuuu\
                                uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu\
                                uuuueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeaaaaaaaaaaaa\
                                aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaoooooooooooooooooooooooooooooo\
                                oooooooooooooooooooooooooooooooooeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\
                                eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeuuuuuuuuuuuuuuuuuuuuuuuuuu\
                                uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuoooooooooooooooooooooooooooooo\
                                ooooooooooooooooooooooooooooooooooooooooabcd";
        let mut t = CFixedString::from_str(test_513_string);
        assert_eq!(t.heap_string.is_some(), true);
        assert_eq!(get_string(&mut t), test_513_string);
    }
}

<commit_msg>fix(cfixed_string): Convert to enum<commit_after>use std::borrow::{Borrow, Cow};
use std::ffi::{CStr, CString};
use std::mem;
use std::ops;
use std::os::raw::c_char;
use std::ptr;

const STRING_SIZE: usize = 512;

/// This is a C String abstractions that presents a CStr like
/// interface for interop purposes but tries to be little nicer
/// by avoiding heap allocations if the string is within the
/// generous bounds (512 bytes) of the statically sized buffer.
/// Strings over this limit will be heap allocated, but the
/// interface outside of this abstraction remains the same.
pub enum CFixedString {
    Local([c_char; STRING_SIZE]),
    Heap(CString),
}

impl CFixedString {
    pub fn from_str(s: &str) -> Self {
        Self::from(s)
    }

    pub fn as_ptr(&self) -> *const c_char {
        match *self {
            CFixedString::Local(ref s) => s.as_ptr(),
            CFixedString::Heap(ref s) => s.as_ptr(),
        }
    }

    /// Returns true if the string has been heap allocated
    pub fn is_allocated(&self) -> bool {
        match *self {
            CFixedString::Local(_) => false,
            _ => true,
        }
    }

    /// Converts a `CFixedString` into a `Cow<str>`.
    ///
    /// This function will calculate the length of this string (which normally
    /// requires a linear amount of work to be done) and then return the
    /// resulting slice as a `Cow<str>`, replacing any invalid UTF-8 sequences
    /// with `U+FFFD REPLACEMENT CHARACTER`. If there are no invalid UTF-8
    /// sequences, this will merely return a borrowed slice.
    pub fn to_string(&self) -> Cow<str> {
        String::from_utf8_lossy(&self.to_bytes())
    }
}

impl<'a> From<&'a str> for CFixedString {
    fn from(s: &'a str) -> Self {
        match s.len() {
            len if len <= STRING_SIZE - 1 => unsafe {
                let mut ret = CFixedString::Local(mem::uninitialized());

                match ret {
                    CFixedString::Local(ref mut l) => {
                        let ptr = l.as_mut_ptr() as *mut u8;
                        ptr::copy(s.as_ptr(), ptr, len);
                        *ptr.offset(len as isize) = 0;
                    },
                    _ => unreachable!(),
                }

                ret
            },
            _ => CFixedString::Heap(CString::new(s).unwrap()),
        }
    }
}

impl From<CFixedString> for String {
    fn from(s: CFixedString) -> Self {
        String::from_utf8_lossy(&s.to_bytes()).into_owned()
    }
}

impl ops::Deref for CFixedString {
    type Target = CStr;

    fn deref(&self) -> &CStr {
        match *self {
            CFixedString::Local(ref s) => unsafe { CStr::from_ptr(s.as_ptr()) },
            CFixedString::Heap(ref s) => s,
        }
    }
}

impl Borrow<CStr> for CFixedString {
    fn borrow(&self) -> &CStr { self }
}

impl AsRef<CStr> for CFixedString {
    fn as_ref(&self) -> &CStr { self }
}

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

    fn gen_string(len: usize) -> String {
        use std::fmt::Write;

        let mut out = String::with_capacity(len);

        for _ in 0..len / 16 {
            out.write_str("zyxvutabcdef9876").unwrap();
        }

        for i in 0..len % 16 {
            out.write_char((i as u8 + 'A' as u8) as char).unwrap();
        }

        assert_eq!(out.len(), len);
        out
    }

    #[test]
    fn test_empty_handler() {
        let short_string = "";

        let t = CFixedString::from_str(short_string);

        assert!(!t.is_allocated());
        assert_eq!(&t.to_string(), short_string);
    }

    #[test]
    fn test_short_1() {
        let short_string = "test_local";

        let t = CFixedString::from_str(short_string);

        assert!(!t.is_allocated());
        assert_eq!(&t.to_string(), short_string);
    }

    #[test]
    fn test_short_2() {
        let short_string = "test_local stoheusthsotheost";

        let t = CFixedString::from_str(short_string);

        assert!(!t.is_allocated());
        assert_eq!(&t.to_string(), short_string);
    }

    #[test]
    fn test_511() {
        // this string (width 511) buffer should just fit
        let test_511_string = gen_string(511);

        let t = CFixedString::from_str(&test_511_string);

        assert!(!t.is_allocated());
        assert_eq!(&t.to_string(), &test_511_string);
    }

    #[test]
    fn test_512() {
        // this string (width 512) buffer should not fit
        let test_512_string = gen_string(512);

        let t = CFixedString::from_str(&test_512_string);

        assert!(t.is_allocated());
        assert_eq!(&t.to_string(), &test_512_string);
    }

    #[test]
    fn test_513() {
        // this string (width 513) buffer should not fit
        let test_513_string = gen_string(513);

        let t = CFixedString::from_str(&test_513_string);

        assert!(t.is_allocated());
        assert_eq!(&t.to_string(), &test_513_string);
    }

    #[test]
    fn test_to_owned() {
        let short = "this is an amazing string";

        let t = CFixedString::from_str(short);

        assert!(!t.is_allocated());
        assert_eq!(&String::from(t), short);

        let long = gen_string(1025);

        let t = CFixedString::from_str(&long);

        assert!(t.is_allocated());
        assert_eq!(&String::from(t), &long);
    }
}<|endoftext|>


<commit_before>use crate::reflect::repeated::ReflectRepeated;
use crate::reflect::repeated::ReflectRepeatedIter;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::reflect::RuntimeTypeBox;

#[derive(Debug, Clone)]
pub(crate) struct DynamicRepeated {
    elem: RuntimeTypeBox,
    vec: Vec<ReflectValueBox>,
}

impl ReflectRepeated for DynamicRepeated {
    fn reflect_iter(&self) -> ReflectRepeatedIter {
        unimplemented!()
    }

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

    fn get(&self, index: usize) -> ReflectValueRef {
        self.vec[index].as_value_ref()
    }

    fn set(&mut self, index: usize, value: ReflectValueBox) {
        assert_eq!(self.elem, value.get_type());
        self.vec[index] = value;
    }

    fn push(&mut self, value: ReflectValueBox) {
        assert_eq!(self.elem, value.get_type());
        self.vec.push(value);
    }

    fn clear(&mut self) {
        self.vec.clear();
    }

    fn element_type(&self) -> RuntimeTypeBox {
        self.elem.clone()
    }
}

impl DynamicRepeated {
    pub fn new(elem: RuntimeTypeBox) -> DynamicRepeated {
        DynamicRepeated {
            elem,
            vec: Vec::new(),
        }
    }
}
<commit_msg>More efficient implementation of repeated fields in dynamic messages<commit_after>use crate::reflect::repeated::ReflectRepeated;
use crate::reflect::repeated::ReflectRepeatedIter;
use crate::reflect::EnumDescriptor;
use crate::reflect::MessageDescriptor;
use crate::reflect::MessageRef;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::reflect::RuntimeTypeBox;
use crate::MessageDyn;

/// Container of repeated values for dynamic messages.
///
/// It is logically similar to `Vec<ReflectValueBox>`, but:
/// * more efficient
/// * asserts all the elements are of the same type, the type which is specified at construction
#[derive(Debug, Clone)]
pub(crate) enum DynamicRepeated {
    U32(Vec<u32>),
    U64(Vec<u64>),
    I32(Vec<i32>),
    I64(Vec<i64>),
    F32(Vec<f32>),
    F64(Vec<f64>),
    Bool(Vec<bool>),
    String(Vec<String>),
    Bytes(Vec<Vec<u8>>),
    Enum(EnumDescriptor, Vec<i32>),
    Message(MessageDescriptor, Vec<Box<dyn MessageDyn>>),
}

impl ReflectRepeated for DynamicRepeated {
    fn reflect_iter(&self) -> ReflectRepeatedIter {
        unimplemented!()
    }

    fn len(&self) -> usize {
        match self {
            DynamicRepeated::U32(v) => v.len(),
            DynamicRepeated::U64(v) => v.len(),
            DynamicRepeated::I32(v) => v.len(),
            DynamicRepeated::I64(v) => v.len(),
            DynamicRepeated::F32(v) => v.len(),
            DynamicRepeated::F64(v) => v.len(),
            DynamicRepeated::Bool(v) => v.len(),
            DynamicRepeated::String(v) => v.len(),
            DynamicRepeated::Bytes(v) => v.len(),
            DynamicRepeated::Enum(.., v) => v.len(),
            DynamicRepeated::Message(.., v) => v.len(),
        }
    }

    fn get(&self, index: usize) -> ReflectValueRef {
        match self {
            DynamicRepeated::U32(v) => ReflectValueRef::U32(v[index]),
            DynamicRepeated::U64(v) => ReflectValueRef::U64(v[index]),
            DynamicRepeated::I32(v) => ReflectValueRef::I32(v[index]),
            DynamicRepeated::I64(v) => ReflectValueRef::I64(v[index]),
            DynamicRepeated::F32(v) => ReflectValueRef::F32(v[index]),
            DynamicRepeated::F64(v) => ReflectValueRef::F64(v[index]),
            DynamicRepeated::Bool(v) => ReflectValueRef::Bool(v[index]),
            DynamicRepeated::String(v) => ReflectValueRef::String(&v[index]),
            DynamicRepeated::Bytes(v) => ReflectValueRef::Bytes(&v[index]),
            DynamicRepeated::Enum(descriptor, v) => {
                ReflectValueRef::Enum(descriptor.clone(), v[index])
            }
            DynamicRepeated::Message(_descriptor, v) => {
                ReflectValueRef::Message(MessageRef::from(&*v[index]))
            }
        }
    }

    fn set(&mut self, index: usize, value: ReflectValueBox) {
        match self {
            DynamicRepeated::U32(v) => v.set(index, value),
            DynamicRepeated::U64(v) => v.set(index, value),
            DynamicRepeated::I32(v) => v.set(index, value),
            DynamicRepeated::I64(v) => v.set(index, value),
            DynamicRepeated::F32(v) => v.set(index, value),
            DynamicRepeated::F64(v) => v.set(index, value),
            DynamicRepeated::Bool(v) => v.set(index, value),
            DynamicRepeated::String(v) => v.set(index, value),
            DynamicRepeated::Bytes(v) => v.set(index, value),
            DynamicRepeated::Enum(descriptor, vs) => match value {
                ReflectValueBox::Enum(value_description, v) => {
                    assert_eq!(*descriptor, value_description);
                    vs[index] = v;
                }
                _ => panic!("Expected enum value"),
            },
            DynamicRepeated::Message(descriptor, vs) => match value {
                ReflectValueBox::Message(message) => {
                    assert_eq!(*descriptor, message.descriptor_dyn());
                    vs[index] = message;
                }
                _ => panic!("Expected message value"),
            },
        }
    }

    fn push(&mut self, value: ReflectValueBox) {
        match self {
            DynamicRepeated::U32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::U64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::I32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::I64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::F32(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::F64(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Bool(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::String(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Bytes(vs) => ReflectRepeated::push(vs, value),
            DynamicRepeated::Enum(descriptor, vs) => match value {
                ReflectValueBox::Enum(value_description, v) => {
                    assert_eq!(*descriptor, value_description);
                    vs.push(v);
                }
                _ => panic!("Expected enum value"),
            },
            DynamicRepeated::Message(descriptor, vs) => match value {
                ReflectValueBox::Message(message) => {
                    assert_eq!(*descriptor, message.descriptor_dyn());
                    vs.push(message);
                }
                _ => panic!("Expected message value"),
            },
        }
    }

    fn clear(&mut self) {
        match self {
            DynamicRepeated::U32(vs) => vs.clear(),
            DynamicRepeated::U64(vs) => vs.clear(),
            DynamicRepeated::I32(vs) => vs.clear(),
            DynamicRepeated::I64(vs) => vs.clear(),
            DynamicRepeated::F32(vs) => vs.clear(),
            DynamicRepeated::F64(vs) => vs.clear(),
            DynamicRepeated::Bool(vs) => vs.clear(),
            DynamicRepeated::String(vs) => vs.clear(),
            DynamicRepeated::Bytes(vs) => vs.clear(),
            DynamicRepeated::Enum(_descriptor, vs) => vs.clear(),
            DynamicRepeated::Message(_descriptor, vs) => vs.clear(),
        }
    }

    fn element_type(&self) -> RuntimeTypeBox {
        match self {
            DynamicRepeated::U32(..) => RuntimeTypeBox::U32,
            DynamicRepeated::U64(..) => RuntimeTypeBox::U64,
            DynamicRepeated::I32(..) => RuntimeTypeBox::I32,
            DynamicRepeated::I64(..) => RuntimeTypeBox::I64,
            DynamicRepeated::F32(..) => RuntimeTypeBox::F32,
            DynamicRepeated::F64(..) => RuntimeTypeBox::F64,
            DynamicRepeated::Bool(..) => RuntimeTypeBox::Bool,
            DynamicRepeated::String(..) => RuntimeTypeBox::String,
            DynamicRepeated::Bytes(..) => RuntimeTypeBox::VecU8,
            DynamicRepeated::Enum(descriptor, _vs) => RuntimeTypeBox::Enum(descriptor.clone()),
            DynamicRepeated::Message(descriptor, _vs) => {
                RuntimeTypeBox::Message(descriptor.clone())
            }
        }
    }
}

impl DynamicRepeated {
    pub fn new(elem: RuntimeTypeBox) -> DynamicRepeated {
        match elem {
            RuntimeTypeBox::U32 => DynamicRepeated::U32(Vec::new()),
            RuntimeTypeBox::U64 => DynamicRepeated::U64(Vec::new()),
            RuntimeTypeBox::I32 => DynamicRepeated::I32(Vec::new()),
            RuntimeTypeBox::I64 => DynamicRepeated::I64(Vec::new()),
            RuntimeTypeBox::F32 => DynamicRepeated::F32(Vec::new()),
            RuntimeTypeBox::F64 => DynamicRepeated::F64(Vec::new()),
            RuntimeTypeBox::Bool => DynamicRepeated::Bool(Vec::new()),
            RuntimeTypeBox::String => DynamicRepeated::String(Vec::new()),
            RuntimeTypeBox::VecU8 => DynamicRepeated::Bytes(Vec::new()),
            RuntimeTypeBox::Enum(enum_descriptor) => {
                DynamicRepeated::Enum(enum_descriptor, Vec::new())
            }
            RuntimeTypeBox::Message(message_descriptor) => {
                DynamicRepeated::Message(message_descriptor, Vec::new())
            }
        }
    }
}
<|endoftext|>


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

use boxed::Box;
use convert::Into;
use error;
use fmt;
use marker::{Send, Sync};
use option::Option::{self, Some, None};
use result;
use sys;

/// A type for results generated by I/O related functions where the `Err` type
/// is hard-wired to `io::Error`.
///
/// This typedef is generally used to avoid writing out `io::Error` directly and
/// is otherwise a direct mapping to `std::result::Result`.
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = result::Result<T, Error>;

/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// `ErrorKind`.
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Error {
    repr: Repr,
}

#[derive(Debug)]
enum Repr {
    Os(i32),
    Custom(Box<Custom>),
}

#[derive(Debug)]
struct Custom {
    kind: ErrorKind,
    error: Box<error::Error+Send+Sync>,
}

/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum ErrorKind {
    /// An entity was not found, often a file.
    #[stable(feature = "rust1", since = "1.0.0")]
    NotFound,
    /// The operation lacked the necessary privileges to complete.
    #[stable(feature = "rust1", since = "1.0.0")]
    PermissionDenied,
    /// The connection was refused by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionRefused,
    /// The connection was reset by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionReset,
    /// The connection was aborted (terminated) by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionAborted,
    /// The network operation failed because it was not connected yet.
    #[stable(feature = "rust1", since = "1.0.0")]
    NotConnected,
    /// A socket address could not be bound because the address is already in
    /// use elsewhere.
    #[stable(feature = "rust1", since = "1.0.0")]
    AddrInUse,
    /// A nonexistent interface was requested or the requested address was not
    /// local.
    #[stable(feature = "rust1", since = "1.0.0")]
    AddrNotAvailable,
    /// The operation failed because a pipe was closed.
    #[stable(feature = "rust1", since = "1.0.0")]
    BrokenPipe,
    /// An entity already exists, often a file.
    #[stable(feature = "rust1", since = "1.0.0")]
    AlreadyExists,
    /// The operation needs to block to complete, but the blocking operation was
    /// requested to not occur.
    #[stable(feature = "rust1", since = "1.0.0")]
    WouldBlock,
    /// A parameter was incorrect.
    #[stable(feature = "rust1", since = "1.0.0")]
    InvalidInput,
    /// Data not valid for the operation were encountered.
    ///
    /// Unlike `InvalidInput`, this typically means that the operation
    /// parameters were valid, however the error was caused by malformed
    /// input data.
    #[stable(feature = "io_invalid_data", since = "1.2.0")]
    InvalidData,
    /// The I/O operation's timeout expired, causing it to be canceled.
    #[stable(feature = "rust1", since = "1.0.0")]
    TimedOut,
    /// An error returned when an operation could not be completed because a
    /// call to `write` returned `Ok(0)`.
    ///
    /// This typically means that an operation could only succeed if it wrote a
    /// particular number of bytes but only a smaller number of bytes could be
    /// written.
    #[stable(feature = "rust1", since = "1.0.0")]
    WriteZero,
    /// This operation was interrupted.
    ///
    /// Interrupted operations can typically be retried.
    #[stable(feature = "rust1", since = "1.0.0")]
    Interrupted,
    /// Any I/O error not part of this list.
    #[stable(feature = "rust1", since = "1.0.0")]
    Other,

    /// Any I/O error not part of this list.
    #[unstable(feature = "io_error_internals",
               reason = "better expressed through extensible enums that this \
                         enum cannot be exhaustively matched against")]
    #[doc(hidden)]
    __Nonexhaustive,
}

impl Error {
    /// Creates a new I/O error from a known kind of error as well as an
    /// arbitrary error payload.
    ///
    /// This function is used to generically create I/O errors which do not
    /// originate from the OS itself. The `error` argument is an arbitrary
    /// payload which will be contained in this `Error`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Error, ErrorKind};
    ///
    /// // errors can be created from strings
    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
    ///
    /// // errors can also be created from other errors
    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new<E>(kind: ErrorKind, error: E) -> Error
        where E: Into<Box<error::Error+Send+Sync>>
    {
        Error {
            repr: Repr::Custom(Box::new(Custom {
                kind: kind,
                error: error.into(),
            }))
        }
    }

    /// Returns an error representing the last OS error which occurred.
    ///
    /// This function reads the value of `errno` for the target platform (e.g.
    /// `GetLastError` on Windows) and will return a corresponding instance of
    /// `Error` for the error code.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn last_os_error() -> Error {
        Error::from_raw_os_error(sys::os::errno() as i32)
    }

    /// Creates a new instance of an `Error` from a particular OS error code.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn from_raw_os_error(code: i32) -> Error {
        Error { repr: Repr::Os(code) }
    }

    /// Returns the OS error that this error represents (if any).
    ///
    /// If this `Error` was constructed via `last_os_error` or
    /// `from_raw_os_error`, then this function will return `Some`, otherwise
    /// it will return `None`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn raw_os_error(&self) -> Option<i32> {
        match self.repr {
            Repr::Os(i) => Some(i),
            Repr::Custom(..) => None,
        }
    }

    /// Returns a reference to the inner error wrapped by this error (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[unstable(feature = "io_error_inner",
               reason = "recently added and requires UFCS to downcast")]
    pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref c) => Some(&*c.error),
        }
    }

    /// Returns a mutable reference to the inner error wrapped by this error
    /// (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[unstable(feature = "io_error_inner",
               reason = "recently added and requires UFCS to downcast")]
    pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref mut c) => Some(&mut *c.error),
        }
    }

    /// Consumes the `Error`, returning its inner error (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[unstable(feature = "io_error_inner",
               reason = "recently added and requires UFCS to downcast")]
    pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(c) => Some(c.error)
        }
    }

    /// Returns the corresponding `ErrorKind` for this error.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn kind(&self) -> ErrorKind {
        match self.repr {
            Repr::Os(code) => sys::decode_error_kind(code),
            Repr::Custom(ref c) => c.kind,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.repr {
            Repr::Os(code) => {
                let detail = sys::os::error_string(code);
                write!(fmt, "{} (os error {})", detail, code)
            }
            Repr::Custom(ref c) => c.error.fmt(fmt),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl error::Error for Error {
    fn description(&self) -> &str {
        match self.repr {
            Repr::Os(..) => "os error",
            Repr::Custom(ref c) => c.error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref c) => c.error.cause(),
        }
    }
}

fn _assert_error_is_sync_send() {
    fn _is_sync_send<T: Sync+Send>() {}
    _is_sync_send::<Error>();
}

#[cfg(test)]
mod test {
    use prelude::v1::*;
    use super::{Error, ErrorKind};
    use error;
    use error::Error as error_Error;
    use fmt;

    #[test]
    fn test_downcasting() {
        #[derive(Debug)]
        struct TestError;

        impl fmt::Display for TestError {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                Ok(())
            }
        }

        impl error::Error for TestError {
            fn description(&self) -> &str {
                "asdf"
            }
        }

        // we have to call all of these UFCS style right now since method
        // resolution won't implicitly drop the Send+Sync bounds
        let mut err = Error::new(ErrorKind::Other, TestError);
        assert!(error::Error::is::<TestError>(err.get_ref().unwrap()));
        assert_eq!("asdf", err.get_ref().unwrap().description());
        assert!(error::Error::is::<TestError>(err.get_mut().unwrap()));
        let extracted = err.into_inner().unwrap();
        error::Error::downcast::<TestError>(extracted).unwrap();
    }
}
<commit_msg>Custom Debug impl for io::Error Fixes #26408<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use boxed::Box;
use convert::Into;
use error;
use fmt;
use marker::{Send, Sync};
use option::Option::{self, Some, None};
use result;
use sys;

/// A type for results generated by I/O related functions where the `Err` type
/// is hard-wired to `io::Error`.
///
/// This typedef is generally used to avoid writing out `io::Error` directly and
/// is otherwise a direct mapping to `std::result::Result`.
#[stable(feature = "rust1", since = "1.0.0")]
pub type Result<T> = result::Result<T, Error>;

/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
/// associated traits.
///
/// Errors mostly originate from the underlying OS, but custom instances of
/// `Error` can be created with crafted error messages and a particular value of
/// `ErrorKind`.
#[derive(Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Error {
    repr: Repr,
}

enum Repr {
    Os(i32),
    Custom(Box<Custom>),
}

#[derive(Debug)]
struct Custom {
    kind: ErrorKind,
    error: Box<error::Error+Send+Sync>,
}

/// A list specifying general categories of I/O error.
///
/// This list is intended to grow over time and it is not recommended to
/// exhaustively match against it.
#[derive(Copy, PartialEq, Eq, Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum ErrorKind {
    /// An entity was not found, often a file.
    #[stable(feature = "rust1", since = "1.0.0")]
    NotFound,
    /// The operation lacked the necessary privileges to complete.
    #[stable(feature = "rust1", since = "1.0.0")]
    PermissionDenied,
    /// The connection was refused by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionRefused,
    /// The connection was reset by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionReset,
    /// The connection was aborted (terminated) by the remote server.
    #[stable(feature = "rust1", since = "1.0.0")]
    ConnectionAborted,
    /// The network operation failed because it was not connected yet.
    #[stable(feature = "rust1", since = "1.0.0")]
    NotConnected,
    /// A socket address could not be bound because the address is already in
    /// use elsewhere.
    #[stable(feature = "rust1", since = "1.0.0")]
    AddrInUse,
    /// A nonexistent interface was requested or the requested address was not
    /// local.
    #[stable(feature = "rust1", since = "1.0.0")]
    AddrNotAvailable,
    /// The operation failed because a pipe was closed.
    #[stable(feature = "rust1", since = "1.0.0")]
    BrokenPipe,
    /// An entity already exists, often a file.
    #[stable(feature = "rust1", since = "1.0.0")]
    AlreadyExists,
    /// The operation needs to block to complete, but the blocking operation was
    /// requested to not occur.
    #[stable(feature = "rust1", since = "1.0.0")]
    WouldBlock,
    /// A parameter was incorrect.
    #[stable(feature = "rust1", since = "1.0.0")]
    InvalidInput,
    /// Data not valid for the operation were encountered.
    ///
    /// Unlike `InvalidInput`, this typically means that the operation
    /// parameters were valid, however the error was caused by malformed
    /// input data.
    #[stable(feature = "io_invalid_data", since = "1.2.0")]
    InvalidData,
    /// The I/O operation's timeout expired, causing it to be canceled.
    #[stable(feature = "rust1", since = "1.0.0")]
    TimedOut,
    /// An error returned when an operation could not be completed because a
    /// call to `write` returned `Ok(0)`.
    ///
    /// This typically means that an operation could only succeed if it wrote a
    /// particular number of bytes but only a smaller number of bytes could be
    /// written.
    #[stable(feature = "rust1", since = "1.0.0")]
    WriteZero,
    /// This operation was interrupted.
    ///
    /// Interrupted operations can typically be retried.
    #[stable(feature = "rust1", since = "1.0.0")]
    Interrupted,
    /// Any I/O error not part of this list.
    #[stable(feature = "rust1", since = "1.0.0")]
    Other,

    /// Any I/O error not part of this list.
    #[unstable(feature = "io_error_internals",
               reason = "better expressed through extensible enums that this \
                         enum cannot be exhaustively matched against")]
    #[doc(hidden)]
    __Nonexhaustive,
}

impl Error {
    /// Creates a new I/O error from a known kind of error as well as an
    /// arbitrary error payload.
    ///
    /// This function is used to generically create I/O errors which do not
    /// originate from the OS itself. The `error` argument is an arbitrary
    /// payload which will be contained in this `Error`.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::io::{Error, ErrorKind};
    ///
    /// // errors can be created from strings
    /// let custom_error = Error::new(ErrorKind::Other, "oh no!");
    ///
    /// // errors can also be created from other errors
    /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn new<E>(kind: ErrorKind, error: E) -> Error
        where E: Into<Box<error::Error+Send+Sync>>
    {
        Error {
            repr: Repr::Custom(Box::new(Custom {
                kind: kind,
                error: error.into(),
            }))
        }
    }

    /// Returns an error representing the last OS error which occurred.
    ///
    /// This function reads the value of `errno` for the target platform (e.g.
    /// `GetLastError` on Windows) and will return a corresponding instance of
    /// `Error` for the error code.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn last_os_error() -> Error {
        Error::from_raw_os_error(sys::os::errno() as i32)
    }

    /// Creates a new instance of an `Error` from a particular OS error code.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn from_raw_os_error(code: i32) -> Error {
        Error { repr: Repr::Os(code) }
    }

    /// Returns the OS error that this error represents (if any).
    ///
    /// If this `Error` was constructed via `last_os_error` or
    /// `from_raw_os_error`, then this function will return `Some`, otherwise
    /// it will return `None`.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn raw_os_error(&self) -> Option<i32> {
        match self.repr {
            Repr::Os(i) => Some(i),
            Repr::Custom(..) => None,
        }
    }

    /// Returns a reference to the inner error wrapped by this error (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[unstable(feature = "io_error_inner",
               reason = "recently added and requires UFCS to downcast")]
    pub fn get_ref(&self) -> Option<&(error::Error+Send+Sync+'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref c) => Some(&*c.error),
        }
    }

    /// Returns a mutable reference to the inner error wrapped by this error
    /// (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[unstable(feature = "io_error_inner",
               reason = "recently added and requires UFCS to downcast")]
    pub fn get_mut(&mut self) -> Option<&mut (error::Error+Send+Sync+'static)> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref mut c) => Some(&mut *c.error),
        }
    }

    /// Consumes the `Error`, returning its inner error (if any).
    ///
    /// If this `Error` was constructed via `new` then this function will
    /// return `Some`, otherwise it will return `None`.
    #[unstable(feature = "io_error_inner",
               reason = "recently added and requires UFCS to downcast")]
    pub fn into_inner(self) -> Option<Box<error::Error+Send+Sync>> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(c) => Some(c.error)
        }
    }

    /// Returns the corresponding `ErrorKind` for this error.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn kind(&self) -> ErrorKind {
        match self.repr {
            Repr::Os(code) => sys::decode_error_kind(code),
            Repr::Custom(ref c) => c.kind,
        }
    }
}

impl fmt::Debug for Repr {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Repr::Os(ref code) =>
                fmt.debug_struct("Os").field("code", code)
                   .field("message", &sys::os::error_string(*code)).finish(),
            &Repr::Custom(ref c) => fmt.debug_tuple("Custom").field(c).finish(),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match self.repr {
            Repr::Os(code) => {
                let detail = sys::os::error_string(code);
                write!(fmt, "{} (os error {})", detail, code)
            }
            Repr::Custom(ref c) => c.error.fmt(fmt),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl error::Error for Error {
    fn description(&self) -> &str {
        match self.repr {
            Repr::Os(..) => "os error",
            Repr::Custom(ref c) => c.error.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self.repr {
            Repr::Os(..) => None,
            Repr::Custom(ref c) => c.error.cause(),
        }
    }
}

fn _assert_error_is_sync_send() {
    fn _is_sync_send<T: Sync+Send>() {}
    _is_sync_send::<Error>();
}

#[cfg(test)]
mod test {
    use prelude::v1::*;
    use super::{Error, ErrorKind};
    use error;
    use error::Error as error_Error;
    use fmt;

    #[test]
    fn test_downcasting() {
        #[derive(Debug)]
        struct TestError;

        impl fmt::Display for TestError {
            fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
                Ok(())
            }
        }

        impl error::Error for TestError {
            fn description(&self) -> &str {
                "asdf"
            }
        }

        // we have to call all of these UFCS style right now since method
        // resolution won't implicitly drop the Send+Sync bounds
        let mut err = Error::new(ErrorKind::Other, TestError);
        assert!(error::Error::is::<TestError>(err.get_ref().unwrap()));
        assert_eq!("asdf", err.get_ref().unwrap().description());
        assert!(error::Error::is::<TestError>(err.get_mut().unwrap()));
        let extracted = err.into_inner().unwrap();
        error::Error::downcast::<TestError>(extracted).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 Bobby Powers. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#![feature(alloc_system)]

extern crate alloc_system;

//extern crate libc;
//use libc::geteuid;

use std::cmp::{Eq, Ordering};
use std::fs::{self, File};
use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Result};

const PROC_PATH: &str = "/proc";

struct CmdStat {
    name: String,
    pid: i32,
    pss: f32,
    shared: f32,
    swap: f32,
    count: i32, // used when summing up
}

impl CmdStat {
    fn try_new(pid: i32) -> Result<Self> {
        let name = proc_name(pid)?;

        let mut stats = CmdStat {
            name,
            pid,
            pss: 0.0,
            shared: 0.0,
            swap: 0.0,
            count: 1,
        };

        stats.collect_memory_usage()?;

        Ok(stats)
    }

    fn collect_memory_usage(&mut self) -> Result<()> {
        const TY_PSS: &str = "Pss:";
        const TY_SWAP: &str = "Swap:";
        const TY_PRIVATE_CLEAN: &str = "Private_Clean:";
        const TY_PRIVATE_DIRTY: &str = "Private_Dirty:";

        let path = format!("/proc/{}/smaps", self.pid);
        let file = File::open(path)?;

        let pss_adjust = 0.5;

        let mut private: f32 = 0.0;

        for line in BufReader::new(file).lines() {
            let line = line.unwrap();
            if line.starts_with(TY_PSS) {
                if let Ok(n) = parse_line(&line) {
                    self.pss += n + pss_adjust;
                }
            } else if line.starts_with(TY_SWAP) {
                if let Ok(n) = parse_line(&line) {
                    self.swap += n;
                }
            } else if line.starts_with(TY_PRIVATE_CLEAN) || line.starts_with(TY_PRIVATE_DIRTY) {
                if let Ok(n) = parse_line(&line) {
                    private += n;
                }
            }
        }

        self.shared = self.pss - private;

        Ok(())
    }
}

fn parse_line(line: &str) -> Result<f32> {
    let kbs = &line[16..24];
    let num: f32 = kbs
        .trim_start()
        .parse()
        .map_err(|_e| Error::new(ErrorKind::Other, "parse error"))?;
    Ok(num)
}

impl PartialEq for CmdStat {
    fn eq(&self, other: &CmdStat) -> bool {
        self.name == other.name
    }
}
impl Eq for CmdStat {}

impl PartialOrd for CmdStat {
    fn partial_cmp(&self, other: &CmdStat) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for CmdStat {
    fn cmp(&self, other: &CmdStat) -> Ordering {
        self.name.cmp(&other.name)
    }
}

#[inline(never)]
fn is_digit(d: char) -> bool {
    d >= '0' && d <= '9'
}

#[inline(never)]
fn first_char(name: &std::ffi::OsStr) -> char {
    use std::os::unix::ffi::OsStrExt;
    name.as_bytes()[0] as char
}

fn is_dir(md: fs::Metadata) -> Result<fs::Metadata> {
    if md.is_dir() {
        Ok(md)
    } else {
        Err(Error::new(ErrorKind::NotFound, "not a directory"))
    }
}

#[inline(never)]
fn get_pids() -> Result<Vec<i32>> {
    let dir = fs::read_dir(PROC_PATH)?;

    // TODO: look at filter_map
    let pids: Vec<i32> = dir
        .filter(|e| e.is_ok()) // ignore bad dirent results
        .map(|e| e.unwrap()) // make this a list of dirents
        .filter(|e| is_digit(first_char(&e.file_name())))
        .filter(|e| fs::metadata(e.path()).and_then(is_dir).is_ok())
        .map(|e| i32::from_str_radix(e.file_name().to_str().unwrap(), 10).unwrap())
        .collect();

    Ok(pids)
}

fn proc_cmdline(pid: i32) -> Result<String> {
    let mut buf = String::new();
    let path = format!("/proc/{}/cmdline", pid);

    // TODO: we don't really care about reading all of the
    // cmdline, just the first 1024 chars is enough.
    let mut f = File::open(path)?;

    f.read_to_string(&mut buf)?;

    Ok(buf)
}

fn proc_name(pid: i32) -> Result<String> {
    let path = format!("/proc/{}/exe", pid);

    let owned_path = fs::read_link(path)?;
    let full_path = owned_path.to_string_lossy();
    let cmdline = proc_cmdline(pid)?;

    let result = if cmdline.starts_with(&*full_path) {
        // the basename (last component) of the path
        owned_path
            .file_name()
            .unwrap()
            .to_string_lossy()
            .to_string()
    } else {
        cmdline
    };

    Ok(result)
}

fn cmdstats_for(pids: Vec<i32>) -> Vec<CmdStat> {
    pids.into_iter()
        .filter_map(|pid| CmdStat::try_new(pid).ok())
        .collect()
}

fn main() {
    // TODO: command line flag parsing

    let pids_r = get_pids();
    if let Err(err) = pids_r {
        println!("get_pids: {}", err);
        return;
    }

    let pids = pids_r.unwrap();

    let mut stats = cmdstats_for(pids);

    stats.sort_unstable();

    stats.dedup_by(|a, b| {
        if a.name != b.name {
            return false;
        }
        b.pss += a.pss;
        b.shared += a.shared;
        b.swap += a.swap;
        b.count += 1;
        true
    });

    stats.sort_unstable_by(|a, b| a.pss.partial_cmp(&b.pss).unwrap_or(Ordering::Equal));

    // TODO: this could be a single iteration
    let total_pss = stats.iter().fold(0.0, |sum, stat| sum + stat.pss);
    let total_swap = stats.iter().fold(0.0, |sum, stat| sum + stat.swap);

    for cmd in &stats {
        let swap = if cmd.swap > 0.0 {
            format!("{:10.1}", cmd.swap)
        } else {
            "".to_string()
        };
        println!(
            "{:10.1}{:10.1}{:10}\t{} ({})",
            cmd.pss / 1024.0,
            cmd.shared / 1024.0,
            swap,
            cmd.name,
            cmd.count
        )
    }

    // print_results
    println!(
        "#{:9.1}{:20.1}\tTOTAL USED BY PROCESSES",
        total_pss / 1024.0,
        total_swap / 1024.0
    );
}
<commit_msg>use smaps_rollup for now<commit_after>// Copyright 2018 Bobby Powers. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

#![feature(alloc_system)]

extern crate alloc_system;

//extern crate libc;
//use libc::geteuid;

use std::cmp::{Eq, Ordering};
use std::fs::{self, File};
use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Result};

const PROC_PATH: &str = "/proc";

struct CmdStat {
    name: String,
    pid: i32,
    pss: f32,
    shared: f32,
    swap: f32,
    count: i32, // used when summing up
}

impl CmdStat {
    fn try_new(pid: i32) -> Result<Self> {
        let name = proc_name(pid)?;

        let mut stats = CmdStat {
            name,
            pid,
            pss: 0.0,
            shared: 0.0,
            swap: 0.0,
            count: 1,
        };

        stats.collect_memory_usage()?;

        Ok(stats)
    }

    fn collect_memory_usage(&mut self) -> Result<()> {
        const TY_PSS: &str = "Pss:";
        const TY_SWAP: &str = "Swap:";
        const TY_PRIVATE_CLEAN: &str = "Private_Clean:";
        const TY_PRIVATE_DIRTY: &str = "Private_Dirty:";

        let path = format!("/proc/{}/smaps_rollup", self.pid);
        let file = File::open(path)?;

        // let pss_adjust = 0.5;
        let pss_adjust = 0.0;

        let mut private: f32 = 0.0;

        for line in BufReader::new(file).lines() {
            let line = line.unwrap();
            if line.starts_with(TY_PSS) {
                if let Ok(n) = parse_line(&line) {
                    self.pss += n + pss_adjust;
                }
            } else if line.starts_with(TY_SWAP) {
                if let Ok(n) = parse_line(&line) {
                    self.swap += n;
                }
            } else if line.starts_with(TY_PRIVATE_CLEAN) || line.starts_with(TY_PRIVATE_DIRTY) {
                if let Ok(n) = parse_line(&line) {
                    private += n;
                }
            }
        }

        self.shared = self.pss - private;

        Ok(())
    }
}

fn parse_line(line: &str) -> Result<f32> {
    let kbs = &line[16..24];
    let num: f32 = kbs
        .trim_start()
        .parse()
        .map_err(|_e| Error::new(ErrorKind::Other, "parse error"))?;
    Ok(num)
}

impl PartialEq for CmdStat {
    fn eq(&self, other: &CmdStat) -> bool {
        self.name == other.name
    }
}
impl Eq for CmdStat {}

impl PartialOrd for CmdStat {
    fn partial_cmp(&self, other: &CmdStat) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for CmdStat {
    fn cmp(&self, other: &CmdStat) -> Ordering {
        self.name.cmp(&other.name)
    }
}

fn is_digit(d: char) -> bool {
    d >= '0' && d <= '9'
}

fn first_char(name: &std::ffi::OsStr) -> char {
    use std::os::unix::ffi::OsStrExt;
    name.as_bytes()[0] as char
}

fn is_dir(md: fs::Metadata) -> Result<fs::Metadata> {
    if md.is_dir() {
        Ok(md)
    } else {
        Err(Error::new(ErrorKind::NotFound, "not a directory"))
    }
}

#[inline(never)]
fn get_pids() -> Result<Vec<i32>> {
    let dir = fs::read_dir(PROC_PATH)?;

    // TODO: look at filter_map
    let pids: Vec<i32> = dir
        .filter(|e| e.is_ok()) // ignore bad dirent results
        .map(|e| e.unwrap()) // make this a list of dirents
        .filter(|e| is_digit(first_char(&e.file_name())))
        .filter(|e| fs::metadata(e.path()).and_then(is_dir).is_ok())
        .map(|e| i32::from_str_radix(e.file_name().to_str().unwrap(), 10).unwrap())
        .collect();

    Ok(pids)
}

fn proc_cmdline(pid: i32) -> Result<String> {
    let mut buf = String::new();
    let path = format!("/proc/{}/cmdline", pid);

    // TODO: we don't really care about reading all of the
    // cmdline, just the first 1024 chars is enough.
    let mut f = File::open(path)?;

    f.read_to_string(&mut buf)?;

    Ok(buf)
}

fn proc_name(pid: i32) -> Result<String> {
    let path = format!("/proc/{}/exe", pid);

    let owned_path = fs::read_link(path)?;
    let full_path = owned_path.to_string_lossy();
    let cmdline = proc_cmdline(pid)?;

    let result = if cmdline.starts_with(&*full_path) {
        // the basename (last component) of the path
        owned_path
            .file_name()
            .unwrap()
            .to_string_lossy()
            .to_string()
    } else {
        cmdline
    };

    Ok(result)
}

fn cmdstats_for(pids: Vec<i32>) -> Vec<CmdStat> {
    pids.into_iter()
        .filter_map(|pid| CmdStat::try_new(pid).ok())
        .collect()
}

fn main() {
    // TODO: command line flag parsing

    let pids_r = get_pids();
    if let Err(err) = pids_r {
        println!("get_pids: {}", err);
        return;
    }

    let pids = pids_r.unwrap();

    let mut stats = cmdstats_for(pids);

    stats.sort_unstable();

    stats.dedup_by(|a, b| {
        if a.name != b.name {
            return false;
        }
        b.pss += a.pss;
        b.shared += a.shared;
        b.swap += a.swap;
        b.count += 1;
        true
    });

    stats.sort_unstable_by(|a, b| a.pss.partial_cmp(&b.pss).unwrap_or(Ordering::Equal));

    // TODO: this could be a single iteration
    let total_pss = stats.iter().fold(0.0, |sum, stat| sum + stat.pss);
    let total_swap = stats.iter().fold(0.0, |sum, stat| sum + stat.swap);

    for cmd in &stats {
        let swap = if cmd.swap > 0.0 {
            format!("{:10.1}", cmd.swap)
        } else {
            "".to_string()
        };
        println!(
            "{:10.1}{:10.1}{:10}\t{} ({})",
            cmd.pss / 1024.0,
            cmd.shared / 1024.0,
            swap,
            cmd.name,
            cmd.count
        )
    }

    // print_results
    println!(
        "#{:9.1}{:20.1}\tTOTAL USED BY PROCESSES",
        total_pss / 1024.0,
        total_swap / 1024.0
    );
}
<|endoftext|>


<commit_before>+ hello
- Hi there!

+ back
- Try again

+ *
- {topic=dummy} {@unknown}
<commit_msg>Mandatory foo<commit_after>+ foo
- Bar?

+ hello
- Hi there!

+ back
- Try again

+ *
- {topic=dummy} {@unknown}
<|endoftext|>


<commit_before><commit_msg>Think I prefer ‘exactly’ for the name of this thing<commit_after><|endoftext|>


<commit_before>use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::path_std;

use rustc_ast::ast::{self, Ident};
use rustc_ast::ast::{Expr, MetaItem};
use rustc_ast::ptr::P;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};

pub fn expand_deriving_debug(
    cx: &mut ExtCtxt<'_>,
    span: Span,
    mitem: &MetaItem,
    item: &Annotatable,
    push: &mut dyn FnMut(Annotatable),
) {
    // &mut ::std::fmt::Formatter
    let fmtr =
        Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));

    let trait_def = TraitDef {
        span,
        attributes: Vec::new(),
        path: path_std!(cx, fmt::Debug),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        is_unsafe: false,
        supports_unions: false,
        methods: vec![MethodDef {
            name: "fmt",
            generics: LifetimeBounds::empty(),
            explicit_self: borrowed_explicit_self(),
            args: vec![(fmtr, "f")],
            ret_ty: Literal(path_std!(cx, fmt::Result)),
            attributes: Vec::new(),
            is_unsafe: false,
            unify_fieldless_variants: false,
            combine_substructure: combine_substructure(Box::new(|a, b, c| {
                show_substructure(a, b, c)
            })),
        }],
        associated_types: Vec::new(),
    };
    trait_def.expand(cx, mitem, item, push)
}

/// We use the debug builders to do the heavy lifting here
fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
    // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
    // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
    // based on the "shape".
    let (ident, vdata, fields) = match substr.fields {
        Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
        EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
        EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
            cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
        }
    };

    // We want to make sure we have the ctxt set so that we can use unstable methods
    let span = cx.with_def_site_ctxt(span);
    let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
    let builder = cx.ident_of("debug_trait_builder", span);
    let builder_expr = cx.expr_ident(span, builder);

    let fmt = substr.nonself_args[0].clone();

    let mut stmts = vec![];
    match vdata {
        ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
            // tuple struct/"normal" variant
            let expr = cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), vec![name]);
            stmts.push(cx.stmt_let(span, true, builder, expr));

            for field in fields {
                // Use double indirection to make sure this works for unsized types
                let field = cx.expr_addr_of(field.span, field.self_.clone());
                let field = cx.expr_addr_of(field.span, field);

                let expr = cx.expr_method_call(
                    span,
                    builder_expr.clone(),
                    Ident::new(sym::field, span),
                    vec![field],
                );

                // Use `let _ = expr;` to avoid triggering the
                // unused_results lint.
                stmts.push(stmt_let_undescore(cx, span, expr));
            }
        }
        ast::VariantData::Struct(..) => {
            // normal struct/struct variant
            let expr =
                cx.expr_method_call(span, fmt, cx.ident_of("debug_struct", span), vec![name]);
            stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));

            for field in fields {
                let name = cx.expr_lit(
                    field.span,
                    ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
                );

                // Use double indirection to make sure this works for unsized types
                let field = cx.expr_addr_of(field.span, field.self_.clone());
                let field = cx.expr_addr_of(field.span, field);
                let expr = cx.expr_method_call(
                    span,
                    builder_expr.clone(),
                    Ident::new(sym::field, span),
                    vec![name, field],
                );
                stmts.push(stmt_let_undescore(cx, span, expr));
            }
        }
    }

    let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]);

    stmts.push(cx.stmt_expr(expr));
    let block = cx.block(span, stmts);
    cx.expr_block(block)
}

fn stmt_let_undescore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast::Stmt {
    let local = P(ast::Local {
        pat: cx.pat_wild(sp),
        ty: None,
        init: Some(expr),
        id: ast::DUMMY_NODE_ID,
        span: sp,
        attrs: ast::AttrVec::new(),
    });
    ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
}
<commit_msg>Rollup merge of #71904 - euclio:function-typo, r=jonas-schievink<commit_after>use crate::deriving::generic::ty::*;
use crate::deriving::generic::*;
use crate::deriving::path_std;

use rustc_ast::ast::{self, Ident};
use rustc_ast::ast::{Expr, MetaItem};
use rustc_ast::ptr::P;
use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};

pub fn expand_deriving_debug(
    cx: &mut ExtCtxt<'_>,
    span: Span,
    mitem: &MetaItem,
    item: &Annotatable,
    push: &mut dyn FnMut(Annotatable),
) {
    // &mut ::std::fmt::Formatter
    let fmtr =
        Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), Borrowed(None, ast::Mutability::Mut));

    let trait_def = TraitDef {
        span,
        attributes: Vec::new(),
        path: path_std!(cx, fmt::Debug),
        additional_bounds: Vec::new(),
        generics: LifetimeBounds::empty(),
        is_unsafe: false,
        supports_unions: false,
        methods: vec![MethodDef {
            name: "fmt",
            generics: LifetimeBounds::empty(),
            explicit_self: borrowed_explicit_self(),
            args: vec![(fmtr, "f")],
            ret_ty: Literal(path_std!(cx, fmt::Result)),
            attributes: Vec::new(),
            is_unsafe: false,
            unify_fieldless_variants: false,
            combine_substructure: combine_substructure(Box::new(|a, b, c| {
                show_substructure(a, b, c)
            })),
        }],
        associated_types: Vec::new(),
    };
    trait_def.expand(cx, mitem, item, push)
}

/// We use the debug builders to do the heavy lifting here
fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> P<Expr> {
    // build fmt.debug_struct(<name>).field(<fieldname>, &<fieldval>)....build()
    // or fmt.debug_tuple(<name>).field(&<fieldval>)....build()
    // based on the "shape".
    let (ident, vdata, fields) = match substr.fields {
        Struct(vdata, fields) => (substr.type_ident, *vdata, fields),
        EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
        EnumNonMatchingCollapsed(..) | StaticStruct(..) | StaticEnum(..) => {
            cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
        }
    };

    // We want to make sure we have the ctxt set so that we can use unstable methods
    let span = cx.with_def_site_ctxt(span);
    let name = cx.expr_lit(span, ast::LitKind::Str(ident.name, ast::StrStyle::Cooked));
    let builder = cx.ident_of("debug_trait_builder", span);
    let builder_expr = cx.expr_ident(span, builder);

    let fmt = substr.nonself_args[0].clone();

    let mut stmts = vec![];
    match vdata {
        ast::VariantData::Tuple(..) | ast::VariantData::Unit(..) => {
            // tuple struct/"normal" variant
            let expr = cx.expr_method_call(span, fmt, cx.ident_of("debug_tuple", span), vec![name]);
            stmts.push(cx.stmt_let(span, true, builder, expr));

            for field in fields {
                // Use double indirection to make sure this works for unsized types
                let field = cx.expr_addr_of(field.span, field.self_.clone());
                let field = cx.expr_addr_of(field.span, field);

                let expr = cx.expr_method_call(
                    span,
                    builder_expr.clone(),
                    Ident::new(sym::field, span),
                    vec![field],
                );

                // Use `let _ = expr;` to avoid triggering the
                // unused_results lint.
                stmts.push(stmt_let_underscore(cx, span, expr));
            }
        }
        ast::VariantData::Struct(..) => {
            // normal struct/struct variant
            let expr =
                cx.expr_method_call(span, fmt, cx.ident_of("debug_struct", span), vec![name]);
            stmts.push(cx.stmt_let(DUMMY_SP, true, builder, expr));

            for field in fields {
                let name = cx.expr_lit(
                    field.span,
                    ast::LitKind::Str(field.name.unwrap().name, ast::StrStyle::Cooked),
                );

                // Use double indirection to make sure this works for unsized types
                let field = cx.expr_addr_of(field.span, field.self_.clone());
                let field = cx.expr_addr_of(field.span, field);
                let expr = cx.expr_method_call(
                    span,
                    builder_expr.clone(),
                    Ident::new(sym::field, span),
                    vec![name, field],
                );
                stmts.push(stmt_let_underscore(cx, span, expr));
            }
        }
    }

    let expr = cx.expr_method_call(span, builder_expr, cx.ident_of("finish", span), vec![]);

    stmts.push(cx.stmt_expr(expr));
    let block = cx.block(span, stmts);
    cx.expr_block(block)
}

fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P<ast::Expr>) -> ast::Stmt {
    let local = P(ast::Local {
        pat: cx.pat_wild(sp),
        ty: None,
        init: Some(expr),
        id: ast::DUMMY_NODE_ID,
        span: sp,
        attrs: ast::AttrVec::new(),
    });
    ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016, 2017 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use helpers::*;

use yaml_rust::Yaml;
use console;
use crowbook::{Result, Book, BookOptions};
use crowbook_intl_runtime::set_lang;
use crowbook::Stats;
use tempdir::TempDir;
use clap::ArgMatches;
use std::process::exit;
use std::io;
use std::io::Read;
use std::env;
use std::fs::File;
use simplelog::{Config, TermLogger, LogLevel, LogLevelFilter, SimpleLogger, WriteLogger};

/// Render a book to specific format
fn render_format(book: &mut Book, emoji: bool, matches: &ArgMatches, format: &str) {
    let mut key = String::from("output.");
    key.push_str(format);

    let mut stdout = false;
    let mut file = None;

    if let Some(f) = matches.value_of("output") {
        if f == "-" {
            stdout = true;
        } else {
            file = Some(String::from(f));
        }
    }

    let res = book.options.get_path(&key);

    let result = match(file, res, stdout) {
        (Some(file), _, _) |
        (None, Ok(file), false) => book.render_format_to_file(format, file),

        (None, Err(_), _) |
        (None, _, true)
        => book.render_format_to(format, &mut io::stdout()),
    };

    match result {
        Err(err) => print_error(&format!("{}", err), emoji),
        Ok(_) => {}
    }
}

pub fn try_main() -> Result<()> {
    let lang = get_lang()
        .or_else(|| {
            match env::var("LANG") {
                Ok(val) => {
                    Some(val)
                },
                Err(_) => None,
            }
        });
    if let Some(val) = lang {
        if val.starts_with("fr") {
            set_lang("fr");
        } else {
            set_lang("en");
        }
    }

    let mut fancy_ui = true;
    let mut emoji = console::Term::stderr().want_emoji();

    let (matches, help, version) = create_matches();

    if matches.is_present("force-emoji") {
        emoji = true;
    }

    if !matches.is_present("quiet") {
        display_header(emoji);
    }

    if matches.is_present("list-options") {
        println!("{}", BookOptions::description(false));
        exit(0);
    }

    if matches.is_present("no-fancy") || matches.is_present("stats") {
        fancy_ui = false;
        emoji = false;
    }

    if matches.is_present("list-options-md") {
        println!("{}", BookOptions::description(true));
        exit(0);
    }

    if matches.is_present("print-template") {
        let template = matches.value_of("print-template").unwrap();
        let mut book = Book::new();
        set_book_options(&mut book, &matches);
        let result = book.get_template(template.as_ref());
        match result {
            Ok(s) => {
                println!("{}", s);
                exit(0);
            }
            Err(_) => print_error_and_exit(&lformat!("{} is not a valid template name.",
                                                     template),
                                           emoji),
        }
    }

    if matches.is_present("help") {
        println!("{}", help);
        exit(0);
    }

    if matches.is_present("version") {
        println!("{}", version);
        exit(0);
    }

    if matches.is_present("create") {
        create_book(&matches);
    }

    if !matches.is_present("BOOK") {
        print_error_and_exit(&lformat!("You must pass the file of a book configuration \
                               file.\n\n{}\n\nFor more information try --help.",
                                       matches.usage()),
                             emoji);
    }

    // ok to unwrap since clap checks it's there
    let s = matches.value_of("BOOK").unwrap();

    // Initalize logger
    let mut log_config = Config::default();
    log_config.target = None;
    log_config.location = None;
    log_config.time = None;
    let verbosity = if matches.is_present("verbose") {
        log_config.time = Some(LogLevel::Error);
        log_config.target = Some(LogLevel::Error);
        fancy_ui = false;
        LogLevelFilter::Debug
    } else if matches.is_present("quiet") {
        fancy_ui = false;
        LogLevelFilter::Error
    } else if fancy_ui {
        LogLevelFilter::Warn
    } else {
        LogLevelFilter::Info
    };

    let error_dir = TempDir::new("crowbook").unwrap();
    let error_path = "error.log";
    if fancy_ui {
        let errors = File::create(error_dir.path().join(error_path)).unwrap();
        let _ = WriteLogger::init(verbosity, log_config, errors);
    } else {
        if TermLogger::init(verbosity, log_config).is_err() {
            // If it failed, not much we can do, we just won't display log
            let _ = SimpleLogger::init(verbosity, log_config);
        }
    }

    {
        let mut book = Book::new();
        if matches.is_present("autograph") {
            println!("{}", &lformat!("Enter autograph: "));
            let mut autograph = String::new();
            match io::stdin().read_to_string(&mut autograph) {
                Ok(_) => {
                    book.options.set_yaml(Yaml::String("autograph".to_string()), Yaml::String(autograph)).unwrap();
                },
                Err(_) => print_error(&lformat!("could not read autograph from stdin"), emoji),
            }
        }

        if fancy_ui {
            book.add_progress_bar(emoji);
        }
        book.set_options(&get_book_options(&matches));

        {
            let res = if matches.is_present("single") {
                if s != "-" {
                    book.load_markdown_file(s)
                } else {
                    book.read_markdown_config(io::stdin())
                }
            } else if s != "-" {
                book.load_file(s)
            } else {
                book.read_config(io::stdin())
            }.map(|_| ());

            match res {
                Ok(..) => {},
                Err(err) => {
                    book.set_error(&format!("{}", err));
                    return Err(err);
                }
            }
        }

        set_book_options(&mut book, &matches);

        if matches.is_present("stats") {
            let stats = Stats::new(&book);
            println!("{}", stats);
            exit(0);
        }

        if let Some(format) = matches.value_of("to") {
            render_format(&mut book, emoji,& matches, format);
        } else {
            book.render_all();
        }
    }
    if fancy_ui {
        let mut errors = String::new();
        let mut file = File::open(error_dir.path().join(error_path)).unwrap();
        file.read_to_string(&mut errors).unwrap();
        if !errors.is_empty() {
            print_warning(&lformat!("Crowbook exited successfully, but the following errors occurred:"),
                          emoji);
            let mut lines: Vec<_> = errors.lines().collect();
            lines.sort();
            lines.dedup();
            for line in &lines {
                if line.starts_with("[ERROR]") {
                    let line = &line[8..];
                    print_error(line, emoji);
                } else if line.starts_with("[WARN]") {
                    let line = &line[7..];
                    print_warning(line, emoji);
                }
            }
        }
    }

    Ok(())
}

pub fn real_main() {
    if let Err(err) = try_main() {
        print_error_and_exit(&format!("{}", err), false);
    }
}
<commit_msg>Fix order of errors/warnings<commit_after>// Copyright (C) 2016, 2017 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Crowbook is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use helpers::*;

use yaml_rust::Yaml;
use console;
use crowbook::{Result, Book, BookOptions};
use crowbook_intl_runtime::set_lang;
use crowbook::Stats;
use tempdir::TempDir;
use clap::ArgMatches;
use std::process::exit;
use std::io;
use std::io::Read;
use std::env;
use std::fs::File;
use simplelog::{Config, TermLogger, LogLevel, LogLevelFilter, SimpleLogger, WriteLogger};

/// Render a book to specific format
fn render_format(book: &mut Book, emoji: bool, matches: &ArgMatches, format: &str) {
    let mut key = String::from("output.");
    key.push_str(format);

    let mut stdout = false;
    let mut file = None;

    if let Some(f) = matches.value_of("output") {
        if f == "-" {
            stdout = true;
        } else {
            file = Some(String::from(f));
        }
    }

    let res = book.options.get_path(&key);

    let result = match(file, res, stdout) {
        (Some(file), _, _) |
        (None, Ok(file), false) => book.render_format_to_file(format, file),

        (None, Err(_), _) |
        (None, _, true)
        => book.render_format_to(format, &mut io::stdout()),
    };

    match result {
        Err(err) => print_error(&format!("{}", err), emoji),
        Ok(_) => {}
    }
}

pub fn try_main() -> Result<()> {
    let lang = get_lang()
        .or_else(|| {
            match env::var("LANG") {
                Ok(val) => {
                    Some(val)
                },
                Err(_) => None,
            }
        });
    if let Some(val) = lang {
        if val.starts_with("fr") {
            set_lang("fr");
        } else {
            set_lang("en");
        }
    }

    let mut fancy_ui = true;
    let mut emoji = console::Term::stderr().want_emoji();

    let (matches, help, version) = create_matches();

    if matches.is_present("force-emoji") {
        emoji = true;
    }

    if !matches.is_present("quiet") {
        display_header(emoji);
    }

    if matches.is_present("list-options") {
        println!("{}", BookOptions::description(false));
        exit(0);
    }

    if matches.is_present("no-fancy") || matches.is_present("stats") {
        fancy_ui = false;
        emoji = false;
    }

    if matches.is_present("list-options-md") {
        println!("{}", BookOptions::description(true));
        exit(0);
    }

    if matches.is_present("print-template") {
        let template = matches.value_of("print-template").unwrap();
        let mut book = Book::new();
        set_book_options(&mut book, &matches);
        let result = book.get_template(template.as_ref());
        match result {
            Ok(s) => {
                println!("{}", s);
                exit(0);
            }
            Err(_) => print_error_and_exit(&lformat!("{} is not a valid template name.",
                                                     template),
                                           emoji),
        }
    }

    if matches.is_present("help") {
        println!("{}", help);
        exit(0);
    }

    if matches.is_present("version") {
        println!("{}", version);
        exit(0);
    }

    if matches.is_present("create") {
        create_book(&matches);
    }

    if !matches.is_present("BOOK") {
        print_error_and_exit(&lformat!("You must pass the file of a book configuration \
                               file.\n\n{}\n\nFor more information try --help.",
                                       matches.usage()),
                             emoji);
    }

    // ok to unwrap since clap checks it's there
    let s = matches.value_of("BOOK").unwrap();

    // Initalize logger
    let mut log_config = Config::default();
    log_config.target = None;
    log_config.location = None;
    log_config.time = None;
    let verbosity = if matches.is_present("verbose") {
        log_config.time = Some(LogLevel::Error);
        log_config.target = Some(LogLevel::Error);
        fancy_ui = false;
        LogLevelFilter::Debug
    } else if matches.is_present("quiet") {
        fancy_ui = false;
        LogLevelFilter::Error
    } else if fancy_ui {
        LogLevelFilter::Warn
    } else {
        LogLevelFilter::Info
    };

    let error_dir = TempDir::new("crowbook").unwrap();
    let error_path = "error.log";
    if fancy_ui {
        let errors = File::create(error_dir.path().join(error_path)).unwrap();
        let _ = WriteLogger::init(verbosity, log_config, errors);
    } else {
        if TermLogger::init(verbosity, log_config).is_err() {
            // If it failed, not much we can do, we just won't display log
            let _ = SimpleLogger::init(verbosity, log_config);
        }
    }

    {
        let mut book = Book::new();
        if matches.is_present("autograph") {
            println!("{}", &lformat!("Enter autograph: "));
            let mut autograph = String::new();
            match io::stdin().read_to_string(&mut autograph) {
                Ok(_) => {
                    book.options.set_yaml(Yaml::String("autograph".to_string()), Yaml::String(autograph)).unwrap();
                },
                Err(_) => print_error(&lformat!("could not read autograph from stdin"), emoji),
            }
        }

        if fancy_ui {
            book.add_progress_bar(emoji);
        }
        book.set_options(&get_book_options(&matches));

        {
            let res = if matches.is_present("single") {
                if s != "-" {
                    book.load_markdown_file(s)
                } else {
                    book.read_markdown_config(io::stdin())
                }
            } else if s != "-" {
                book.load_file(s)
            } else {
                book.read_config(io::stdin())
            }.map(|_| ());

            match res {
                Ok(..) => {},
                Err(err) => {
                    book.set_error(&format!("{}", err));
                    return Err(err);
                }
            }
        }

        set_book_options(&mut book, &matches);

        if matches.is_present("stats") {
            let stats = Stats::new(&book);
            println!("{}", stats);
            exit(0);
        }

        if let Some(format) = matches.value_of("to") {
            render_format(&mut book, emoji,& matches, format);
        } else {
            book.render_all();
        }
    }
    if fancy_ui {
        let mut errors = String::new();
        let mut file = File::open(error_dir.path().join(error_path)).unwrap();
        file.read_to_string(&mut errors).unwrap();
        if !errors.is_empty() {
            print_warning(&lformat!("Crowbook exited successfully, but the following errors occurred:"),
                          emoji);
            // Non-efficient dedup algorithm but we need to keep the order
            let mut lines: Vec<String> = vec!();
            for line in errors.lines().into_iter() {
                let mut contains = false;
                for l in &lines {
                    if &*l == line {
                        contains = true;
                        break;
                    }
                }
                if !contains {
                    lines.push(line.to_string());
                }
            }
            for line in &lines {
                if line.starts_with("[ERROR]") {
                    let line = &line[8..];
                    print_error(line, emoji);
                } else if line.starts_with("[WARN]") {
                    let line = &line[7..];
                    print_warning(line, emoji);
                }
            }
        }
    }

    Ok(())
}

pub fn real_main() {
    if let Err(err) = try_main() {
        print_error_and_exit(&format!("{}", err), false);
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::path::{PathBuf, Path};

use std::collections::BTreeMap;
use rustc_serialize::{Decoder};

use quire::parse_config;
use quire::validate as V;

use super::containers;
use super::containers::Container;
use super::command::{MainCommand, command_validator};
use super::range::Range;
use super::validate::validate_config;
use super::version::MinimumVagga;

#[derive(RustcDecodable)]
pub struct Config {
    pub minimum_vagga: Option<String>,
    pub commands: BTreeMap<String, MainCommand>,
    pub containers: BTreeMap<String, Container>,
}

impl Config {
    pub fn get_container(&self, name: &str) -> Result<&Container, String> {
        self.containers.get(name)
        .ok_or_else(|| format!("Container {} not found", name))
    }
}

pub fn config_validator<'a>() -> V::Structure<'a> {
    V::Structure::new()
    .member("minimum_vagga", MinimumVagga::new()
        .optional()
        .current_version(env!("VAGGA_VERSION").to_string()))
    .member("containers", V::Mapping::new(
        V::Scalar::new(),
        containers::container_validator()))
    .member("commands", V::Mapping::new(
        V::Scalar::new(),
        command_validator()))
}

fn find_config_path(work_dir: &PathBuf) -> Option<(PathBuf, PathBuf)> {
    let mut dir = work_dir.clone();
    loop {
        let fname = dir.join(".vagga/vagga.yaml");
        if fname.exists() {
            return Some((dir, fname));
        }
        let fname = dir.join("vagga.yaml");
        if fname.exists() {
            return Some((dir, fname));
        }
        if !dir.pop() {
            return None;
        }
    }
}

pub fn find_config(work_dir: &PathBuf) -> Result<(Config, PathBuf), String> {
    let (cfg_dir, filename) = match find_config_path(work_dir) {
        Some(pair) => pair,
        None => return Err(format!(
            "Config not found in path {}", work_dir.display())),
    };
    assert!(cfg_dir.is_absolute());
    let cfg = try!(read_config(&filename));
    try!(validate_config(&cfg));
    return Ok((cfg, cfg_dir));
}

pub fn read_config(filename: &Path) -> Result<Config, String> {
    let mut config: Config = match parse_config(
        filename, &config_validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Config {} cannot be read: {}",
                filename.display(), e));
        }
    };
    for (_, ref mut container) in config.containers.iter_mut() {
        if container.uids.len() == 0 {
            container.uids.push(Range::new(0, 65535));
        }
        if container.gids.len() == 0 {
            container.gids.push(Range::new(0, 65535));
        }
    }
    return Ok(config);
}
<commit_msg>Add quotes to container name in error message<commit_after>use std::default::Default;
use std::path::{PathBuf, Path};

use std::collections::BTreeMap;
use rustc_serialize::{Decoder};

use quire::parse_config;
use quire::validate as V;

use super::containers;
use super::containers::Container;
use super::command::{MainCommand, command_validator};
use super::range::Range;
use super::validate::validate_config;
use super::version::MinimumVagga;

#[derive(RustcDecodable)]
pub struct Config {
    pub minimum_vagga: Option<String>,
    pub commands: BTreeMap<String, MainCommand>,
    pub containers: BTreeMap<String, Container>,
}

impl Config {
    pub fn get_container(&self, name: &str) -> Result<&Container, String> {
        self.containers.get(name)
        .ok_or_else(|| format!("Container {:?} not found", name))
    }
}

pub fn config_validator<'a>() -> V::Structure<'a> {
    V::Structure::new()
    .member("minimum_vagga", MinimumVagga::new()
        .optional()
        .current_version(env!("VAGGA_VERSION").to_string()))
    .member("containers", V::Mapping::new(
        V::Scalar::new(),
        containers::container_validator()))
    .member("commands", V::Mapping::new(
        V::Scalar::new(),
        command_validator()))
}

fn find_config_path(work_dir: &PathBuf) -> Option<(PathBuf, PathBuf)> {
    let mut dir = work_dir.clone();
    loop {
        let fname = dir.join(".vagga/vagga.yaml");
        if fname.exists() {
            return Some((dir, fname));
        }
        let fname = dir.join("vagga.yaml");
        if fname.exists() {
            return Some((dir, fname));
        }
        if !dir.pop() {
            return None;
        }
    }
}

pub fn find_config(work_dir: &PathBuf) -> Result<(Config, PathBuf), String> {
    let (cfg_dir, filename) = match find_config_path(work_dir) {
        Some(pair) => pair,
        None => return Err(format!(
            "Config not found in path {}", work_dir.display())),
    };
    assert!(cfg_dir.is_absolute());
    let cfg = try!(read_config(&filename));
    try!(validate_config(&cfg));
    return Ok((cfg, cfg_dir));
}

pub fn read_config(filename: &Path) -> Result<Config, String> {
    let mut config: Config = match parse_config(
        filename, &config_validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Config {} cannot be read: {}",
                filename.display(), e));
        }
    };
    for (_, ref mut container) in config.containers.iter_mut() {
        if container.uids.len() == 0 {
            container.uids.push(Range::new(0, 65535));
        }
        if container.gids.len() == 0 {
            container.gids.push(Range::new(0, 65535));
        }
    }
    return Ok(config);
}
<|endoftext|>


<commit_before>use toml:: { Parser };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
use std::io;

pub struct Configuration {
    host: String,
    port: String
}
/*
impl Configuration {
    pub fn fromFile(path: Path) -> Self {

        let mut f = try!(File::open("foo.txt"));
        let mut s = String::new();
        f.read_to_string(s);

        match from_utf8(s.as_bytes()) {
            Ok(v) => {
                let mut parser = Parser::new(v);
                match parser.parse() {
                    Some(table) => {
                        let host = table.get(&"host").unwrap();
                        let port = table.get(&"port").unwrap();

                        Configuration {
                            host: host.to_string(),
                            port: port.to_string()
                        }
                    },
                    None => println!("parse errors: {:?}", parser.errors)
                };
            },
            Err(err) => println!("{}", err)
        };

//        Configuration { host: "127.0.0.1".to_string(), port: "6767".to_string() }
    }
}

*/

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            host: "127.0.0.1".to_string(),
            port: "6767".to_string()
        }
    }
}

fn readTomlFile(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(content.clone())
}
<commit_msg>add toml file<commit_after>use toml:: { Parser };
use std::default:: { Default };
use std::path:: { Path };
use std::fs::File;
use std::io:: { Read, Result };
//use std::io;
use std::borrow:: { Borrow };

pub struct Configuration {
    host: String,
    port: String
}

impl Configuration {
    pub fn fromFile(path: &Path) -> Self {
        from_toml_file(path).unwrap()
    }
}

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            host: "127.0.0.1".to_string(),
            port: "6767".to_string()
        }
    }
}

pub fn from_toml_file(path: &Path) -> Option<Configuration> {
    let content = read_file(path).unwrap();
    let mut parser = Parser::new(content.borrow());

    match parser.parse() {
        Some(table) => {
            let host = table.get(&"host".to_string()).unwrap();
            let port = table.get(&"port".to_string()).unwrap();

            Some(
                Configuration {
                    host: host.to_string(),
                    port: port.to_string()
                }
            )
        },
        None => None
    }
}

pub fn read_file(path: &Path) -> Result<String> {
    let mut file = try!(File::open(path));
    let mut buffer = String::new();
    let _ = try!(file.read_to_string(&mut buffer));
    Ok(buffer.clone())
}
<|endoftext|>


<commit_before>#[link(name = "ironkernel",
       vers = "0.1",
       license = "MIT")];
// Forked from pczarn/rustboot
#[no_std];
#[feature(asm, globs, macro_rules)];

use core::slice::iter; // for the iterator
use core::iter::Iterator; // for the loop
use core::option::{Some, Option, None}; // for the loop
use core::str::*;
use core::vec;

use platform::*;

#[path = "rust-core/core/mod.rs"]
mod core;

mod kernel {
    pub mod int;
    pub mod memory;
}

#[cfg(target_arch = "arm")]
#[path = "arch/arm/"]
mod platform {
    pub mod cpu;
    pub mod io;
    pub mod drivers;
}

#[cfg(target_arch = "arm")]
#[path = "rust-core/support.rs"]
mod support;

fn keydown(key: char) {
    unsafe {
        io::write_char(key);
    }
}

/// Name courtesy of John
unsafe fn suckit(key: u8) {
    drivers::keydown.map(|f| {
        f(key as char);
    });
}

/// Name also courtesy of John
#[lang = "exchange_free"]
unsafe fn blow_me(msg: &str) {
    for c in core::slice::iter(as_bytes(msg)) {
        suckit(*c);
    }
}

#[lang="start"]
#[no_mangle]
pub unsafe fn main() {
    io::keydown(keydown);
    let table = cpu::interrupt::table::new();
    table.load();
    drivers::init(table);
    suckit('t' as u8);
    suckit('e' as u8);
    blow_me(&"piss");
    suckit(8 as u8);
    suckit(8 as u8);
    suckit(8 as u8);
    suckit(8 as u8);
    blow_me(&"workworkwork");
}
<commit_msg>Made function names not offensive.<commit_after>#[link(name = "ironkernel",
       vers = "0.1",
       license = "MIT")];
// Forked from pczarn/rustboot
#[no_std];
#[feature(asm, globs, macro_rules)];

use core::slice::iter; // for the iterator
use core::iter::Iterator; // for the loop
use core::option::{Some, Option, None}; // for the loop
use core::str::*;
use core::vec;

use platform::*;

#[path = "rust-core/core/mod.rs"]
mod core;

mod kernel {
    pub mod int;
    pub mod memory;
}

#[cfg(target_arch = "arm")]
#[path = "arch/arm/"]
mod platform {
    pub mod cpu;
    pub mod io;
    pub mod drivers;
}

#[cfg(target_arch = "arm")]
#[path = "rust-core/support.rs"]
mod support;

fn keydown(key: char) {
    unsafe {
        io::write_char(key);
    }
}

unsafe fn putchar(key: u8) {
    drivers::keydown.map(|f| {
        f(key as char);
    });
}

#[lang = "exchange_free"]
unsafe fn putstr(msg: &str) {
    for c in core::slice::iter(as_bytes(msg)) {
        putchar(*c);
    }
}

#[lang="start"]
#[no_mangle]
pub unsafe fn main() {
    io::keydown(keydown);
    let table = cpu::interrupt::table::new();
    table.load();
    drivers::init(table);
    putchar('t' as u8);
    putchar('e' as u8);
    putchar(8 as u8);
    putchar(8 as u8);
    putchar(8 as u8);
    putchar(8 as u8);
    putstr(&"workworkwork");
}
<|endoftext|>


<commit_before>fn foo() -> int { 3 }
fn bar() -> int { 4 }
fn quux() -> int { 5 }

fn main() {
    struct IntPair { x: int, y: int }

    let p34 = IntPair{ x: 3, y: 4 };

    fn zero_x(p: IntPair) -> IntPair { IntPair{ x: 0, ..p } }

    println!("p34: {:?} zeroed p34: {:?}", p34, zero_x(p34));

let p34 = IntPair{ x: 3, y: 4 };
let x_adjuster =
  |new_x| { IntPair{ x: new_x, ..p34 } };

let p14 = x_adjuster(1);
let p24 = x_adjuster(2);
println!("p34.x: {} p14.x: {}", p34.x, p14.x);

    let y = { let x = foo(); 2 + x };
    println!("y: {}", y);

    rest();
}

fn rest() {
    struct IntPair { x: int, y: int }

    impl IntPair {
        fn zeroed_x_copy(self) -> IntPair {
            return IntPair { x: 0, ..self }
        }

        fn replace_x(&mut self, new_x: int) {
            self.x = new_x;
        }
    }

    let mut p_tmp = IntPair{ x: 5, y: 6 };
    let p06 = p_tmp.zeroed_x_copy();
    p_tmp.replace_x(17);
    println!("p_tmp.x: {} p06.x: {}", p_tmp.x, p06.x);
}
<commit_msg>More play code.<commit_after>struct Dollars { amt: int }
struct Euros { amt: int }
trait Currency {
    fn render(&self) -> ~str;
    fn to_euros(&self) -> Euros;
}
impl Currency for Dollars {
    fn render(&self) -> ~str { format!("${}", self.amt) }
    fn to_euros(&self) -> Euros { Euros { amt: (self.amt as f64 * 0.73) as int } }
}
impl Currency for Euros {
    fn render(&self) -> ~str { format!("€{}", self.amt) }
    fn to_euros(&self) -> Euros { *self }
}

fn add_as_euros<C:Currency>(a: &C, b: &C) -> Euros {
    Euros{ amt: a.to_euros().amt + b.to_euros().amt }
}

fn accumeuros(a: &Currency, b: &Currency) -> Euros {
    Euros{ amt: a.to_euros().amt + b.to_euros().amt }
}

fn eg_eu_eu() {
    let eu100 = Euros { amt: 100 };
    let eu200 = Euros { amt: 200 };
    println!("{:?}", add_as_euros(&eu100, &eu200));
}

fn eg_us_us() {
    let us100 = Dollars { amt: 100 };
    let us200 = Dollars { amt: 200 };
    println!("{:?}", add_as_euros(&us100, &us200));
}

#[cfg(us_eu)]
fn eg_us_eu() {
    let us100 = Dollars { amt: 100 };
    let eu200 = Euros { amt: 200 };
    println!("{:?}", add_as_euros(&us100, &eu200));
}

#[cfg(not(us_eu))]
fn eg_us_eu() {
    let us100 = Dollars { amt: 100 };
    let eu200 = Euros { amt: 200 };
    println!("{:?}", accumeuros(&us100 as &Currency,
                                &eu200 as &Currency));
}

#[cfg(not(us_eu))]
fn main() {
    eg_us_us();
    eg_eu_eu();
    eg_us_eu();
}
#[cfg(us_eu)]
fn main() {
    eg_us_eu();
}

struct Pair { x: int, y: int }
fn main_old2() {

let _p34 = Pair{ x: 3, y: 4 };

fn zero_x(p: Pair) -> Pair {
  return Pair{ x: 0, ..p };
}

    let p34 = Pair{ x: 3, y: 4 };
    let x_adjuster =
        |new_x| { Pair{ x: new_x, ..p34 } };

    let p14 = x_adjuster(1);
    let _p24 = x_adjuster(2);
    println!("p34: {:?} p14: {:?}", p34, p14);
}

fn foo() -> int { 3 }
fn bar() -> int { 4 }
fn quux() -> int { 5 }

fn main_old() {
    struct IntPair { x: int, y: int }

    let p34 = IntPair{ x: 3, y: 4 };

    fn zero_x(p: IntPair) -> IntPair { IntPair{ x: 0, ..p } }

    println!("p34: {:?} zeroed p34: {:?}", p34, zero_x(p34));

let p34 = IntPair{ x: 3, y: 4 };
let x_adjuster =
  |new_x| { IntPair{ x: new_x, ..p34 } };

let p14 = x_adjuster(1);
let _p24 = x_adjuster(2);
println!("p34.x: {} p14.x: {}", p34.x, p14.x);

    let y = { let x = foo(); 2 + x };
    println!("y: {}", y);

    rest();
}

fn rest() {
    struct IntPair { x: int, y: int }

    impl IntPair {
        fn zeroed_x_copy(self) -> IntPair {
            return IntPair { x: 0, ..self }
        }

        fn replace_x(&mut self, new_x: int) {
            self.x = new_x;
        }
    }

    let mut p_tmp = IntPair{ x: 5, y: 6 };
    let p06 = p_tmp.zeroed_x_copy();
    p_tmp.replace_x(17);
    println!("p_tmp.x: {} p06.x: {}", p_tmp.x, p06.x);
}
<|endoftext|>