proclist 0.9.2

Cross-platform library to retrieve OS processes information.
Documentation
use integrations::osx::ffi::*;
use libc::*;
use std;
use types::*;

pub struct ProcessInfoIterator {
    pids: Vec<i32>,
    index: isize,
}

impl ProcessInfoIterator {
    #[inline]
    pub fn new() -> ProcessInfoIterator {
        ProcessInfoIterator {
            pids: Vec::new(),
            index: -1,
        }
    }
}

impl std::iter::Iterator for ProcessInfoIterator {
    type Item = Result<ProcessInfo, Error>;
    #[inline]
    fn next(&mut self) -> Option<Result<ProcessInfo, Error>> {
        unsafe {
            self.index += 1;
            if self.index == 0 {
                self.pids = match get_pids() {
                    Result::Ok(pids) => pids,
                    Result::Err(err) => return Option::Some(Result::Err(err)),
                };
            }
            if self.index as usize >= self.pids.len() {
                return Option::None;
            }
            let pid = self.pids[self.index as usize];
            let name = match get_name(pid) {
                Result::Ok(name) => name,
                Result::Err(err) => return Option::Some(Result::Err(err)),
            };
            let info = match get_info(pid) {
                Result::Ok(info) => info,
                Result::Err(err) => return Option::Some(Result::Err(err)),
            };
            Option::Some(Result::Ok(ProcessInfo {
                name,
                pid: info.pbi_pid,
                parent_pid: info.pbi_ppid,
            }))
        }
    }
}

#[inline]
unsafe fn get_pids() -> Result<Vec<i32>, Error> {
    let buf_size = proc_listpids(PROC_ALL_PIDS, 0, std::ptr::null_mut(), 0);
    if buf_size <= 0 {
        return Result::Err(Error::foreign_with_errno("proc_listpids"));
    }
    let pids_count = buf_size as usize / 4;
    let mut pids = Vec::<i32>::with_capacity(pids_count);
    let buf_ptr = pids.as_mut_ptr() as *mut c_void;
    if proc_listpids(PROC_ALL_PIDS, 0, buf_ptr, buf_size as u32) <= 0 {
        return Result::Err(Error::foreign_with_errno("proc_listpids"));
    }
    pids.set_len(pids_count);
    Result::Ok(pids)
}

#[inline]
unsafe fn get_name(pid: i32) -> Result<String, Error> {
    let mut buf = Vec::<u8>::with_capacity(PROC_PIDPATHINFO_MAXSIZE);
    let buf_ptr = buf.as_mut_ptr() as *mut c_void;
    let buf_size = buf.capacity() as u32;
    let name_len = proc_name(pid, buf_ptr, buf_size);
    if name_len <= 0 {
        return Result::Err(Error::foreign_with_errno("proc_name"));
    }
    buf.set_len(name_len as usize);
    match String::from_utf8(buf) {
        Result::Ok(name) => Result::Ok(name),
        Result::Err(err) => {
            let description = String::from("Can't parse process name");
            Result::Err(Error::internal_with_cause(description, &err))
        }
    }
}

#[inline]
unsafe fn get_info(pid: i32) -> Result<proc_bsdinfo, Error> {
    let mut info = std::mem::zeroed::<proc_bsdinfo>();
    let buf_ptr = &mut info as *mut _ as *mut c_void;
    let buf_size = std::mem::size_of::<proc_bsdinfo>() as i32;
    if proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, buf_ptr, buf_size) <= 0 {
        return Result::Err(Error::foreign_with_errno("proc_pidinfo"));
    }
    Result::Ok(info)
}