use crate::{NetworkData, Networks, NetworksExt, UserExt};
use std::convert::From;
use std::fmt;
use std::str::FromStr;
pub trait PidExt<T>: Copy + From<T> + FromStr + fmt::Display {
fn as_u32(self) -> u32;
fn from_u32(v: u32) -> Self;
}
macro_rules! pid_decl {
($typ:ty) => {
#[doc = include_str!("../md_doc/pid.md")]
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Pid(pub(crate) $typ);
impl From<$typ> for Pid {
fn from(v: $typ) -> Self {
Self(v)
}
}
impl From<Pid> for $typ {
fn from(v: Pid) -> Self {
v.0
}
}
impl PidExt<$typ> for Pid {
fn as_u32(self) -> u32 {
self.0 as u32
}
fn from_u32(v: u32) -> Self {
Self(v as _)
}
}
impl FromStr for Pid {
type Err = <$typ as FromStr>::Err;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(<$typ>::from_str(s)?))
}
}
impl fmt::Display for Pid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
};
}
cfg_if::cfg_if! {
if #[cfg(all(
not(feature = "unknown-ci"),
any(
target_os = "freebsd",
target_os = "linux",
target_os = "android",
target_os = "macos",
target_os = "ios",
)
))] {
use libc::pid_t;
pid_decl!(pid_t);
} else {
pid_decl!(usize);
}
}
macro_rules! impl_get_set {
($ty_name:ident, $name:ident, $with:ident, $without:ident $(, $extra_doc:literal)? $(,)?) => {
#[doc = concat!("Returns the value of the \"", stringify!($name), "\" refresh kind.")]
$(#[doc = concat!("
", $extra_doc, "
")])?
#[doc = concat!("
```
use sysinfo::", stringify!($ty_name), ";
let r = ", stringify!($ty_name), "::new();
assert_eq!(r.", stringify!($name), "(), false);
let r = r.with_", stringify!($name), "();
assert_eq!(r.", stringify!($name), "(), true);
let r = r.without_", stringify!($name), "();
assert_eq!(r.", stringify!($name), "(), false);
```")]
pub fn $name(&self) -> bool {
self.$name
}
#[doc = concat!("Sets the value of the \"", stringify!($name), "\" refresh kind to `true`.
```
use sysinfo::", stringify!($ty_name), ";
let r = ", stringify!($ty_name), "::new();
assert_eq!(r.", stringify!($name), "(), false);
let r = r.with_", stringify!($name), "();
assert_eq!(r.", stringify!($name), "(), true);
```")]
#[must_use]
pub fn $with(mut self) -> Self {
self.$name = true;
self
}
#[doc = concat!("Sets the value of the \"", stringify!($name), "\" refresh kind to `false`.
```
use sysinfo::", stringify!($ty_name), ";
let r = ", stringify!($ty_name), "::everything();
assert_eq!(r.", stringify!($name), "(), true);
let r = r.without_", stringify!($name), "();
assert_eq!(r.", stringify!($name), "(), false);
```")]
#[must_use]
pub fn $without(mut self) -> Self {
self.$name = false;
self
}
};
($ty_name:ident, $name:ident, $with:ident, $without:ident, $typ:ty $(,)?) => {
#[doc = concat!("Returns the value of the \"", stringify!($name), "\" refresh kind.
```
use sysinfo::{", stringify!($ty_name), ", ", stringify!($typ), "};
let r = ", stringify!($ty_name), "::new();
assert_eq!(r.", stringify!($name), "().is_some(), false);
let r = r.with_", stringify!($name), "(", stringify!($typ), "::everything());
assert_eq!(r.", stringify!($name), "().is_some(), true);
let r = r.without_", stringify!($name), "();
assert_eq!(r.", stringify!($name), "().is_some(), false);
```")]
pub fn $name(&self) -> Option<$typ> {
self.$name
}
#[doc = concat!("Sets the value of the \"", stringify!($name), "\" refresh kind to `true`.
```
use sysinfo::{", stringify!($ty_name), ", ", stringify!($typ), "};
let r = ", stringify!($ty_name), "::new();
assert_eq!(r.", stringify!($name), "().is_some(), false);
let r = r.with_", stringify!($name), "(", stringify!($typ), "::everything());
assert_eq!(r.", stringify!($name), "().is_some(), true);
```")]
#[must_use]
pub fn $with(mut self, kind: $typ) -> Self {
self.$name = Some(kind);
self
}
#[doc = concat!("Sets the value of the \"", stringify!($name), "\" refresh kind to `false`.
```
use sysinfo::", stringify!($ty_name), ";
let r = ", stringify!($ty_name), "::everything();
assert_eq!(r.", stringify!($name), "().is_some(), true);
let r = r.without_", stringify!($name), "();
assert_eq!(r.", stringify!($name), "().is_some(), false);
```")]
#[must_use]
pub fn $without(mut self) -> Self {
self.$name = None;
self
}
};
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ProcessRefreshKind {
cpu: bool,
disk_usage: bool,
user: bool,
}
impl ProcessRefreshKind {
pub fn new() -> Self {
Self::default()
}
pub fn everything() -> Self {
Self {
cpu: true,
disk_usage: true,
user: true,
}
}
impl_get_set!(ProcessRefreshKind, cpu, with_cpu, without_cpu);
impl_get_set!(
ProcessRefreshKind,
disk_usage,
with_disk_usage,
without_disk_usage
);
impl_get_set!(
ProcessRefreshKind,
user,
with_user,
without_user,
r#"This refresh is about `user_id` and `group_id`. Please note that it has an effect mostly
on Windows as other platforms get this information alongside the Process information directly."#,
);
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct CpuRefreshKind {
cpu_usage: bool,
frequency: bool,
}
impl CpuRefreshKind {
pub fn new() -> Self {
Self::default()
}
pub fn everything() -> Self {
Self {
cpu_usage: true,
frequency: true,
}
}
impl_get_set!(CpuRefreshKind, cpu_usage, with_cpu_usage, without_cpu_usage);
impl_get_set!(CpuRefreshKind, frequency, with_frequency, without_frequency);
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct RefreshKind {
networks: bool,
networks_list: bool,
processes: Option<ProcessRefreshKind>,
disks_list: bool,
disks: bool,
memory: bool,
cpu: Option<CpuRefreshKind>,
components: bool,
components_list: bool,
users_list: bool,
}
impl RefreshKind {
pub fn new() -> Self {
Self::default()
}
pub fn everything() -> Self {
Self {
networks: true,
networks_list: true,
processes: Some(ProcessRefreshKind::everything()),
disks: true,
disks_list: true,
memory: true,
cpu: Some(CpuRefreshKind::everything()),
components: true,
components_list: true,
users_list: true,
}
}
impl_get_set!(
RefreshKind,
processes,
with_processes,
without_processes,
ProcessRefreshKind
);
impl_get_set!(RefreshKind, networks, with_networks, without_networks);
impl_get_set!(
RefreshKind,
networks_list,
with_networks_list,
without_networks_list
);
impl_get_set!(RefreshKind, disks, with_disks, without_disks);
impl_get_set!(RefreshKind, disks_list, with_disks_list, without_disks_list);
impl_get_set!(RefreshKind, memory, with_memory, without_memory);
impl_get_set!(RefreshKind, cpu, with_cpu, without_cpu, CpuRefreshKind);
impl_get_set!(RefreshKind, components, with_components, without_components);
impl_get_set!(
RefreshKind,
components_list,
with_components_list,
without_components_list
);
impl_get_set!(RefreshKind, users_list, with_users_list, without_users_list);
}
pub struct NetworksIter<'a> {
inner: std::collections::hash_map::Iter<'a, String, NetworkData>,
}
impl<'a> NetworksIter<'a> {
pub(crate) fn new(v: std::collections::hash_map::Iter<'a, String, NetworkData>) -> Self {
NetworksIter { inner: v }
}
}
impl<'a> Iterator for NetworksIter<'a> {
type Item = (&'a String, &'a NetworkData);
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl<'a> IntoIterator for &'a Networks {
type Item = (&'a String, &'a NetworkData);
type IntoIter = NetworksIter<'a>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum DiskType {
HDD,
SSD,
Unknown(isize),
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Debug)]
pub enum Signal {
Hangup,
Interrupt,
Quit,
Illegal,
Trap,
Abort,
IOT,
Bus,
FloatingPointException,
Kill,
User1,
Segv,
User2,
Pipe,
Alarm,
Term,
Child,
Continue,
Stop,
TSTP,
TTIN,
TTOU,
Urgent,
XCPU,
XFSZ,
VirtualAlarm,
Profiling,
Winch,
IO,
Poll,
Power,
Sys,
}
impl std::fmt::Display for Signal {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match *self {
Self::Hangup => "Hangup",
Self::Interrupt => "Interrupt",
Self::Quit => "Quit",
Self::Illegal => "Illegal",
Self::Trap => "Trap",
Self::Abort => "Abort",
Self::IOT => "IOT",
Self::Bus => "Bus",
Self::FloatingPointException => "FloatingPointException",
Self::Kill => "Kill",
Self::User1 => "User1",
Self::Segv => "Segv",
Self::User2 => "User2",
Self::Pipe => "Pipe",
Self::Alarm => "Alarm",
Self::Term => "Term",
Self::Child => "Child",
Self::Continue => "Continue",
Self::Stop => "Stop",
Self::TSTP => "TSTP",
Self::TTIN => "TTIN",
Self::TTOU => "TTOU",
Self::Urgent => "Urgent",
Self::XCPU => "XCPU",
Self::XFSZ => "XFSZ",
Self::VirtualAlarm => "VirtualAlarm",
Self::Profiling => "Profiling",
Self::Winch => "Winch",
Self::IO => "IO",
Self::Poll => "Poll",
Self::Power => "Power",
Self::Sys => "Sys",
};
f.write_str(s)
}
}
#[repr(C)]
#[derive(Default, Debug, Clone)]
pub struct LoadAvg {
pub one: f64,
pub five: f64,
pub fifteen: f64,
}
macro_rules! xid {
($(#[$outer:meta])+ $name:ident, $type:ty) => {
$(#[$outer])+
#[repr(transparent)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct $name(pub(crate) $type);
impl std::ops::Deref for $name {
type Target = $type;
fn deref(&self) -> &Self::Target {
&self.0
}
}
};
}
macro_rules! uid {
($(#[$outer:meta])+ $type:ty) => {
xid!($(#[$outer])+ Uid, $type);
};
}
macro_rules! gid {
($(#[$outer:meta])+ $type:ty) => {
xid!($(#[$outer])+ #[derive(Copy)] Gid, $type);
};
}
cfg_if::cfg_if! {
if #[cfg(all(
not(feature = "unknown-ci"),
any(
target_os = "freebsd",
target_os = "linux",
target_os = "android",
target_os = "macos",
target_os = "ios",
)
))] {
uid!(
libc::uid_t
);
gid!(
libc::gid_t
);
} else if #[cfg(windows)] {
uid!(
Box<str>
);
gid!(
u32
);
} else {
uid!(
u32
);
gid!(
u32
);
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct User {
pub(crate) uid: Uid,
pub(crate) gid: Gid,
pub(crate) name: String,
pub(crate) groups: Vec<String>,
}
impl UserExt for User {
fn id(&self) -> &Uid {
&self.uid
}
fn group_id(&self) -> Gid {
self.gid
}
fn name(&self) -> &str {
&self.name
}
fn groups(&self) -> &[String] {
&self.groups
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd)]
pub struct DiskUsage {
pub total_written_bytes: u64,
pub written_bytes: u64,
pub total_read_bytes: u64,
pub read_bytes: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ProcessStatus {
Idle,
Run,
Sleep,
Stop,
Zombie,
Tracing,
Dead,
Wakekill,
Waking,
Parked,
LockBlocked,
Unknown(u32),
}
#[allow(clippy::unnecessary_wraps)]
pub fn get_current_pid() -> Result<Pid, &'static str> {
cfg_if::cfg_if! {
if #[cfg(feature = "unknown-ci")] {
fn inner() -> Result<Pid, &'static str> {
Err("Unknown platform (CI)")
}
} else if #[cfg(any(
target_os = "freebsd",
target_os = "linux",
target_os = "android",
target_os = "macos",
target_os = "ios",
))] {
fn inner() -> Result<Pid, &'static str> {
unsafe { Ok(Pid(libc::getpid())) }
}
} else if #[cfg(windows)] {
fn inner() -> Result<Pid, &'static str> {
use winapi::um::processthreadsapi::GetCurrentProcessId;
unsafe { Ok(Pid(GetCurrentProcessId() as _)) }
}
} else {
fn inner() -> Result<Pid, &'static str> {
Err("Unknown platform")
}
}
}
inner()
}
#[cfg(test)]
mod tests {
use super::ProcessStatus;
#[test]
fn check_display_impl_process_status() {
println!("{} {:?}", ProcessStatus::Parked, ProcessStatus::Idle);
}
}