Skip to main content

mtl_gpu/mtl4/
library_function_descriptor.rs

1//! MTL4 LibraryFunctionDescriptor implementation.
2//!
3//! Corresponds to `Metal/MTL4LibraryFunctionDescriptor.hpp`.
4
5use std::ffi::c_void;
6use std::ptr::NonNull;
7
8use mtl_foundation::Referencing;
9use mtl_sys::{msg_send_0, msg_send_1, sel};
10
11use crate::Library;
12
13// ============================================================
14// LibraryFunctionDescriptor
15// ============================================================
16
17/// Descriptor for a function from a library.
18///
19/// C++ equivalent: `MTL4::LibraryFunctionDescriptor`
20///
21/// LibraryFunctionDescriptor extends FunctionDescriptor to reference
22/// a specific function from a Metal library by name.
23#[repr(transparent)]
24pub struct LibraryFunctionDescriptor(NonNull<c_void>);
25
26impl LibraryFunctionDescriptor {
27    /// Create a LibraryFunctionDescriptor from a raw pointer.
28    #[inline]
29    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
30        NonNull::new(ptr).map(Self)
31    }
32
33    /// Get the raw pointer.
34    #[inline]
35    pub fn as_raw(&self) -> *mut c_void {
36        self.0.as_ptr()
37    }
38
39    /// Create a new library function descriptor.
40    pub fn new() -> Option<Self> {
41        unsafe {
42            let class = mtl_sys::Class::get("MTL4LibraryFunctionDescriptor")?;
43            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
44            if ptr.is_null() {
45                return None;
46            }
47            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
48            Self::from_raw(ptr)
49        }
50    }
51
52    /// Get the library.
53    ///
54    /// C++ equivalent: `MTL::Library* library() const`
55    pub fn library(&self) -> Option<Library> {
56        unsafe {
57            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(library));
58            Library::from_raw(ptr)
59        }
60    }
61
62    /// Set the library.
63    ///
64    /// C++ equivalent: `void setLibrary(const MTL::Library*)`
65    pub fn set_library(&self, library: &Library) {
66        unsafe {
67            let _: () = msg_send_1(self.as_ptr(), sel!(setLibrary:), library.as_ptr());
68        }
69    }
70
71    /// Get the function name.
72    ///
73    /// C++ equivalent: `NS::String* name() const`
74    pub fn name(&self) -> Option<String> {
75        unsafe {
76            let ns_string: *mut c_void = msg_send_0(self.as_ptr(), sel!(name));
77            if ns_string.is_null() {
78                return None;
79            }
80            let c_str: *const i8 = msg_send_0(ns_string, sel!(UTF8String));
81            if c_str.is_null() {
82                return None;
83            }
84            Some(
85                std::ffi::CStr::from_ptr(c_str)
86                    .to_string_lossy()
87                    .into_owned(),
88            )
89        }
90    }
91
92    /// Set the function name.
93    ///
94    /// C++ equivalent: `void setName(const NS::String*)`
95    pub fn set_name(&self, name: &str) {
96        if let Some(ns_name) = mtl_foundation::String::from_str(name) {
97            unsafe {
98                let _: () = msg_send_1(self.as_ptr(), sel!(setName:), ns_name.as_ptr());
99            }
100        }
101    }
102}
103
104impl Default for LibraryFunctionDescriptor {
105    fn default() -> Self {
106        Self::new().expect("Failed to create MTL4LibraryFunctionDescriptor")
107    }
108}
109
110impl Clone for LibraryFunctionDescriptor {
111    fn clone(&self) -> Self {
112        unsafe {
113            mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
114        }
115        Self(self.0)
116    }
117}
118
119impl Drop for LibraryFunctionDescriptor {
120    fn drop(&mut self) {
121        unsafe {
122            mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
123        }
124    }
125}
126
127impl Referencing for LibraryFunctionDescriptor {
128    #[inline]
129    fn as_ptr(&self) -> *const c_void {
130        self.0.as_ptr()
131    }
132}
133
134unsafe impl Send for LibraryFunctionDescriptor {}
135unsafe impl Sync for LibraryFunctionDescriptor {}
136
137impl std::fmt::Debug for LibraryFunctionDescriptor {
138    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139        f.debug_struct("LibraryFunctionDescriptor")
140            .field("name", &self.name())
141            .finish()
142    }
143}
144
145#[cfg(test)]
146mod tests {
147    use super::*;
148
149    #[test]
150    fn test_library_function_descriptor_size() {
151        assert_eq!(
152            std::mem::size_of::<LibraryFunctionDescriptor>(),
153            std::mem::size_of::<*mut c_void>()
154        );
155    }
156}