use std::{fmt, num::NonZeroU32, process::Child};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub struct ProcessId(NonZeroU32);
impl ProcessId {
pub const fn new(pid: u32) -> Option<Self> {
match NonZeroU32::new(pid) {
Some(pid) => Some(Self(pid)),
None => None,
}
}
pub fn current() -> Self {
Self::new(std::process::id()).expect("a running process has a nonzero PID")
}
pub fn of(child: &Child) -> Self {
Self::new(child.id()).expect("a spawned child has a nonzero PID")
}
pub const fn get(self) -> u32 {
self.0.get()
}
}
impl fmt::Display for ProcessId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn pid_zero_is_not_a_process() {
assert_eq!(ProcessId::new(0), None);
assert_eq!(ProcessId::new(7).unwrap().get(), 7);
assert_eq!(ProcessId::new(7).unwrap().to_string(), "7");
}
#[test]
fn current_and_child_pids_come_from_the_os() {
assert_eq!(ProcessId::current().get(), std::process::id());
let mut child = std::process::Command::new(std::env::current_exe().unwrap())
.arg("--list")
.stdout(std::process::Stdio::null())
.spawn()
.unwrap();
assert_eq!(ProcessId::of(&child).get(), child.id());
child.wait().unwrap();
}
}