Skip to main content

mtl_gpu/mtl4/
library_descriptor.rs

1//! MTL4 LibraryDescriptor implementation.
2//!
3//! Corresponds to `Metal/MTL4LibraryDescriptor.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::CompileOptions;
12
13// ============================================================
14// LibraryDescriptor
15// ============================================================
16
17/// Descriptor for creating a Metal library.
18///
19/// C++ equivalent: `MTL4::LibraryDescriptor`
20///
21/// LibraryDescriptor specifies the source code, name, and compile
22/// options for creating a Metal shader library.
23#[repr(transparent)]
24pub struct LibraryDescriptor(NonNull<c_void>);
25
26impl LibraryDescriptor {
27    /// Create a LibraryDescriptor 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 descriptor.
40    pub fn new() -> Option<Self> {
41        unsafe {
42            let class = mtl_sys::Class::get("MTL4LibraryDescriptor")?;
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 name.
53    ///
54    /// C++ equivalent: `NS::String* name() const`
55    pub fn name(&self) -> Option<String> {
56        unsafe {
57            let ns_string: *mut c_void = msg_send_0(self.as_ptr(), sel!(name));
58            if ns_string.is_null() {
59                return None;
60            }
61            let c_str: *const i8 = msg_send_0(ns_string, sel!(UTF8String));
62            if c_str.is_null() {
63                return None;
64            }
65            Some(
66                std::ffi::CStr::from_ptr(c_str)
67                    .to_string_lossy()
68                    .into_owned(),
69            )
70        }
71    }
72
73    /// Set the name.
74    ///
75    /// C++ equivalent: `void setName(const NS::String*)`
76    pub fn set_name(&self, name: &str) {
77        if let Some(ns_name) = mtl_foundation::String::from_str(name) {
78            unsafe {
79                let _: () = msg_send_1(self.as_ptr(), sel!(setName:), ns_name.as_ptr());
80            }
81        }
82    }
83
84    /// Get the source code.
85    ///
86    /// C++ equivalent: `NS::String* source() const`
87    pub fn source(&self) -> Option<String> {
88        unsafe {
89            let ns_string: *mut c_void = msg_send_0(self.as_ptr(), sel!(source));
90            if ns_string.is_null() {
91                return None;
92            }
93            let c_str: *const i8 = msg_send_0(ns_string, sel!(UTF8String));
94            if c_str.is_null() {
95                return None;
96            }
97            Some(
98                std::ffi::CStr::from_ptr(c_str)
99                    .to_string_lossy()
100                    .into_owned(),
101            )
102        }
103    }
104
105    /// Set the source code.
106    ///
107    /// C++ equivalent: `void setSource(const NS::String*)`
108    pub fn set_source(&self, source: &str) {
109        if let Some(ns_source) = mtl_foundation::String::from_str(source) {
110            unsafe {
111                let _: () = msg_send_1(self.as_ptr(), sel!(setSource:), ns_source.as_ptr());
112            }
113        }
114    }
115
116    /// Get the compile options.
117    ///
118    /// C++ equivalent: `MTL::CompileOptions* options() const`
119    pub fn options(&self) -> Option<CompileOptions> {
120        unsafe {
121            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(options));
122            CompileOptions::from_raw(ptr)
123        }
124    }
125
126    /// Set the compile options.
127    ///
128    /// C++ equivalent: `void setOptions(const MTL::CompileOptions*)`
129    pub fn set_options(&self, options: &CompileOptions) {
130        unsafe {
131            let _: () = msg_send_1(self.as_ptr(), sel!(setOptions:), options.as_ptr());
132        }
133    }
134}
135
136impl Clone for LibraryDescriptor {
137    fn clone(&self) -> Self {
138        unsafe {
139            mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
140        }
141        Self(self.0)
142    }
143}
144
145impl Drop for LibraryDescriptor {
146    fn drop(&mut self) {
147        unsafe {
148            mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
149        }
150    }
151}
152
153impl Referencing for LibraryDescriptor {
154    #[inline]
155    fn as_ptr(&self) -> *const c_void {
156        self.0.as_ptr()
157    }
158}
159
160unsafe impl Send for LibraryDescriptor {}
161unsafe impl Sync for LibraryDescriptor {}
162
163impl std::fmt::Debug for LibraryDescriptor {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        f.debug_struct("LibraryDescriptor")
166            .field("name", &self.name())
167            .finish()
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[test]
176    fn test_library_descriptor_size() {
177        assert_eq!(
178            std::mem::size_of::<LibraryDescriptor>(),
179            std::mem::size_of::<*mut c_void>()
180        );
181    }
182}