<commit_before>#![allow(dead_code, unused_imports)]

extern crate fitsio_sys as sys;
extern crate libc;

use std::ptr;
use std::ffi;

mod stringutils;

/// Error type
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    status: i32,
    message: String,
}

pub type Result<T> = std::result::Result<T, FitsError>;

/// Hdu description type
///
/// Any way of describing a HDU - number or string which either
/// changes the hdu by absolute number, or by name.
pub trait DescribesHdu {
    fn change_hdu(&self, fptr: &FitsFile) -> Result<()>;
}

impl DescribesHdu for usize {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        unsafe {
            sys::ffmahd(f.fptr, (*self + 1) as i32, &mut _hdu_type, &mut status);
        }
        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

impl<'a> DescribesHdu for &'a str {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        let c_hdu_name = ffi::CString::new(*self).unwrap();

        unsafe {
            sys::ffmnhd(f.fptr,
                        sys::HduType::ANY_HDU as libc::c_int,
                        c_hdu_name.into_raw(),
                        0,
                        &mut status);
        }

        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

/// Trait applied to types which can be read from a FITS header
///
/// This is currently:
///
/// * i32
/// * i64
/// * f32
/// * f64
/// * String
pub trait ReadsKey {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> where Self: std::marker::Sized;
}

macro_rules! reads_key_impl {
    ($t:ty, $func:ident) => (
        impl ReadsKey for $t {
            fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;
                let mut value: Self = Self::default();

                unsafe {
                    sys::$func(f.fptr,
                           c_name.into_raw(),
                           &mut value,
                           ptr::null_mut(),
                           &mut status);
                }

                match status {
                    0 => Ok(value),
                    s => {
                        Err(FitsError {
                            status: s,
                            message: stringutils::status_to_string(s).unwrap(),
                        })
                    }
                }
            }
        }
    )
}

reads_key_impl!(i32, ffgkyl);
reads_key_impl!(i64, ffgkyj);
reads_key_impl!(f32, ffgkye);
reads_key_impl!(f64, ffgkyd);

impl ReadsKey for String {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;
        let mut value: Vec<libc::c_char> = vec![0; sys::MAX_VALUE_LENGTH];

        unsafe {
            sys::ffgkys(f.fptr,
                        c_name.into_raw(),
                        value.as_mut_ptr(),
                        ptr::null_mut(),
                        &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                Ok(String::from_utf8(value).unwrap())
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum HduInfo {
    ImageInfo {
        dimensions: usize,
        shape: Vec<usize>,
    },
    TableInfo {
        column_names: Vec<String>,
        column_types: Vec<sys::DataType>,
        num_rows: usize,
    },
}

pub struct FitsFile {
    fptr: *mut sys::fitsfile,
    pub filename: String,
}

fn typechar_to_data_type<T: Into<String>>(typechar: T) -> sys::DataType {
    match typechar.into().as_str() {
        "X" => sys::DataType::TBIT,
        "B" => sys::DataType::TBYTE,
        "L" => sys::DataType::TLOGICAL,
        "A" => sys::DataType::TSTRING,
        "I" => sys::DataType::TSHORT,
        "J" => sys::DataType::TLONG,
        "E" => sys::DataType::TFLOAT,
        "D" => sys::DataType::TDOUBLE,
        "C" => sys::DataType::TCOMPLEX,
        "M" => sys::DataType::TDBLCOMPLEX,
        other => panic!("Unhandled case: {}", other),
    }
}

unsafe fn fetch_hdu_info(fptr: *mut sys::fitsfile) -> Result<HduInfo> {
    let mut status = 0;
    let mut hdu_type = 0;

    sys::ffghdt(fptr, &mut hdu_type, &mut status);
    let hdu_type =
        match hdu_type {
            0 => {
                let mut dimensions = 0;
                sys::ffgidm(fptr, &mut dimensions, &mut status);

                let mut shape = vec![0; dimensions as usize];
                sys::ffgisz(fptr, dimensions, shape.as_mut_ptr(), &mut status);

                HduInfo::ImageInfo {
                    dimensions: dimensions as usize,
                    shape: shape.iter().map(|v| *v as usize).collect(),
                }
            }
            1 | 2 => {
                let mut num_rows = 0;
                sys::ffgnrw(fptr, &mut num_rows, &mut status);

                let mut num_cols = 0;
                sys::ffgncl(fptr, &mut num_cols, &mut status);
                let mut column_names = Vec::with_capacity(num_cols as usize);
                let mut column_types = Vec::with_capacity(num_cols as usize);

                for i in 0..num_cols {
                    let mut name_buffer: Vec<libc::c_char> = vec![0; 71];
                    let mut type_buffer: Vec<libc::c_char> = vec![0; 71];
                    sys::ffgbcl(fptr,
                                (i + 1) as i32,
                                name_buffer.as_mut_ptr(),
                                ptr::null_mut(),
                                type_buffer.as_mut_ptr(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                &mut status);
                    column_names.push(stringutils::buf_to_string(&name_buffer).unwrap());
                    column_types.push(typechar_to_data_type(stringutils::buf_to_string(&type_buffer)
                            .unwrap()));
                }

                HduInfo::TableInfo {
                    column_names: column_names,
                    column_types: column_types,
                    num_rows: num_rows as usize,
                }
            }
            _ => panic!("Invalid hdu type found"),
        };

    match status {
        0 => Ok(hdu_type),
        _ => {
            Err(FitsError {
                status: status,
                message: stringutils::status_to_string(status).unwrap(),
            })
        }
    }
}

impl FitsFile {
    pub fn open(filename: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            sys::ffopen(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        sys::FileOpenMode::READONLY as libc::c_int,
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: filename.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }

    pub fn create(path: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            sys::ffinit(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: path.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }

    pub fn hdu<T: DescribesHdu>(&mut self, hdu_description: T) -> Result<&Self> {
        try!(hdu_description.change_hdu(self));
        Ok(self)
    }

    fn hdu_number(&self) -> usize {
        let mut hdu_num = 0;
        unsafe {
            sys::ffghdn(self.fptr, &mut hdu_num);
        }
        (hdu_num - 1) as usize
    }

    pub fn read_key<T: ReadsKey>(&self, name: &str) -> Result<T> {
        T::read_key(self, name)
    }

    fn fetch_hdu_info(&self) -> Result<HduInfo> {
        unsafe { fetch_hdu_info(self.fptr) }
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        let mut status = 0;
        unsafe {
            sys::ffclos(self.fptr, &mut status);
        }
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::*;
    use sys;
    use super::typechar_to_data_type;

    #[test]
    fn typechar_conversions() {
        let input = vec![
            "X",
            "B",
            "L",
            "A",
            "I",
            "J",
            "E",
            "D",
            "C",
            "M",
        ];
        let expected = vec![
            sys::DataType::TBIT,
            sys::DataType::TBYTE,
            sys::DataType::TLOGICAL,
            sys::DataType::TSTRING,
            sys::DataType::TSHORT,
            sys::DataType::TLONG,
            sys::DataType::TFLOAT,
            sys::DataType::TDOUBLE,
            sys::DataType::TCOMPLEX,
            sys::DataType::TDBLCOMPLEX,
        ];

        input.iter()
            .zip(expected)
            .map(|(&i, e)| {
                assert_eq!(typechar_to_data_type(i), e);
            })
            .collect::<Vec<_>>();
    }

    #[test]
    fn opening_an_existing_file() {
        match FitsFile::open("../testdata/full_example.fits") {
            Ok(_) => {}
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn creating_a_new_file() {
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        match FitsFile::create(filename.to_str().unwrap()) {
            Ok(_) => assert!(filename.exists()),
            Err(e) => panic!("Error: {:?}", e),
        }
    }

    #[test]
    fn fetching_a_hdu() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        for i in 0..2 {
            assert_eq!(f.hdu(i).unwrap().hdu_number(), i);
        }
        match f.hdu(2) {
            Err(e) => assert_eq!(e.status, 107),
            _ => panic!("Error checking for failure"),
        }

        let tbl_hdu = f.hdu("TESTEXT").unwrap();
        assert_eq!(tbl_hdu.hdu_number(), 1);
    }

    #[test]
    fn reading_header_keys() {
        let mut f = FitsFile::open("../testdata/full_example.fits").unwrap();
        match f.hdu(0).unwrap().read_key::<i64>("INTTEST") {
            Ok(value) => assert_eq!(value, 42),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.hdu(0).unwrap().read_key::<f64>("DBLTEST") {
            Ok(value) => assert_eq!(value, 0.09375),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.hdu(0).unwrap().read_key::<String>("TEST") {
            Ok(value) => assert_eq!(value, "value"),
            Err(e) => panic!("Error reading key: {:?}", e),
        }
    }
}
<commit_msg>Remove hdu method<commit_after>#![allow(dead_code, unused_imports)]

extern crate fitsio_sys as sys;
extern crate libc;

use std::ptr;
use std::ffi;

mod stringutils;

/// Error type
#[derive(Debug, PartialEq, Eq)]
pub struct FitsError {
    status: i32,
    message: String,
}

pub type Result<T> = std::result::Result<T, FitsError>;

/// Hdu description type
///
/// Any way of describing a HDU - number or string which either
/// changes the hdu by absolute number, or by name.
pub trait DescribesHdu {
    fn change_hdu(&self, fptr: &FitsFile) -> Result<()>;
}

impl DescribesHdu for usize {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        unsafe {
            sys::ffmahd(f.fptr, (*self + 1) as i32, &mut _hdu_type, &mut status);
        }
        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

impl<'a> DescribesHdu for &'a str {
    fn change_hdu(&self, f: &FitsFile) -> Result<()> {
        let mut _hdu_type = 0;
        let mut status = 0;
        let c_hdu_name = ffi::CString::new(*self).unwrap();

        unsafe {
            sys::ffmnhd(f.fptr,
                        sys::HduType::ANY_HDU as libc::c_int,
                        c_hdu_name.into_raw(),
                        0,
                        &mut status);
        }

        match status {
            0 => Ok(()),
            _ => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }
}

/// Trait applied to types which can be read from a FITS header
///
/// This is currently:
///
/// * i32
/// * i64
/// * f32
/// * f64
/// * String
pub trait ReadsKey {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> where Self: std::marker::Sized;
}

macro_rules! reads_key_impl {
    ($t:ty, $func:ident) => (
        impl ReadsKey for $t {
            fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
                let c_name = ffi::CString::new(name).unwrap();
                let mut status = 0;
                let mut value: Self = Self::default();

                unsafe {
                    sys::$func(f.fptr,
                           c_name.into_raw(),
                           &mut value,
                           ptr::null_mut(),
                           &mut status);
                }

                match status {
                    0 => Ok(value),
                    s => {
                        Err(FitsError {
                            status: s,
                            message: stringutils::status_to_string(s).unwrap(),
                        })
                    }
                }
            }
        }
    )
}

reads_key_impl!(i32, ffgkyl);
reads_key_impl!(i64, ffgkyj);
reads_key_impl!(f32, ffgkye);
reads_key_impl!(f64, ffgkyd);

impl ReadsKey for String {
    fn read_key(f: &FitsFile, name: &str) -> Result<Self> {
        let c_name = ffi::CString::new(name).unwrap();
        let mut status = 0;
        let mut value: Vec<libc::c_char> = vec![0; sys::MAX_VALUE_LENGTH];

        unsafe {
            sys::ffgkys(f.fptr,
                        c_name.into_raw(),
                        value.as_mut_ptr(),
                        ptr::null_mut(),
                        &mut status);
        }

        match status {
            0 => {
                let value: Vec<u8> = value.iter()
                    .map(|&x| x as u8)
                    .filter(|&x| x != 0)
                    .collect();
                Ok(String::from_utf8(value).unwrap())
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }
}

#[derive(PartialEq, Eq, Debug)]
pub enum HduInfo {
    ImageInfo {
        dimensions: usize,
        shape: Vec<usize>,
    },
    TableInfo {
        column_names: Vec<String>,
        column_types: Vec<sys::DataType>,
        num_rows: usize,
    },
}

pub struct FitsFile {
    fptr: *mut sys::fitsfile,
    pub filename: String,
}

fn typechar_to_data_type<T: Into<String>>(typechar: T) -> sys::DataType {
    match typechar.into().as_str() {
        "X" => sys::DataType::TBIT,
        "B" => sys::DataType::TBYTE,
        "L" => sys::DataType::TLOGICAL,
        "A" => sys::DataType::TSTRING,
        "I" => sys::DataType::TSHORT,
        "J" => sys::DataType::TLONG,
        "E" => sys::DataType::TFLOAT,
        "D" => sys::DataType::TDOUBLE,
        "C" => sys::DataType::TCOMPLEX,
        "M" => sys::DataType::TDBLCOMPLEX,
        other => panic!("Unhandled case: {}", other),
    }
}

unsafe fn fetch_hdu_info(fptr: *mut sys::fitsfile) -> Result<HduInfo> {
    let mut status = 0;
    let mut hdu_type = 0;

    sys::ffghdt(fptr, &mut hdu_type, &mut status);
    let hdu_type =
        match hdu_type {
            0 => {
                let mut dimensions = 0;
                sys::ffgidm(fptr, &mut dimensions, &mut status);

                let mut shape = vec![0; dimensions as usize];
                sys::ffgisz(fptr, dimensions, shape.as_mut_ptr(), &mut status);

                HduInfo::ImageInfo {
                    dimensions: dimensions as usize,
                    shape: shape.iter().map(|v| *v as usize).collect(),
                }
            }
            1 | 2 => {
                let mut num_rows = 0;
                sys::ffgnrw(fptr, &mut num_rows, &mut status);

                let mut num_cols = 0;
                sys::ffgncl(fptr, &mut num_cols, &mut status);
                let mut column_names = Vec::with_capacity(num_cols as usize);
                let mut column_types = Vec::with_capacity(num_cols as usize);

                for i in 0..num_cols {
                    let mut name_buffer: Vec<libc::c_char> = vec![0; 71];
                    let mut type_buffer: Vec<libc::c_char> = vec![0; 71];
                    sys::ffgbcl(fptr,
                                (i + 1) as i32,
                                name_buffer.as_mut_ptr(),
                                ptr::null_mut(),
                                type_buffer.as_mut_ptr(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                ptr::null_mut(),
                                &mut status);
                    column_names.push(stringutils::buf_to_string(&name_buffer).unwrap());
                    column_types.push(typechar_to_data_type(stringutils::buf_to_string(&type_buffer)
                            .unwrap()));
                }

                HduInfo::TableInfo {
                    column_names: column_names,
                    column_types: column_types,
                    num_rows: num_rows as usize,
                }
            }
            _ => panic!("Invalid hdu type found"),
        };

    match status {
        0 => Ok(hdu_type),
        _ => {
            Err(FitsError {
                status: status,
                message: stringutils::status_to_string(status).unwrap(),
            })
        }
    }
}

impl FitsFile {
    pub fn open(filename: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(filename).unwrap();

        unsafe {
            sys::ffopen(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        sys::FileOpenMode::READONLY as libc::c_int,
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: filename.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }

    }

    pub fn create(path: &str) -> Result<Self> {
        let mut fptr = ptr::null_mut();
        let mut status = 0;
        let c_filename = ffi::CString::new(path).unwrap();

        unsafe {
            sys::ffinit(&mut fptr as *mut *mut sys::fitsfile,
                        c_filename.as_ptr(),
                        &mut status);
        }

        match status {
            0 => {
                Ok(FitsFile {
                    fptr: fptr,
                    filename: path.to_string(),
                })
            }
            status => {
                Err(FitsError {
                    status: status,
                    message: stringutils::status_to_string(status).unwrap(),
                })
            }
        }
    }

    pub fn change_hdu<T: DescribesHdu>(&self, hdu_description: T) -> Result<()> {
        hdu_description.change_hdu(self)
    }

    fn hdu_number(&self) -> usize {
        let mut hdu_num = 0;
        unsafe {
            sys::ffghdn(self.fptr, &mut hdu_num);
        }
        (hdu_num - 1) as usize
    }

    pub fn read_key<T: ReadsKey>(&self, name: &str) -> Result<T> {
        T::read_key(self, name)
    }

    fn fetch_hdu_info(&self) -> Result<HduInfo> {
        unsafe { fetch_hdu_info(self.fptr) }
    }
}

impl Drop for FitsFile {
    fn drop(&mut self) {
        let mut status = 0;
        unsafe {
            sys::ffclos(self.fptr, &mut status);
        }
    }
}

#[cfg(test)]
mod test {
    extern crate tempdir;
    use super::*;
    use sys;
    use super::typechar_to_data_type;

    #[test]
    fn typechar_conversions() {
        let input = vec![
            "X",
            "B",
            "L",
            "A",
            "I",
            "J",
            "E",
            "D",
            "C",
            "M",
        ];
        let expected = vec![
            sys::DataType::TBIT,
            sys::DataType::TBYTE,
            sys::DataType::TLOGICAL,
            sys::DataType::TSTRING,
            sys::DataType::TSHORT,
            sys::DataType::TLONG,
            sys::DataType::TFLOAT,
            sys::DataType::TDOUBLE,
            sys::DataType::TCOMPLEX,
            sys::DataType::TDBLCOMPLEX,
        ];

        input.iter()
            .zip(expected)
            .map(|(&i, e)| {
                assert_eq!(typechar_to_data_type(i), e);
            })
            .collect::<Vec<_>>();
    }

    #[test]
    fn opening_an_existing_file() {
        match FitsFile::open("../testdata/full_example.fits") {
            Ok(_) => {}
            Err(e) => panic!("{:?}", e),
        }
    }

    #[test]
    fn creating_a_new_file() {
        let tdir = tempdir::TempDir::new("fitsio-").unwrap();
        let tdir_path = tdir.path();
        let filename = tdir_path.join("test.fits");
        assert!(!filename.exists());

        match FitsFile::create(filename.to_str().unwrap()) {
            Ok(_) => assert!(filename.exists()),
            Err(e) => panic!("Error: {:?}", e),
        }
    }

    #[test]
    fn fetching_a_hdu() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        for i in 0..2 {
            f.change_hdu(i).unwrap();
            assert_eq!(f.hdu_number(), i);
        }

        match f.change_hdu(2) {
            Err(e) => assert_eq!(e.status, 107),
            _ => panic!("Error checking for failure"),
        }

        f.change_hdu("TESTEXT").unwrap();
        assert_eq!(f.hdu_number(), 1);
    }

    #[test]
    fn reading_header_keys() {
        let f = FitsFile::open("../testdata/full_example.fits").unwrap();
        match f.read_key::<i64>("INTTEST") {
            Ok(value) => assert_eq!(value, 42),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.read_key::<f64>("DBLTEST") {
            Ok(value) => assert_eq!(value, 0.09375),
            Err(e) => panic!("Error reading key: {:?}", e),
        }

        match f.read_key::<String>("TEST") {
            Ok(value) => assert_eq!(value, "value"),
            Err(e) => panic!("Error reading key: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>use serde::de::Error as DeError;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use super::*;

#[cfg(feature="cache")]
use ::internal::prelude::*;

#[cfg(feature="cache")]
use super::permissions::{self, Permissions};
#[cfg(feature="cache")]
use ::client::CACHE;

pub fn deserialize_emojis<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<EmojiId, Emoji>, D::Error> {
    let vec: Vec<Emoji> = Deserialize::deserialize(deserializer)?;
    let mut emojis = HashMap::new();

    for emoji in vec {
        emojis.insert(emoji.id, emoji);
    }

    Ok(emojis)
}

pub fn deserialize_guild_channels<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<ChannelId, Arc<RwLock<GuildChannel>>>, D::Error> {
    let vec: Vec<GuildChannel> = Deserialize::deserialize(deserializer)?;
    let mut map = HashMap::new();

    for channel in vec {
        map.insert(channel.id, Arc::new(RwLock::new(channel)));
    }

    Ok(map)
}

pub fn deserialize_members<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<UserId, Member>, D::Error> {
    let vec: Vec<Member> = Deserialize::deserialize(deserializer)?;
    let mut members = HashMap::new();

    for member in vec {
        let user_id = member.user.read().unwrap().id;

        members.insert(user_id, member);
    }

    Ok(members)
}

pub fn deserialize_presences<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<UserId, Presence>, D::Error> {
    let vec: Vec<Presence> = Deserialize::deserialize(deserializer)?;
    let mut presences = HashMap::new();

    for presence in vec {
        presences.insert(presence.user_id, presence);
    }

    Ok(presences)
}

pub fn deserialize_private_channels<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<ChannelId, Channel>, D::Error> {
    let vec: Vec<Channel> = Deserialize::deserialize(deserializer)?;
    let mut private_channels = HashMap::new();

    for private_channel in vec {
        let id = match private_channel {
            Channel::Group(ref group) => group.read().unwrap().channel_id,
            Channel::Private(ref channel) => channel.read().unwrap().id,
            Channel::Guild(_) => unreachable!("Guild private channel decode"),
        };

        private_channels.insert(id, private_channel);
    }

    Ok(private_channels)
}

pub fn deserialize_roles<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<RoleId, Role>, D::Error> {
    let vec: Vec<Role> = Deserialize::deserialize(deserializer)?;
    let mut roles = HashMap::new();

    for role in vec {
        roles.insert(role.id, role);
    }

    Ok(roles)
}

pub fn deserialize_single_recipient<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<Arc<RwLock<User>>, D::Error> {
    let mut users: Vec<User> = Deserialize::deserialize(deserializer)?;
    let user = if users.is_empty() {
        return Err(DeError::custom("Expected a single recipient"));
    } else {
        users.remove(0)
    };

    Ok(Arc::new(RwLock::new(user)))
}

pub fn deserialize_users<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<UserId, Arc<RwLock<User>>>, D::Error> {
    let vec: Vec<User> = Deserialize::deserialize(deserializer)?;
    let mut users = HashMap::new();

    for user in vec {
        users.insert(user.id, Arc::new(RwLock::new(user)));
    }

    Ok(users)
}

pub fn deserialize_u16<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<u16, D::Error> {
    deserializer.deserialize_u16(U16Visitor)
}

pub fn deserialize_u64<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<u64, D::Error> {
    deserializer.deserialize_u64(U64Visitor)
}

pub fn deserialize_voice_states<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<UserId, VoiceState>, D::Error> {
    let vec: Vec<VoiceState> = Deserialize::deserialize(deserializer)?;
    let mut voice_states = HashMap::new();

    for voice_state in vec {
        voice_states.insert(voice_state.user_id, voice_state);
    }

    Ok(voice_states)
}

#[cfg(feature="cache")]
pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Result<bool> {
    let cache = CACHE.read().unwrap();
    let current_user = &cache.user;

    let channel = match cache.channel(channel_id) {
        Some(channel) => channel,
        None => return Err(Error::Client(ClientError::ItemMissing)),
    };

    let guild_id = match channel {
        Channel::Group(_) | Channel::Private(_) => {
            return Ok(permissions == permissions::MANAGE_MESSAGES);
        },
        Channel::Guild(channel) => channel.read().unwrap().guild_id,
    };

    let guild = match cache.guild(guild_id) {
        Some(guild) => guild,
        None => return Err(Error::Client(ClientError::ItemMissing)),
    };

    let perms = guild.read().unwrap().permissions_for(channel_id, current_user.id);

    permissions.remove(perms);

    Ok(permissions.is_empty())
}

pub struct U16Visitor;

impl<'de> Visitor<'de> for U16Visitor {
    type Value = u16;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        formatter.write_str("identifier")
    }

    fn visit_str<E: DeError>(self, v: &str) -> StdResult<Self::Value, E> {
        match v.parse::<u16>() {
            Ok(v) => Ok(v),
            Err(_) => {
                let mut s = String::new();
                s.push_str("Unknown ");
                s.push_str(stringify!($name));
                s.push_str(" value: ");
                s.push_str(v);

                Err(DeError::custom(s))
            },
        }
    }

    fn visit_i64<E: DeError>(self, v: i64) -> StdResult<Self::Value, E> {
        Ok(v as u16)
    }

    fn visit_u64<E: DeError>(self, v: u64) -> StdResult<Self::Value, E> {
        Ok(v as u16)
    }
}

pub struct U64Visitor;

impl<'de> Visitor<'de> for U64Visitor {
    type Value = u64;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        formatter.write_str("identifier")
    }

    fn visit_str<E: DeError>(self, v: &str) -> StdResult<Self::Value, E> {
        match v.parse::<u64>() {
            Ok(v) => Ok(v),
            Err(_) => {
                let mut s = String::new();
                s.push_str("Unknown ");
                s.push_str(stringify!($name));
                s.push_str(" value: ");
                s.push_str(v);

                Err(DeError::custom(s))
            },
        }
    }

    fn visit_i64<E: DeError>(self, v: i64) -> StdResult<Self::Value, E> {
        Ok(v as u64)
    }

    fn visit_u64<E: DeError>(self, v: u64) -> StdResult<Self::Value, E> {
        Ok(v)
    }
}
<commit_msg>Fix permissions when sending to DMs or groups<commit_after>use serde::de::Error as DeError;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use super::*;

#[cfg(feature="cache")]
use ::internal::prelude::*;

#[cfg(feature="cache")]
use super::permissions::Permissions;
#[cfg(feature="cache")]
use ::client::CACHE;

pub fn deserialize_emojis<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<EmojiId, Emoji>, D::Error> {
    let vec: Vec<Emoji> = Deserialize::deserialize(deserializer)?;
    let mut emojis = HashMap::new();

    for emoji in vec {
        emojis.insert(emoji.id, emoji);
    }

    Ok(emojis)
}

pub fn deserialize_guild_channels<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<ChannelId, Arc<RwLock<GuildChannel>>>, D::Error> {
    let vec: Vec<GuildChannel> = Deserialize::deserialize(deserializer)?;
    let mut map = HashMap::new();

    for channel in vec {
        map.insert(channel.id, Arc::new(RwLock::new(channel)));
    }

    Ok(map)
}

pub fn deserialize_members<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<UserId, Member>, D::Error> {
    let vec: Vec<Member> = Deserialize::deserialize(deserializer)?;
    let mut members = HashMap::new();

    for member in vec {
        let user_id = member.user.read().unwrap().id;

        members.insert(user_id, member);
    }

    Ok(members)
}

pub fn deserialize_presences<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<UserId, Presence>, D::Error> {
    let vec: Vec<Presence> = Deserialize::deserialize(deserializer)?;
    let mut presences = HashMap::new();

    for presence in vec {
        presences.insert(presence.user_id, presence);
    }

    Ok(presences)
}

pub fn deserialize_private_channels<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<ChannelId, Channel>, D::Error> {
    let vec: Vec<Channel> = Deserialize::deserialize(deserializer)?;
    let mut private_channels = HashMap::new();

    for private_channel in vec {
        let id = match private_channel {
            Channel::Group(ref group) => group.read().unwrap().channel_id,
            Channel::Private(ref channel) => channel.read().unwrap().id,
            Channel::Guild(_) => unreachable!("Guild private channel decode"),
        };

        private_channels.insert(id, private_channel);
    }

    Ok(private_channels)
}

pub fn deserialize_roles<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<RoleId, Role>, D::Error> {
    let vec: Vec<Role> = Deserialize::deserialize(deserializer)?;
    let mut roles = HashMap::new();

    for role in vec {
        roles.insert(role.id, role);
    }

    Ok(roles)
}

pub fn deserialize_single_recipient<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<Arc<RwLock<User>>, D::Error> {
    let mut users: Vec<User> = Deserialize::deserialize(deserializer)?;
    let user = if users.is_empty() {
        return Err(DeError::custom("Expected a single recipient"));
    } else {
        users.remove(0)
    };

    Ok(Arc::new(RwLock::new(user)))
}

pub fn deserialize_users<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<UserId, Arc<RwLock<User>>>, D::Error> {
    let vec: Vec<User> = Deserialize::deserialize(deserializer)?;
    let mut users = HashMap::new();

    for user in vec {
        users.insert(user.id, Arc::new(RwLock::new(user)));
    }

    Ok(users)
}

pub fn deserialize_u16<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<u16, D::Error> {
    deserializer.deserialize_u16(U16Visitor)
}

pub fn deserialize_u64<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<u64, D::Error> {
    deserializer.deserialize_u64(U64Visitor)
}

pub fn deserialize_voice_states<'de, D: Deserializer<'de>>(deserializer: D)
    -> StdResult<HashMap<UserId, VoiceState>, D::Error> {
    let vec: Vec<VoiceState> = Deserialize::deserialize(deserializer)?;
    let mut voice_states = HashMap::new();

    for voice_state in vec {
        voice_states.insert(voice_state.user_id, voice_state);
    }

    Ok(voice_states)
}

#[cfg(feature="cache")]
pub fn user_has_perms(channel_id: ChannelId, mut permissions: Permissions) -> Result<bool> {
    let cache = CACHE.read().unwrap();
    let current_user = &cache.user;

    let channel = match cache.channel(channel_id) {
        Some(channel) => channel,
        None => return Err(Error::Client(ClientError::ItemMissing)),
    };

    let guild_id = match channel {
        Channel::Guild(channel) => channel.read().unwrap().guild_id,
        Channel::Group(_) | Channel::Private(_) => {
            // Both users in DMs, and all users in groups, will have the same
            // permissions.
            //
            // The only exception to this is when the current user is blocked by
            // the recipient in a DM channel, which results in the current user
            // not being able to send messages.
            //
            // Since serenity can't _reasonably_ check and keep track of these,
            // just assume that all permissions are granted and return `true`.
            return Ok(true);
        },
    };

    let guild = match cache.guild(guild_id) {
        Some(guild) => guild,
        None => return Err(Error::Client(ClientError::ItemMissing)),
    };

    let perms = guild.read().unwrap().permissions_for(channel_id, current_user.id);

    permissions.remove(perms);

    Ok(permissions.is_empty())
}

pub struct U16Visitor;

impl<'de> Visitor<'de> for U16Visitor {
    type Value = u16;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        formatter.write_str("identifier")
    }

    fn visit_str<E: DeError>(self, v: &str) -> StdResult<Self::Value, E> {
        match v.parse::<u16>() {
            Ok(v) => Ok(v),
            Err(_) => {
                let mut s = String::new();
                s.push_str("Unknown ");
                s.push_str(stringify!($name));
                s.push_str(" value: ");
                s.push_str(v);

                Err(DeError::custom(s))
            },
        }
    }

    fn visit_i64<E: DeError>(self, v: i64) -> StdResult<Self::Value, E> {
        Ok(v as u16)
    }

    fn visit_u64<E: DeError>(self, v: u64) -> StdResult<Self::Value, E> {
        Ok(v as u16)
    }
}

pub struct U64Visitor;

impl<'de> Visitor<'de> for U64Visitor {
    type Value = u64;

    fn expecting(&self, formatter: &mut Formatter) -> FmtResult {
        formatter.write_str("identifier")
    }

    fn visit_str<E: DeError>(self, v: &str) -> StdResult<Self::Value, E> {
        match v.parse::<u64>() {
            Ok(v) => Ok(v),
            Err(_) => {
                let mut s = String::new();
                s.push_str("Unknown ");
                s.push_str(stringify!($name));
                s.push_str(" value: ");
                s.push_str(v);

                Err(DeError::custom(s))
            },
        }
    }

    fn visit_i64<E: DeError>(self, v: i64) -> StdResult<Self::Value, E> {
        Ok(v as u64)
    }

    fn visit_u64<E: DeError>(self, v: u64) -> StdResult<Self::Value, E> {
        Ok(v)
    }
}
<|endoftext|>


<commit_before>
use {
    AddBevel,
    AddImage,
    AddRound,
    BackEnd,
    BevelRectangleColorContext,
    Borrowed,
    Clear,
    Field,
    Fill,
    Image,
    ImageRectangleColorContext,
    RoundRectangleColorContext,
    Value,
};
use triangulation::{
    rect_tri_list_xy_f32,
    rect_tri_list_rgba_f32,
};
use internal::{
    CanColor,
    CanRectangle,
    CanTransform,
    CanViewTransform,
    Color,
    HasColor,
    HasRectangle,
    HasTransform,
    HasViewTransform,
    Matrix2d,
    Rectangle,
};

/// A rectangle color context.
pub struct RectangleColorContext<'a> {
    /// View transformation.
    pub view: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> Clone for RectangleColorContext<'a> {
    #[inline(always)]
    fn clone(&self) -> RectangleColorContext<'static> {
        RectangleColorContext {
            view: Value(*self.view.get()),
            transform: Value(*self.transform.get()),
            rect: Value(*self.rect.get()),
            color: Value(*self.color.get()),
        }
    }
}

impl<'a> HasTransform<'a, Matrix2d> for RectangleColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, RectangleColorContext<'a>, Matrix2d> for RectangleColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> RectangleColorContext<'a> {
        RectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Value(value),
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasViewTransform<'a, Matrix2d> for RectangleColorContext<'a> {
    #[inline(always)]
    fn get_view_transform(&'a self) -> &'a Matrix2d {
        self.view.get()
    }
}

impl<'a> CanViewTransform<'a, RectangleColorContext<'a>, Matrix2d>
for RectangleColorContext<'a> {
    #[inline(always)]
    fn view_transform(&'a self, value: Matrix2d) -> RectangleColorContext<'a> {
        RectangleColorContext {
            view: Value(value),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for RectangleColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, RectangleColorContext<'a>, Color> for RectangleColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> RectangleColorContext<'a> {
        RectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
            rect: Borrowed(self.rect.get()),
        }
    }
}

impl<'a> HasRectangle<'a, Rectangle> for RectangleColorContext<'a> {
    #[inline(always)]
    fn get_rectangle(&'a self) -> &'a Rectangle {
        self.rect.get()
    }
}

impl<'a> CanRectangle<'a, RectangleColorContext<'a>, Rectangle> for RectangleColorContext<'a> {
    #[inline(always)]
    fn rectangle(&'a self, rect: Rectangle) -> RectangleColorContext<'a> {
        RectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(rect),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> Fill<'a> for RectangleColorContext<'a> {
    #[inline(always)]
    fn fill<B: BackEnd<I>, I: Image>(&'a self, back_end: &mut B) {
        if back_end.supports_tri_list_xy_f32_rgba_f32() {
            let rect = self.rect.get();
            let color = self.color.get();
            // Complete transparency does not need to be rendered.
            if color[3] == 0.0 { return; }
            // Turn on alpha blending if not completely opaque.
            let needs_alpha = color[3] != 1.0;
            if needs_alpha { back_end.enable_alpha_blend(); }
            back_end.tri_list_xy_f32_rgba_f32(
                rect_tri_list_xy_f32(*self.transform.get(), *rect),
                rect_tri_list_rgba_f32(*color)
            );
            if needs_alpha { back_end.disable_alpha_blend(); }
        } else {
            unimplemented!();
        }
    }
}

impl<'a, B: BackEnd<I>, I: Image> Clear<B, I> for RectangleColorContext<'a> {
    fn clear(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        } else {
            unimplemented!();
        }
    }
}

impl<'a> AddRound<'a, RoundRectangleColorContext<'a>> for RectangleColorContext<'a> {
    #[inline(always)]
    fn round(&'a self, radius: f64) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Value(radius),
        }
    }
}

impl<'a> AddBevel<'a, BevelRectangleColorContext<'a>> for RectangleColorContext<'a> {
    #[inline(always)]
    fn bevel(&'a self, radius: f64) -> BevelRectangleColorContext<'a> {
        BevelRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            rect: Borrowed(self.rect.get()),
            bevel_radius: Value(radius),
        }
    }
}

impl<'a, 'b, I: Image> AddImage<'a, 'b, ImageRectangleColorContext<'a, 'b, I>, I> for RectangleColorContext<'a> {
    fn image(&'a self, image: &'b I) -> ImageRectangleColorContext<'a, 'b, I> {
        let (w, h) = image.get_size();
        ImageRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            image: Value(image),
            source_rect: Value([0, 0, w as i32, h as i32]),
            color: Borrowed(self.color.get()),
        }
    }
}

<commit_msg>Implemented `AddBorder` for `RectangleColorContext`<commit_after>
use {
    AddBevel,
    AddBorder,
    AddImage,
    AddRound,
    BackEnd,
    BevelRectangleColorContext,
    Borrowed,
    Clear,
    Field,
    Fill,
    Image,
    ImageRectangleColorContext,
    RectangleBorderColorContext,
    RoundRectangleColorContext,
    Value,
};
use triangulation::{
    rect_tri_list_xy_f32,
    rect_tri_list_rgba_f32,
};
use internal::{
    CanColor,
    CanRectangle,
    CanTransform,
    CanViewTransform,
    Color,
    HasColor,
    HasRectangle,
    HasTransform,
    HasViewTransform,
    Matrix2d,
    Rectangle,
};

/// A rectangle color context.
pub struct RectangleColorContext<'a> {
    /// View transformation.
    pub view: Field<'a, Matrix2d>,
    /// Current transformation.
    pub transform: Field<'a, Matrix2d>,
    /// Current rectangle.
    pub rect: Field<'a, Rectangle>,
    /// Current color.
    pub color: Field<'a, Color>,
}

impl<'a> Clone for RectangleColorContext<'a> {
    #[inline(always)]
    fn clone(&self) -> RectangleColorContext<'static> {
        RectangleColorContext {
            view: Value(*self.view.get()),
            transform: Value(*self.transform.get()),
            rect: Value(*self.rect.get()),
            color: Value(*self.color.get()),
        }
    }
}

impl<'a> HasTransform<'a, Matrix2d> for RectangleColorContext<'a> {
    #[inline(always)]
    fn get_transform(&'a self) -> &'a Matrix2d {
        self.transform.get()
    }
}

impl<'a> CanTransform<'a, RectangleColorContext<'a>, Matrix2d> for RectangleColorContext<'a> {
    #[inline(always)]
    fn transform(&'a self, value: Matrix2d) -> RectangleColorContext<'a> {
        RectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Value(value),
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasViewTransform<'a, Matrix2d> for RectangleColorContext<'a> {
    #[inline(always)]
    fn get_view_transform(&'a self) -> &'a Matrix2d {
        self.view.get()
    }
}

impl<'a> CanViewTransform<'a, RectangleColorContext<'a>, Matrix2d>
for RectangleColorContext<'a> {
    #[inline(always)]
    fn view_transform(&'a self, value: Matrix2d) -> RectangleColorContext<'a> {
        RectangleColorContext {
            view: Value(value),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> HasColor<'a, Color> for RectangleColorContext<'a> {
    #[inline(always)]
    fn get_color(&'a self) -> &'a Color {
        self.color.get()
    }
}

impl<'a> CanColor<'a, RectangleColorContext<'a>, Color> for RectangleColorContext<'a> {
    #[inline(always)]
    fn color(&'a self, value: Color) -> RectangleColorContext<'a> {
        RectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            color: Value(value),
            rect: Borrowed(self.rect.get()),
        }
    }
}

impl<'a> HasRectangle<'a, Rectangle> for RectangleColorContext<'a> {
    #[inline(always)]
    fn get_rectangle(&'a self) -> &'a Rectangle {
        self.rect.get()
    }
}

impl<'a> CanRectangle<'a, RectangleColorContext<'a>, Rectangle> for RectangleColorContext<'a> {
    #[inline(always)]
    fn rectangle(&'a self, rect: Rectangle) -> RectangleColorContext<'a> {
        RectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            rect: Value(rect),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> Fill<'a> for RectangleColorContext<'a> {
    #[inline(always)]
    fn fill<B: BackEnd<I>, I: Image>(&'a self, back_end: &mut B) {
        if back_end.supports_tri_list_xy_f32_rgba_f32() {
            let rect = self.rect.get();
            let color = self.color.get();
            // Complete transparency does not need to be rendered.
            if color[3] == 0.0 { return; }
            // Turn on alpha blending if not completely opaque.
            let needs_alpha = color[3] != 1.0;
            if needs_alpha { back_end.enable_alpha_blend(); }
            back_end.tri_list_xy_f32_rgba_f32(
                rect_tri_list_xy_f32(*self.transform.get(), *rect),
                rect_tri_list_rgba_f32(*color)
            );
            if needs_alpha { back_end.disable_alpha_blend(); }
        } else {
            unimplemented!();
        }
    }
}

impl<'a, B: BackEnd<I>, I: Image> Clear<B, I> for RectangleColorContext<'a> {
    fn clear(&self, back_end: &mut B) {
        if back_end.supports_clear_rgba() {
            let color = self.color.get();
            back_end.clear_rgba(color[0], color[1], color[2], color[3]);
        } else {
            unimplemented!();
        }
    }
}

impl<'a> AddRound<'a, RoundRectangleColorContext<'a>> for RectangleColorContext<'a> {
    #[inline(always)]
    fn round(&'a self, radius: f64) -> RoundRectangleColorContext<'a> {
        RoundRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            rect: Borrowed(self.rect.get()),
            round_radius: Value(radius),
        }
    }
}

impl<'a> AddBevel<'a, BevelRectangleColorContext<'a>> for RectangleColorContext<'a> {
    #[inline(always)]
    fn bevel(&'a self, radius: f64) -> BevelRectangleColorContext<'a> {
        BevelRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            color: Borrowed(self.color.get()),
            rect: Borrowed(self.rect.get()),
            bevel_radius: Value(radius),
        }
    }
}

impl<'a, 'b, I: Image> AddImage<'a, 'b, ImageRectangleColorContext<'a, 'b, I>, I> for RectangleColorContext<'a> {
    fn image(&'a self, image: &'b I) -> ImageRectangleColorContext<'a, 'b, I> {
        let (w, h) = image.get_size();
        ImageRectangleColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            image: Value(image),
            source_rect: Value([0, 0, w as i32, h as i32]),
            color: Borrowed(self.color.get()),
        }
    }
}

impl<'a> AddBorder<'a, RectangleBorderColorContext<'a>> for RectangleColorContext<'a> {
    #[inline(always)]
    fn border_radius(&'a self, radius: f64) -> RectangleBorderColorContext<'a> {
        RectangleBorderColorContext {
            view: Borrowed(self.view.get()),
            transform: Borrowed(self.transform.get()),
            rect: Borrowed(self.rect.get()),
            color: Borrowed(self.color.get()),
            border: Value(radius),
        }
    }
}

<|endoftext|>


<commit_before>use super::theme::Theme;
use super::settings::*;
use super::super::LoadingError;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::io::{BufReader, BufRead, Seek};
use walkdir::WalkDir;
use std::fs::File;

#[derive(Debug, Serialize, Deserialize)]
pub struct ThemeSet {
    pub themes: BTreeMap<String, Theme>,
}

/// A set of themes, includes convenient methods for loading and discovering themes.
impl ThemeSet {
    /// Creates an empty set
    pub fn new() -> ThemeSet {
        ThemeSet { themes: BTreeMap::new() }
    }

    /// Returns all the themes found in a folder, good for enumerating before loading one with get_theme
    pub fn discover_theme_paths<P: AsRef<Path>>(folder: P) -> Result<Vec<PathBuf>, LoadingError> {
        let mut themes = Vec::new();
        for entry in WalkDir::new(folder) {
            let entry = entry.map_err(LoadingError::WalkDir)?;
            if entry.path().extension().map_or(false, |e| e == "tmTheme") {
                themes.push(entry.path().to_owned());
            }
        }
        Ok(themes)
    }

    /// Loads a theme given a path to a .tmTheme file
    pub fn get_theme<P: AsRef<Path>>(path: P) -> Result<Theme, LoadingError> {
        let file = File::open(path)?;
        let mut file = BufReader::new(file);
        Self::load_from_reader(&mut file)
    }

    /// Loads a theme given a readable stream
    pub fn load_from_reader<R: BufRead + Seek>(r: &mut R) -> Result<Theme, LoadingError> {
        Ok(Theme::parse_settings(read_plist(r)?)?)
    }

    /// Generate a `ThemeSet` from all themes in a folder
    pub fn load_from_folder<P: AsRef<Path>>(folder: P) -> Result<ThemeSet, LoadingError> {
        let mut theme_set = Self::new();
        theme_set.load_themes(folder)?;
        Ok(theme_set)
    }

    /// Load all the themes in the folder into this `ThemeSet`
    pub fn load_themes<P: AsRef<Path>>(&mut self, folder: P) -> Result<(), LoadingError> {
        let paths = Self::discover_theme_paths(folder)?;
        for p in &paths {
            let theme = Self::get_theme(p)?;
            let basename =
                p.file_stem().and_then(|x| x.to_str()).ok_or(LoadingError::BadPath)?;
            self.themes.insert(basename.to_owned(), theme);
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use highlighting::{ThemeSet, Color};
    #[test]
    fn can_parse_common_themes() {
        let themes = ThemeSet::load_from_folder("testdata").unwrap();
        let all_themes: Vec<&str> = themes.themes.keys().map(|x| &**x).collect();
        assert!(all_themes.contains(&"base16-ocean.dark"));

        println!("{:?}", all_themes);

        let theme = ThemeSet::get_theme("testdata/spacegray/base16-ocean.dark.tmTheme").unwrap();
        assert_eq!(theme.name.unwrap(), "Base16 Ocean Dark");
        assert_eq!(theme.settings.selection.unwrap(),
                   Color {
                       r: 0x4f,
                       g: 0x5b,
                       b: 0x66,
                       a: 0xff,
                   });
        assert_eq!(theme.scopes[0].style.foreground.unwrap(),
                   Color {
                       r: 0xc0,
                       g: 0xc5,
                       b: 0xce,
                       a: 0xFF,
                   });
        // assert!(false);
    }
}
<commit_msg>Rename load_themes on ThemeSet<commit_after>use super::theme::Theme;
use super::settings::*;
use super::super::LoadingError;
use std::collections::BTreeMap;
use std::path::{Path, PathBuf};
use std::io::{BufReader, BufRead, Seek};
use walkdir::WalkDir;
use std::fs::File;

#[derive(Debug, Serialize, Deserialize)]
pub struct ThemeSet {
    pub themes: BTreeMap<String, Theme>,
}

/// A set of themes, includes convenient methods for loading and discovering themes.
impl ThemeSet {
    /// Creates an empty set
    pub fn new() -> ThemeSet {
        ThemeSet { themes: BTreeMap::new() }
    }

    /// Returns all the themes found in a folder, good for enumerating before loading one with get_theme
    pub fn discover_theme_paths<P: AsRef<Path>>(folder: P) -> Result<Vec<PathBuf>, LoadingError> {
        let mut themes = Vec::new();
        for entry in WalkDir::new(folder) {
            let entry = entry.map_err(LoadingError::WalkDir)?;
            if entry.path().extension().map_or(false, |e| e == "tmTheme") {
                themes.push(entry.path().to_owned());
            }
        }
        Ok(themes)
    }

    /// Loads a theme given a path to a .tmTheme file
    pub fn get_theme<P: AsRef<Path>>(path: P) -> Result<Theme, LoadingError> {
        let file = File::open(path)?;
        let mut file = BufReader::new(file);
        Self::load_from_reader(&mut file)
    }

    /// Loads a theme given a readable stream
    pub fn load_from_reader<R: BufRead + Seek>(r: &mut R) -> Result<Theme, LoadingError> {
        Ok(Theme::parse_settings(read_plist(r)?)?)
    }

    /// Generate a `ThemeSet` from all themes in a folder
    pub fn load_from_folder<P: AsRef<Path>>(folder: P) -> Result<ThemeSet, LoadingError> {
        let mut theme_set = Self::new();
        theme_set.add_from_folder(folder)?;
        Ok(theme_set)
    }

    /// Load all the themes in the folder into this `ThemeSet`
    pub fn add_from_folder<P: AsRef<Path>>(&mut self, folder: P) -> Result<(), LoadingError> {
        let paths = Self::discover_theme_paths(folder)?;
        for p in &paths {
            let theme = Self::get_theme(p)?;
            let basename =
                p.file_stem().and_then(|x| x.to_str()).ok_or(LoadingError::BadPath)?;
            self.themes.insert(basename.to_owned(), theme);
        }

        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use highlighting::{ThemeSet, Color};
    #[test]
    fn can_parse_common_themes() {
        let themes = ThemeSet::load_from_folder("testdata").unwrap();
        let all_themes: Vec<&str> = themes.themes.keys().map(|x| &**x).collect();
        assert!(all_themes.contains(&"base16-ocean.dark"));

        println!("{:?}", all_themes);

        let theme = ThemeSet::get_theme("testdata/spacegray/base16-ocean.dark.tmTheme").unwrap();
        assert_eq!(theme.name.unwrap(), "Base16 Ocean Dark");
        assert_eq!(theme.settings.selection.unwrap(),
                   Color {
                       r: 0x4f,
                       g: 0x5b,
                       b: 0x66,
                       a: 0xff,
                   });
        assert_eq!(theme.scopes[0].style.foreground.unwrap(),
                   Color {
                       r: 0xc0,
                       g: 0xc5,
                       b: 0xce,
                       a: 0xFF,
                   });
        // assert!(false);
    }
}
<|endoftext|>


<commit_before>

use std::ops::Add;
use std::ops::Sub;
//use std::ops::Mul;
use std::cmp;

#[derive(Debug, Eq)]
pub struct BaseN {
    pub base: usize,
    pub vec: Vec<u8>
}

impl BaseN {

    /// Creates new BaseN
    pub fn new(base: usize) -> BaseN/*<T>*/ {
        BaseN { base: base, vec: Vec::new() }
    }

    /// Creates new BaseN with initial vector capacity
    pub fn with_capacity(base: usize, capacity: usize) -> BaseN {
        BaseN { base: base, vec: Vec::with_capacity(capacity) }
    }

    /// Creates new BaseN with existing base and vec
    pub fn with_existing(base: usize, vec: Vec<u8>) -> BaseN {
        BaseN { base: base, vec: vec }
    }

    /// Creates a new BaseN from usize value
    pub fn from_usize(base: usize, val: usize) -> Result<BaseN, &'static str> {

        let mut new_vec:Vec<u8> = Vec::new();
        let mut val10: usize = val;
        loop {
            let val = val10 / base;
            match val {
                0 => {
                    new_vec.push(val10 as u8);
                    break;
                }
                _ => {
                    let remainder = val10 % base;
                    //println!("{}", remainder);
                    new_vec.push(remainder as u8);
                    val10 = val;
                }
            }
        }
        let new_basen: BaseN = BaseN { base: base, vec: new_vec };

        Ok(new_basen)
    }

    /// Converts existing mutable BaseN to new base
    pub fn to_base_mut(&mut self, new_base: usize) -> Result<bool, &'static str> {

        if self.base == new_base {
            return Ok(true);
        }

        let mut val10: usize = self.to_usize().unwrap();

        loop {
            let val = val10 / new_base;
            match val {
                0 => {
                    self.vec.push(val10 as u8);
                    break;
                }
                _ => {
                    let remainder = val10 % new_base;
                    self.vec.push(remainder as u8);
                    val10 = val;
                }
            }
        }

        Ok(true)
    }

    /// Converts to a new BaseN copy
    pub fn to_base(&self, new_base: usize) -> Result<BaseN, &'static str> {

        //TODO: If base is same, just return existing??
        if self.base == new_base {
            return Ok(self.clone());
        }

        // TODO: Create copy, convert mutable, or both?
        //let new_basen = BaseN::new(new_base);

        //println!("converting base {} to base {}", self.base, new_base);
        let val10: usize = self.to_usize().unwrap();
        //println!("{}", val10);

        BaseN::from_usize(new_base, val10)

    }

    /// Converts existing BaseN to a usize
    pub fn to_usize(&self) -> Result<usize, &'static str> {
        let mut val10: usize = 0;
        for (i, x) in self.vec.iter().enumerate() {
            val10 = val10 + (*x as usize) * self.base.pow(i as u32);
        }
        Ok(val10)
    }

}

//impl Copy for BaseN { }

impl PartialEq for BaseN {
    fn eq(&self, other: &BaseN) -> bool {
        (self.vec == other.vec)
            && (self.base == other.base)
    }
}

impl Clone for BaseN {
    fn clone(&self) -> Self {
        BaseN { base: self.base, vec: self.vec.clone() }
    }

    fn clone_from(&mut self, source: &Self) {
        self.vec.clone_from(&source.vec);
        self.base = source.base;
    }
}

impl Add for BaseN {
    type Output = Result<BaseN, &'static str>;

    // Option<> because might overflow, bases incorrect, etc.
    // I suppose you could add a base16 to base10 with an internal convert
    fn add(self, rhs: BaseN) -> Result<BaseN, &'static str> {

        let add_basen = if rhs.base==self.base {
            rhs
        } else {
            rhs.to_base(self.base).unwrap()
            // TODO: Throw error?  Don't actually know
            // what base user wanted to end with
        };

        // TODO: Use zip() w/ carry array instead?
        let max = cmp::max(self.vec.len(), add_basen.vec.len());
        let mut new_vec: Vec<u8> = Vec::with_capacity(max);

        let mut carry: u8 = 0;

        for i in 0..max {
            match (self.vec.get(i), add_basen.vec.get(i)) {
                (Some(x), Some(y)) => {
                    let sum: u8 = *x + *y + carry;
                    carry = sum / (add_basen.base as u8);
                    new_vec.push(sum % (add_basen.base as u8));
                },
                (Some(x), None) => {
                    // no carry, but need to resize
                    let sum: u8 = *x + carry;
                    carry = sum / (add_basen.base as u8);
                    new_vec.push(sum % (add_basen.base as u8));
                },
                (_, _) => break // no ops needed

            }
        }

        let new_basen: BaseN = BaseN { base: add_basen.base, vec: new_vec };

        Ok(new_basen)
    }
}

impl Sub for BaseN {
    type Output = Result<BaseN, &'static str>;

    // Option<> because might overflow, bases incorrect, etc.
    // I suppose you could add a base16 to base10 with an internal convert
    fn sub(self, rhs: BaseN) -> Result<BaseN, &'static str> {

        let sub_basen = if rhs.base==self.base {
            rhs
        } else {
            rhs.to_base(self.base).unwrap()
            // TODO: Throw error?  Don't actually know
            // what base user wanted to end with
        };

        let max = cmp::max(self.vec.len(), sub_basen.vec.len());
        let mut new_vec: Vec<u8> = Vec::with_capacity(max);

        let mut borrow: u8 = 0;

        for i in 0..max {
            match (self.vec.get(i), sub_basen.vec.get(i)) {
                (Some(x), Some(y)) => {
                    let mut diff: i8 = (*x as i8) - (*y as i8) - (borrow as i8);
                    borrow = if diff < 0 {
                        diff += self.base as i8; 1 } else { 0 };
                    new_vec.push(diff as u8);
                },
                (Some(x), None) => {
                    let mut diff: i8 = (*x as i8) - (borrow as i8);
                    borrow = if diff < 0 {
                        diff += self.base as i8; 1 } else { 0 };
                    new_vec.push(diff as u8);
                },
                (_, _) => break // no ops needed

            }
        }

        let new_basen: BaseN = BaseN { base: sub_basen.base, vec: new_vec };

        Ok(new_basen)
    }
}

<commit_msg>Implement eq for different bases<commit_after>

use std::ops::Add;
use std::ops::Sub;
//use std::ops::Mul;
use std::cmp;

#[derive(Debug, Eq)]
pub struct BaseN {
    pub base: usize,
    pub vec: Vec<u8>
}

impl BaseN {

    /// Creates new BaseN
    pub fn new(base: usize) -> BaseN/*<T>*/ {
        BaseN { base: base, vec: Vec::new() }
    }

    /// Creates new BaseN with initial vector capacity
    pub fn with_capacity(base: usize, capacity: usize) -> BaseN {
        BaseN { base: base, vec: Vec::with_capacity(capacity) }
    }

    /// Creates new BaseN with existing base and vec
    pub fn with_existing(base: usize, vec: Vec<u8>) -> BaseN {
        BaseN { base: base, vec: vec }
    }

    /// Creates a new BaseN from usize value
    pub fn from_usize(base: usize, val: usize) -> Result<BaseN, &'static str> {

        let mut new_vec:Vec<u8> = Vec::new();
        let mut val10: usize = val;
        loop {
            let val = val10 / base;
            match val {
                0 => {
                    new_vec.push(val10 as u8);
                    break;
                }
                _ => {
                    let remainder = val10 % base;
                    //println!("{}", remainder);
                    new_vec.push(remainder as u8);
                    val10 = val;
                }
            }
        }
        let new_basen: BaseN = BaseN { base: base, vec: new_vec };

        Ok(new_basen)
    }

    /// Converts existing mutable BaseN to new base
    pub fn to_base_mut(&mut self, new_base: usize) -> Result<bool, &'static str> {

        if self.base == new_base {
            return Ok(true);
        }

        let mut val10: usize = self.to_usize().unwrap();

        loop {
            let val = val10 / new_base;
            match val {
                0 => {
                    self.vec.push(val10 as u8);
                    break;
                }
                _ => {
                    let remainder = val10 % new_base;
                    self.vec.push(remainder as u8);
                    val10 = val;
                }
            }
        }

        Ok(true)
    }

    /// Converts to a new BaseN copy
    pub fn to_base(&self, new_base: usize) -> Result<BaseN, &'static str> {

        //TODO: If base is same, just return existing??
        if self.base == new_base {
            return Ok(self.clone());
        }

        // TODO: Create copy, convert mutable, or both?
        //let new_basen = BaseN::new(new_base);

        //println!("converting base {} to base {}", self.base, new_base);
        let val10: usize = self.to_usize().unwrap();
        //println!("{}", val10);

        BaseN::from_usize(new_base, val10)

    }

    /// Converts existing BaseN to a usize
    pub fn to_usize(&self) -> Result<usize, &'static str> {
        let mut val10: usize = 0;
        for (i, x) in self.vec.iter().enumerate() {
            val10 = val10 + (*x as usize) * self.base.pow(i as u32);
        }
        Ok(val10)
    }

}

//impl Copy for BaseN { }

impl PartialEq for BaseN {
    fn eq(&self, other: &BaseN) -> bool {
        if self.base == other.base {
            (self.vec == other.vec)
        } else {
            self.vec == other.to_base(self.base).unwrap().vec

        }
    }
}

impl Clone for BaseN {
    fn clone(&self) -> Self {
        BaseN { base: self.base, vec: self.vec.clone() }
    }

    fn clone_from(&mut self, source: &Self) {
        self.vec.clone_from(&source.vec);
        self.base = source.base;
    }
}

impl Add for BaseN {
    type Output = Result<BaseN, &'static str>;

    // Option<> because might overflow, bases incorrect, etc.
    // I suppose you could add a base16 to base10 with an internal convert
    fn add(self, rhs: BaseN) -> Result<BaseN, &'static str> {

        let add_basen = if rhs.base==self.base {
            rhs
        } else {
            rhs.to_base(self.base).unwrap()
            // TODO: Throw error?  Don't actually know
            // what base user wanted to end with
        };

        // TODO: Use zip() w/ carry array instead?
        let max = cmp::max(self.vec.len(), add_basen.vec.len());
        let mut new_vec: Vec<u8> = Vec::with_capacity(max);

        let mut carry: u8 = 0;

        for i in 0..max {
            match (self.vec.get(i), add_basen.vec.get(i)) {
                (Some(x), Some(y)) => {
                    let sum: u8 = *x + *y + carry;
                    carry = sum / (add_basen.base as u8);
                    new_vec.push(sum % (add_basen.base as u8));
                },
                (Some(x), None) => {
                    // no carry, but need to resize
                    let sum: u8 = *x + carry;
                    carry = sum / (add_basen.base as u8);
                    new_vec.push(sum % (add_basen.base as u8));
                },
                (_, _) => break // no ops needed

            }
        }

        let new_basen: BaseN = BaseN { base: add_basen.base, vec: new_vec };

        Ok(new_basen)
    }
}

impl Sub for BaseN {
    type Output = Result<BaseN, &'static str>;

    // Option<> because might overflow, bases incorrect, etc.
    // I suppose you could add a base16 to base10 with an internal convert
    fn sub(self, rhs: BaseN) -> Result<BaseN, &'static str> {

        let sub_basen = if rhs.base==self.base {
            rhs
        } else {
            rhs.to_base(self.base).unwrap()
            // TODO: Throw error?  Don't actually know
            // what base user wanted to end with
        };

        let max = cmp::max(self.vec.len(), sub_basen.vec.len());
        let mut new_vec: Vec<u8> = Vec::with_capacity(max);

        let mut borrow: u8 = 0;

        for i in 0..max {
            match (self.vec.get(i), sub_basen.vec.get(i)) {
                (Some(x), Some(y)) => {
                    let mut diff: i8 = (*x as i8) - (*y as i8) - (borrow as i8);
                    borrow = if diff < 0 {
                        diff += self.base as i8; 1 } else { 0 };
                    new_vec.push(diff as u8);
                },
                (Some(x), None) => {
                    let mut diff: i8 = (*x as i8) - (borrow as i8);
                    borrow = if diff < 0 {
                        diff += self.base as i8; 1 } else { 0 };
                    new_vec.push(diff as u8);
                },
                (_, _) => break // no ops needed

            }
        }

        let new_basen: BaseN = BaseN { base: sub_basen.base, vec: new_vec };

        Ok(new_basen)
    }
}

<|endoftext|>


<commit_before>// Copyright 2015 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(str_char)]

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

use std::fs;
use std::fs::{File};
use std::io::{Read, Error, ErrorKind};
use std::path::{PathBuf};

const PROC_PATH: &'static str = "/proc";

struct CmdInfo {
    name: &'static str,
    pss: f32,
    shared: f32,
    heap: f32,
    swap: f32,
}

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

#[inline(never)]
fn first_char(name: std::ffi::OsString) -> char {
    name.to_str().unwrap().char_at(0)
}

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

#[inline(never)]
fn get_pids() -> Result<Vec<i32>, String> {
    let dir = fs::read_dir(PROC_PATH);
    if let Err(err)= dir {
	return Err(format!("read_dir({}): {}", PROC_PATH, err));
    }

    // TODO: look at filter_map
    let pids: Vec<i32> = dir.unwrap()
	.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(|md| is_dir(md)).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<Vec<u8>, String> {
    const BUFSIZ: usize = 1024;
    let mut buf = Vec::with_capacity(BUFSIZ);
    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 = match File::open(path) {
	Ok(f) => f,
	Err(_) => return Err("open failed".to_string())
    };

    if f.read_to_end(&mut buf).is_ok() {
	return Ok(buf)
    }

    Err("proc_cmdline failed".to_string())
}

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

    if let Ok(full_path) = fs::read_link(path) {
	if let Ok(cmdline) = proc_cmdline(pid) {

	}
    }

    Err("proc_name failed".to_string())
}

fn cmdinfo_new(pid: i32) -> CmdInfo {

    let proc_name = proc_name(pid);

    return CmdInfo{
	name: "wah",
	pss: 0.0,
	shared: 0.0,
	heap: 0.0,
	swap: 0.0,
    }
}

fn cmdinfos_for(pids: Vec<i32>) -> Result<Vec<CmdInfo>, String> {

    Err("not implemented".to_string())
}

fn main() {

    // command line flag parsing

    // check euid
    // unsafe {
    // 	let uid = geteuid();
    // 	if uid != 0 {
    // 	    println!("we aren't root");
    // 	}
    // }

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

    let pids = pids_r.unwrap();
    // get details of all pids (possibly in parallel)
    let infos = cmdinfos_for(pids);

    // sort pid details

    // find total

    // print_results

    println!("Hello, world!");
}
<commit_msg>rust: use option<commit_after>// Copyright 2015 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(str_char)]

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

use std::fs;
use std::fs::{File};
use std::io::{Read, Error, ErrorKind};
use std::path::{PathBuf};

const PROC_PATH: &'static str = "/proc";

struct CmdInfo {
    name: String,
    pss: f32,
    shared: f32,
    heap: f32,
    swap: f32,
}

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

#[inline(never)]
fn first_char(name: std::ffi::OsString) -> char {
    name.to_str().unwrap().char_at(0)
}

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

#[inline(never)]
fn get_pids() -> Result<Vec<i32>, String> {
    let dir = fs::read_dir(PROC_PATH);
    if let Err(err)= dir {
	return Err(format!("read_dir({}): {}", PROC_PATH, err));
    }

    // TODO: look at filter_map
    let pids: Vec<i32> = dir.unwrap()
	.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(|md| is_dir(md)).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<Vec<u8>, String> {
    const BUFSIZ: usize = 1024;
    let mut buf = Vec::with_capacity(BUFSIZ);
    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 = match File::open(path) {
	Ok(f) => f,
	Err(_) => return Err("open failed".to_string())
    };

    if f.read_to_end(&mut buf).is_ok() {
	return Ok(buf)
    }

    Err("proc_cmdline failed".to_string())
}

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

    if let Ok(full_path) = fs::read_link(path) {
	if let Ok(cmdline) = proc_cmdline(pid) {

	}
    }

    Err("proc_name failed".to_string())
}

fn cmdinfo_new(pid: i32) -> Option<CmdInfo> {

    if let Ok(proc_name) = proc_name(pid) {
	return Some(CmdInfo{
	    name: proc_name.to_string_lossy(),
	    pss: 0.0,
	    shared: 0.0,
	    heap: 0.0,
	    swap: 0.0,
	})
    }
    None
}

fn cmdinfos_for(pids: Vec<i32>) -> Result<Vec<CmdInfo>, String> {

    Err("not implemented".to_string())
}

fn main() {

    // command line flag parsing

    // check euid
    // unsafe {
    // 	let uid = geteuid();
    // 	if uid != 0 {
    // 	    println!("we aren't root");
    // 	}
    // }

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

    let pids = pids_r.unwrap();
    // get details of all pids (possibly in parallel)
    let infos = cmdinfos_for(pids);

    // sort pid details

    // find total

    // print_results

    println!("Hello, world!");
}
<|endoftext|>


<commit_before>use crate::common::util::*;
use std::io::Read;

#[test]
fn test_output_simple() {
    new_ucmd!()
        .args(&["alpha.txt"])
        .succeeds()
        .stdout_only("abcde\nfghij\nklmno\npqrst\nuvwxyz\n");
}

#[test]
fn test_no_options() {
    for fixture in &["empty.txt", "alpha.txt", "nonewline.txt"] {
        // Give fixture through command line file argument
        new_ucmd!()
            .args(&[fixture])
            .succeeds()
            .stdout_is_fixture(fixture);
        // Give fixture through stdin
        new_ucmd!()
            .pipe_in_fixture(fixture)
            .succeeds()
            .stdout_is_fixture(fixture);
    }
}

#[test]
#[cfg(unix)]
fn test_no_options_big_input() {
    for &n in &[
        0,
        1,
        42,
        16 * 1024 - 7,
        16 * 1024 - 1,
        16 * 1024,
        16 * 1024 + 1,
        16 * 1024 + 3,
        32 * 1024,
        64 * 1024,
        80 * 1024,
        96 * 1024,
        112 * 1024,
        128 * 1024,
    ] {
        let data = vec_of_size(n);
        let data2 = data.clone();
        assert_eq!(data.len(), data2.len());
        new_ucmd!().pipe_in(data).succeeds().stdout_is_bytes(&data2);
    }
}

#[test]
#[cfg(unix)]
fn test_fifo_symlink() {
    use std::fs::OpenOptions;
    use std::io::Write;
    use std::thread;

    let s = TestScenario::new(util_name!());
    s.fixtures.mkdir("dir");
    s.fixtures.mkfifo("dir/pipe");
    assert!(s.fixtures.is_fifo("dir/pipe"));

    // Make cat read the pipe through a symlink
    s.fixtures.symlink_file("dir/pipe", "sympipe");
    let proc = s.ucmd().args(&["sympipe"]).run_no_wait();

    let data = vec_of_size(128 * 1024);
    let data2 = data.clone();

    let pipe_path = s.fixtures.plus("dir/pipe");
    let thread = thread::spawn(move || {
        let mut pipe = OpenOptions::new()
            .write(true)
            .create(false)
            .open(pipe_path)
            .unwrap();
        pipe.write_all(&data).unwrap();
    });

    let output = proc.wait_with_output().unwrap();
    assert_eq!(&output.stdout, &data2);
    thread.join().unwrap();
}

#[test]
fn test_directory() {
    let s = TestScenario::new(util_name!());
    s.fixtures.mkdir("test_directory");
    s.ucmd()
        .args(&["test_directory"])
        .fails()
        .stderr_is("cat: test_directory: Is a directory");
}

#[test]
fn test_directory_and_file() {
    let s = TestScenario::new(util_name!());
    s.fixtures.mkdir("test_directory2");
    for fixture in &["empty.txt", "alpha.txt", "nonewline.txt"] {
        s.ucmd()
            .args(&["test_directory2", fixture])
            .fails()
            .stderr_is("cat: test_directory2: Is a directory")
            .stdout_is_fixture(fixture);
    }
}

#[test]
fn test_three_directories_and_file_and_stdin() {
    let s = TestScenario::new(util_name!());
    s.fixtures.mkdir("test_directory3");
    s.fixtures.mkdir("test_directory3/test_directory4");
    s.fixtures.mkdir("test_directory3/test_directory5");
    s.ucmd()
        .args(&[
            "test_directory3/test_directory4",
            "alpha.txt",
            "-",
            "filewhichdoesnotexist.txt",
            "nonewline.txt",
            "test_directory3/test_directory5",
            "test_directory3/../test_directory3/test_directory5",
            "test_directory3",
        ])
        .pipe_in("stdout bytes")
        .fails()
        .stderr_is_fixture("three_directories_and_file_and_stdin.stderr.expected")
        .stdout_is(
            "abcde\nfghij\nklmno\npqrst\nuvwxyz\nstdout bytestext without a trailing newline",
        );
}

#[test]
fn test_output_multi_files_print_all_chars() {
    new_ucmd!()
        .args(&["alpha.txt", "256.txt", "-A", "-n"])
        .succeeds()
        .stdout_only(
            "     1\tabcde$\n     2\tfghij$\n     3\tklmno$\n     4\tpqrst$\n     \
             5\tuvwxyz$\n     6\t^@^A^B^C^D^E^F^G^H^I$\n     \
             7\t^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\\^]^^^_ \
             !\"#$%&\'()*+,-./0123456789:;\
             <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?M-^@M-^AM-^\
             BM-^CM-^DM-^EM-^FM-^GM-^HM-^IM-^JM-^KM-^LM-^MM-^NM-^OM-^PM-^QM-^RM-^SM-^TM-^UM-^V\
             M-^WM-^XM-^YM-^ZM-^[M-^\\M-^]M-^^M-^_M- \
             M-!M-\"M-#M-$M-%M-&M-\'M-(M-)M-*M-+M-,M--M-.M-/M-0M-1M-2M-3M-4M-5M-6M-7M-8M-9M-:\
             M-;M-<M-=M->M-?M-@M-AM-BM-CM-DM-EM-FM-GM-HM-IM-JM-KM-LM-MM-NM-OM-PM-QM-RM-SM-TM-U\
             M-VM-WM-XM-YM-ZM-[M-\\M-]M-^M-_M-`M-aM-bM-cM-dM-eM-fM-gM-hM-iM-jM-kM-lM-mM-nM-oM-\
             pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?",
        );
}

#[test]
fn test_numbered_lines_no_trailing_newline() {
    new_ucmd!()
        .args(&["nonewline.txt", "alpha.txt", "-n"])
        .succeeds()
        .stdout_only(
            "     1\ttext without a trailing newlineabcde\n     2\tfghij\n     \
             3\tklmno\n     4\tpqrst\n     5\tuvwxyz\n",
        );
}

#[test]
fn test_stdin_show_nonprinting() {
    for same_param in vec!["-v", "--show-nonprinting"] {
        new_ucmd!()
            .args(&[same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("\t^@\n");
    }
}

#[test]
fn test_stdin_show_tabs() {
    for same_param in vec!["-T", "--show-tabs"] {
        new_ucmd!()
            .args(&[same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("^I\0\n");
    }
}

#[test]
fn test_stdin_show_ends() {
    for same_param in vec!["-E", "--show-ends"] {
        new_ucmd!()
            .args(&[same_param, "-"])
            .pipe_in("\t\0\n\t")
            .succeeds()
            .stdout_only("\t\0$\n\t");
    }
}

#[test]
fn test_stdin_show_all() {
    for same_param in vec!["-A", "--show-all"] {
        new_ucmd!()
            .args(&[same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("^I^@$\n");
    }
}

#[test]
fn test_stdin_nonprinting_and_endofline() {
    new_ucmd!()
        .args(&["-e"])
        .pipe_in("\t\0\n")
        .succeeds()
        .stdout_only("\t^@$\n");
}

#[test]
fn test_stdin_nonprinting_and_tabs() {
    new_ucmd!()
        .args(&["-t"])
        .pipe_in("\t\0\n")
        .succeeds()
        .stdout_only("^I^@\n");
}

#[test]
fn test_stdin_squeeze_blank() {
    for same_param in vec!["-s", "--squeeze-blank"] {
        new_ucmd!()
            .arg(same_param)
            .pipe_in("\n\na\n\n\n\n\nb\n\n\n")
            .succeeds()
            .stdout_only("\na\n\nb\n\n");
    }
}

#[test]
fn test_stdin_number_non_blank() {
    for same_param in vec!["-b", "--number-nonblank"] {
        new_ucmd!()
            .arg(same_param)
            .arg("-")
            .pipe_in("\na\nb\n\n\nc")
            .succeeds()
            .stdout_only("\n     1\ta\n     2\tb\n\n\n     3\tc");
    }
}

#[test]
fn test_non_blank_overrides_number() {
    for same_param in vec!["-b", "--number-nonblank"] {
        new_ucmd!()
            .args(&[same_param, "-"])
            .pipe_in("\na\nb\n\n\nc")
            .succeeds()
            .stdout_only("\n     1\ta\n     2\tb\n\n\n     3\tc");
    }
}

#[test]
fn test_squeeze_blank_before_numbering() {
    for same_param in vec!["-s", "--squeeze-blank"] {
        new_ucmd!()
            .args(&[same_param, "-n", "-"])
            .pipe_in("a\n\n\nb")
            .succeeds()
            .stdout_only("     1\ta\n     2\t\n     3\tb");
    }
}

/// This tests reading from Unix character devices
#[test]
#[cfg(unix)]
fn test_dev_random() {
    let mut buf = [0; 2048];
    let mut proc = new_ucmd!().args(&["/dev/random"]).run_no_wait();
    let mut proc_stdout = proc.stdout.take().unwrap();
    proc_stdout.read_exact(&mut buf).unwrap();

    let num_zeroes = buf.iter().fold(0, |mut acc, &n| {
        if n == 0 {
            acc += 1;
        }
        acc
    });
    // The probability of more than 512 zero bytes is essentially zero if the
    // output is truly random.
    assert!(num_zeroes < 512);
    proc.kill().unwrap();
}

/// Reading from /dev/full should return an infinite amount of zero bytes.
/// Wikipedia says there is support on Linux, FreeBSD, and NetBSD.
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_dev_full() {
    let mut buf = [0; 2048];
    let mut proc = new_ucmd!().args(&["/dev/full"]).run_no_wait();
    let mut proc_stdout = proc.stdout.take().unwrap();
    let expected = [0; 2048];
    proc_stdout.read_exact(&mut buf).unwrap();
    assert_eq!(&buf[..], &expected[..]);
    proc.kill().unwrap();
}

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_dev_full_show_all() {
    let mut buf = [0; 2048];
    let mut proc = new_ucmd!().args(&["-A", "/dev/full"]).run_no_wait();
    let mut proc_stdout = proc.stdout.take().unwrap();
    proc_stdout.read_exact(&mut buf).unwrap();

    let expected: Vec<u8> = (0..buf.len())
        .map(|n| if n & 1 == 0 { b'^' } else { b'@' })
        .collect();

    assert_eq!(&buf[..], &expected[..]);
    proc.kill().unwrap();
}

#[test]
#[cfg(unix)]
fn test_domain_socket() {
    use std::io::prelude::*;
    use std::thread;
    use tempdir::TempDir;
    use unix_socket::UnixListener;

    let dir = TempDir::new("unix_socket").expect("failed to create dir");
    let socket_path = dir.path().join("sock");
    let listener = UnixListener::bind(&socket_path).expect("failed to create socket");

    let thread = thread::spawn(move || {
        let mut stream = listener.accept().expect("failed to accept connection").0;
        stream
            .write_all(b"a\tb")
            .expect("failed to write test data");
    });

    new_ucmd!()
        .args(&[socket_path])
        .succeeds()
        .stdout_only("a\tb");

    thread.join().unwrap();
}
<commit_msg>Also disable on test_three_directories_and_file_and_stdin<commit_after>use crate::common::util::*;
use std::io::Read;

#[test]
fn test_output_simple() {
    new_ucmd!()
        .args(&["alpha.txt"])
        .succeeds()
        .stdout_only("abcde\nfghij\nklmno\npqrst\nuvwxyz\n");
}

#[test]
fn test_no_options() {
    for fixture in &["empty.txt", "alpha.txt", "nonewline.txt"] {
        // Give fixture through command line file argument
        new_ucmd!()
            .args(&[fixture])
            .succeeds()
            .stdout_is_fixture(fixture);
        // Give fixture through stdin
        new_ucmd!()
            .pipe_in_fixture(fixture)
            .succeeds()
            .stdout_is_fixture(fixture);
    }
}

#[test]
#[cfg(unix)]
fn test_no_options_big_input() {
    for &n in &[
        0,
        1,
        42,
        16 * 1024 - 7,
        16 * 1024 - 1,
        16 * 1024,
        16 * 1024 + 1,
        16 * 1024 + 3,
        32 * 1024,
        64 * 1024,
        80 * 1024,
        96 * 1024,
        112 * 1024,
        128 * 1024,
    ] {
        let data = vec_of_size(n);
        let data2 = data.clone();
        assert_eq!(data.len(), data2.len());
        new_ucmd!().pipe_in(data).succeeds().stdout_is_bytes(&data2);
    }
}

#[test]
#[cfg(unix)]
fn test_fifo_symlink() {
    use std::fs::OpenOptions;
    use std::io::Write;
    use std::thread;

    let s = TestScenario::new(util_name!());
    s.fixtures.mkdir("dir");
    s.fixtures.mkfifo("dir/pipe");
    assert!(s.fixtures.is_fifo("dir/pipe"));

    // Make cat read the pipe through a symlink
    s.fixtures.symlink_file("dir/pipe", "sympipe");
    let proc = s.ucmd().args(&["sympipe"]).run_no_wait();

    let data = vec_of_size(128 * 1024);
    let data2 = data.clone();

    let pipe_path = s.fixtures.plus("dir/pipe");
    let thread = thread::spawn(move || {
        let mut pipe = OpenOptions::new()
            .write(true)
            .create(false)
            .open(pipe_path)
            .unwrap();
        pipe.write_all(&data).unwrap();
    });

    let output = proc.wait_with_output().unwrap();
    assert_eq!(&output.stdout, &data2);
    thread.join().unwrap();
}

#[test]
fn test_directory() {
    let s = TestScenario::new(util_name!());
    s.fixtures.mkdir("test_directory");
    s.ucmd()
        .args(&["test_directory"])
        .fails()
        .stderr_is("cat: test_directory: Is a directory");
}

#[test]
fn test_directory_and_file() {
    let s = TestScenario::new(util_name!());
    s.fixtures.mkdir("test_directory2");
    for fixture in &["empty.txt", "alpha.txt", "nonewline.txt"] {
        s.ucmd()
            .args(&["test_directory2", fixture])
            .fails()
            .stderr_is("cat: test_directory2: Is a directory")
            .stdout_is_fixture(fixture);
    }
}

#[test]
#[cfg(unix)]
fn test_three_directories_and_file_and_stdin() {
    let s = TestScenario::new(util_name!());
    s.fixtures.mkdir("test_directory3");
    s.fixtures.mkdir("test_directory3/test_directory4");
    s.fixtures.mkdir("test_directory3/test_directory5");
    s.ucmd()
        .args(&[
            "test_directory3/test_directory4",
            "alpha.txt",
            "-",
            "filewhichdoesnotexist.txt",
            "nonewline.txt",
            "test_directory3/test_directory5",
            "test_directory3/../test_directory3/test_directory5",
            "test_directory3",
        ])
        .pipe_in("stdout bytes")
        .fails()
        .stderr_is_fixture("three_directories_and_file_and_stdin.stderr.expected")
        .stdout_is(
            "abcde\nfghij\nklmno\npqrst\nuvwxyz\nstdout bytestext without a trailing newline",
        );
}

#[test]
fn test_output_multi_files_print_all_chars() {
    new_ucmd!()
        .args(&["alpha.txt", "256.txt", "-A", "-n"])
        .succeeds()
        .stdout_only(
            "     1\tabcde$\n     2\tfghij$\n     3\tklmno$\n     4\tpqrst$\n     \
             5\tuvwxyz$\n     6\t^@^A^B^C^D^E^F^G^H^I$\n     \
             7\t^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^[^\\^]^^^_ \
             !\"#$%&\'()*+,-./0123456789:;\
             <=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~^?M-^@M-^AM-^\
             BM-^CM-^DM-^EM-^FM-^GM-^HM-^IM-^JM-^KM-^LM-^MM-^NM-^OM-^PM-^QM-^RM-^SM-^TM-^UM-^V\
             M-^WM-^XM-^YM-^ZM-^[M-^\\M-^]M-^^M-^_M- \
             M-!M-\"M-#M-$M-%M-&M-\'M-(M-)M-*M-+M-,M--M-.M-/M-0M-1M-2M-3M-4M-5M-6M-7M-8M-9M-:\
             M-;M-<M-=M->M-?M-@M-AM-BM-CM-DM-EM-FM-GM-HM-IM-JM-KM-LM-MM-NM-OM-PM-QM-RM-SM-TM-U\
             M-VM-WM-XM-YM-ZM-[M-\\M-]M-^M-_M-`M-aM-bM-cM-dM-eM-fM-gM-hM-iM-jM-kM-lM-mM-nM-oM-\
             pM-qM-rM-sM-tM-uM-vM-wM-xM-yM-zM-{M-|M-}M-~M-^?",
        );
}

#[test]
fn test_numbered_lines_no_trailing_newline() {
    new_ucmd!()
        .args(&["nonewline.txt", "alpha.txt", "-n"])
        .succeeds()
        .stdout_only(
            "     1\ttext without a trailing newlineabcde\n     2\tfghij\n     \
             3\tklmno\n     4\tpqrst\n     5\tuvwxyz\n",
        );
}

#[test]
fn test_stdin_show_nonprinting() {
    for same_param in vec!["-v", "--show-nonprinting"] {
        new_ucmd!()
            .args(&[same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("\t^@\n");
    }
}

#[test]
fn test_stdin_show_tabs() {
    for same_param in vec!["-T", "--show-tabs"] {
        new_ucmd!()
            .args(&[same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("^I\0\n");
    }
}

#[test]
fn test_stdin_show_ends() {
    for same_param in vec!["-E", "--show-ends"] {
        new_ucmd!()
            .args(&[same_param, "-"])
            .pipe_in("\t\0\n\t")
            .succeeds()
            .stdout_only("\t\0$\n\t");
    }
}

#[test]
fn test_stdin_show_all() {
    for same_param in vec!["-A", "--show-all"] {
        new_ucmd!()
            .args(&[same_param])
            .pipe_in("\t\0\n")
            .succeeds()
            .stdout_only("^I^@$\n");
    }
}

#[test]
fn test_stdin_nonprinting_and_endofline() {
    new_ucmd!()
        .args(&["-e"])
        .pipe_in("\t\0\n")
        .succeeds()
        .stdout_only("\t^@$\n");
}

#[test]
fn test_stdin_nonprinting_and_tabs() {
    new_ucmd!()
        .args(&["-t"])
        .pipe_in("\t\0\n")
        .succeeds()
        .stdout_only("^I^@\n");
}

#[test]
fn test_stdin_squeeze_blank() {
    for same_param in vec!["-s", "--squeeze-blank"] {
        new_ucmd!()
            .arg(same_param)
            .pipe_in("\n\na\n\n\n\n\nb\n\n\n")
            .succeeds()
            .stdout_only("\na\n\nb\n\n");
    }
}

#[test]
fn test_stdin_number_non_blank() {
    for same_param in vec!["-b", "--number-nonblank"] {
        new_ucmd!()
            .arg(same_param)
            .arg("-")
            .pipe_in("\na\nb\n\n\nc")
            .succeeds()
            .stdout_only("\n     1\ta\n     2\tb\n\n\n     3\tc");
    }
}

#[test]
fn test_non_blank_overrides_number() {
    for same_param in vec!["-b", "--number-nonblank"] {
        new_ucmd!()
            .args(&[same_param, "-"])
            .pipe_in("\na\nb\n\n\nc")
            .succeeds()
            .stdout_only("\n     1\ta\n     2\tb\n\n\n     3\tc");
    }
}

#[test]
fn test_squeeze_blank_before_numbering() {
    for same_param in vec!["-s", "--squeeze-blank"] {
        new_ucmd!()
            .args(&[same_param, "-n", "-"])
            .pipe_in("a\n\n\nb")
            .succeeds()
            .stdout_only("     1\ta\n     2\t\n     3\tb");
    }
}

/// This tests reading from Unix character devices
#[test]
#[cfg(unix)]
fn test_dev_random() {
    let mut buf = [0; 2048];
    let mut proc = new_ucmd!().args(&["/dev/random"]).run_no_wait();
    let mut proc_stdout = proc.stdout.take().unwrap();
    proc_stdout.read_exact(&mut buf).unwrap();

    let num_zeroes = buf.iter().fold(0, |mut acc, &n| {
        if n == 0 {
            acc += 1;
        }
        acc
    });
    // The probability of more than 512 zero bytes is essentially zero if the
    // output is truly random.
    assert!(num_zeroes < 512);
    proc.kill().unwrap();
}

/// Reading from /dev/full should return an infinite amount of zero bytes.
/// Wikipedia says there is support on Linux, FreeBSD, and NetBSD.
#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_dev_full() {
    let mut buf = [0; 2048];
    let mut proc = new_ucmd!().args(&["/dev/full"]).run_no_wait();
    let mut proc_stdout = proc.stdout.take().unwrap();
    let expected = [0; 2048];
    proc_stdout.read_exact(&mut buf).unwrap();
    assert_eq!(&buf[..], &expected[..]);
    proc.kill().unwrap();
}

#[test]
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "netbsd"))]
fn test_dev_full_show_all() {
    let mut buf = [0; 2048];
    let mut proc = new_ucmd!().args(&["-A", "/dev/full"]).run_no_wait();
    let mut proc_stdout = proc.stdout.take().unwrap();
    proc_stdout.read_exact(&mut buf).unwrap();

    let expected: Vec<u8> = (0..buf.len())
        .map(|n| if n & 1 == 0 { b'^' } else { b'@' })
        .collect();

    assert_eq!(&buf[..], &expected[..]);
    proc.kill().unwrap();
}

#[test]
#[cfg(unix)]
fn test_domain_socket() {
    use std::io::prelude::*;
    use std::thread;
    use tempdir::TempDir;
    use unix_socket::UnixListener;

    let dir = TempDir::new("unix_socket").expect("failed to create dir");
    let socket_path = dir.path().join("sock");
    let listener = UnixListener::bind(&socket_path).expect("failed to create socket");

    let thread = thread::spawn(move || {
        let mut stream = listener.accept().expect("failed to accept connection").0;
        stream
            .write_all(b"a\tb")
            .expect("failed to write test data");
    });

    new_ucmd!()
        .args(&[socket_path])
        .succeeds()
        .stdout_only("a\tb");

    thread.join().unwrap();
}
<|endoftext|>