Skip to main content

mtl_gpu/library/
function_constant.rs

1//! Function constant definition.
2
3use std::ffi::c_void;
4use std::ptr::NonNull;
5
6use mtl_foundation::{Referencing, UInteger};
7use mtl_sys::{msg_send_0, sel};
8
9use crate::enums::DataType;
10
11/// Function constant definition.
12///
13/// C++ equivalent: `MTL::FunctionConstant`
14///
15/// Contains information about a function constant defined in shader code.
16#[repr(transparent)]
17pub struct FunctionConstant(pub(crate) NonNull<c_void>);
18
19impl FunctionConstant {
20    /// Allocate a new function constant.
21    ///
22    /// C++ equivalent: `static FunctionConstant* alloc()`
23    pub fn alloc() -> Option<Self> {
24        unsafe {
25            let cls = mtl_sys::Class::get("MTLFunctionConstant")?;
26            let ptr: *mut c_void = msg_send_0(cls.as_ptr(), sel!(alloc));
27            Self::from_raw(ptr)
28        }
29    }
30
31    /// Initialize an allocated function constant.
32    ///
33    /// C++ equivalent: `FunctionConstant* init()`
34    pub fn init(&self) -> Option<Self> {
35        unsafe {
36            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(init));
37            Self::from_raw(ptr)
38        }
39    }
40
41    /// Create a new function constant.
42    pub fn new() -> Option<Self> {
43        Self::alloc()?.init()
44    }
45
46    /// Create from a raw pointer.
47    ///
48    /// # Safety
49    ///
50    /// The pointer must be a valid Metal function constant object.
51    #[inline]
52    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
53        NonNull::new(ptr).map(Self)
54    }
55
56    /// Get the raw pointer.
57    #[inline]
58    pub fn as_raw(&self) -> *mut c_void {
59        self.0.as_ptr()
60    }
61
62    /// Get the function constant name.
63    ///
64    /// C++ equivalent: `NS::String* name() const`
65    pub fn name(&self) -> Option<String> {
66        unsafe {
67            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(name));
68            if ptr.is_null() {
69                return None;
70            }
71            let utf8_ptr: *const std::ffi::c_char =
72                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
73            if utf8_ptr.is_null() {
74                return None;
75            }
76            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
77            Some(c_str.to_string_lossy().into_owned())
78        }
79    }
80
81    /// Get the function constant data type.
82    ///
83    /// C++ equivalent: `DataType type() const`
84    #[inline]
85    pub fn constant_type(&self) -> DataType {
86        unsafe { msg_send_0(self.as_ptr(), sel!(type)) }
87    }
88
89    /// Get the function constant index.
90    ///
91    /// C++ equivalent: `NS::UInteger index() const`
92    #[inline]
93    pub fn index(&self) -> UInteger {
94        unsafe { msg_send_0(self.as_ptr(), sel!(index)) }
95    }
96
97    /// Check if the function constant is required.
98    ///
99    /// C++ equivalent: `bool required() const`
100    #[inline]
101    pub fn required(&self) -> bool {
102        unsafe { msg_send_0(self.as_ptr(), sel!(required)) }
103    }
104}
105
106impl Clone for FunctionConstant {
107    fn clone(&self) -> Self {
108        unsafe {
109            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
110        }
111        Self(self.0)
112    }
113}
114
115impl Drop for FunctionConstant {
116    fn drop(&mut self) {
117        unsafe {
118            msg_send_0::<()>(self.as_ptr(), sel!(release));
119        }
120    }
121}
122
123impl Referencing for FunctionConstant {
124    #[inline]
125    fn as_ptr(&self) -> *const c_void {
126        self.0.as_ptr()
127    }
128}
129
130unsafe impl Send for FunctionConstant {}
131unsafe impl Sync for FunctionConstant {}
132
133impl std::fmt::Debug for FunctionConstant {
134    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
135        f.debug_struct("FunctionConstant")
136            .field("name", &self.name())
137            .field("type", &self.constant_type())
138            .field("index", &self.index())
139            .field("required", &self.required())
140            .finish()
141    }
142}