Skip to main content

kunobi_daemon/
pid.rs

1//! A nonzero operating-system process ID, used wherever the crate names a
2//! process.
3
4use std::{fmt, num::NonZeroU32, process::Child};
5
6/// A nonzero operating-system process ID.
7///
8/// PID 0 names no single process: on Unix it addresses the caller's process
9/// group, so every API that signals, watches or compares a process takes this
10/// type instead of a raw `u32`.
11#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
12pub struct ProcessId(NonZeroU32);
13
14impl ProcessId {
15    /// `None` for PID 0.
16    pub const fn new(pid: u32) -> Option<Self> {
17        match NonZeroU32::new(pid) {
18            Some(pid) => Some(Self(pid)),
19            None => None,
20        }
21    }
22
23    /// This process.
24    pub fn current() -> Self {
25        Self::new(std::process::id()).expect("a running process has a nonzero PID")
26    }
27
28    /// A child this process spawned.
29    pub fn of(child: &Child) -> Self {
30        Self::new(child.id()).expect("a spawned child has a nonzero PID")
31    }
32
33    /// The raw PID.
34    pub const fn get(self) -> u32 {
35        self.0.get()
36    }
37}
38
39impl fmt::Display for ProcessId {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        self.0.fmt(f)
42    }
43}
44
45#[cfg(test)]
46mod tests {
47    use super::*;
48
49    #[test]
50    fn pid_zero_is_not_a_process() {
51        assert_eq!(ProcessId::new(0), None);
52        assert_eq!(ProcessId::new(7).unwrap().get(), 7);
53        assert_eq!(ProcessId::new(7).unwrap().to_string(), "7");
54    }
55
56    #[test]
57    fn current_and_child_pids_come_from_the_os() {
58        assert_eq!(ProcessId::current().get(), std::process::id());
59        let mut child = std::process::Command::new(std::env::current_exe().unwrap())
60            .arg("--list")
61            .stdout(std::process::Stdio::null())
62            .spawn()
63            .unwrap();
64        assert_eq!(ProcessId::of(&child).get(), child.id());
65        child.wait().unwrap();
66    }
67}