Skip to main content

mtl_gpu/device/
architecture.rs

1//! GPU architecture information.
2//!
3//! Corresponds to `MTL::Architecture` in `Metal/MTLDevice.hpp`.
4
5use std::ffi::c_void;
6use std::ptr::NonNull;
7
8use mtl_foundation::{Copying, Referencing};
9use mtl_sys::{class, msg_send_0, sel};
10
11/// GPU architecture information.
12///
13/// C++ equivalent: `MTL::Architecture`
14#[repr(transparent)]
15pub struct Architecture(NonNull<c_void>);
16
17impl Architecture {
18    /// Create an Architecture from a raw pointer.
19    ///
20    /// # Safety
21    ///
22    /// The pointer must be a valid MTLArchitecture object.
23    #[inline]
24    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
25        NonNull::new(ptr).map(Self)
26    }
27
28    /// Allocate a new Architecture instance.
29    ///
30    /// C++ equivalent: `static Architecture* alloc()`
31    #[inline]
32    pub fn alloc() -> Option<Self> {
33        unsafe {
34            let cls = class!(MTLArchitecture);
35            let ptr: *mut c_void = msg_send_0(cls.as_ptr(), sel!(alloc));
36            Self::from_raw(ptr)
37        }
38    }
39
40    /// Initialize an allocated Architecture.
41    ///
42    /// C++ equivalent: `Architecture* init()`
43    #[inline]
44    pub fn init(self) -> Option<Self> {
45        unsafe {
46            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(init));
47            // Consume self without releasing
48            std::mem::forget(self);
49            Self::from_raw(ptr)
50        }
51    }
52
53    /// Get the architecture name.
54    ///
55    /// C++ equivalent: `NS::String* name() const`
56    #[inline]
57    pub fn name(&self) -> &str {
58        unsafe {
59            let ns_string: *mut c_void = msg_send_0(self.as_ptr(), sel!(name));
60            if ns_string.is_null() {
61                return "";
62            }
63            // Get UTF-8 bytes from NSString
64            let c_str: *const std::ffi::c_char = msg_send_0(ns_string, sel!(UTF8String));
65            if c_str.is_null() {
66                return "";
67            }
68            std::ffi::CStr::from_ptr(c_str).to_str().unwrap_or("")
69        }
70    }
71}
72
73impl Clone for Architecture {
74    fn clone(&self) -> Self {
75        self.retain();
76        Self(self.0)
77    }
78}
79
80impl Referencing for Architecture {
81    #[inline]
82    fn as_ptr(&self) -> *const c_void {
83        self.0.as_ptr()
84    }
85}
86
87impl Copying for Architecture {
88    fn copy(&self) -> Option<Self> {
89        unsafe {
90            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
91            Self::from_raw(ptr)
92        }
93    }
94}
95
96impl Drop for Architecture {
97    fn drop(&mut self) {
98        self.release();
99    }
100}
101
102// SAFETY: Architecture is an immutable value object
103unsafe impl Send for Architecture {}
104unsafe impl Sync for Architecture {}
105
106impl std::fmt::Debug for Architecture {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        f.debug_struct("Architecture")
109            .field("name", &self.name())
110            .finish()
111    }
112}
113
114impl std::fmt::Display for Architecture {
115    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116        write!(f, "{}", self.name())
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123
124    #[test]
125    fn test_architecture_size() {
126        assert_eq!(
127            std::mem::size_of::<Architecture>(),
128            std::mem::size_of::<*mut c_void>()
129        );
130    }
131}