Skip to main content

mtl_gpu/library/
vertex_attribute.rs

1//! Vertex attribute reflection information.
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/// Vertex attribute reflection information.
12///
13/// C++ equivalent: `MTL::VertexAttribute`
14///
15/// Contains information about a vertex attribute in a vertex function.
16#[repr(transparent)]
17pub struct VertexAttribute(pub(crate) NonNull<c_void>);
18
19impl VertexAttribute {
20    /// Allocate a new vertex attribute.
21    ///
22    /// C++ equivalent: `static VertexAttribute* alloc()`
23    pub fn alloc() -> Option<Self> {
24        unsafe {
25            let cls = mtl_sys::Class::get("MTLVertexAttribute")?;
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 vertex attribute.
32    ///
33    /// C++ equivalent: `VertexAttribute* 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 vertex attribute.
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 vertex attribute 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 attribute 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 attribute index.
82    ///
83    /// C++ equivalent: `NS::UInteger attributeIndex() const`
84    #[inline]
85    pub fn attribute_index(&self) -> UInteger {
86        unsafe { msg_send_0(self.as_ptr(), sel!(attributeIndex)) }
87    }
88
89    /// Get the attribute data type.
90    ///
91    /// C++ equivalent: `DataType attributeType() const`
92    #[inline]
93    pub fn attribute_type(&self) -> DataType {
94        unsafe { msg_send_0(self.as_ptr(), sel!(attributeType)) }
95    }
96
97    /// Check if the attribute is active.
98    ///
99    /// C++ equivalent: `bool isActive() const`
100    #[inline]
101    pub fn is_active(&self) -> bool {
102        unsafe { msg_send_0(self.as_ptr(), sel!(isActive)) }
103    }
104
105    /// Check if this is patch data.
106    ///
107    /// C++ equivalent: `bool isPatchData() const`
108    #[inline]
109    pub fn is_patch_data(&self) -> bool {
110        unsafe { msg_send_0(self.as_ptr(), sel!(isPatchData)) }
111    }
112
113    /// Check if this is patch control point data.
114    ///
115    /// C++ equivalent: `bool isPatchControlPointData() const`
116    #[inline]
117    pub fn is_patch_control_point_data(&self) -> bool {
118        unsafe { msg_send_0(self.as_ptr(), sel!(isPatchControlPointData)) }
119    }
120}
121
122impl Clone for VertexAttribute {
123    fn clone(&self) -> Self {
124        unsafe {
125            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
126        }
127        Self(self.0)
128    }
129}
130
131impl Drop for VertexAttribute {
132    fn drop(&mut self) {
133        unsafe {
134            msg_send_0::<()>(self.as_ptr(), sel!(release));
135        }
136    }
137}
138
139impl Referencing for VertexAttribute {
140    #[inline]
141    fn as_ptr(&self) -> *const c_void {
142        self.0.as_ptr()
143    }
144}
145
146unsafe impl Send for VertexAttribute {}
147unsafe impl Sync for VertexAttribute {}
148
149impl std::fmt::Debug for VertexAttribute {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        f.debug_struct("VertexAttribute")
152            .field("name", &self.name())
153            .field("attribute_index", &self.attribute_index())
154            .field("attribute_type", &self.attribute_type())
155            .field("is_active", &self.is_active())
156            .finish()
157    }
158}