monitrs_core/model/
identity.rs1use core::fmt;
9
10#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct ProcessIdentity {
24 pub pid: u32,
26 pub start_key: u64,
28}
29
30impl ProcessIdentity {
31 #[must_use]
33 pub const fn new(pid: u32, start_key: u64) -> Self {
34 Self { pid, start_key }
35 }
36
37 #[must_use]
43 pub const fn is_reuse_of(&self, other: &Self) -> bool {
44 self.pid == other.pid && self.start_key != other.start_key
45 }
46}
47
48impl fmt::Display for ProcessIdentity {
49 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 write!(f, "{}", self.pid)
53 }
54}
55
56#[derive(Clone, Debug, Eq, PartialEq)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
59pub struct UserIdentity {
60 pub uid: u32,
62 pub name: Option<Box<str>>,
67}
68
69impl UserIdentity {
70 #[must_use]
72 pub fn display_name(&self) -> String {
73 match &self.name {
74 Some(name) => name.to_string(),
75 None => self.uid.to_string(),
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn identity_requires_both_pid_and_start_key_to_match() {
86 let a = ProcessIdentity::new(31842, 900_100);
87 let b = ProcessIdentity::new(31842, 900_100);
88 let recycled = ProcessIdentity::new(31842, 977_400);
89 let other = ProcessIdentity::new(1221, 900_100);
90
91 assert_eq!(a, b);
92 assert_ne!(a, recycled);
93 assert_ne!(a, other);
94 }
95
96 #[test]
97 fn pid_reuse_is_detected_and_a_different_pid_is_not_reuse() {
98 let pinned = ProcessIdentity::new(31842, 900_100);
99 let recycled = ProcessIdentity::new(31842, 977_400);
100 let unrelated = ProcessIdentity::new(1221, 977_400);
101
102 assert!(
103 recycled.is_reuse_of(&pinned),
104 "same PID, different start key"
105 );
106 assert!(!pinned.is_reuse_of(&pinned), "identical is not reuse");
107 assert!(
108 !unrelated.is_reuse_of(&pinned),
109 "different PID is not reuse"
110 );
111 }
112
113 #[test]
114 fn display_shows_only_the_pid() {
115 assert_eq!(ProcessIdentity::new(31842, 900_100).to_string(), "31842");
116 }
117
118 #[test]
119 fn unresolvable_user_names_fall_back_to_the_numeric_id() {
120 let named = UserIdentity {
121 uid: 501,
122 name: Some("gabor".into()),
123 };
124 let anonymous = UserIdentity {
125 uid: 501,
126 name: None,
127 };
128 assert_eq!(named.display_name(), "gabor");
129 assert_eq!(anonymous.display_name(), "501");
130 }
131}