<commit_before><commit_msg>Fix code style + remove mut & use in Admin service<commit_after><|endoftext|>


<commit_before>macro_rules! skip_bytes (
  ($input: expr, $length: expr, $offset: expr) => (
    {
      match take!($input, $length) {
        $crate::nom::IResult::Done(i, bytes)   => {
          let head        = bytes[0] << $offset;
          let tail        = &bytes[1..];
          let is_all_zero = tail.iter().all(|byte| *byte == 0);

          if head == 0 && is_all_zero {
            $crate::nom::IResult::Done(i, bytes)
          } else {
            $crate::nom::IResult::Error($crate::nom::Err::Position(
              $crate::nom::ErrorCode::Digit as u32, $input))
          }
        }
        $crate::nom::IResult::Error(error)     =>
          $crate::nom::IResult::Error(error),
        $crate::nom::IResult::Incomplete(need) =>
          $crate::nom::IResult::Incomplete(need),
      }
    }
  );
);

macro_rules! count_slice (
  ($input: expr, $submac: ident!( $($args:tt)* ), $result: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;

      for result in $result {
        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            *result = o;

            input   = i;
            count  += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorCode::Count as u32, $input.0))
      } else if count == $result.len() {
        $crate::nom::IResult::Done(input, ())
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_slice!($i, call!($f), $count);
  );
);

macro_rules! count_bits (
  ($input: expr, $submac: ident!( $($args:tt)* ), $count: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;
      let mut result   = Vec::with_capacity($count);

      loop {
        if count == $count {
          break;
        }

        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            result.push(o);

            input  = i;
            count += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorCode::Count as u32, $input.0))
      } else if count == $count {
        $crate::nom::IResult::Done(input, result)
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_bits!($i, call!($f), $count);
  );
);
<commit_msg>Add macro for correctly parsing small signed ints<commit_after>macro_rules! skip_bytes (
  ($input: expr, $length: expr, $offset: expr) => (
    {
      match take!($input, $length) {
        $crate::nom::IResult::Done(i, bytes)   => {
          let head        = bytes[0] << $offset;
          let tail        = &bytes[1..];
          let is_all_zero = tail.iter().all(|byte| *byte == 0);

          if head == 0 && is_all_zero {
            $crate::nom::IResult::Done(i, bytes)
          } else {
            $crate::nom::IResult::Error($crate::nom::Err::Position(
              $crate::nom::ErrorCode::Digit as u32, $input))
          }
        }
        $crate::nom::IResult::Error(error)     =>
          $crate::nom::IResult::Error(error),
        $crate::nom::IResult::Incomplete(need) =>
          $crate::nom::IResult::Incomplete(need),
      }
    }
  );
);

macro_rules! count_slice (
  ($input: expr, $submac: ident!( $($args:tt)* ), $result: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;

      for result in $result {
        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            *result = o;

            input   = i;
            count  += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorCode::Count as u32, $input.0))
      } else if count == $result.len() {
        $crate::nom::IResult::Done(input, ())
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_slice!($i, call!($f), $count);
  );
);

macro_rules! count_bits (
  ($input: expr, $submac: ident!( $($args:tt)* ), $count: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;
      let mut result   = Vec::with_capacity($count);

      loop {
        if count == $count {
          break;
        }

        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            result.push(o);

            input  = i;
            count += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorCode::Count as u32, $input.0))
      } else if count == $count {
        $crate::nom::IResult::Done(input, result)
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_bits!($i, call!($f), $count);
  );
);

macro_rules! take_signed_bits (
  ($input: expr, $count: expr) => (
    map!($input, take_bits!(u32, $count), |value| {
      if $count >= 32 || value < (1 << ($count - 1)) {
        value as i32
      } else {
        (value as i32).wrapping_sub(1 << $count)
      }
    });
  );
);
<|endoftext|>


<commit_before>/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Maciej Dziardziel <fiedzia@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code.
 */

extern crate libc;

use libc::{c_int, pid_t};
use std::fmt;
use std::io;
use std::process::Child;
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use std::time::{Duration, Instant};

// This is basically sys::unix::process::ExitStatus
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum ExitStatus {
    Code(i32),
    Signal(i32),
}

impl ExitStatus {
    fn from_status(status: c_int) -> ExitStatus {
        if status & 0x7F != 0 { // WIFSIGNALED(status)
            ExitStatus::Signal(status & 0x7F)
        } else {
            ExitStatus::Code(status & 0xFF00 >> 8)
        }
    }

    pub fn success(&self) -> bool {
        match *self {
            ExitStatus::Code(code) => code == 0,
            _ => false,
        }
    }

    pub fn code(&self) -> Option<i32> {
        match *self {
            ExitStatus::Code(code) => Some(code),
            _ => None,
        }
    }

    pub fn signal(&self) -> Option<i32> {
        match *self {
            ExitStatus::Signal(code) => Some(code),
            _ => None,
        }
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ExitStatus::Code(code) => write!(f, "exit code: {}", code),
            ExitStatus::Signal(code) => write!(f, "exit code: {}", code),
        }
    }
}

/// Missing methods for Child objects
pub trait ChildExt {
    /// Send a signal to a Child process.
    fn send_signal(&mut self, signal: usize) -> io::Result<()>;

    /// Wait for a process to finish or return after the specified duration.
    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>>;
}

impl ChildExt for Child {
    fn send_signal(&mut self, signal: usize) -> io::Result<()> {
        if unsafe { libc::kill(self.id() as pid_t,
                               signal as i32) } != 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }

    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>> {
        // The result will be written to that Option, protected by a Mutex
        // Then the Condvar will be signaled
        let state = Arc::new((
            Mutex::new(Option::None::<io::Result<ExitStatus>>),
            Condvar::new(),
        ));

        // Start the waiting thread
        let state_th = state.clone();
        let pid_th = self.id();
        thread::spawn(move || {
            let &(ref lock_th, ref cvar_th) = &*state_th;
            // Child::wait() would need a &mut to self, can't use that...
            // use waitpid() directly, with our own ExitStatus
            let mut status: c_int = 0;
            let r = unsafe { libc::waitpid(pid_th as i32, &mut status, 0) };
            // Fill the Option and notify on the Condvar
            let mut exitstatus_th = lock_th.lock().unwrap();
            if r != pid_th as c_int {
                *exitstatus_th = Some(Err(io::Error::last_os_error()));
            } else {
                let s = ExitStatus::from_status(status);
                *exitstatus_th = Some(Ok(s));
            }
            cvar_th.notify_one();
        });

        // Main thread waits
        let &(ref lock, ref cvar) = &*state;
        let mut exitstatus = lock.lock().unwrap();
        // Condvar::wait_timeout_ms() can wake too soon, in this case wait again
        let start = Instant::now();
        loop {
            if let Some(exitstatus) = exitstatus.take() {
                return exitstatus.map(Some);
            }
            if start.elapsed() >= timeout {
                return Ok(None)
            }
            let cvar_timeout = timeout - start.elapsed();
            exitstatus = cvar.wait_timeout(exitstatus, cvar_timeout).unwrap().0;
        }
    }
}
<commit_msg>uucore::process: add functions to obtain uid/gid, euid/egid<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Maciej Dziardziel <fiedzia@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE file
// that was distributed with this source code.
//

use super::libc;
use libc::{c_int, pid_t, uid_t, gid_t};
use std::fmt;
use std::io;
use std::process::Child;
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use std::time::{Duration, Instant};

pub fn geteuid() -> uid_t {
    unsafe {
        libc::geteuid()
    }
}

pub fn getegid() -> gid_t {
    unsafe {
        libc::getegid()
    }
}

pub fn getgid() -> gid_t {
    unsafe {
        libc::getgid()
    }
}

pub fn getuid() -> uid_t {
    unsafe {
        libc::getuid()
    }
}

// This is basically sys::unix::process::ExitStatus
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum ExitStatus {
    Code(i32),
    Signal(i32),
}

impl ExitStatus {
    fn from_status(status: c_int) -> ExitStatus {
        if status & 0x7F != 0 {
            // WIFSIGNALED(status)
            ExitStatus::Signal(status & 0x7F)
        } else {
            ExitStatus::Code(status & 0xFF00 >> 8)
        }
    }

    pub fn success(&self) -> bool {
        match *self {
            ExitStatus::Code(code) => code == 0,
            _ => false,
        }
    }

    pub fn code(&self) -> Option<i32> {
        match *self {
            ExitStatus::Code(code) => Some(code),
            _ => None,
        }
    }

    pub fn signal(&self) -> Option<i32> {
        match *self {
            ExitStatus::Signal(code) => Some(code),
            _ => None,
        }
    }
}

impl fmt::Display for ExitStatus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ExitStatus::Code(code) => write!(f, "exit code: {}", code),
            ExitStatus::Signal(code) => write!(f, "exit code: {}", code),
        }
    }
}

/// Missing methods for Child objects
pub trait ChildExt {
    /// Send a signal to a Child process.
    fn send_signal(&mut self, signal: usize) -> io::Result<()>;

    /// Wait for a process to finish or return after the specified duration.
    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>>;
}

impl ChildExt for Child {
    fn send_signal(&mut self, signal: usize) -> io::Result<()> {
        if unsafe { libc::kill(self.id() as pid_t, signal as i32) } != 0 {
            Err(io::Error::last_os_error())
        } else {
            Ok(())
        }
    }

    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>> {
        // The result will be written to that Option, protected by a Mutex
        // Then the Condvar will be signaled
        let state = Arc::new((Mutex::new(Option::None::<io::Result<ExitStatus>>), Condvar::new()));

        // Start the waiting thread
        let state_th = state.clone();
        let pid_th = self.id();
        thread::spawn(move || {
            let &(ref lock_th, ref cvar_th) = &*state_th;
            // Child::wait() would need a &mut to self, can't use that...
            // use waitpid() directly, with our own ExitStatus
            let mut status: c_int = 0;
            let r = unsafe { libc::waitpid(pid_th as i32, &mut status, 0) };
            // Fill the Option and notify on the Condvar
            let mut exitstatus_th = lock_th.lock().unwrap();
            if r != pid_th as c_int {
                *exitstatus_th = Some(Err(io::Error::last_os_error()));
            } else {
                let s = ExitStatus::from_status(status);
                *exitstatus_th = Some(Ok(s));
            }
            cvar_th.notify_one();
        });

        // Main thread waits
        let &(ref lock, ref cvar) = &*state;
        let mut exitstatus = lock.lock().unwrap();
        // Condvar::wait_timeout_ms() can wake too soon, in this case wait again
        let start = Instant::now();
        loop {
            if let Some(exitstatus) = exitstatus.take() {
                return exitstatus.map(Some);
            }
            if start.elapsed() >= timeout {
                return Ok(None);
            }
            let cvar_timeout = timeout - start.elapsed();
            exitstatus = cvar.wait_timeout(exitstatus, cvar_timeout).unwrap().0;
        }
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use sys::component::{self, Component};
use sys::disk::Disk;
use sys::processor::*;

use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::mem::{size_of, zeroed};

use DiskExt;
use Pid;
use ProcessExt;
use RefreshKind;
use SystemExt;

use windows::network::{self, NetworkData};
use windows::process::{compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process};
use windows::processor::CounterValue;
use windows::tools::*;

use ntapi::ntexapi::{
    NtQuerySystemInformation, SystemProcessInformation, SYSTEM_PROCESS_INFORMATION,
};
use winapi::shared::minwindef::{DWORD, FALSE};
use winapi::shared::ntdef::{PVOID, ULONG};
use winapi::shared::ntstatus::STATUS_INFO_LENGTH_MISMATCH;
use winapi::shared::winerror::ERROR_SUCCESS;
use winapi::um::minwinbase::STILL_ACTIVE;
use winapi::um::pdh::PdhEnumObjectItemsW;
use winapi::um::processthreadsapi::GetExitCodeProcess;
use winapi::um::sysinfoapi::{GlobalMemoryStatusEx, MEMORYSTATUSEX};
use winapi::um::winnt::HANDLE;

use rayon::prelude::*;

/// Struct containing system's information.
pub struct System {
    process_list: HashMap<usize, Process>,
    mem_total: u64,
    mem_free: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    temperatures: Vec<Component>,
    disks: Vec<Disk>,
    query: Option<Query>,
    network: NetworkData,
    uptime: u64,
}

// Useful for parallel iterations.
struct Wrap<T>(T);

unsafe impl<T> Send for Wrap<T> {}
unsafe impl<T> Sync for Wrap<T> {}

impl SystemExt for System {
    #[allow(non_snake_case)]
    fn new_with_specifics(refreshes: RefreshKind) -> System {
        let mut s = System {
            process_list: HashMap::with_capacity(500),
            mem_total: 0,
            mem_free: 0,
            swap_total: 0,
            swap_free: 0,
            processors: init_processors(),
            temperatures: component::get_components(),
            disks: Vec::with_capacity(2),
            query: Query::new(),
            network: network::new(),
            uptime: get_uptime(),
        };
        // TODO: in case a translation fails, it might be nice to log it somewhere...
        if let Some(ref mut query) = s.query {
            let x = unsafe { load_symbols() };
            if let Some(processor_trans) = get_translation(&"Processor".to_owned(), &x) {
                let idle_time_trans = get_translation(&"% Idle Time".to_owned(), &x);
                let proc_time_trans = get_translation(&"% Processor Time".to_owned(), &x);
                if let Some(ref proc_time_trans) = proc_time_trans {
                    add_counter(
                        format!("\\{}(_Total)\\{}", processor_trans, proc_time_trans),
                        query,
                        get_key_used(&mut s.processors[0]),
                        "tot_0".to_owned(),
                        CounterValue::Float(0.),
                    );
                }
                if let Some(ref idle_time_trans) = idle_time_trans {
                    add_counter(
                        format!("\\{}(_Total)\\{}", processor_trans, idle_time_trans),
                        query,
                        get_key_idle(&mut s.processors[0]),
                        "tot_1".to_owned(),
                        CounterValue::Float(0.),
                    );
                }
                for (pos, proc_) in s.processors.iter_mut().skip(1).enumerate() {
                    if let Some(ref proc_time_trans) = proc_time_trans {
                        add_counter(
                            format!("\\{}({})\\{}", processor_trans, pos, proc_time_trans),
                            query,
                            get_key_used(proc_),
                            format!("{}_0", pos),
                            CounterValue::Float(0.),
                        );
                    }
                    if let Some(ref idle_time_trans) = idle_time_trans {
                        add_counter(
                            format!("\\{}({})\\{}", processor_trans, pos, idle_time_trans),
                            query,
                            get_key_idle(proc_),
                            format!("{}_1", pos),
                            CounterValue::Float(0.),
                        );
                    }
                }
            }

            if let Some(network_trans) = get_translation(&"Network Interface".to_owned(), &x) {
                let network_in_trans = get_translation(&"Bytes Received/Sec".to_owned(), &x);
                let network_out_trans = get_translation(&"Bytes Sent/sec".to_owned(), &x);

                const PERF_DETAIL_WIZARD: DWORD = 400;
                const PDH_MORE_DATA: DWORD = 0x800007D2;

                let mut network_trans_utf16: Vec<u16> = network_trans.encode_utf16().collect();
                network_trans_utf16.push(0);
                let mut dwCounterListSize: DWORD = 0;
                let mut dwInstanceListSize: DWORD = 0;
                let status = unsafe {
                    PdhEnumObjectItemsW(
                        ::std::ptr::null(),
                        ::std::ptr::null(),
                        network_trans_utf16.as_ptr(),
                        ::std::ptr::null_mut(),
                        &mut dwCounterListSize,
                        ::std::ptr::null_mut(),
                        &mut dwInstanceListSize,
                        PERF_DETAIL_WIZARD,
                        0,
                    )
                };
                if status != PDH_MORE_DATA as i32 {
                    eprintln!("PdhEnumObjectItems invalid status: {:x}", status);
                } else {
                    let mut pwsCounterListBuffer: Vec<u16> =
                        Vec::with_capacity(dwCounterListSize as usize);
                    let mut pwsInstanceListBuffer: Vec<u16> =
                        Vec::with_capacity(dwInstanceListSize as usize);
                    unsafe {
                        pwsCounterListBuffer.set_len(dwCounterListSize as usize);
                        pwsInstanceListBuffer.set_len(dwInstanceListSize as usize);
                    }
                    let status = unsafe {
                        PdhEnumObjectItemsW(
                            ::std::ptr::null(),
                            ::std::ptr::null(),
                            network_trans_utf16.as_ptr(),
                            pwsCounterListBuffer.as_mut_ptr(),
                            &mut dwCounterListSize,
                            pwsInstanceListBuffer.as_mut_ptr(),
                            &mut dwInstanceListSize,
                            PERF_DETAIL_WIZARD,
                            0,
                        )
                    };
                    if status != ERROR_SUCCESS as i32 {
                        eprintln!("PdhEnumObjectItems invalid status: {:x}", status);
                    } else {
                        for (pos, x) in pwsInstanceListBuffer
                            .split(|x| *x == 0)
                            .filter(|x| x.len() > 0)
                            .enumerate()
                        {
                            let net_interface = String::from_utf16(x).expect("invalid utf16");
                            if let Some(ref network_in_trans) = network_in_trans {
                                let mut key_in = None;
                                add_counter(
                                    format!(
                                        "\\{}({})\\{}",
                                        network_trans, net_interface, network_in_trans
                                    ),
                                    query,
                                    &mut key_in,
                                    format!("net{}_in", pos),
                                    CounterValue::Integer(0),
                                );
                                if key_in.is_some() {
                                    network::get_keys_in(&mut s.network).push(key_in.unwrap());
                                }
                            }
                            if let Some(ref network_out_trans) = network_out_trans {
                                let mut key_out = None;
                                add_counter(
                                    format!(
                                        "\\{}({})\\{}",
                                        network_trans, net_interface, network_out_trans
                                    ),
                                    query,
                                    &mut key_out,
                                    format!("net{}_out", pos),
                                    CounterValue::Integer(0),
                                );
                                if key_out.is_some() {
                                    network::get_keys_out(&mut s.network).push(key_out.unwrap());
                                }
                            }
                        }
                    }
                }
            }
            query.start();
        }
        s.refresh_specifics(refreshes);
        s
    }

    fn refresh_cpu(&mut self) {
        self.uptime = get_uptime();
        if let Some(ref mut query) = self.query {
            for p in self.processors.iter_mut() {
                let mut idle_time = None;
                if let &mut Some(ref key_idle) = get_key_idle(p) {
                    idle_time = Some(query.get(&key_idle.unique_id).expect("key disappeared"));
                }
                if let Some(idle_time) = idle_time {
                    set_cpu_usage(p, 1. - idle_time);
                }
            }
        }
    }

    fn refresh_memory(&mut self) {
        self.uptime = get_uptime();
        unsafe {
            let mut mem_info: MEMORYSTATUSEX = zeroed();
            mem_info.dwLength = size_of::<MEMORYSTATUSEX>() as u32;
            GlobalMemoryStatusEx(&mut mem_info);
            self.mem_total = auto_cast!(mem_info.ullTotalPhys, u64);
            self.mem_free = auto_cast!(mem_info.ullAvailPhys, u64);
            //self.swap_total = auto_cast!(mem_info.ullTotalPageFile - mem_info.ullTotalPhys, u64);
            //self.swap_free = auto_cast!(mem_info.ullAvailPageFile, u64);
        }
    }

    fn refresh_temperatures(&mut self) {
        // does nothing for the moment...
    }

    fn refresh_network(&mut self) {
        network::refresh(&mut self.network, &self.query);
    }

    fn refresh_process(&mut self, pid: Pid) -> bool {
        if refresh_existing_process(self, pid, true) == false {
            self.process_list.remove(&pid);
            false
        } else {
            true
        }
    }

    fn refresh_processes(&mut self) {
        // Windows 10 notebook requires at least 512kb of memory to make it in one go
        let mut buffer_size: usize = 512 * 1024;

        loop {
            let mut process_information: Vec<u8> = Vec::with_capacity(buffer_size);

            let mut cb_needed = 0;
            let ntstatus = unsafe {
                process_information.set_len(buffer_size);
                NtQuerySystemInformation(
                    SystemProcessInformation,
                    process_information.as_mut_ptr() as PVOID,
                    buffer_size as ULONG,
                    &mut cb_needed,
                )
            };

            if ntstatus != STATUS_INFO_LENGTH_MISMATCH {
                if ntstatus < 0 {
                    eprintln!(
                        "Couldn't get process infos: NtQuerySystemInformation returned {}",
                        ntstatus
                    );
                }

                // Parse the data block to get process information
                let mut process_ids = Vec::with_capacity(500);
                let mut process_information_offset = 0;
                loop {
                    let p = unsafe {
                        process_information
                            .as_ptr()
                            .offset(process_information_offset)
                            as *const SYSTEM_PROCESS_INFORMATION
                    };
                    let pi = unsafe { &*p };

                    process_ids.push(Wrap(p));

                    if pi.NextEntryOffset == 0 {
                        break;
                    }

                    process_information_offset += pi.NextEntryOffset as isize;
                }
                let nb_processors = self.processors.len() as u64;
                let process_list = Wrap(UnsafeCell::new(&mut self.process_list));
                let system_time = get_system_computation_time();
                // TODO: instead of using parallel iterator only here, would be better to be able
                //       to run it over `process_information` directly!
                let processes = process_ids
                    .into_par_iter()
                    .filter_map(|pi| unsafe {
                        let pi = *pi.0;
                        let pid = pi.UniqueProcessId as usize;
                        if let Some(proc_) = (*process_list.0.get()).get_mut(&pid) {
                            proc_.memory = (pi.WorkingSetSize as u64) >> 10u64;
                            proc_.virtual_memory = (pi.VirtualSize as u64) >> 10u64;
                            compute_cpu_usage(proc_, nb_processors, system_time);
                            proc_.updated = true;
                            return None;
                        }
                        let mut real_len = 0;
                        while real_len < pi.ImageName.Length as usize
                            && *pi.ImageName.Buffer.offset(real_len as isize) != 0
                        {
                            real_len += 1;
                        }
                        let name: &[u16] =
                            ::std::slice::from_raw_parts(pi.ImageName.Buffer, real_len);
                        let mut p = Process::new_full(
                            pid,
                            if pi.InheritedFromUniqueProcessId as usize != 0 {
                                Some(pi.InheritedFromUniqueProcessId as usize)
                            } else {
                                None
                            },
                            (pi.WorkingSetSize as u64) >> 10u64,
                            (pi.VirtualSize as u64) >> 10u64,
                            String::from_utf16_lossy(name),
                        );
                        compute_cpu_usage(&mut p, nb_processors, system_time);
                        Some(p)
                    })
                    .collect::<Vec<_>>();
                self.process_list.retain(|_, v| {
                    let x = v.updated;
                    v.updated = false;
                    x
                });
                for p in processes.into_iter() {
                    self.process_list.insert(p.pid(), p);
                }

                break;
            }

            // GetNewBufferSize
            if cb_needed == 0 {
                buffer_size *= 2;
                continue;
            }
            // allocating a few more kilo bytes just in case there are some new process
            // kicked in since new call to NtQuerySystemInformation
            buffer_size = (cb_needed + (1024 * 10)) as usize;
        }
    }

    fn refresh_disks(&mut self) {
        for disk in &mut self.disks {
            disk.update();
        }
    }

    fn refresh_disk_list(&mut self) {
        self.disks = unsafe { get_disks() };
    }

    fn get_process_list(&self) -> &HashMap<Pid, Process> {
        &self.process_list
    }

    fn get_process(&self, pid: Pid) -> Option<&Process> {
        self.process_list.get(&(pid as usize))
    }

    fn get_processor_list(&self) -> &[Processor] {
        &self.processors[..]
    }

    fn get_total_memory(&self) -> u64 {
        self.mem_total >> 10
    }

    fn get_free_memory(&self) -> u64 {
        self.mem_free >> 10
    }

    fn get_used_memory(&self) -> u64 {
        (self.mem_total - self.mem_free) >> 10
    }

    fn get_total_swap(&self) -> u64 {
        self.swap_total >> 10
    }

    fn get_free_swap(&self) -> u64 {
        self.swap_free >> 10
    }

    fn get_used_swap(&self) -> u64 {
        (self.swap_total - self.swap_free) >> 10
    }

    fn get_components_list(&self) -> &[Component] {
        &self.temperatures[..]
    }

    fn get_disks(&self) -> &[Disk] {
        &self.disks[..]
    }

    fn get_network(&self) -> &NetworkData {
        &self.network
    }

    fn get_uptime(&self) -> u64 {
        self.uptime
    }
}

fn is_proc_running(handle: HANDLE) -> bool {
    let mut exit_code = 0;
    let ret = unsafe { GetExitCodeProcess(handle, &mut exit_code) };
    !(ret == FALSE || exit_code != STILL_ACTIVE)
}

fn refresh_existing_process(s: &mut System, pid: Pid, compute_cpu: bool) -> bool {
    if let Some(ref mut entry) = s.process_list.get_mut(&(pid as usize)) {
        if !is_proc_running(get_handle(entry)) {
            return false;
        }
        update_proc_info(entry);
        if compute_cpu {
            compute_cpu_usage(entry, s.processors.len() as u64, get_system_computation_time());
        }
        true
    } else {
        false
    }
}
<commit_msg>Improve process name getter<commit_after>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use sys::component::{self, Component};
use sys::disk::Disk;
use sys::processor::*;

use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::mem::{size_of, zeroed};

use DiskExt;
use Pid;
use ProcessExt;
use RefreshKind;
use SystemExt;

use windows::network::{self, NetworkData};
use windows::process::{compute_cpu_usage, get_handle, get_system_computation_time, update_proc_info, Process};
use windows::processor::CounterValue;
use windows::tools::*;

use ntapi::ntexapi::{
    NtQuerySystemInformation, SystemProcessInformation, SYSTEM_PROCESS_INFORMATION,
};
use winapi::shared::minwindef::{DWORD, FALSE};
use winapi::shared::ntdef::{PVOID, ULONG};
use winapi::shared::ntstatus::STATUS_INFO_LENGTH_MISMATCH;
use winapi::shared::winerror::ERROR_SUCCESS;
use winapi::um::minwinbase::STILL_ACTIVE;
use winapi::um::pdh::PdhEnumObjectItemsW;
use winapi::um::processthreadsapi::GetExitCodeProcess;
use winapi::um::sysinfoapi::{GlobalMemoryStatusEx, MEMORYSTATUSEX};
use winapi::um::winnt::HANDLE;

use rayon::prelude::*;

/// Struct containing system's information.
pub struct System {
    process_list: HashMap<usize, Process>,
    mem_total: u64,
    mem_free: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    temperatures: Vec<Component>,
    disks: Vec<Disk>,
    query: Option<Query>,
    network: NetworkData,
    uptime: u64,
}

// Useful for parallel iterations.
struct Wrap<T>(T);

unsafe impl<T> Send for Wrap<T> {}
unsafe impl<T> Sync for Wrap<T> {}

impl SystemExt for System {
    #[allow(non_snake_case)]
    fn new_with_specifics(refreshes: RefreshKind) -> System {
        let mut s = System {
            process_list: HashMap::with_capacity(500),
            mem_total: 0,
            mem_free: 0,
            swap_total: 0,
            swap_free: 0,
            processors: init_processors(),
            temperatures: component::get_components(),
            disks: Vec::with_capacity(2),
            query: Query::new(),
            network: network::new(),
            uptime: get_uptime(),
        };
        // TODO: in case a translation fails, it might be nice to log it somewhere...
        if let Some(ref mut query) = s.query {
            let x = unsafe { load_symbols() };
            if let Some(processor_trans) = get_translation(&"Processor".to_owned(), &x) {
                let idle_time_trans = get_translation(&"% Idle Time".to_owned(), &x);
                let proc_time_trans = get_translation(&"% Processor Time".to_owned(), &x);
                if let Some(ref proc_time_trans) = proc_time_trans {
                    add_counter(
                        format!("\\{}(_Total)\\{}", processor_trans, proc_time_trans),
                        query,
                        get_key_used(&mut s.processors[0]),
                        "tot_0".to_owned(),
                        CounterValue::Float(0.),
                    );
                }
                if let Some(ref idle_time_trans) = idle_time_trans {
                    add_counter(
                        format!("\\{}(_Total)\\{}", processor_trans, idle_time_trans),
                        query,
                        get_key_idle(&mut s.processors[0]),
                        "tot_1".to_owned(),
                        CounterValue::Float(0.),
                    );
                }
                for (pos, proc_) in s.processors.iter_mut().skip(1).enumerate() {
                    if let Some(ref proc_time_trans) = proc_time_trans {
                        add_counter(
                            format!("\\{}({})\\{}", processor_trans, pos, proc_time_trans),
                            query,
                            get_key_used(proc_),
                            format!("{}_0", pos),
                            CounterValue::Float(0.),
                        );
                    }
                    if let Some(ref idle_time_trans) = idle_time_trans {
                        add_counter(
                            format!("\\{}({})\\{}", processor_trans, pos, idle_time_trans),
                            query,
                            get_key_idle(proc_),
                            format!("{}_1", pos),
                            CounterValue::Float(0.),
                        );
                    }
                }
            }

            if let Some(network_trans) = get_translation(&"Network Interface".to_owned(), &x) {
                let network_in_trans = get_translation(&"Bytes Received/Sec".to_owned(), &x);
                let network_out_trans = get_translation(&"Bytes Sent/sec".to_owned(), &x);

                const PERF_DETAIL_WIZARD: DWORD = 400;
                const PDH_MORE_DATA: DWORD = 0x800007D2;

                let mut network_trans_utf16: Vec<u16> = network_trans.encode_utf16().collect();
                network_trans_utf16.push(0);
                let mut dwCounterListSize: DWORD = 0;
                let mut dwInstanceListSize: DWORD = 0;
                let status = unsafe {
                    PdhEnumObjectItemsW(
                        ::std::ptr::null(),
                        ::std::ptr::null(),
                        network_trans_utf16.as_ptr(),
                        ::std::ptr::null_mut(),
                        &mut dwCounterListSize,
                        ::std::ptr::null_mut(),
                        &mut dwInstanceListSize,
                        PERF_DETAIL_WIZARD,
                        0,
                    )
                };
                if status != PDH_MORE_DATA as i32 {
                    eprintln!("PdhEnumObjectItems invalid status: {:x}", status);
                } else {
                    let mut pwsCounterListBuffer: Vec<u16> =
                        Vec::with_capacity(dwCounterListSize as usize);
                    let mut pwsInstanceListBuffer: Vec<u16> =
                        Vec::with_capacity(dwInstanceListSize as usize);
                    unsafe {
                        pwsCounterListBuffer.set_len(dwCounterListSize as usize);
                        pwsInstanceListBuffer.set_len(dwInstanceListSize as usize);
                    }
                    let status = unsafe {
                        PdhEnumObjectItemsW(
                            ::std::ptr::null(),
                            ::std::ptr::null(),
                            network_trans_utf16.as_ptr(),
                            pwsCounterListBuffer.as_mut_ptr(),
                            &mut dwCounterListSize,
                            pwsInstanceListBuffer.as_mut_ptr(),
                            &mut dwInstanceListSize,
                            PERF_DETAIL_WIZARD,
                            0,
                        )
                    };
                    if status != ERROR_SUCCESS as i32 {
                        eprintln!("PdhEnumObjectItems invalid status: {:x}", status);
                    } else {
                        for (pos, x) in pwsInstanceListBuffer
                            .split(|x| *x == 0)
                            .filter(|x| x.len() > 0)
                            .enumerate()
                        {
                            let net_interface = String::from_utf16(x).expect("invalid utf16");
                            if let Some(ref network_in_trans) = network_in_trans {
                                let mut key_in = None;
                                add_counter(
                                    format!(
                                        "\\{}({})\\{}",
                                        network_trans, net_interface, network_in_trans
                                    ),
                                    query,
                                    &mut key_in,
                                    format!("net{}_in", pos),
                                    CounterValue::Integer(0),
                                );
                                if key_in.is_some() {
                                    network::get_keys_in(&mut s.network).push(key_in.unwrap());
                                }
                            }
                            if let Some(ref network_out_trans) = network_out_trans {
                                let mut key_out = None;
                                add_counter(
                                    format!(
                                        "\\{}({})\\{}",
                                        network_trans, net_interface, network_out_trans
                                    ),
                                    query,
                                    &mut key_out,
                                    format!("net{}_out", pos),
                                    CounterValue::Integer(0),
                                );
                                if key_out.is_some() {
                                    network::get_keys_out(&mut s.network).push(key_out.unwrap());
                                }
                            }
                        }
                    }
                }
            }
            query.start();
        }
        s.refresh_specifics(refreshes);
        s
    }

    fn refresh_cpu(&mut self) {
        self.uptime = get_uptime();
        if let Some(ref mut query) = self.query {
            for p in self.processors.iter_mut() {
                let mut idle_time = None;
                if let &mut Some(ref key_idle) = get_key_idle(p) {
                    idle_time = Some(query.get(&key_idle.unique_id).expect("key disappeared"));
                }
                if let Some(idle_time) = idle_time {
                    set_cpu_usage(p, 1. - idle_time);
                }
            }
        }
    }

    fn refresh_memory(&mut self) {
        self.uptime = get_uptime();
        unsafe {
            let mut mem_info: MEMORYSTATUSEX = zeroed();
            mem_info.dwLength = size_of::<MEMORYSTATUSEX>() as u32;
            GlobalMemoryStatusEx(&mut mem_info);
            self.mem_total = auto_cast!(mem_info.ullTotalPhys, u64);
            self.mem_free = auto_cast!(mem_info.ullAvailPhys, u64);
            //self.swap_total = auto_cast!(mem_info.ullTotalPageFile - mem_info.ullTotalPhys, u64);
            //self.swap_free = auto_cast!(mem_info.ullAvailPageFile, u64);
        }
    }

    fn refresh_temperatures(&mut self) {
        // does nothing for the moment...
    }

    fn refresh_network(&mut self) {
        network::refresh(&mut self.network, &self.query);
    }

    fn refresh_process(&mut self, pid: Pid) -> bool {
        if refresh_existing_process(self, pid, true) == false {
            self.process_list.remove(&pid);
            false
        } else {
            true
        }
    }

    fn refresh_processes(&mut self) {
        // Windows 10 notebook requires at least 512kb of memory to make it in one go
        let mut buffer_size: usize = 512 * 1024;

        loop {
            let mut process_information: Vec<u8> = Vec::with_capacity(buffer_size);

            let mut cb_needed = 0;
            let ntstatus = unsafe {
                process_information.set_len(buffer_size);
                NtQuerySystemInformation(
                    SystemProcessInformation,
                    process_information.as_mut_ptr() as PVOID,
                    buffer_size as ULONG,
                    &mut cb_needed,
                )
            };

            if ntstatus != STATUS_INFO_LENGTH_MISMATCH {
                if ntstatus < 0 {
                    eprintln!(
                        "Couldn't get process infos: NtQuerySystemInformation returned {}",
                        ntstatus
                    );
                }

                // Parse the data block to get process information
                let mut process_ids = Vec::with_capacity(500);
                let mut process_information_offset = 0;
                loop {
                    let p = unsafe {
                        process_information
                            .as_ptr()
                            .offset(process_information_offset)
                            as *const SYSTEM_PROCESS_INFORMATION
                    };
                    let pi = unsafe { &*p };

                    process_ids.push(Wrap(p));

                    if pi.NextEntryOffset == 0 {
                        break;
                    }

                    process_information_offset += pi.NextEntryOffset as isize;
                }
                let nb_processors = self.processors.len() as u64;
                let process_list = Wrap(UnsafeCell::new(&mut self.process_list));
                let system_time = get_system_computation_time();
                // TODO: instead of using parallel iterator only here, would be better to be able
                //       to run it over `process_information` directly!
                let processes = process_ids
                    .into_par_iter()
                    .filter_map(|pi| unsafe {
                        let pi = *pi.0;
                        let pid = pi.UniqueProcessId as usize;
                        if let Some(proc_) = (*process_list.0.get()).get_mut(&pid) {
                            proc_.memory = (pi.WorkingSetSize as u64) >> 10u64;
                            proc_.virtual_memory = (pi.VirtualSize as u64) >> 10u64;
                            compute_cpu_usage(proc_, nb_processors, system_time);
                            proc_.updated = true;
                            return None;
                        }
                        let name = get_process_name(&pi, pid);
                        let mut p = Process::new_full(
                            pid,
                            if pi.InheritedFromUniqueProcessId as usize != 0 {
                                Some(pi.InheritedFromUniqueProcessId as usize)
                            } else {
                                None
                            },
                            (pi.WorkingSetSize as u64) >> 10u64,
                            (pi.VirtualSize as u64) >> 10u64,
                            name,
                        );
                        compute_cpu_usage(&mut p, nb_processors, system_time);
                        Some(p)
                    })
                    .collect::<Vec<_>>();
                self.process_list.retain(|_, v| {
                    let x = v.updated;
                    v.updated = false;
                    x
                });
                for p in processes.into_iter() {
                    self.process_list.insert(p.pid(), p);
                }

                break;
            }

            // GetNewBufferSize
            if cb_needed == 0 {
                buffer_size *= 2;
                continue;
            }
            // allocating a few more kilo bytes just in case there are some new process
            // kicked in since new call to NtQuerySystemInformation
            buffer_size = (cb_needed + (1024 * 10)) as usize;
        }
    }

    fn refresh_disks(&mut self) {
        for disk in &mut self.disks {
            disk.update();
        }
    }

    fn refresh_disk_list(&mut self) {
        self.disks = unsafe { get_disks() };
    }

    fn get_process_list(&self) -> &HashMap<Pid, Process> {
        &self.process_list
    }

    fn get_process(&self, pid: Pid) -> Option<&Process> {
        self.process_list.get(&(pid as usize))
    }

    fn get_processor_list(&self) -> &[Processor] {
        &self.processors[..]
    }

    fn get_total_memory(&self) -> u64 {
        self.mem_total >> 10
    }

    fn get_free_memory(&self) -> u64 {
        self.mem_free >> 10
    }

    fn get_used_memory(&self) -> u64 {
        (self.mem_total - self.mem_free) >> 10
    }

    fn get_total_swap(&self) -> u64 {
        self.swap_total >> 10
    }

    fn get_free_swap(&self) -> u64 {
        self.swap_free >> 10
    }

    fn get_used_swap(&self) -> u64 {
        (self.swap_total - self.swap_free) >> 10
    }

    fn get_components_list(&self) -> &[Component] {
        &self.temperatures[..]
    }

    fn get_disks(&self) -> &[Disk] {
        &self.disks[..]
    }

    fn get_network(&self) -> &NetworkData {
        &self.network
    }

    fn get_uptime(&self) -> u64 {
        self.uptime
    }
}

fn is_proc_running(handle: HANDLE) -> bool {
    let mut exit_code = 0;
    let ret = unsafe { GetExitCodeProcess(handle, &mut exit_code) };
    !(ret == FALSE || exit_code != STILL_ACTIVE)
}

fn refresh_existing_process(s: &mut System, pid: Pid, compute_cpu: bool) -> bool {
    if let Some(ref mut entry) = s.process_list.get_mut(&(pid as usize)) {
        if !is_proc_running(get_handle(entry)) {
            return false;
        }
        update_proc_info(entry);
        if compute_cpu {
            compute_cpu_usage(entry, s.processors.len() as u64, get_system_computation_time());
        }
        true
    } else {
        false
    }
}

fn get_process_name(process: &SYSTEM_PROCESS_INFORMATION, process_id: usize) -> String {
    let name = &process.ImageName;
    if name.Buffer.is_null() {
        match process_id {
            0 => "Idle".to_owned(),
            4 => "System".to_owned(),
            _ => format!("<no name> Process {}", process_id),
        }
    } else {
        let slice = unsafe {
            std::slice::from_raw_parts(
                name.Buffer,
                //The length is in bytes, not the length of string
                name.Length as usize / std::mem::size_of::<u16>(),
            )
        };

        String::from_utf16_lossy(slice)
    }
}
<|endoftext|>


<commit_before>// Unused mut warning is false in this context
#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_stream;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate hyper_tls;
extern crate time;
extern crate clap;

mod utils;
mod models;
mod client;
mod app;
mod endpoint;
mod cli;

use app::*;
use models::*;
use client::*;
use cli::*;

use std::io::{self, BufRead};
use std::thread;
use futures::{Stream, Sink, Future};
use futures::sync::mpsc;
use futures::sync::mpsc::Receiver;
use futures::stream::BoxStream;

fn main() {

    let mut app_domain = AppDomain::new();
    let mut app_cache: AppCache = AppCache::new();
    let mut app_state_machine: AppStateMachine = AppStateMachine::new();

    info!(&app_domain.logger, "Application started");
    app_cache.retrieved_top_stories = get_top_story_ids(&mut app_domain, &mut app_state_machine)
        .ok();
    front_page(&mut app_domain, &mut app_cache, &mut app_state_machine);
    run_gui_client(&mut app_domain, &mut app_cache, &mut app_state_machine);
}

fn front_page(app_domain: &mut AppDomain,
              app_cache: &mut AppCache,
              app_state_machine: &mut AppStateMachine) {
    let top_stories = app_cache.retrieved_top_stories.as_ref().unwrap();
    info!(&app_domain.logger,
          format!("Received {} top stories", top_stories.values.len()));
    let mut index = 0;
    for item_id in top_stories.values.iter().take(10) {
        index += 1;
        let s = format!("{}", item_id);
        let item: HnItem = client::get_item_by_id(&s, app_domain, app_state_machine)
            .unwrap();
        print_headline_with_author(&item, &index);
    }
}

#[derive(Debug)]
struct Stats {
    pub success: usize,
    pub failure: usize,
}

fn run_gui_client(app_domain: &mut AppDomain,
                  app_cache: &mut AppCache,
                  app_state_machine: &mut AppStateMachine) {
    let (mut tx, rx) = mpsc::channel(1);
    thread::spawn(|| loop {
        let stdin = io::stdin();
        for line in stdin.lock().lines() {
            tx = tx.send(line).wait().unwrap();
        }
    });
    let mut stats = Stats {
        success: 0,
        failure: 0,
    };

    let f2 = rx.for_each(|res| {
        match res {
            Ok(_) => stats.success += 1,
            Err(_) => stats.failure += 1,
        }
        println!("{}", format!("{:?}", stats));
        Ok(())
    });
    app_domain.core.run(f2);

}
<commit_msg>made the gui listener work now with stdin in another thread<commit_after>// Unused mut warning is false in this context
#[macro_use]
extern crate slog;
extern crate slog_term;
extern crate slog_stream;

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;
extern crate futures;
extern crate hyper;
extern crate tokio_core;
extern crate hyper_tls;
extern crate time;
extern crate clap;

mod utils;
mod models;
mod client;
mod app;
mod endpoint;
mod cli;

use app::*;
use models::*;
use client::*;
use cli::*;

use std::io::{self, BufRead};
use std::thread::spawn;
use std::thread;
use futures::{Stream, Sink, Future};
use futures::sync::mpsc;
use futures::sync::mpsc::{Receiver, Sender};
use futures::stream::BoxStream;

fn main() {

    let mut app_domain = AppDomain::new();
    let mut app_cache: AppCache = AppCache::new();
    let mut app_state_machine: AppStateMachine = AppStateMachine::new();

    info!(&app_domain.logger, "Application started");
    app_cache.retrieved_top_stories = get_top_story_ids(&mut app_domain, &mut app_state_machine)
        .ok();
    front_page(&mut app_domain, &mut app_cache, &mut app_state_machine);
    let (mut tx, rx) = mpsc::channel(1);

    let listener = rx.for_each(|res| stdin_listener_sink(res));
    spawn(move || {
        let stdin = io::stdin();
        for line in stdin.lock().lines() {
            tx = tx.send(line).wait().unwrap();
        }
    });

    app_domain.core.run(listener);

    // run_gui_client(&mut app_domain, &mut app_cache, &mut app_state_machine);
}
fn stdin_listener_sink(res:Result<String, io::Error>) -> Result<(),()> {
        match res {
            Ok(_res) => println!("{}", _res),
            Err(_) => println!("{}", "Error"),
        }
        Ok(())
}

fn front_page(app_domain: &mut AppDomain,
              app_cache: &mut AppCache,
              app_state_machine: &mut AppStateMachine) {
    let top_stories = app_cache.retrieved_top_stories.as_ref().unwrap();
    info!(&app_domain.logger,
          format!("Received {} top stories", top_stories.values.len()));
    let mut index = 0;
    for item_id in top_stories.values.iter().take(10) {
        index += 1;
        let s = format!("{}", item_id);
        let item: HnItem = client::get_item_by_id(&s, app_domain, app_state_machine).unwrap();
        print_headline_with_author(&item, &index);
    }
}

<|endoftext|>


<commit_before>use std::os::raw;

#[repr(C)]
pub struct PDUISCInterface {
    pub send_command: extern "C" fn(*mut raw::c_void, raw::c_uint, u64, u64) -> u64,
    pub update: extern "C" fn(*mut raw::c_void),
    pub draw: extern "C" fn(*mut raw::c_void),
    pub private_data: *mut raw::c_void,
}

pub struct Scintilla {
    api: *mut PDUISCInterface,
}

impl Scintilla {
    pub fn new(api: *mut PDUISCInterface) -> Scintilla {
        Scintilla { api: api }
    }

    #[inline]
    pub fn send_command(&self, message: u32, p0: u64, p1: u64) -> u64 {
        unsafe { ((*self.api).send_command)((*self.api).private_data, message, p0, p1) }
    }

    #[inline]
    pub fn update(&self) {
        unsafe { ((*self.api).update)((*self.api).private_data) }
    }

    #[inline]
    pub fn draw(&self) {
        unsafe { ((*self.api).draw)((*self.api).private_data) }
    }
}
<commit_msg>Added send_command_str<commit_after>use std::os::raw;

#[repr(C)]
pub struct PDUISCInterface {
    pub send_command: extern "C" fn(*mut raw::c_void, raw::c_uint, u64, u64) -> u64,
    pub update: extern "C" fn(*mut raw::c_void),
    pub draw: extern "C" fn(*mut raw::c_void),
    pub private_data: *mut raw::c_void,
}

pub struct Scintilla {
    api: *mut PDUISCInterface,
}

impl Scintilla {
    pub fn new(api: *mut PDUISCInterface) -> Scintilla {
        Scintilla { api: api }
    }

    #[inline]
    pub fn send_command(&self, message: u32, p0: u64, p1: u64) -> u64 {
        unsafe { ((*self.api).send_command)((*self.api).private_data, message, p0, p1) }
    }

    #[inline]
    pub fn send_command_str(&self, message: u32, data: &str) -> u64 {
        unsafe {
            let ptr = data.as_ptr() as u64;
            ((*self.api).send_command)((*self.api).private_data, message, data.len() as u64, ptr)
        }
    }

    #[inline]
    pub fn update(&self) {
        unsafe { ((*self.api).update)((*self.api).private_data) }
    }

    #[inline]
    pub fn draw(&self) {
        unsafe { ((*self.api).draw)((*self.api).private_data) }
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;

use toml::Value;

use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;

#[derive(Debug)]
pub struct UpdateHook {
    storepath: PathBuf,

    position: HookPosition,
    config: Option<Value>,
}

impl UpdateHook {

    pub fn new(storepath: PathBuf, p: HookPosition) -> UpdateHook {
        UpdateHook {
            storepath: storepath,
            position: p,
            config: None,
        }
    }

}

impl Hook for UpdateHook {

    fn name(&self) -> &'static str {
        "stdhook_git_update"
    }

    fn set_config(&mut self, config: &Value) {
        self.config = Some(config.clone());
    }

}

impl HookDataAccessorProvider for UpdateHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for UpdateHook {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        debug!("[GIT UPDATE HOOK]: {:?}", id);
        Ok(())
    }

}

<commit_msg>Add Runtime for UpdateHook<commit_after>use std::path::PathBuf;

use toml::Value;

use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;

use vcs::git::runtime::Runtime as GRuntime;

#[derive(Debug)]
pub struct UpdateHook {
    storepath: PathBuf,

    runtime: GRuntime,

    position: HookPosition,
}

impl UpdateHook {

    pub fn new(storepath: PathBuf, p: HookPosition) -> UpdateHook {
        UpdateHook {
            runtime: GRuntime::new(&storepath),
            storepath: storepath,
            position: p,
        }
    }

}

impl Hook for UpdateHook {

    fn name(&self) -> &'static str {
        "stdhook_git_update"
    }

    fn set_config(&mut self, config: &Value) {
        self.config = Some(config.clone());
    }

}

impl HookDataAccessorProvider for UpdateHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for UpdateHook {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        debug!("[GIT UPDATE HOOK]: {:?}", id);
        Ok(())
    }

}

<|endoftext|>


<commit_before>use std::convert::TryFrom;
use std::os::unix::process::CommandExt;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;

use nmk::bin_name::{TMUX, ZSH};
use nmk::env_name::NMK_TMUX_VERSION;
use nmk::platform::is_mac;

use crate::cmdline::Opt;
use crate::core::*;
use crate::utils::{is_dev_machine, print_usage_time};

#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Version {
    V26,
    V27,
    V28,
    V29,
    V29a,
    V30,
    V30a,
    V31,
    V31a,
    V31b,
}

impl FromStr for Version {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Version::*;
        let v = match s {
            "2.6" => V26,
            "2.7" => V27,
            "2.8" => V28,
            "2.9" => V29,
            "2.9a" => V29a,
            "3.0" => V30,
            "3.0a" => V30a,
            "3.1" => V31,
            "3.1a" => V31a,
            "3.1b" => V31b,
            _ => return Err(()),
        };
        Ok(v)
    }
}

impl AsRef<str> for Version {
    fn as_ref(&self) -> &'static str {
        use Version::*;
        match *self {
            V26 => "2.6",
            V27 => "2.7",
            V28 => "2.8",
            V29 => "2.9",
            V29a => "2.9a",
            V30 => "3.0",
            V30a => "3.0a",
            V31 => "3.1",
            V31a => "3.1a",
            V31b => "3.1b",
        }
    }
}

#[derive(Debug)]
pub enum ParseVersionError {
    BadVersionOutput(String),
    UnsupportedVersion(String),
}

impl Version {
    // Try parse `tmux -v` result
    fn try_from_version_output(version_output: &str) -> Result<Self, ParseVersionError> {
        let version_number = version_output
            .trim()
            .split(" ")
            .nth(1)
            .ok_or_else(|| ParseVersionError::BadVersionOutput(version_output.to_string()))?;
        Self::try_from(version_number)
    }

    pub fn as_str(&self) -> &str {
        self.as_ref()
    }
}

impl TryFrom<&str> for Version {
    type Error = ParseVersionError;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        Self::from_str(value).map_err(|_| ParseVersionError::UnsupportedVersion(value.to_owned()))
    }
}

pub struct Tmux {
    nmk_home: PathBuf,
    tmux_dir: PathBuf,
    config: PathBuf,
    pub bin: PathBuf,
    pub version: Version,
}

fn find_config(tmux_dir: &PathBuf, version: Version) -> PathBuf {
    let version: &str = version.as_ref();
    let config = tmux_dir.join(format!("{}.conf", version));
    assert!(
        config.exists(),
        "Unable to find config for tmux version: {}",
        version
    );
    config
}

fn find_version() -> Result<Version, ParseVersionError> {
    if let Ok(s) = std::env::var(NMK_TMUX_VERSION) {
        log::debug!("Using tmux version from environment variable");
        Version::try_from(s.as_str())
    } else {
        let output = Command::new(TMUX)
            .arg("-V")
            .output()
            .expect("tmux not found");
        if !output.status.success() {
            let code = output.status.code().expect("tmux is terminated by signal");
            panic!("tmux exit with status: {}", code);
        }
        let version_output =
            std::str::from_utf8(&output.stdout).expect("tmux version output contain non utf-8");
        Version::try_from_version_output(version_output)
    }
}

impl Tmux {
    pub fn new(nmk_home: &Path) -> Tmux {
        let tmux_dir = nmk_home.join("tmux");
        assert!(
            tmux_dir.is_dir(),
            "{} is not directory",
            tmux_dir.to_string_lossy()
        );
        let bin = which::which(TMUX).expect("Cannot find tmux binary");
        let version = find_version().unwrap_or_else(|e| match e {
            ParseVersionError::BadVersionOutput(s) => panic!("Bad tmux output: {}", s),
            ParseVersionError::UnsupportedVersion(s) => panic!("Unsupported tmux version: {}", s),
        });
        let config = find_config(&tmux_dir, version);
        Tmux {
            nmk_home: nmk_home.to_owned(),
            tmux_dir,
            bin,
            version,
            config,
        }
    }

    pub fn setup_environment(&self, opt: &Opt, is_color_term: bool) {
        set_env(
            "NMK_TMUX_DEFAULT_SHELL",
            which::which(ZSH).expect("zsh not found"),
        );
        set_env("NMK_TMUX_DETACH_ON_DESTROY", on_off!(opt.detach_on_destroy));
        set_env("NMK_TMUX_HISTORY", self.tmux_dir.join(".tmux_history"));
        set_env("NMK_TMUX_VERSION", &self.version.as_str());
        let default_term = if is_color_term {
            "screen-256color"
        } else {
            "screen"
        };
        set_env("NMK_TMUX_DEFAULT_TERMINAL", default_term);
        set_env("NMK_TMUX_256_COLOR", one_hot!(is_color_term));
    }

    // On remote server, I don't want to show full tmux config path in `ps` output
    //
    // We can do that by leak some file descriptor to tmux server so it can access config by
    // using /proc/self/fd/<FD number>
    //
    // We can't use normal std::fs::File because Rust open file with FD_CLOEXEC flag.
    // That flag is default for a good reason but it doesn't fit our use case.
    fn open_config_with_leak_descriptor(&self) -> PathBuf {
        use nix::fcntl::{open, OFlag};
        use nix::sys::stat::Mode;
        let raw_fd =
            open(&self.config, OFlag::O_RDONLY, Mode::empty()).expect("Unable to open config file");
        PathBuf::from(format!("/proc/self/fd/{}", raw_fd))
    }

    pub fn exec(&self, opt: &Opt, is_color_term: bool) -> ! {
        let mut cmd = Command::new(TMUX);
        cmd.args(&["-L", &opt.socket]);
        if is_color_term {
            cmd.arg("-2");
        }
        if opt.unicode {
            cmd.arg("-u");
        }
        cmd.arg("-f");
        if !is_mac() && std::env::var("SSH_CONNECTION").is_ok() {
            cmd.arg(self.open_config_with_leak_descriptor());
        } else {
            cmd.arg(&self.config);
        }
        let tmux_args = opt.args();
        if tmux_args.is_empty() {
            // Attach to tmux or create new session
            cmd.args(&["new-session", "-A"]);
            if self.version < Version::V31 {
                cmd.args(&["-s", "0"]);
            }
        } else {
            cmd.args(tmux_args);
        }
        log::debug!("exec command: {:?}", cmd);
        print_usage_time(&opt);
        if self.is_vendored_tmux() && is_dev_machine() {
            log::warn!("Using vendored tmux on development machine")
        }
        let err = cmd.exec();
        panic!("exec {:?} fail with {:?}", cmd, err);
    }

    pub fn is_vendored_tmux(&self) -> bool {
        self.bin.starts_with(&self.nmk_home)
    }
}

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

    #[test]
    fn test_version() {
        let tmux_output = "tmux 3.1b";

        let actual = Version::try_from_version_output(tmux_output);
        assert!(matches!(actual, Ok(Version::V31b)));
    }
}
<commit_msg>I don't think it useful but keep it here, revert back to use absolute path config<commit_after>use std::convert::TryFrom;
use std::os::unix::process::CommandExt;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;

use nmk::bin_name::{TMUX, ZSH};
use nmk::env_name::NMK_TMUX_VERSION;

use crate::cmdline::Opt;
use crate::core::*;
use crate::utils::{is_dev_machine, print_usage_time};

#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub enum Version {
    V26,
    V27,
    V28,
    V29,
    V29a,
    V30,
    V30a,
    V31,
    V31a,
    V31b,
}

impl FromStr for Version {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        use Version::*;
        let v = match s {
            "2.6" => V26,
            "2.7" => V27,
            "2.8" => V28,
            "2.9" => V29,
            "2.9a" => V29a,
            "3.0" => V30,
            "3.0a" => V30a,
            "3.1" => V31,
            "3.1a" => V31a,
            "3.1b" => V31b,
            _ => return Err(()),
        };
        Ok(v)
    }
}

impl AsRef<str> for Version {
    fn as_ref(&self) -> &'static str {
        use Version::*;
        match *self {
            V26 => "2.6",
            V27 => "2.7",
            V28 => "2.8",
            V29 => "2.9",
            V29a => "2.9a",
            V30 => "3.0",
            V30a => "3.0a",
            V31 => "3.1",
            V31a => "3.1a",
            V31b => "3.1b",
        }
    }
}

#[derive(Debug)]
pub enum ParseVersionError {
    BadVersionOutput(String),
    UnsupportedVersion(String),
}

impl Version {
    // Try parse `tmux -v` result
    fn try_from_version_output(version_output: &str) -> Result<Self, ParseVersionError> {
        let version_number = version_output
            .trim()
            .split(" ")
            .nth(1)
            .ok_or_else(|| ParseVersionError::BadVersionOutput(version_output.to_string()))?;
        Self::try_from(version_number)
    }

    pub fn as_str(&self) -> &str {
        self.as_ref()
    }
}

impl TryFrom<&str> for Version {
    type Error = ParseVersionError;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        Self::from_str(value).map_err(|_| ParseVersionError::UnsupportedVersion(value.to_owned()))
    }
}

pub struct Tmux {
    nmk_home: PathBuf,
    tmux_dir: PathBuf,
    config: PathBuf,
    pub bin: PathBuf,
    pub version: Version,
}

fn find_config(tmux_dir: &PathBuf, version: Version) -> PathBuf {
    let version: &str = version.as_ref();
    let config = tmux_dir.join(format!("{}.conf", version));
    assert!(
        config.exists(),
        "Unable to find config for tmux version: {}",
        version
    );
    config
}

fn find_version() -> Result<Version, ParseVersionError> {
    if let Ok(s) = std::env::var(NMK_TMUX_VERSION) {
        log::debug!("Using tmux version from environment variable");
        Version::try_from(s.as_str())
    } else {
        let output = Command::new(TMUX)
            .arg("-V")
            .output()
            .expect("tmux not found");
        if !output.status.success() {
            let code = output.status.code().expect("tmux is terminated by signal");
            panic!("tmux exit with status: {}", code);
        }
        let version_output =
            std::str::from_utf8(&output.stdout).expect("tmux version output contain non utf-8");
        Version::try_from_version_output(version_output)
    }
}

impl Tmux {
    pub fn new(nmk_home: &Path) -> Tmux {
        let tmux_dir = nmk_home.join("tmux");
        assert!(
            tmux_dir.is_dir(),
            "{} is not directory",
            tmux_dir.to_string_lossy()
        );
        let bin = which::which(TMUX).expect("Cannot find tmux binary");
        let version = find_version().unwrap_or_else(|e| match e {
            ParseVersionError::BadVersionOutput(s) => panic!("Bad tmux output: {}", s),
            ParseVersionError::UnsupportedVersion(s) => panic!("Unsupported tmux version: {}", s),
        });
        let config = find_config(&tmux_dir, version);
        Tmux {
            nmk_home: nmk_home.to_owned(),
            tmux_dir,
            bin,
            version,
            config,
        }
    }

    pub fn setup_environment(&self, opt: &Opt, is_color_term: bool) {
        set_env(
            "NMK_TMUX_DEFAULT_SHELL",
            which::which(ZSH).expect("zsh not found"),
        );
        set_env("NMK_TMUX_DETACH_ON_DESTROY", on_off!(opt.detach_on_destroy));
        set_env("NMK_TMUX_HISTORY", self.tmux_dir.join(".tmux_history"));
        set_env("NMK_TMUX_VERSION", &self.version.as_str());
        let default_term = if is_color_term {
            "screen-256color"
        } else {
            "screen"
        };
        set_env("NMK_TMUX_DEFAULT_TERMINAL", default_term);
        set_env("NMK_TMUX_256_COLOR", one_hot!(is_color_term));
    }

    // On remote server, I don't want to show full tmux config path in `ps` output
    //
    // We can do that by leak some file descriptor to tmux server so it can access config by
    // using /proc/self/fd/<FD number>
    //
    // We can't use normal std::fs::File because Rust open file with FD_CLOEXEC flag.
    // That flag is default for a good reason but it doesn't fit our use case.
    #[allow(dead_code)]
    fn open_config_with_leak_descriptor(&self) -> PathBuf {
        use nix::fcntl::{open, OFlag};
        use nix::sys::stat::Mode;
        let raw_fd =
            open(&self.config, OFlag::O_RDONLY, Mode::empty()).expect("Unable to open config file");
        PathBuf::from(format!("/proc/self/fd/{}", raw_fd))
    }

    pub fn exec(&self, opt: &Opt, is_color_term: bool) -> ! {
        let mut cmd = Command::new(TMUX);
        cmd.args(&["-L", &opt.socket]);
        if is_color_term {
            cmd.arg("-2");
        }
        if opt.unicode {
            cmd.arg("-u");
        }
        cmd.arg("-f");
        cmd.arg(&self.config);
        let tmux_args = opt.args();
        if tmux_args.is_empty() {
            // Attach to tmux or create new session
            cmd.args(&["new-session", "-A"]);
            if self.version < Version::V31 {
                cmd.args(&["-s", "0"]);
            }
        } else {
            cmd.args(tmux_args);
        }
        log::debug!("exec command: {:?}", cmd);
        print_usage_time(&opt);
        if self.is_vendored_tmux() && is_dev_machine() {
            log::warn!("Using vendored tmux on development machine")
        }
        let err = cmd.exec();
        panic!("exec {:?} fail with {:?}", cmd, err);
    }

    pub fn is_vendored_tmux(&self) -> bool {
        self.bin.starts_with(&self.nmk_home)
    }
}

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

    #[test]
    fn test_version() {
        let tmux_output = "tmux 3.1b";

        let actual = Version::try_from_version_output(tmux_output);
        assert!(matches!(actual, Ok(Version::V31b)));
    }
}
<|endoftext|>


<commit_before>/// Reads numbers from stdin, one per line, and writes them to a serialized histogram on stdout.

extern crate hdrsample;
extern crate clap;

use std::io::BufRead;

use clap::{App, Arg, SubCommand};

use hdrsample::Histogram;
use hdrsample::serialization::{V2Serializer, V2DeflateSerializer};

fn main() {
    let default_max = format!("{}", u64::max_value());
    let matches = App::new("hdrsample cli")
            .subcommand(SubCommand::with_name("serialize")
                    .arg(Arg::with_name("min")
                            .long("min")
                            .help("Minimum discernible value")
                            .takes_value(true)
                            .default_value("1"))
                    .arg(Arg::with_name("max")
                            .long("max")
                            .help("Maximum trackable value")
                            .takes_value(true)
                            .default_value(default_max.as_str()))
                    .arg(Arg::with_name("sigfig")
                            .long("sigfig")
                            .help("Number of significant digits")
                            .takes_value(true)
                            .default_value("3"))
                    .arg(Arg::with_name("compression")
                            .short("c")
                            .long("compression")
                            .help("Enable compression"))
                    .arg(Arg::with_name("resize")
                            .short("r")
                            .long("resize")
                            .help("Enable auto resize")))
            .get_matches();

    match matches.subcommand_name() {
        Some("serialize") => {
            let sub_matches = matches.subcommand_matches("serialize").unwrap();
            let min = sub_matches.value_of("min").unwrap().parse().unwrap();
            let max = sub_matches.value_of("max").unwrap().parse().unwrap();
            let sigfig = sub_matches.value_of("sigfig").unwrap().parse().unwrap();

            let mut h: Histogram<u64> = Histogram::new_with_bounds(min, max, sigfig).unwrap();

            if sub_matches.is_present("resize") {
                h.auto(true);
            }

            serialize(h, sub_matches.is_present("compression"));
        },
        _ => unreachable!()
    }
}

fn serialize(mut h: Histogram<u64>, compression: bool) {
    let stdin = std::io::stdin();
    let stdin_handle = stdin.lock();

    for num in stdin_handle.lines()
            .map(|l| l.expect("Should be able to read stdin"))
            .map(|s| s.parse().expect("Each line must be a u64")) {
        h.record(num).unwrap();
    }

    let stdout = std::io::stdout();
    let mut stdout_handle = stdout.lock();

    if compression {
        V2DeflateSerializer::new().serialize(&h, &mut stdout_handle).unwrap();
    } else {
        V2Serializer::new().serialize(&h, &mut stdout_handle).unwrap();
    }
}
<commit_msg>Add quantile iteration output to CLI example<commit_after>/// Reads numbers from stdin, one per line, and writes them to a serialized histogram on stdout.

extern crate hdrsample;
extern crate clap;

use std::io;
use std::io::{Write, BufRead};
use std::fmt::Display;

use clap::{App, Arg, SubCommand};

use hdrsample::{Histogram, RecordError};
use hdrsample::serialization::{V2Serializer, V2SerializeError, V2DeflateSerializer, V2DeflateSerializeError, Deserializer, DeserializeError};

fn main() {
    let default_max = format!("{}", u64::max_value());
    let matches = App::new("hdrsample cli")
            .subcommand(SubCommand::with_name("serialize")
                    .about("Transform number-per-line input from stdin into a serialized histogram on stdout")
                    .arg(Arg::with_name("min")
                            .long("min")
                            .help("Minimum discernible value")
                            .takes_value(true)
                            .default_value("1"))
                    .arg(Arg::with_name("max")
                            .long("max")
                            .help("Maximum trackable value")
                            .takes_value(true)
                            .default_value(default_max.as_str()))
                    .arg(Arg::with_name("sigfig")
                            .long("sigfig")
                            .help("Number of significant digits")
                            .takes_value(true)
                            .default_value("3"))
                    .arg(Arg::with_name("compression")
                            .short("c")
                            .long("compression")
                            .help("Enable compression"))
                    .arg(Arg::with_name("resize")
                            .short("r")
                            .long("resize")
                            .help("Enable auto resize")))
            .subcommand(SubCommand::with_name("quantiles")
                    .about("Display quantiles to stdout from serialized histogram stdin")
                    .arg(Arg::with_name("ticks")
                            .short("t")
                            .long("ticks-per-half")
                            .takes_value(true)
                            .required(true)
                            .help("Ticks per half distance"))
                    .arg(Arg::with_name("quantile-precision")
                            .long("quantile-precision")
                            .takes_value(true)
                            .default_value("5")))
            .get_matches();

    let stdin = std::io::stdin();
    let stdin_handle = stdin.lock();

    let stdout = std::io::stdout();
    let stdout_handle = stdout.lock();

    match matches.subcommand_name() {
        Some("serialize") => {
            let sub_matches = matches.subcommand_matches("serialize").unwrap();
            let min = sub_matches.value_of("min").unwrap().parse().unwrap();
            let max = sub_matches.value_of("max").unwrap().parse().unwrap();
            let sigfig = sub_matches.value_of("sigfig").unwrap().parse().unwrap();

            let mut h: Histogram<u64> = Histogram::new_with_bounds(min, max, sigfig).unwrap();

            if sub_matches.is_present("resize") {
                h.auto(true);
            }

            serialize(stdin_handle, stdout_handle, h, sub_matches.is_present("compression"))
        }
        Some("quantiles") => {
            let sub_matches = matches.subcommand_matches("quantiles").unwrap();
            let ticks_per_half = sub_matches.value_of("ticks").unwrap().parse().unwrap();
            let quantile_precision = sub_matches.value_of("quantile-precision").unwrap().parse().unwrap();
            quantiles(stdin_handle, stdout_handle, quantile_precision, ticks_per_half)
        }
        _ => unreachable!()
    }.expect("Subcommand failed")
}

/// Read numbers, one from each line, from stdin and output the resulting serialized histogram.
fn serialize<R: BufRead, W: Write>(reader: R, mut writer: W, mut h: Histogram<u64>, compression: bool) -> Result<(), CliError> {
    for num in reader.lines()
            .map(|l| l.expect("Should be able to read stdin"))
            .map(|s| s.parse().expect("Each line must be a u64")) {
        h.record(num)?;
    }

    if compression {
        V2DeflateSerializer::new().serialize(&h, &mut writer)?;
    } else {
        V2Serializer::new().serialize(&h, &mut writer)?;
    }

    Ok(())
}

/// Output histogram data in a format similar to the Java impl's
/// `AbstractHistogram#outputPercentileDistribution`.
fn quantiles<R: BufRead, W: Write>(mut reader: R, mut writer: W, quantile_precision: usize, ticks_per_half: u32) -> Result<(), CliError> {
    let hist: Histogram<u64> = Deserializer::new().deserialize(&mut reader)?;

    writer.write_all(
        format!(
            "{:>12} {:>quantile_precision$} {:>10} {:>14}\n\n",
            "Value",
            "Quantile",
            "TotalCount",
            "1/(1-Quantile)",
            quantile_precision = quantile_precision + 2 // + 2 from leading "0." for numbers
        ).as_ref(),
    )?;
    let mut sum = 0;
    for v in hist.iter_quantiles(ticks_per_half) {
        sum += v.count_since_last_iteration();
        if v.quantile() < 1.0 {
            writer.write_all(
                format!(
                    "{:12} {:1.*} {:10} {:14.2}\n",
                    v.value(),
                    quantile_precision,
                    v.quantile(),
                    sum,
                    1_f64 / (1_f64 - v.quantile())
                ).as_ref(),
            )?;
        } else {
            writer.write_all(
                format!(
                    "{:12} {:1.*} {:10} {:>14}\n",
                    v.value(),
                    quantile_precision,
                    v.quantile(),
                    sum,
                    "∞"
                ).as_ref(),
            )?;
        }
    }

    fn write_extra_data<T1: Display, T2: Display, W: Write>(
        writer: &mut W, label1: &str, data1: T1, label2: &str, data2: T2) -> Result<(), io::Error> {
        writer.write_all(format!("#[{:10} = {:12.2}, {:14} = {:12.2}]\n",
                                 label1, data1, label2, data2).as_ref())
    }

    write_extra_data(&mut writer, "Mean", hist.mean(), "StdDeviation", hist.stdev())?;
    write_extra_data(&mut writer, "Max", hist.max(), "Total count", hist.count())?;
    write_extra_data(&mut writer, "Buckets", hist.buckets(), "SubBuckets", hist.len())?;

    Ok(())
}

// A handy way to enable ? use in subcommands by mapping common errors.
// Normally I frown on excessive use of From as it's too "magic", but in the limited confines of
// subcommands, the convenience seems worth it.
#[derive(Debug)]
enum CliError {
    IoError(io::Error),
    HistogramSerializeError(V2SerializeError),
    HistogramSerializeCompressedError(V2DeflateSerializeError),
    HistogramDeserializeError(DeserializeError),
    HistogramRecordError(RecordError)
}

impl From<io::Error> for CliError {
    fn from(e: io::Error) -> Self {
        CliError::IoError(e)
    }
}

impl From<V2SerializeError> for CliError {
    fn from(e: V2SerializeError) -> Self {
        CliError::HistogramSerializeError(e)
    }
}

impl From<V2DeflateSerializeError> for CliError {
    fn from(e: V2DeflateSerializeError) -> Self {
        CliError::HistogramSerializeCompressedError(e)
    }
}

impl From<RecordError> for CliError {
    fn from(e: RecordError) -> Self {
        CliError::HistogramRecordError(e)
    }
}

impl From<DeserializeError> for CliError {
    fn from(e: DeserializeError) -> Self {
        CliError::HistogramDeserializeError(e)
    }
}
<|endoftext|>


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

#[link(name = "geom", vers = "0.1")];

extern mod extra;
extern mod std;

pub use matrix::Matrix4;
pub use matrix2d::Matrix2D;
pub use point::Point2D;
pub use rect::Rect;
pub use side_offsets::SideOffsets2D;
pub use size::Size2D;

pub mod matrix;
pub mod matrix2d;
pub mod point;
pub mod rect;
pub mod side_offsets;
pub mod size;

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

#[crate_id = "github.com/mozilla-servo/rust-geom#geom:0.1"];

extern mod extra;
extern mod std;

pub use matrix::Matrix4;
pub use matrix2d::Matrix2D;
pub use point::Point2D;
pub use rect::Rect;
pub use side_offsets::SideOffsets2D;
pub use size::Size2D;

pub mod matrix;
pub mod matrix2d;
pub mod point;
pub mod rect;
pub mod side_offsets;
pub mod size;

<|endoftext|>


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

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11.0-pre"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://static.rust-lang.org/doc/master")]

#![deny(deprecated_owned_vector)]
#![feature(macro_registrar, managed_boxes)]

extern crate syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("fourcc"),
        NormalTT(box BasicMacroExpander {
            expander: expand_syntax_ext,
            span: None,
        },
        None));
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<commit_msg>Change static.rust-lang.org to doc.rust-lang.org<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Syntax extension to generate FourCCs.

Once loaded, fourcc!() is called with a single 4-character string,
and an optional ident that is either `big`, `little`, or `target`.
The ident represents endianness, and specifies in which direction
the characters should be read. If the ident is omitted, it is assumed
to be `big`, i.e. left-to-right order. It returns a u32.

# Examples

To load the extension and use it:

```rust,ignore
#[phase(syntax)]
extern crate fourcc;

fn main() {
    let val = fourcc!("\xC0\xFF\xEE!");
    assert_eq!(val, 0xC0FFEE21u32);
    let little_val = fourcc!("foo ", little);
    assert_eq!(little_val, 0x21EEFFC0u32);
}
```

# References

* [Wikipedia: FourCC](http://en.wikipedia.org/wiki/FourCC)

*/

#![crate_id = "fourcc#0.11.0-pre"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![license = "MIT/ASL2"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/")]

#![deny(deprecated_owned_vector)]
#![feature(macro_registrar, managed_boxes)]

extern crate syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::attr::contains;
use syntax::codemap::{Span, mk_sp};
use syntax::ext::base;
use syntax::ext::base::{SyntaxExtension, BasicMacroExpander, NormalTT, ExtCtxt, MacExpr};
use syntax::ext::build::AstBuilder;
use syntax::parse;
use syntax::parse::token;
use syntax::parse::token::InternedString;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("fourcc"),
        NormalTT(box BasicMacroExpander {
            expander: expand_syntax_ext,
            span: None,
        },
        None));
}

pub fn expand_syntax_ext(cx: &mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
                         -> Box<base::MacResult> {
    let (expr, endian) = parse_tts(cx, tts);

    let little = match endian {
        None => false,
        Some(Ident{ident, span}) => match token::get_ident(ident).get() {
            "little" => true,
            "big" => false,
            "target" => target_endian_little(cx, sp),
            _ => {
                cx.span_err(span, "invalid endian directive in fourcc!");
                target_endian_little(cx, sp)
            }
        }
    };

    let s = match expr.node {
        // expression is a literal
        ast::ExprLit(ref lit) => match lit.node {
            // string literal
            ast::LitStr(ref s, _) => {
                if s.get().char_len() != 4 {
                    cx.span_err(expr.span, "string literal with len != 4 in fourcc!");
                }
                s
            }
            _ => {
                cx.span_err(expr.span, "unsupported literal in fourcc!");
                return base::DummyResult::expr(sp)
            }
        },
        _ => {
            cx.span_err(expr.span, "non-literal in fourcc!");
            return base::DummyResult::expr(sp)
        }
    };

    let mut val = 0u32;
    for codepoint in s.get().chars().take(4) {
        let byte = if codepoint as u32 > 0xFF {
            cx.span_err(expr.span, "fourcc! literal character out of range 0-255");
            0u8
        } else {
            codepoint as u8
        };

        val = if little {
            (val >> 8) | ((byte as u32) << 24)
        } else {
            (val << 8) | (byte as u32)
        };
    }
    let e = cx.expr_lit(sp, ast::LitUint(val as u64, ast::TyU32));
    MacExpr::new(e)
}

struct Ident {
    ident: ast::Ident,
    span: Span
}

fn parse_tts(cx: &ExtCtxt, tts: &[ast::TokenTree]) -> (@ast::Expr, Option<Ident>) {
    let p = &mut parse::new_parser_from_tts(cx.parse_sess(),
                                            cx.cfg(),
                                            tts.iter()
                                               .map(|x| (*x).clone())
                                               .collect());
    let ex = p.parse_expr();
    let id = if p.token == token::EOF {
        None
    } else {
        p.expect(&token::COMMA);
        let lo = p.span.lo;
        let ident = p.parse_ident();
        let hi = p.last_span.hi;
        Some(Ident{ident: ident, span: mk_sp(lo, hi)})
    };
    if p.token != token::EOF {
        p.unexpected();
    }
    (ex, id)
}

fn target_endian_little(cx: &ExtCtxt, sp: Span) -> bool {
    let meta = cx.meta_name_value(sp, InternedString::new("target_endian"),
        ast::LitStr(InternedString::new("little"), ast::CookedStr));
    contains(cx.cfg().as_slice(), meta)
}

// FIXME (10872): This is required to prevent an LLVM assert on Windows
#[test]
fn dummy_test() { }
<|endoftext|>