Skip to main content

mtl_gpu/
function_log.rs

1//! Function log types.
2//!
3//! Corresponds to `Metal/MTLFunctionLog.hpp`.
4//!
5//! These types provide access to validation and debug information
6//! from shader function execution.
7
8use std::ffi::c_void;
9use std::ptr::NonNull;
10
11use mtl_foundation::{Referencing, UInteger};
12use mtl_sys::{msg_send_0, sel};
13
14use crate::enums::FunctionLogType;
15use crate::library::Function;
16
17// ============================================================================
18// LogContainer
19// ============================================================================
20
21/// A container for function logs.
22///
23/// C++ equivalent: `MTL::LogContainer`
24///
25/// This is an opaque container that holds function log entries.
26/// It conforms to FastEnumeration in Objective-C, which maps to
27/// iteration in Rust.
28#[repr(transparent)]
29pub struct LogContainer(pub(crate) NonNull<c_void>);
30
31impl LogContainer {
32    /// Create from a raw pointer.
33    #[inline]
34    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
35        NonNull::new(ptr).map(Self)
36    }
37
38    /// Get the raw pointer.
39    #[inline]
40    pub fn as_raw(&self) -> *mut c_void {
41        self.0.as_ptr()
42    }
43}
44
45impl Clone for LogContainer {
46    fn clone(&self) -> Self {
47        unsafe {
48            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
49        }
50        Self(self.0)
51    }
52}
53
54impl Drop for LogContainer {
55    fn drop(&mut self) {
56        unsafe {
57            msg_send_0::<()>(self.as_ptr(), sel!(release));
58        }
59    }
60}
61
62impl Referencing for LogContainer {
63    #[inline]
64    fn as_ptr(&self) -> *const c_void {
65        self.0.as_ptr()
66    }
67}
68
69unsafe impl Send for LogContainer {}
70unsafe impl Sync for LogContainer {}
71
72// ============================================================================
73// FunctionLogDebugLocation
74// ============================================================================
75
76/// Debug location information for a function log entry.
77///
78/// C++ equivalent: `MTL::FunctionLogDebugLocation`
79///
80/// Contains source file location information including URL, line number,
81/// column number, and function name.
82#[repr(transparent)]
83pub struct FunctionLogDebugLocation(pub(crate) NonNull<c_void>);
84
85impl FunctionLogDebugLocation {
86    /// Create from a raw pointer.
87    #[inline]
88    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
89        NonNull::new(ptr).map(Self)
90    }
91
92    /// Get the raw pointer.
93    #[inline]
94    pub fn as_raw(&self) -> *mut c_void {
95        self.0.as_ptr()
96    }
97
98    /// Get the source file URL.
99    ///
100    /// C++ equivalent: `NS::URL* URL() const`
101    pub fn url(&self) -> Option<String> {
102        unsafe {
103            let url_ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(URL));
104            if url_ptr.is_null() {
105                return None;
106            }
107            // Get absoluteString from NSURL
108            let str_ptr: *mut c_void = msg_send_0(url_ptr, sel!(absoluteString));
109            if str_ptr.is_null() {
110                return None;
111            }
112            let utf8_ptr: *const std::ffi::c_char =
113                mtl_sys::msg_send_0(str_ptr, sel!(UTF8String));
114            if utf8_ptr.is_null() {
115                return None;
116            }
117            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
118            Some(c_str.to_string_lossy().into_owned())
119        }
120    }
121
122    /// Get the line number.
123    ///
124    /// C++ equivalent: `NS::UInteger line() const`
125    #[inline]
126    pub fn line(&self) -> UInteger {
127        unsafe { msg_send_0(self.as_ptr(), sel!(line)) }
128    }
129
130    /// Get the column number.
131    ///
132    /// C++ equivalent: `NS::UInteger column() const`
133    #[inline]
134    pub fn column(&self) -> UInteger {
135        unsafe { msg_send_0(self.as_ptr(), sel!(column)) }
136    }
137
138    /// Get the function name.
139    ///
140    /// C++ equivalent: `NS::String* functionName() const`
141    pub fn function_name(&self) -> Option<String> {
142        unsafe {
143            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(functionName));
144            if ptr.is_null() {
145                return None;
146            }
147            let utf8_ptr: *const std::ffi::c_char =
148                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
149            if utf8_ptr.is_null() {
150                return None;
151            }
152            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
153            Some(c_str.to_string_lossy().into_owned())
154        }
155    }
156}
157
158impl Clone for FunctionLogDebugLocation {
159    fn clone(&self) -> Self {
160        unsafe {
161            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
162        }
163        Self(self.0)
164    }
165}
166
167impl Drop for FunctionLogDebugLocation {
168    fn drop(&mut self) {
169        unsafe {
170            msg_send_0::<()>(self.as_ptr(), sel!(release));
171        }
172    }
173}
174
175impl Referencing for FunctionLogDebugLocation {
176    #[inline]
177    fn as_ptr(&self) -> *const c_void {
178        self.0.as_ptr()
179    }
180}
181
182unsafe impl Send for FunctionLogDebugLocation {}
183unsafe impl Sync for FunctionLogDebugLocation {}
184
185// ============================================================================
186// FunctionLog
187// ============================================================================
188
189/// A log entry from shader function execution.
190///
191/// C++ equivalent: `MTL::FunctionLog`
192///
193/// Contains information about validation errors or other log messages
194/// generated during shader execution.
195#[repr(transparent)]
196pub struct FunctionLog(pub(crate) NonNull<c_void>);
197
198impl FunctionLog {
199    /// Create from a raw pointer.
200    #[inline]
201    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
202        NonNull::new(ptr).map(Self)
203    }
204
205    /// Get the raw pointer.
206    #[inline]
207    pub fn as_raw(&self) -> *mut c_void {
208        self.0.as_ptr()
209    }
210
211    /// Get the log type.
212    ///
213    /// C++ equivalent: `FunctionLogType type() const`
214    #[inline]
215    pub fn log_type(&self) -> FunctionLogType {
216        unsafe { msg_send_0(self.as_ptr(), sel!(type)) }
217    }
218
219    /// Get the debug location.
220    ///
221    /// C++ equivalent: `FunctionLogDebugLocation* debugLocation() const`
222    pub fn debug_location(&self) -> Option<FunctionLogDebugLocation> {
223        unsafe {
224            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(debugLocation));
225            if ptr.is_null() {
226                return None;
227            }
228            let _: *mut c_void = msg_send_0(ptr, sel!(retain));
229            FunctionLogDebugLocation::from_raw(ptr)
230        }
231    }
232
233    /// Get the encoder label.
234    ///
235    /// C++ equivalent: `NS::String* encoderLabel() const`
236    pub fn encoder_label(&self) -> Option<String> {
237        unsafe {
238            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(encoderLabel));
239            if ptr.is_null() {
240                return None;
241            }
242            let utf8_ptr: *const std::ffi::c_char =
243                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
244            if utf8_ptr.is_null() {
245                return None;
246            }
247            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
248            Some(c_str.to_string_lossy().into_owned())
249        }
250    }
251
252    /// Get the function that generated this log entry.
253    ///
254    /// C++ equivalent: `Function* function() const`
255    pub fn function(&self) -> Option<Function> {
256        unsafe {
257            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(function));
258            if ptr.is_null() {
259                return None;
260            }
261            let _: *mut c_void = msg_send_0(ptr, sel!(retain));
262            Function::from_raw(ptr)
263        }
264    }
265}
266
267impl Clone for FunctionLog {
268    fn clone(&self) -> Self {
269        unsafe {
270            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
271        }
272        Self(self.0)
273    }
274}
275
276impl Drop for FunctionLog {
277    fn drop(&mut self) {
278        unsafe {
279            msg_send_0::<()>(self.as_ptr(), sel!(release));
280        }
281    }
282}
283
284impl Referencing for FunctionLog {
285    #[inline]
286    fn as_ptr(&self) -> *const c_void {
287        self.0.as_ptr()
288    }
289}
290
291unsafe impl Send for FunctionLog {}
292unsafe impl Sync for FunctionLog {}
293
294#[cfg(test)]
295mod tests {
296    use super::*;
297
298    #[test]
299    fn test_type_sizes() {
300        assert_eq!(
301            std::mem::size_of::<LogContainer>(),
302            std::mem::size_of::<*mut c_void>()
303        );
304        assert_eq!(
305            std::mem::size_of::<FunctionLogDebugLocation>(),
306            std::mem::size_of::<*mut c_void>()
307        );
308        assert_eq!(
309            std::mem::size_of::<FunctionLog>(),
310            std::mem::size_of::<*mut c_void>()
311        );
312    }
313}