1use std::ffi::c_void;
6use std::ptr::NonNull;
7
8use mtl_foundation::{Integer, Referencing, UInteger};
9use mtl_sys::{msg_send_0, msg_send_1, sel};
10
11#[repr(transparent)]
19#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
20pub struct CounterHeapType(pub Integer);
21
22impl CounterHeapType {
23 pub const INVALID: Self = Self(0);
25
26 pub const TIMESTAMP: Self = Self(1);
28}
29
30#[repr(transparent)]
34#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
35pub struct TimestampGranularity(pub Integer);
36
37impl TimestampGranularity {
38 pub const RELAXED: Self = Self(0);
40
41 pub const PRECISE: Self = Self(1);
43}
44
45#[repr(C, packed)]
53#[derive(Copy, Clone, Debug, Default)]
54pub struct TimestampHeapEntry {
55 pub timestamp: u64,
57}
58
59#[repr(transparent)]
67pub struct CounterHeapDescriptor(NonNull<c_void>);
68
69impl CounterHeapDescriptor {
70 #[inline]
72 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
73 NonNull::new(ptr).map(Self)
74 }
75
76 #[inline]
78 pub fn as_raw(&self) -> *mut c_void {
79 self.0.as_ptr()
80 }
81
82 pub fn new() -> Option<Self> {
84 unsafe {
85 let class = mtl_sys::Class::get("MTL4CounterHeapDescriptor")?;
86 let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
87 if ptr.is_null() {
88 return None;
89 }
90 let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
91 Self::from_raw(ptr)
92 }
93 }
94
95 pub fn heap_type(&self) -> CounterHeapType {
99 unsafe { msg_send_0(self.as_ptr(), sel!(type)) }
100 }
101
102 pub fn set_heap_type(&self, heap_type: CounterHeapType) {
106 unsafe {
107 let _: () = msg_send_1(self.as_ptr(), sel!(setType:), heap_type);
108 }
109 }
110
111 pub fn count(&self) -> UInteger {
115 unsafe { msg_send_0(self.as_ptr(), sel!(count)) }
116 }
117
118 pub fn set_count(&self, count: UInteger) {
122 unsafe {
123 let _: () = msg_send_1(self.as_ptr(), sel!(setCount:), count);
124 }
125 }
126}
127
128impl Default for CounterHeapDescriptor {
129 fn default() -> Self {
130 Self::new().expect("Failed to create MTL4CounterHeapDescriptor")
131 }
132}
133
134impl Clone for CounterHeapDescriptor {
135 fn clone(&self) -> Self {
136 unsafe {
137 mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
138 }
139 Self(self.0)
140 }
141}
142
143impl Drop for CounterHeapDescriptor {
144 fn drop(&mut self) {
145 unsafe {
146 mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
147 }
148 }
149}
150
151impl Referencing for CounterHeapDescriptor {
152 #[inline]
153 fn as_ptr(&self) -> *const c_void {
154 self.0.as_ptr()
155 }
156}
157
158unsafe impl Send for CounterHeapDescriptor {}
159unsafe impl Sync for CounterHeapDescriptor {}
160
161impl std::fmt::Debug for CounterHeapDescriptor {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 f.debug_struct("CounterHeapDescriptor")
164 .field("type", &self.heap_type())
165 .field("count", &self.count())
166 .finish()
167 }
168}
169
170#[repr(transparent)]
180pub struct CounterHeap(NonNull<c_void>);
181
182impl CounterHeap {
183 #[inline]
185 pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
186 NonNull::new(ptr).map(Self)
187 }
188
189 #[inline]
191 pub fn as_raw(&self) -> *mut c_void {
192 self.0.as_ptr()
193 }
194
195 pub fn label(&self) -> Option<String> {
199 unsafe {
200 let ns_string: *mut c_void = msg_send_0(self.as_ptr(), sel!(label));
201 if ns_string.is_null() {
202 return None;
203 }
204 let c_str: *const i8 = msg_send_0(ns_string, sel!(UTF8String));
205 if c_str.is_null() {
206 return None;
207 }
208 Some(
209 std::ffi::CStr::from_ptr(c_str)
210 .to_string_lossy()
211 .into_owned(),
212 )
213 }
214 }
215
216 pub fn set_label(&self, label: &str) {
220 if let Some(ns_label) = mtl_foundation::String::from_str(label) {
221 unsafe {
222 let _: () = msg_send_1(self.as_ptr(), sel!(setLabel:), ns_label.as_ptr());
223 }
224 }
225 }
226
227 pub fn heap_type(&self) -> CounterHeapType {
231 unsafe { msg_send_0(self.as_ptr(), sel!(type)) }
232 }
233
234 pub fn count(&self) -> UInteger {
238 unsafe { msg_send_0(self.as_ptr(), sel!(count)) }
239 }
240
241 pub fn invalidate_counter_range(&self, location: UInteger, length: UInteger) {
245 unsafe {
246 let range = (location, length);
247 let _: () = msg_send_1(self.as_ptr(), sel!(invalidateCounterRange:), range);
248 }
249 }
250
251 pub fn resolve_counter_range_raw(&self, location: UInteger, length: UInteger) -> *mut c_void {
258 unsafe {
259 let range = (location, length);
260 msg_send_1(self.as_ptr(), sel!(resolveCounterRange:), range)
261 }
262 }
263}
264
265impl Clone for CounterHeap {
266 fn clone(&self) -> Self {
267 unsafe {
268 mtl_sys::msg_send_0::<*mut c_void>(self.as_ptr(), mtl_sys::sel!(retain));
269 }
270 Self(self.0)
271 }
272}
273
274impl Drop for CounterHeap {
275 fn drop(&mut self) {
276 unsafe {
277 mtl_sys::msg_send_0::<()>(self.as_ptr(), mtl_sys::sel!(release));
278 }
279 }
280}
281
282impl Referencing for CounterHeap {
283 #[inline]
284 fn as_ptr(&self) -> *const c_void {
285 self.0.as_ptr()
286 }
287}
288
289unsafe impl Send for CounterHeap {}
290unsafe impl Sync for CounterHeap {}
291
292impl std::fmt::Debug for CounterHeap {
293 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294 f.debug_struct("CounterHeap")
295 .field("label", &self.label())
296 .field("type", &self.heap_type())
297 .field("count", &self.count())
298 .finish()
299 }
300}
301
302#[cfg(test)]
303mod tests {
304 use super::*;
305
306 #[test]
307 fn test_counter_heap_descriptor_size() {
308 assert_eq!(
309 std::mem::size_of::<CounterHeapDescriptor>(),
310 std::mem::size_of::<*mut c_void>()
311 );
312 }
313
314 #[test]
315 fn test_counter_heap_size() {
316 assert_eq!(
317 std::mem::size_of::<CounterHeap>(),
318 std::mem::size_of::<*mut c_void>()
319 );
320 }
321
322 #[test]
323 fn test_timestamp_heap_entry_size() {
324 assert_eq!(std::mem::size_of::<TimestampHeapEntry>(), 8);
325 }
326
327 #[test]
328 fn test_counter_heap_type_values() {
329 assert_eq!(CounterHeapType::INVALID.0, 0);
330 assert_eq!(CounterHeapType::TIMESTAMP.0, 1);
331 }
332
333 #[test]
334 fn test_timestamp_granularity_values() {
335 assert_eq!(TimestampGranularity::RELAXED.0, 0);
336 assert_eq!(TimestampGranularity::PRECISE.0, 1);
337 }
338}