use crate::{
ComponentInner, ComponentsInner, CpuInner, NetworkDataInner, NetworksInner, ProcessInner,
SystemInner, UserInner,
};
use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::convert::{From, TryFrom};
use std::ffi::OsStr;
use std::fmt;
use std::path::Path;
use std::str::FromStr;
pub struct System {
pub(crate) inner: SystemInner,
}
impl Default for System {
fn default() -> System {
System::new()
}
}
impl System {
pub fn new() -> Self {
Self::new_with_specifics(RefreshKind::new())
}
pub fn new_all() -> Self {
Self::new_with_specifics(RefreshKind::everything())
}
pub fn new_with_specifics(refreshes: RefreshKind) -> Self {
let mut s = Self {
inner: SystemInner::new(),
};
s.refresh_specifics(refreshes);
s
}
pub fn refresh_specifics(&mut self, refreshes: RefreshKind) {
if let Some(kind) = refreshes.memory() {
self.refresh_memory_specifics(kind);
}
if let Some(kind) = refreshes.cpu() {
self.refresh_cpu_specifics(kind);
}
if let Some(kind) = refreshes.processes() {
self.refresh_processes_specifics(kind);
}
}
pub fn refresh_all(&mut self) {
self.refresh_specifics(RefreshKind::everything());
}
pub fn refresh_memory(&mut self) {
self.refresh_memory_specifics(MemoryRefreshKind::everything())
}
pub fn refresh_memory_specifics(&mut self, refresh_kind: MemoryRefreshKind) {
self.inner.refresh_memory_specifics(refresh_kind)
}
pub fn refresh_cpu_usage(&mut self) {
self.refresh_cpu_specifics(CpuRefreshKind::new().with_cpu_usage())
}
pub fn refresh_cpu_frequency(&mut self) {
self.refresh_cpu_specifics(CpuRefreshKind::new().with_frequency())
}
pub fn refresh_cpu(&mut self) {
self.refresh_cpu_specifics(CpuRefreshKind::everything())
}
pub fn refresh_cpu_specifics(&mut self, refresh_kind: CpuRefreshKind) {
self.inner.refresh_cpu_specifics(refresh_kind)
}
pub fn refresh_processes(&mut self) {
self.refresh_processes_specifics(
ProcessRefreshKind::new()
.with_memory()
.with_cpu()
.with_disk_usage()
.with_exe(UpdateKind::OnlyIfNotSet),
);
}
pub fn refresh_processes_specifics(&mut self, refresh_kind: ProcessRefreshKind) {
self.inner.refresh_processes_specifics(None, refresh_kind)
}
pub fn refresh_pids(&mut self, pids: &[Pid]) {
self.refresh_pids_specifics(
pids,
ProcessRefreshKind::new()
.with_memory()
.with_cpu()
.with_disk_usage()
.with_exe(UpdateKind::OnlyIfNotSet),
);
}
pub fn refresh_pids_specifics(&mut self, pids: &[Pid], refresh_kind: ProcessRefreshKind) {
if pids.is_empty() {
return;
}
self.inner
.refresh_processes_specifics(Some(pids), refresh_kind)
}
pub fn refresh_process(&mut self, pid: Pid) -> bool {
self.refresh_process_specifics(
pid,
ProcessRefreshKind::new()
.with_memory()
.with_cpu()
.with_disk_usage()
.with_exe(UpdateKind::OnlyIfNotSet),
)
}
pub fn refresh_process_specifics(
&mut self,
pid: Pid,
refresh_kind: ProcessRefreshKind,
) -> bool {
self.inner.refresh_process_specifics(pid, refresh_kind)
}
pub fn processes(&self) -> &HashMap<Pid, Process> {
self.inner.processes()
}
pub fn process(&self, pid: Pid) -> Option<&Process> {
self.inner.process(pid)
}
pub fn processes_by_name<'a: 'b, 'b>(
&'a self,
name: &'b str,
) -> impl Iterator<Item = &'a Process> + 'b {
self.processes()
.values()
.filter(move |val: &&Process| val.name().contains(name))
}
pub fn processes_by_exact_name<'a: 'b, 'b>(
&'a self,
name: &'b str,
) -> impl Iterator<Item = &'a Process> + 'b {
self.processes()
.values()
.filter(move |val: &&Process| val.name() == name)
}
pub fn global_cpu_info(&self) -> &Cpu {
self.inner.global_cpu_info()
}
pub fn cpus(&self) -> &[Cpu] {
self.inner.cpus()
}
pub fn physical_core_count(&self) -> Option<usize> {
self.inner.physical_core_count()
}
pub fn total_memory(&self) -> u64 {
self.inner.total_memory()
}
pub fn free_memory(&self) -> u64 {
self.inner.free_memory()
}
pub fn available_memory(&self) -> u64 {
self.inner.available_memory()
}
pub fn used_memory(&self) -> u64 {
self.inner.used_memory()
}
pub fn total_swap(&self) -> u64 {
self.inner.total_swap()
}
pub fn free_swap(&self) -> u64 {
self.inner.free_swap()
}
pub fn used_swap(&self) -> u64 {
self.inner.used_swap()
}
pub fn cgroup_limits(&self) -> Option<CGroupLimits> {
self.inner.cgroup_limits()
}
pub fn uptime() -> u64 {
SystemInner::uptime()
}
pub fn boot_time() -> u64 {
SystemInner::boot_time()
}
pub fn load_average() -> LoadAvg {
SystemInner::load_average()
}
pub fn name() -> Option<String> {
SystemInner::name()
}
pub fn kernel_version() -> Option<String> {
SystemInner::kernel_version()
}
pub fn os_version() -> Option<String> {
SystemInner::os_version()
}
pub fn long_os_version() -> Option<String> {
SystemInner::long_os_version()
}
pub fn distribution_id() -> String {
SystemInner::distribution_id()
}
pub fn host_name() -> Option<String> {
SystemInner::host_name()
}
pub fn cpu_arch() -> Option<String> {
SystemInner::cpu_arch()
}
}
pub struct Process {
pub(crate) inner: ProcessInner,
}
impl Process {
pub fn kill(&self) -> bool {
self.kill_with(Signal::Kill).unwrap_or(false)
}
pub fn kill_with(&self, signal: Signal) -> Option<bool> {
self.inner.kill_with(signal)
}
pub fn name(&self) -> &str {
self.inner.name()
}
pub fn cmd(&self) -> &[String] {
self.inner.cmd()
}
pub fn exe(&self) -> Option<&Path> {
self.inner.exe()
}
pub fn pid(&self) -> Pid {
self.inner.pid()
}
pub fn environ(&self) -> &[String] {
self.inner.environ()
}
pub fn cwd(&self) -> Option<&Path> {
self.inner.cwd()
}
pub fn root(&self) -> Option<&Path> {
self.inner.root()
}
pub fn memory(&self) -> u64 {
self.inner.memory()
}
pub fn virtual_memory(&self) -> u64 {
self.inner.virtual_memory()
}
pub fn parent(&self) -> Option<Pid> {
self.inner.parent()
}
pub fn status(&self) -> ProcessStatus {
self.inner.status()
}
pub fn start_time(&self) -> u64 {
self.inner.start_time()
}
pub fn run_time(&self) -> u64 {
self.inner.run_time()
}
pub fn cpu_usage(&self) -> f32 {
self.inner.cpu_usage()
}
pub fn disk_usage(&self) -> DiskUsage {
self.inner.disk_usage()
}
pub fn user_id(&self) -> Option<&Uid> {
self.inner.user_id()
}
pub fn effective_user_id(&self) -> Option<&Uid> {
self.inner.effective_user_id()
}
pub fn group_id(&self) -> Option<Gid> {
self.inner.group_id()
}
pub fn effective_group_id(&self) -> Option<Gid> {
self.inner.effective_group_id()
}
pub fn wait(&self) {
self.inner.wait()
}
pub fn session_id(&self) -> Option<Pid> {
self.inner.session_id()
}
pub fn tasks(&self) -> Option<&HashSet<Pid>> {
cfg_if::cfg_if! {
if #[cfg(all(
any(target_os = "linux", target_os = "android"),
not(feature = "unknown-ci")
))] {
self.inner.tasks.as_ref()
} else {
None
}
}
}
}
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<usize> for Pid {
fn from(v: usize) -> Self {
Self(v as _)
}
}
impl From<Pid> for usize {
fn from(v: Pid) -> Self {
v.0 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)
}
}
impl Pid {
pub fn as_u32(self) -> u32 {
self.0 as _
}
pub fn from_u32(v: u32) -> Self {
Self(v as _)
}
}
};
}
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, UpdateKind $(, $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), ", UpdateKind};
let r = ", stringify!($ty_name), "::new();
assert_eq!(r.", stringify!($name), "(), UpdateKind::Never);
let r = r.with_", stringify!($name), "(UpdateKind::OnlyIfNotSet);
assert_eq!(r.", stringify!($name), "(), UpdateKind::OnlyIfNotSet);
let r = r.without_", stringify!($name), "();
assert_eq!(r.", stringify!($name), "(), UpdateKind::Never);
```")]
pub fn $name(&self) -> UpdateKind {
self.$name
}
#[doc = concat!("Sets the value of the \"", stringify!($name), "\" refresh kind.
```
use sysinfo::{", stringify!($ty_name), ", UpdateKind};
let r = ", stringify!($ty_name), "::new();
assert_eq!(r.", stringify!($name), "(), UpdateKind::Never);
let r = r.with_", stringify!($name), "(UpdateKind::OnlyIfNotSet);
assert_eq!(r.", stringify!($name), "(), UpdateKind::OnlyIfNotSet);
```")]
#[must_use]
pub fn $with(mut self, kind: UpdateKind) -> Self {
self.$name = kind;
self
}
#[doc = concat!("Sets the value of the \"", stringify!($name), "\" refresh kind to `UpdateKind::Never`.
```
use sysinfo::{", stringify!($ty_name), ", UpdateKind};
let r = ", stringify!($ty_name), "::everything();
assert_eq!(r.", stringify!($name), "(), UpdateKind::OnlyIfNotSet);
let r = r.without_", stringify!($name), "();
assert_eq!(r.", stringify!($name), "(), UpdateKind::Never);
```")]
#[must_use]
pub fn $without(mut self) -> Self {
self.$name = UpdateKind::Never;
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 `Some(...)`.
```
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 `None`.
```
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 enum UpdateKind {
#[default]
Never,
Always,
OnlyIfNotSet,
}
impl UpdateKind {
#[allow(dead_code)] pub(crate) fn needs_update(self, f: impl Fn() -> bool) -> bool {
match self {
Self::Never => false,
Self::Always => true,
Self::OnlyIfNotSet => f(),
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct ProcessRefreshKind {
cpu: bool,
disk_usage: bool,
memory: bool,
user: UpdateKind,
cwd: UpdateKind,
root: UpdateKind,
environ: UpdateKind,
cmd: UpdateKind,
exe: UpdateKind,
}
impl ProcessRefreshKind {
pub fn new() -> Self {
Self::default()
}
pub fn everything() -> Self {
Self {
cpu: true,
disk_usage: true,
memory: true,
user: UpdateKind::OnlyIfNotSet,
cwd: UpdateKind::OnlyIfNotSet,
root: UpdateKind::OnlyIfNotSet,
environ: UpdateKind::OnlyIfNotSet,
cmd: UpdateKind::OnlyIfNotSet,
exe: UpdateKind::OnlyIfNotSet,
}
}
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,
UpdateKind,
"\
It will retrieve the following information:
* user ID
* user effective ID (if available on the platform)
* user group ID (if available on the platform)
* user effective ID (if available on the platform)"
);
impl_get_set!(ProcessRefreshKind, memory, with_memory, without_memory);
impl_get_set!(ProcessRefreshKind, cwd, with_cwd, without_cwd, UpdateKind);
impl_get_set!(
ProcessRefreshKind,
root,
with_root,
without_root,
UpdateKind
);
impl_get_set!(
ProcessRefreshKind,
environ,
with_environ,
without_environ,
UpdateKind
);
impl_get_set!(ProcessRefreshKind, cmd, with_cmd, without_cmd, UpdateKind);
impl_get_set!(ProcessRefreshKind, exe, with_exe, without_exe, UpdateKind);
}
#[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 MemoryRefreshKind {
ram: bool,
swap: bool,
}
impl MemoryRefreshKind {
pub fn new() -> Self {
Self::default()
}
pub fn everything() -> Self {
Self {
ram: true,
swap: true,
}
}
impl_get_set!(MemoryRefreshKind, ram, with_ram, without_ram);
impl_get_set!(MemoryRefreshKind, swap, with_swap, without_swap);
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct RefreshKind {
processes: Option<ProcessRefreshKind>,
memory: Option<MemoryRefreshKind>,
cpu: Option<CpuRefreshKind>,
}
impl RefreshKind {
pub fn new() -> Self {
Self::default()
}
pub fn everything() -> Self {
Self {
processes: Some(ProcessRefreshKind::everything()),
memory: Some(MemoryRefreshKind::everything()),
cpu: Some(CpuRefreshKind::everything()),
}
}
impl_get_set!(
RefreshKind,
processes,
with_processes,
without_processes,
ProcessRefreshKind
);
impl_get_set!(
RefreshKind,
memory,
with_memory,
without_memory,
MemoryRefreshKind
);
impl_get_set!(RefreshKind, cpu, with_cpu, without_cpu, CpuRefreshKind);
}
pub struct Networks {
pub(crate) inner: NetworksInner,
}
impl<'a> IntoIterator for &'a Networks {
type Item = (&'a String, &'a NetworkData);
type IntoIter = std::collections::hash_map::Iter<'a, String, NetworkData>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl Default for Networks {
fn default() -> Self {
Networks::new()
}
}
impl Networks {
pub fn new() -> Self {
Self {
inner: NetworksInner::new(),
}
}
pub fn new_with_refreshed_list() -> Self {
let mut networks = Self::new();
networks.refresh_list();
networks
}
pub fn list(&self) -> &HashMap<String, NetworkData> {
self.inner.list()
}
pub fn refresh_list(&mut self) {
self.inner.refresh_list()
}
pub fn refresh(&mut self) {
self.inner.refresh()
}
}
impl std::ops::Deref for Networks {
type Target = HashMap<String, NetworkData>;
fn deref(&self) -> &Self::Target {
self.list()
}
}
pub struct NetworkData {
pub(crate) inner: NetworkDataInner,
}
impl NetworkData {
pub fn received(&self) -> u64 {
self.inner.received()
}
pub fn total_received(&self) -> u64 {
self.inner.total_received()
}
pub fn transmitted(&self) -> u64 {
self.inner.transmitted()
}
pub fn total_transmitted(&self) -> u64 {
self.inner.total_transmitted()
}
pub fn packets_received(&self) -> u64 {
self.inner.packets_received()
}
pub fn total_packets_received(&self) -> u64 {
self.inner.total_packets_received()
}
pub fn packets_transmitted(&self) -> u64 {
self.inner.packets_transmitted()
}
pub fn total_packets_transmitted(&self) -> u64 {
self.inner.total_packets_transmitted()
}
pub fn errors_on_received(&self) -> u64 {
self.inner.errors_on_received()
}
pub fn total_errors_on_received(&self) -> u64 {
self.inner.total_errors_on_received()
}
pub fn errors_on_transmitted(&self) -> u64 {
self.inner.errors_on_transmitted()
}
pub fn total_errors_on_transmitted(&self) -> u64 {
self.inner.total_errors_on_transmitted()
}
pub fn mac_address(&self) -> MacAddr {
self.inner.mac_address()
}
}
pub struct Disk {
pub(crate) inner: crate::DiskInner,
}
impl Disk {
pub fn kind(&self) -> DiskKind {
self.inner.kind()
}
pub fn name(&self) -> &OsStr {
self.inner.name()
}
pub fn file_system(&self) -> &OsStr {
self.inner.file_system()
}
pub fn mount_point(&self) -> &Path {
self.inner.mount_point()
}
pub fn total_space(&self) -> u64 {
self.inner.total_space()
}
pub fn available_space(&self) -> u64 {
self.inner.available_space()
}
pub fn is_removable(&self) -> bool {
self.inner.is_removable()
}
pub fn refresh(&mut self) -> bool {
self.inner.refresh()
}
}
pub struct Disks {
inner: crate::DisksInner,
}
impl Default for Disks {
fn default() -> Self {
Self::new()
}
}
impl From<Disks> for Vec<Disk> {
fn from(disks: Disks) -> Vec<Disk> {
disks.inner.into_vec()
}
}
impl From<Vec<Disk>> for Disks {
fn from(disks: Vec<Disk>) -> Self {
Self {
inner: crate::DisksInner::from_vec(disks),
}
}
}
impl<'a> IntoIterator for &'a Disks {
type Item = &'a Disk;
type IntoIter = std::slice::Iter<'a, Disk>;
fn into_iter(self) -> Self::IntoIter {
self.list().iter()
}
}
impl<'a> IntoIterator for &'a mut Disks {
type Item = &'a mut Disk;
type IntoIter = std::slice::IterMut<'a, Disk>;
fn into_iter(self) -> Self::IntoIter {
self.list_mut().iter_mut()
}
}
impl Disks {
pub fn new() -> Self {
Self {
inner: crate::DisksInner::new(),
}
}
pub fn new_with_refreshed_list() -> Self {
let mut disks = Self::new();
disks.refresh_list();
disks
}
pub fn list(&self) -> &[Disk] {
self.inner.list()
}
pub fn list_mut(&mut self) -> &mut [Disk] {
self.inner.list_mut()
}
pub fn refresh(&mut self) {
for disk in self.list_mut() {
disk.refresh();
}
}
pub fn refresh_list(&mut self) {
self.inner.refresh_list();
}
}
impl std::ops::Deref for Disks {
type Target = [Disk];
fn deref(&self) -> &Self::Target {
self.list()
}
}
impl std::ops::DerefMut for Disks {
fn deref_mut(&mut self) -> &mut Self::Target {
self.list_mut()
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum DiskKind {
HDD,
SSD,
Unknown(isize),
}
impl fmt::Display for DiskKind {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
DiskKind::HDD => "HDD",
DiskKind::SSD => "SSD",
_ => "Unknown",
})
}
}
pub struct Users {
users: Vec<User>,
}
impl Default for Users {
fn default() -> Self {
Self::new()
}
}
impl From<Users> for Vec<User> {
fn from(users: Users) -> Self {
users.users
}
}
impl From<Vec<User>> for Users {
fn from(users: Vec<User>) -> Self {
Self { users }
}
}
impl std::ops::Deref for Users {
type Target = [User];
fn deref(&self) -> &Self::Target {
self.list()
}
}
impl std::ops::DerefMut for Users {
fn deref_mut(&mut self) -> &mut Self::Target {
self.list_mut()
}
}
impl<'a> IntoIterator for &'a Users {
type Item = &'a User;
type IntoIter = std::slice::Iter<'a, User>;
fn into_iter(self) -> Self::IntoIter {
self.list().iter()
}
}
impl<'a> IntoIterator for &'a mut Users {
type Item = &'a mut User;
type IntoIter = std::slice::IterMut<'a, User>;
fn into_iter(self) -> Self::IntoIter {
self.list_mut().iter_mut()
}
}
impl Users {
pub fn new() -> Self {
Self { users: Vec::new() }
}
pub fn new_with_refreshed_list() -> Self {
let mut users = Self::new();
users.refresh_list();
users
}
pub fn list(&self) -> &[User] {
&self.users
}
pub fn list_mut(&mut self) -> &mut [User] {
&mut self.users
}
pub fn refresh_list(&mut self) {
crate::sys::get_users(&mut self.users);
}
pub fn get_user_by_id(&self, user_id: &Uid) -> Option<&User> {
self.users.iter().find(|user| user.id() == user_id)
}
}
#[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)
}
}
#[derive(Default, Debug, Clone)]
pub struct CGroupLimits {
pub total_memory: u64,
pub free_memory: u64,
pub free_swap: u64,
}
#[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 $(, $trait:ty)?) => {
$(#[$outer])+
#[repr(transparent)]
#[derive(Clone, PartialEq, Eq, Hash, 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
}
}
$(
impl TryFrom<usize> for $name {
type Error = <$type as TryFrom<usize>>::Error;
fn try_from(t: usize) -> Result<Self, <$type as TryFrom<usize>>::Error> {
Ok(Self(<$type>::try_from(t)?))
}
}
impl $trait for $name {
type Err = <$type as FromStr>::Err;
fn from_str(t: &str) -> Result<Self, <$type as FromStr>::Err> {
Ok(Self(<$type>::from_str(t)?))
}
}
)?
};
}
macro_rules! uid {
($type:ty$(, $trait:ty)?) => {
xid!(
Uid,
$type
$(, $trait)?
);
};
}
macro_rules! gid {
($type:ty) => {
xid!(
#[derive(Copy)]
Gid,
$type,
FromStr
);
};
}
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, FromStr);
gid!(libc::gid_t);
} else if #[cfg(windows)] {
uid!(crate::windows::Sid);
gid!(u32);
impl FromStr for Uid {
type Err = <crate::windows::Sid as FromStr>::Err;
fn from_str(t: &str) -> Result<Self, Self::Err> {
Ok(Self(t.parse()?))
}
}
} else {
uid!(u32, FromStr);
gid!(u32);
}
}
pub struct User {
pub(crate) inner: UserInner,
}
impl PartialEq for User {
fn eq(&self, other: &Self) -> bool {
self.id() == other.id()
&& self.group_id() == other.group_id()
&& self.name() == other.name()
}
}
impl Eq for User {}
impl PartialOrd for User {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for User {
fn cmp(&self, other: &Self) -> Ordering {
self.name().cmp(other.name())
}
}
impl User {
pub fn id(&self) -> &Uid {
self.inner.id()
}
pub fn group_id(&self) -> Gid {
self.inner.group_id()
}
pub fn name(&self) -> &str {
self.inner.name()
}
pub fn groups(&self) -> Vec<Group> {
self.inner.groups()
}
}
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Group {
pub(crate) id: Gid,
pub(crate) name: String,
}
impl Group {
pub fn id(&self) -> &Gid {
&self.id
}
pub fn name(&self) -> &str {
&self.name
}
}
#[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,
UninterruptibleDiskSleep,
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 windows::Win32::System::Threading::GetCurrentProcessId;
unsafe { Ok(Pid(GetCurrentProcessId() as _)) }
}
} else {
fn inner() -> Result<Pid, &'static str> {
Err("Unknown platform")
}
}
}
inner()
}
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct MacAddr(pub [u8; 6]);
impl MacAddr {
pub const UNSPECIFIED: Self = MacAddr([0; 6]);
pub fn is_unspecified(&self) -> bool {
self == &MacAddr::UNSPECIFIED
}
}
impl fmt::Display for MacAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let data = &self.0;
write!(
f,
"{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
data[0], data[1], data[2], data[3], data[4], data[5],
)
}
}
pub struct Components {
pub(crate) inner: ComponentsInner,
}
impl Default for Components {
fn default() -> Self {
Self::new()
}
}
impl From<Components> for Vec<Component> {
fn from(components: Components) -> Self {
components.inner.into_vec()
}
}
impl From<Vec<Component>> for Components {
fn from(components: Vec<Component>) -> Self {
Self {
inner: ComponentsInner::from_vec(components),
}
}
}
impl std::ops::Deref for Components {
type Target = [Component];
fn deref(&self) -> &Self::Target {
self.list()
}
}
impl std::ops::DerefMut for Components {
fn deref_mut(&mut self) -> &mut Self::Target {
self.list_mut()
}
}
impl<'a> IntoIterator for &'a Components {
type Item = &'a Component;
type IntoIter = std::slice::Iter<'a, Component>;
fn into_iter(self) -> Self::IntoIter {
self.list().iter()
}
}
impl<'a> IntoIterator for &'a mut Components {
type Item = &'a mut Component;
type IntoIter = std::slice::IterMut<'a, Component>;
fn into_iter(self) -> Self::IntoIter {
self.list_mut().iter_mut()
}
}
impl Components {
pub fn new() -> Self {
Self {
inner: ComponentsInner::new(),
}
}
pub fn new_with_refreshed_list() -> Self {
let mut components = Self::new();
components.refresh_list();
components
}
pub fn list(&self) -> &[Component] {
self.inner.list()
}
pub fn list_mut(&mut self) -> &mut [Component] {
self.inner.list_mut()
}
pub fn refresh(&mut self) {
for component in self.list_mut() {
component.refresh();
}
}
pub fn refresh_list(&mut self) {
self.inner.refresh_list()
}
}
pub struct Component {
pub(crate) inner: ComponentInner,
}
impl Component {
pub fn temperature(&self) -> f32 {
self.inner.temperature()
}
pub fn max(&self) -> f32 {
self.inner.max()
}
pub fn critical(&self) -> Option<f32> {
self.inner.critical()
}
pub fn label(&self) -> &str {
self.inner.label()
}
pub fn refresh(&mut self) {
self.inner.refresh()
}
}
pub struct Cpu {
pub(crate) inner: CpuInner,
}
impl Cpu {
pub fn cpu_usage(&self) -> f32 {
self.inner.cpu_usage()
}
pub fn name(&self) -> &str {
self.inner.name()
}
pub fn vendor_id(&self) -> &str {
self.inner.vendor_id()
}
pub fn brand(&self) -> &str {
self.inner.brand()
}
pub fn frequency(&self) -> u64 {
self.inner.frequency()
}
}