Skip to main content

mtl_foundation/
process_info.rs

1//! Process information for Foundation.
2//!
3//! Corresponds to `Foundation/NSProcessInfo.hpp`.
4//!
5//! # C++ Equivalent
6//!
7//! ```cpp
8//! namespace NS {
9//! _NS_ENUM(NS::Integer, ProcessInfoThermalState) {
10//!     ProcessInfoThermalStateNominal = 0,
11//!     ProcessInfoThermalStateFair = 1,
12//!     ProcessInfoThermalStateSerious = 2,
13//!     ProcessInfoThermalStateCritical = 3
14//! };
15//!
16//! _NS_OPTIONS(std::uint64_t, ActivityOptions) { ... };
17//!
18//! class ProcessInfo : public Referencing<ProcessInfo> {
19//! public:
20//!     static ProcessInfo*     processInfo();
21//!     class Array*            arguments() const;
22//!     class Dictionary*       environment() const;
23//!     // ... many more methods
24//! };
25//! }
26//! ```
27
28use std::ffi::c_void;
29use std::ptr::NonNull;
30
31use mtl_sys::{class, msg_send_0, msg_send_1, msg_send_2, sel};
32
33use crate::array::Array;
34use crate::dictionary::Dictionary;
35use crate::object::{Object, Referencing};
36use crate::string::String;
37use crate::types::{Integer, OperatingSystemVersion, TimeInterval, UInteger};
38
39/// Thermal state of the system.
40///
41/// C++ equivalent: `NS::ProcessInfoThermalState`
42#[repr(transparent)]
43#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
44pub struct ProcessInfoThermalState(pub Integer);
45
46impl ProcessInfoThermalState {
47    /// Nominal thermal state.
48    pub const NOMINAL: Self = Self(0);
49    /// Fair thermal state.
50    pub const FAIR: Self = Self(1);
51    /// Serious thermal state.
52    pub const SERIOUS: Self = Self(2);
53    /// Critical thermal state.
54    pub const CRITICAL: Self = Self(3);
55}
56
57/// Activity options for process activities.
58///
59/// C++ equivalent: `NS::ActivityOptions`
60#[repr(transparent)]
61#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
62pub struct ActivityOptions(pub u64);
63
64impl ActivityOptions {
65    /// Disable idle display sleep.
66    pub const IDLE_DISPLAY_SLEEP_DISABLED: Self = Self(1 << 40);
67    /// Disable idle system sleep.
68    pub const IDLE_SYSTEM_SLEEP_DISABLED: Self = Self(1 << 20);
69    /// Disable sudden termination.
70    pub const SUDDEN_TERMINATION_DISABLED: Self = Self(1 << 14);
71    /// Disable automatic termination.
72    pub const AUTOMATIC_TERMINATION_DISABLED: Self = Self(1 << 15);
73    /// User-initiated activity.
74    pub const USER_INITIATED: Self = Self(0x00FFFFFF | (1 << 20));
75    /// User-initiated activity allowing idle system sleep.
76    pub const USER_INITIATED_ALLOWING_IDLE_SYSTEM_SLEEP: Self = Self(0x00FFFFFF);
77    /// Background activity.
78    pub const BACKGROUND: Self = Self(0x000000FF);
79    /// Latency-critical activity.
80    pub const LATENCY_CRITICAL: Self = Self(0xFF00000000);
81
82    /// Returns the raw bits.
83    #[inline]
84    pub const fn bits(&self) -> u64 {
85        self.0
86    }
87
88    /// Creates from raw bits.
89    #[inline]
90    pub const fn from_bits(bits: u64) -> Self {
91        Self(bits)
92    }
93}
94
95impl std::ops::BitOr for ActivityOptions {
96    type Output = Self;
97    #[inline]
98    fn bitor(self, rhs: Self) -> Self {
99        Self(self.0 | rhs.0)
100    }
101}
102
103impl std::ops::BitAnd for ActivityOptions {
104    type Output = Self;
105    #[inline]
106    fn bitand(self, rhs: Self) -> Self {
107        Self(self.0 & rhs.0)
108    }
109}
110
111/// Device certification type.
112///
113/// C++ equivalent: `NS::DeviceCertification`
114pub type DeviceCertification = Integer;
115
116/// Process performance profile type.
117///
118/// C++ equivalent: `NS::ProcessPerformanceProfile`
119pub type ProcessPerformanceProfile = Integer;
120
121/// An Objective-C process info object.
122///
123/// C++ equivalent: `NS::ProcessInfo`
124#[repr(transparent)]
125#[derive(Clone)]
126pub struct ProcessInfo(NonNull<c_void>);
127
128impl ProcessInfo {
129    /// Get the process info singleton.
130    ///
131    /// C++ equivalent: `static ProcessInfo* processInfo()`
132    #[inline]
133    pub fn process_info() -> Option<Self> {
134        unsafe {
135            let ptr: *mut c_void = msg_send_0(class!(NSProcessInfo).as_ptr(), sel!(processInfo));
136            Self::from_ptr(ptr)
137        }
138    }
139
140    /// Get the command-line arguments.
141    ///
142    /// C++ equivalent: `class Array* arguments() const`
143    #[inline]
144    pub fn arguments(&self) -> *mut Array<String> {
145        unsafe { msg_send_0(self.as_ptr(), sel!(arguments)) }
146    }
147
148    /// Get the environment dictionary.
149    ///
150    /// C++ equivalent: `class Dictionary* environment() const`
151    #[inline]
152    pub fn environment(&self) -> *mut Dictionary {
153        unsafe { msg_send_0(self.as_ptr(), sel!(environment)) }
154    }
155
156    /// Get the host name.
157    ///
158    /// C++ equivalent: `class String* hostName() const`
159    #[inline]
160    pub fn host_name(&self) -> *mut String {
161        unsafe { msg_send_0(self.as_ptr(), sel!(hostName)) }
162    }
163
164    /// Get the process name.
165    ///
166    /// C++ equivalent: `class String* processName() const`
167    #[inline]
168    pub fn process_name(&self) -> *mut String {
169        unsafe { msg_send_0(self.as_ptr(), sel!(processName)) }
170    }
171
172    /// Set the process name.
173    ///
174    /// C++ equivalent: `void setProcessName(const String* pString)`
175    #[inline]
176    pub fn set_process_name(&self, name: &String) {
177        unsafe {
178            let _: () = msg_send_1(self.as_ptr(), sel!(setProcessName:), name.as_ptr());
179        }
180    }
181
182    /// Get the process identifier.
183    ///
184    /// C++ equivalent: `int processIdentifier() const`
185    #[inline]
186    pub fn process_identifier(&self) -> i32 {
187        unsafe { msg_send_0(self.as_ptr(), sel!(processIdentifier)) }
188    }
189
190    /// Get a globally unique string.
191    ///
192    /// C++ equivalent: `class String* globallyUniqueString() const`
193    #[inline]
194    pub fn globally_unique_string(&self) -> *mut String {
195        unsafe { msg_send_0(self.as_ptr(), sel!(globallyUniqueString)) }
196    }
197
198    /// Get the user name.
199    #[inline]
200    pub fn user_name(&self) -> *mut String {
201        unsafe { msg_send_0(self.as_ptr(), sel!(userName)) }
202    }
203
204    /// Get the full user name.
205    #[inline]
206    pub fn full_user_name(&self) -> *mut String {
207        unsafe { msg_send_0(self.as_ptr(), sel!(fullUserName)) }
208    }
209
210    /// Get the operating system identifier.
211    ///
212    /// C++ equivalent: `UInteger operatingSystem() const`
213    #[inline]
214    pub fn operating_system(&self) -> UInteger {
215        unsafe { msg_send_0(self.as_ptr(), sel!(operatingSystem)) }
216    }
217
218    /// Get the operating system version.
219    ///
220    /// C++ equivalent: `OperatingSystemVersion operatingSystemVersion() const`
221    #[inline]
222    pub fn operating_system_version(&self) -> OperatingSystemVersion {
223        unsafe { msg_send_0(self.as_ptr(), sel!(operatingSystemVersion)) }
224    }
225
226    /// Get the operating system version string.
227    ///
228    /// C++ equivalent: `class String* operatingSystemVersionString() const`
229    #[inline]
230    pub fn operating_system_version_string(&self) -> *mut String {
231        unsafe { msg_send_0(self.as_ptr(), sel!(operatingSystemVersionString)) }
232    }
233
234    /// Check if the operating system is at least a given version.
235    ///
236    /// C++ equivalent: `bool isOperatingSystemAtLeastVersion(OperatingSystemVersion version) const`
237    #[inline]
238    pub fn is_operating_system_at_least_version(&self, version: OperatingSystemVersion) -> bool {
239        unsafe {
240            msg_send_1(
241                self.as_ptr(),
242                sel!(isOperatingSystemAtLeastVersion:),
243                version,
244            )
245        }
246    }
247
248    /// Get the processor count.
249    ///
250    /// C++ equivalent: `UInteger processorCount() const`
251    #[inline]
252    pub fn processor_count(&self) -> UInteger {
253        unsafe { msg_send_0(self.as_ptr(), sel!(processorCount)) }
254    }
255
256    /// Get the active processor count.
257    ///
258    /// C++ equivalent: `UInteger activeProcessorCount() const`
259    #[inline]
260    pub fn active_processor_count(&self) -> UInteger {
261        unsafe { msg_send_0(self.as_ptr(), sel!(activeProcessorCount)) }
262    }
263
264    /// Get the physical memory size.
265    ///
266    /// C++ equivalent: `unsigned long long physicalMemory() const`
267    #[inline]
268    pub fn physical_memory(&self) -> u64 {
269        unsafe { msg_send_0(self.as_ptr(), sel!(physicalMemory)) }
270    }
271
272    /// Get the system uptime.
273    ///
274    /// C++ equivalent: `TimeInterval systemUptime() const`
275    #[inline]
276    pub fn system_uptime(&self) -> TimeInterval {
277        unsafe { msg_send_0(self.as_ptr(), sel!(systemUptime)) }
278    }
279
280    /// Disable sudden termination.
281    ///
282    /// C++ equivalent: `void disableSuddenTermination()`
283    #[inline]
284    pub fn disable_sudden_termination(&self) {
285        unsafe {
286            msg_send_0::<()>(self.as_ptr(), sel!(disableSuddenTermination));
287        }
288    }
289
290    /// Enable sudden termination.
291    ///
292    /// C++ equivalent: `void enableSuddenTermination()`
293    #[inline]
294    pub fn enable_sudden_termination(&self) {
295        unsafe {
296            msg_send_0::<()>(self.as_ptr(), sel!(enableSuddenTermination));
297        }
298    }
299
300    /// Disable automatic termination.
301    ///
302    /// C++ equivalent: `void disableAutomaticTermination(const class String* pReason)`
303    #[inline]
304    pub fn disable_automatic_termination(&self, reason: &String) {
305        unsafe {
306            let _: () = msg_send_1(
307                self.as_ptr(),
308                sel!(disableAutomaticTermination:),
309                reason.as_ptr(),
310            );
311        }
312    }
313
314    /// Enable automatic termination.
315    ///
316    /// C++ equivalent: `void enableAutomaticTermination(const class String* pReason)`
317    #[inline]
318    pub fn enable_automatic_termination(&self, reason: &String) {
319        unsafe {
320            let _: () = msg_send_1(
321                self.as_ptr(),
322                sel!(enableAutomaticTermination:),
323                reason.as_ptr(),
324            );
325        }
326    }
327
328    /// Check if automatic termination support is enabled.
329    ///
330    /// C++ equivalent: `bool automaticTerminationSupportEnabled() const`
331    #[inline]
332    pub fn automatic_termination_support_enabled(&self) -> bool {
333        unsafe { msg_send_0(self.as_ptr(), sel!(automaticTerminationSupportEnabled)) }
334    }
335
336    /// Set automatic termination support enabled.
337    ///
338    /// C++ equivalent: `void setAutomaticTerminationSupportEnabled(bool enabled)`
339    #[inline]
340    pub fn set_automatic_termination_support_enabled(&self, enabled: bool) {
341        unsafe {
342            let _: () = msg_send_1(
343                self.as_ptr(),
344                sel!(setAutomaticTerminationSupportEnabled:),
345                enabled,
346            );
347        }
348    }
349
350    /// Begin an activity.
351    ///
352    /// C++ equivalent: `class Object* beginActivity(ActivityOptions options, const class String* pReason)`
353    #[inline]
354    pub fn begin_activity(&self, options: ActivityOptions, reason: &String) -> *mut Object {
355        unsafe {
356            msg_send_2(
357                self.as_ptr(),
358                sel!(beginActivityWithOptions:reason:),
359                options.0,
360                reason.as_ptr(),
361            )
362        }
363    }
364
365    /// End an activity.
366    ///
367    /// C++ equivalent: `void endActivity(class Object* pActivity)`
368    #[inline]
369    pub fn end_activity(&self, activity: &Object) {
370        unsafe {
371            let _: () = msg_send_1(self.as_ptr(), sel!(endActivity:), activity.as_ptr());
372        }
373    }
374
375    /// Get the thermal state.
376    ///
377    /// C++ equivalent: `ProcessInfoThermalState thermalState() const`
378    #[inline]
379    pub fn thermal_state(&self) -> ProcessInfoThermalState {
380        unsafe { msg_send_0(self.as_ptr(), sel!(thermalState)) }
381    }
382
383    /// Check if low power mode is enabled.
384    ///
385    /// C++ equivalent: `bool isLowPowerModeEnabled() const`
386    #[inline]
387    pub fn is_low_power_mode_enabled(&self) -> bool {
388        unsafe { msg_send_0(self.as_ptr(), sel!(isLowPowerModeEnabled)) }
389    }
390
391    /// Check if this is an iOS app running on Mac.
392    ///
393    /// C++ equivalent: `bool isiOSAppOnMac() const`
394    #[inline]
395    pub fn is_ios_app_on_mac(&self) -> bool {
396        unsafe { msg_send_0(self.as_ptr(), sel!(isiOSAppOnMac)) }
397    }
398
399    /// Check if this is a Mac Catalyst app.
400    ///
401    /// C++ equivalent: `bool isMacCatalystApp() const`
402    #[inline]
403    pub fn is_mac_catalyst_app(&self) -> bool {
404        unsafe { msg_send_0(self.as_ptr(), sel!(isMacCatalystApp)) }
405    }
406
407    /// Check if the device is certified.
408    ///
409    /// C++ equivalent: `bool isDeviceCertified(DeviceCertification performanceTier) const`
410    #[inline]
411    pub fn is_device_certified(&self, performance_tier: DeviceCertification) -> bool {
412        unsafe { msg_send_1(self.as_ptr(), sel!(isDeviceCertified:), performance_tier) }
413    }
414
415    /// Check if the process has a performance profile.
416    ///
417    /// C++ equivalent: `bool hasPerformanceProfile(ProcessPerformanceProfile performanceProfile) const`
418    #[inline]
419    pub fn has_performance_profile(&self, performance_profile: ProcessPerformanceProfile) -> bool {
420        unsafe {
421            msg_send_1(
422                self.as_ptr(),
423                sel!(hasPerformanceProfile:),
424                performance_profile,
425            )
426        }
427    }
428
429    /// Create a ProcessInfo from a raw pointer.
430    ///
431    /// # Safety
432    ///
433    /// The pointer must be a valid Objective-C NSProcessInfo object.
434    #[inline]
435    pub unsafe fn from_ptr(ptr: *mut c_void) -> Option<Self> {
436        NonNull::new(ptr).map(Self)
437    }
438}
439
440impl Referencing for ProcessInfo {
441    #[inline]
442    fn as_ptr(&self) -> *const c_void {
443        self.0.as_ptr()
444    }
445}
446
447unsafe impl Send for ProcessInfo {}
448unsafe impl Sync for ProcessInfo {}
449
450impl std::fmt::Debug for ProcessInfo {
451    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
452        f.debug_struct("ProcessInfo").field("ptr", &self.0).finish()
453    }
454}
455
456#[cfg(test)]
457mod tests {
458    use super::*;
459
460    #[test]
461    fn test_process_info_size() {
462        assert_eq!(
463            std::mem::size_of::<ProcessInfo>(),
464            std::mem::size_of::<*mut c_void>()
465        );
466    }
467
468    #[test]
469    fn test_thermal_state_values() {
470        assert_eq!(ProcessInfoThermalState::NOMINAL.0, 0);
471        assert_eq!(ProcessInfoThermalState::FAIR.0, 1);
472        assert_eq!(ProcessInfoThermalState::SERIOUS.0, 2);
473        assert_eq!(ProcessInfoThermalState::CRITICAL.0, 3);
474    }
475}