Skip to main content

mtl_gpu/function_table/
mod.rs

1//! Function table types.
2//!
3//! Corresponds to `Metal/MTLFunctionHandle.hpp`, `Metal/MTLVisibleFunctionTable.hpp`,
4//! and `Metal/MTLIntersectionFunctionTable.hpp`.
5//!
6//! Function tables provide a way to dynamically dispatch to shader functions,
7//! which is essential for ray tracing and other advanced rendering techniques.
8
9use std::ffi::c_void;
10use std::ptr::NonNull;
11
12use mtl_foundation::{Range, Referencing, UInteger};
13use mtl_sys::{Class, msg_send_0, msg_send_1, msg_send_2, msg_send_3, sel};
14
15use crate::Buffer;
16use crate::enums::{FunctionType, IntersectionFunctionSignature};
17use crate::types::ResourceID;
18
19// ============================================================================
20// IntersectionFunctionBufferArguments
21// ============================================================================
22
23/// Arguments for an intersection function buffer.
24///
25/// C++ equivalent: `MTL::IntersectionFunctionBufferArguments`
26#[repr(C, packed)]
27#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
28pub struct IntersectionFunctionBufferArguments {
29    pub intersection_function_buffer: u64,
30    pub intersection_function_buffer_size: u64,
31    pub intersection_function_stride: u64,
32}
33
34// ============================================================================
35// FunctionHandle
36// ============================================================================
37
38/// A handle to a compiled function.
39///
40/// C++ equivalent: `MTL::FunctionHandle`
41#[repr(transparent)]
42pub struct FunctionHandle(pub(crate) NonNull<c_void>);
43
44impl FunctionHandle {
45    /// Create a FunctionHandle from a raw pointer.
46    ///
47    /// # Safety
48    ///
49    /// The pointer must be a valid Metal function handle object.
50    #[inline]
51    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
52        NonNull::new(ptr).map(Self)
53    }
54
55    /// Get the raw pointer to the function handle.
56    #[inline]
57    pub fn as_raw(&self) -> *mut c_void {
58        self.0.as_ptr()
59    }
60
61    // =========================================================================
62    // Properties
63    // =========================================================================
64
65    /// Get the device that created this function handle.
66    ///
67    /// C++ equivalent: `Device* device() const`
68    pub fn device(&self) -> crate::Device {
69        unsafe {
70            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(device));
71            let _: *mut c_void = msg_send_0(ptr, sel!(retain));
72            crate::Device::from_raw(ptr).expect("function handle has no device")
73        }
74    }
75
76    /// Get the type of the function.
77    ///
78    /// C++ equivalent: `FunctionType functionType() const`
79    #[inline]
80    pub fn function_type(&self) -> FunctionType {
81        unsafe { msg_send_0(self.as_ptr(), sel!(functionType)) }
82    }
83
84    /// Get the GPU resource ID for bindless access.
85    ///
86    /// C++ equivalent: `ResourceID gpuResourceID() const`
87    #[inline]
88    pub fn gpu_resource_id(&self) -> ResourceID {
89        unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
90    }
91
92    /// Get the name of the function.
93    ///
94    /// C++ equivalent: `NS::String* name() const`
95    pub fn name(&self) -> Option<String> {
96        unsafe {
97            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(name));
98            if ptr.is_null() {
99                return None;
100            }
101            let utf8_ptr: *const std::ffi::c_char =
102                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
103            if utf8_ptr.is_null() {
104                return None;
105            }
106            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
107            Some(c_str.to_string_lossy().into_owned())
108        }
109    }
110}
111
112impl Clone for FunctionHandle {
113    fn clone(&self) -> Self {
114        unsafe {
115            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
116        }
117        Self(self.0)
118    }
119}
120
121impl Drop for FunctionHandle {
122    fn drop(&mut self) {
123        unsafe {
124            msg_send_0::<()>(self.as_ptr(), sel!(release));
125        }
126    }
127}
128
129impl Referencing for FunctionHandle {
130    #[inline]
131    fn as_ptr(&self) -> *const c_void {
132        self.0.as_ptr()
133    }
134}
135
136unsafe impl Send for FunctionHandle {}
137unsafe impl Sync for FunctionHandle {}
138
139impl std::fmt::Debug for FunctionHandle {
140    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141        f.debug_struct("FunctionHandle")
142            .field("name", &self.name())
143            .field("function_type", &self.function_type())
144            .finish()
145    }
146}
147
148// ============================================================================
149// VisibleFunctionTableDescriptor
150// ============================================================================
151
152/// A descriptor for creating a visible function table.
153///
154/// C++ equivalent: `MTL::VisibleFunctionTableDescriptor`
155#[repr(transparent)]
156pub struct VisibleFunctionTableDescriptor(pub(crate) NonNull<c_void>);
157
158impl VisibleFunctionTableDescriptor {
159    /// Create a new visible function table descriptor.
160    ///
161    /// C++ equivalent: `static VisibleFunctionTableDescriptor* alloc()->init()`
162    pub fn new() -> Option<Self> {
163        unsafe {
164            let class = Class::get("MTLVisibleFunctionTableDescriptor")?;
165            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
166            if ptr.is_null() {
167                return None;
168            }
169            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
170            Self::from_raw(ptr)
171        }
172    }
173
174    /// Create a new visible function table descriptor using the class method.
175    ///
176    /// C++ equivalent: `static VisibleFunctionTableDescriptor* visibleFunctionTableDescriptor()`
177    pub fn visible_function_table_descriptor() -> Option<Self> {
178        unsafe {
179            let class = Class::get("MTLVisibleFunctionTableDescriptor")?;
180            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(visibleFunctionTableDescriptor));
181            if ptr.is_null() {
182                return None;
183            }
184            // Retain since this is an autoreleased object
185            msg_send_0::<*mut c_void>(ptr, sel!(retain));
186            Self::from_raw(ptr)
187        }
188    }
189
190    /// Create a VisibleFunctionTableDescriptor from a raw pointer.
191    ///
192    /// # Safety
193    ///
194    /// The pointer must be a valid Metal visible function table descriptor object.
195    #[inline]
196    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
197        NonNull::new(ptr).map(Self)
198    }
199
200    /// Get the raw pointer to the descriptor.
201    #[inline]
202    pub fn as_raw(&self) -> *mut c_void {
203        self.0.as_ptr()
204    }
205
206    // =========================================================================
207    // Properties
208    // =========================================================================
209
210    /// Get the number of functions in the table.
211    ///
212    /// C++ equivalent: `NS::UInteger functionCount() const`
213    #[inline]
214    pub fn function_count(&self) -> UInteger {
215        unsafe { msg_send_0(self.as_ptr(), sel!(functionCount)) }
216    }
217
218    /// Set the number of functions in the table.
219    ///
220    /// C++ equivalent: `void setFunctionCount(NS::UInteger functionCount)`
221    #[inline]
222    pub fn set_function_count(&self, function_count: UInteger) {
223        unsafe {
224            let _: () = msg_send_1(self.as_ptr(), sel!(setFunctionCount:), function_count);
225        }
226    }
227}
228
229impl Clone for VisibleFunctionTableDescriptor {
230    fn clone(&self) -> Self {
231        unsafe {
232            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
233        }
234        Self(self.0)
235    }
236}
237
238impl Drop for VisibleFunctionTableDescriptor {
239    fn drop(&mut self) {
240        unsafe {
241            msg_send_0::<()>(self.as_ptr(), sel!(release));
242        }
243    }
244}
245
246impl Referencing for VisibleFunctionTableDescriptor {
247    #[inline]
248    fn as_ptr(&self) -> *const c_void {
249        self.0.as_ptr()
250    }
251}
252
253unsafe impl Send for VisibleFunctionTableDescriptor {}
254unsafe impl Sync for VisibleFunctionTableDescriptor {}
255
256impl std::fmt::Debug for VisibleFunctionTableDescriptor {
257    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
258        f.debug_struct("VisibleFunctionTableDescriptor")
259            .field("function_count", &self.function_count())
260            .finish()
261    }
262}
263
264// ============================================================================
265// VisibleFunctionTable
266// ============================================================================
267
268/// A table of visible functions for shader function pointers.
269///
270/// C++ equivalent: `MTL::VisibleFunctionTable`
271///
272/// Inherits from Resource.
273#[repr(transparent)]
274pub struct VisibleFunctionTable(pub(crate) NonNull<c_void>);
275
276impl VisibleFunctionTable {
277    /// Create a VisibleFunctionTable from a raw pointer.
278    ///
279    /// # Safety
280    ///
281    /// The pointer must be a valid Metal visible function table object.
282    #[inline]
283    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
284        NonNull::new(ptr).map(Self)
285    }
286
287    /// Get the raw pointer to the function table.
288    #[inline]
289    pub fn as_raw(&self) -> *mut c_void {
290        self.0.as_ptr()
291    }
292
293    // =========================================================================
294    // Properties
295    // =========================================================================
296
297    /// Get the GPU resource ID for bindless access.
298    ///
299    /// C++ equivalent: `ResourceID gpuResourceID() const`
300    #[inline]
301    pub fn gpu_resource_id(&self) -> ResourceID {
302        unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
303    }
304
305    // =========================================================================
306    // Methods
307    // =========================================================================
308
309    /// Set a function at the specified index.
310    ///
311    /// C++ equivalent: `void setFunction(const MTL::FunctionHandle* function, NS::UInteger index)`
312    pub fn set_function(&self, function: &FunctionHandle, index: UInteger) {
313        unsafe {
314            let _: () = msg_send_2(
315                self.as_ptr(),
316                sel!(setFunction:atIndex:),
317                function.as_ptr(),
318                index,
319            );
320        }
321    }
322
323    /// Set multiple functions at a range of indices.
324    ///
325    /// C++ equivalent: `void setFunctions(const MTL::FunctionHandle* const functions[], NS::Range range)`
326    pub fn set_functions(&self, functions: &[&FunctionHandle], range: Range) {
327        let ptrs: Vec<*const c_void> = functions.iter().map(|f| f.as_ptr()).collect();
328        unsafe {
329            let _: () = msg_send_2(
330                self.as_ptr(),
331                sel!(setFunctions:withRange:),
332                ptrs.as_ptr(),
333                range,
334            );
335        }
336    }
337}
338
339impl Clone for VisibleFunctionTable {
340    fn clone(&self) -> Self {
341        unsafe {
342            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
343        }
344        Self(self.0)
345    }
346}
347
348impl Drop for VisibleFunctionTable {
349    fn drop(&mut self) {
350        unsafe {
351            msg_send_0::<()>(self.as_ptr(), sel!(release));
352        }
353    }
354}
355
356impl Referencing for VisibleFunctionTable {
357    #[inline]
358    fn as_ptr(&self) -> *const c_void {
359        self.0.as_ptr()
360    }
361}
362
363unsafe impl Send for VisibleFunctionTable {}
364unsafe impl Sync for VisibleFunctionTable {}
365
366impl std::fmt::Debug for VisibleFunctionTable {
367    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
368        f.debug_struct("VisibleFunctionTable").finish()
369    }
370}
371
372// ============================================================================
373// IntersectionFunctionTableDescriptor
374// ============================================================================
375
376/// A descriptor for creating an intersection function table.
377///
378/// C++ equivalent: `MTL::IntersectionFunctionTableDescriptor`
379#[repr(transparent)]
380pub struct IntersectionFunctionTableDescriptor(pub(crate) NonNull<c_void>);
381
382impl IntersectionFunctionTableDescriptor {
383    /// Create a new intersection function table descriptor.
384    ///
385    /// C++ equivalent: `static IntersectionFunctionTableDescriptor* alloc()->init()`
386    pub fn new() -> Option<Self> {
387        unsafe {
388            let class = Class::get("MTLIntersectionFunctionTableDescriptor")?;
389            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
390            if ptr.is_null() {
391                return None;
392            }
393            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
394            Self::from_raw(ptr)
395        }
396    }
397
398    /// Create a new intersection function table descriptor using the class method.
399    ///
400    /// C++ equivalent: `static IntersectionFunctionTableDescriptor* intersectionFunctionTableDescriptor()`
401    pub fn intersection_function_table_descriptor() -> Option<Self> {
402        unsafe {
403            let class = Class::get("MTLIntersectionFunctionTableDescriptor")?;
404            let ptr: *mut c_void =
405                msg_send_0(class.as_ptr(), sel!(intersectionFunctionTableDescriptor));
406            if ptr.is_null() {
407                return None;
408            }
409            // Retain since this is an autoreleased object
410            msg_send_0::<*mut c_void>(ptr, sel!(retain));
411            Self::from_raw(ptr)
412        }
413    }
414
415    /// Create an IntersectionFunctionTableDescriptor from a raw pointer.
416    ///
417    /// # Safety
418    ///
419    /// The pointer must be a valid Metal intersection function table descriptor object.
420    #[inline]
421    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
422        NonNull::new(ptr).map(Self)
423    }
424
425    /// Get the raw pointer to the descriptor.
426    #[inline]
427    pub fn as_raw(&self) -> *mut c_void {
428        self.0.as_ptr()
429    }
430
431    // =========================================================================
432    // Properties
433    // =========================================================================
434
435    /// Get the number of functions in the table.
436    ///
437    /// C++ equivalent: `NS::UInteger functionCount() const`
438    #[inline]
439    pub fn function_count(&self) -> UInteger {
440        unsafe { msg_send_0(self.as_ptr(), sel!(functionCount)) }
441    }
442
443    /// Set the number of functions in the table.
444    ///
445    /// C++ equivalent: `void setFunctionCount(NS::UInteger functionCount)`
446    #[inline]
447    pub fn set_function_count(&self, function_count: UInteger) {
448        unsafe {
449            let _: () = msg_send_1(self.as_ptr(), sel!(setFunctionCount:), function_count);
450        }
451    }
452}
453
454impl Clone for IntersectionFunctionTableDescriptor {
455    fn clone(&self) -> Self {
456        unsafe {
457            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
458        }
459        Self(self.0)
460    }
461}
462
463impl Drop for IntersectionFunctionTableDescriptor {
464    fn drop(&mut self) {
465        unsafe {
466            msg_send_0::<()>(self.as_ptr(), sel!(release));
467        }
468    }
469}
470
471impl Referencing for IntersectionFunctionTableDescriptor {
472    #[inline]
473    fn as_ptr(&self) -> *const c_void {
474        self.0.as_ptr()
475    }
476}
477
478unsafe impl Send for IntersectionFunctionTableDescriptor {}
479unsafe impl Sync for IntersectionFunctionTableDescriptor {}
480
481impl std::fmt::Debug for IntersectionFunctionTableDescriptor {
482    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
483        f.debug_struct("IntersectionFunctionTableDescriptor")
484            .field("function_count", &self.function_count())
485            .finish()
486    }
487}
488
489// ============================================================================
490// IntersectionFunctionTable
491// ============================================================================
492
493/// A table of intersection functions for ray tracing.
494///
495/// C++ equivalent: `MTL::IntersectionFunctionTable`
496///
497/// Inherits from Resource.
498#[repr(transparent)]
499pub struct IntersectionFunctionTable(pub(crate) NonNull<c_void>);
500
501impl IntersectionFunctionTable {
502    /// Create an IntersectionFunctionTable from a raw pointer.
503    ///
504    /// # Safety
505    ///
506    /// The pointer must be a valid Metal intersection function table object.
507    #[inline]
508    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
509        NonNull::new(ptr).map(Self)
510    }
511
512    /// Get the raw pointer to the function table.
513    #[inline]
514    pub fn as_raw(&self) -> *mut c_void {
515        self.0.as_ptr()
516    }
517
518    // =========================================================================
519    // Properties
520    // =========================================================================
521
522    /// Get the GPU resource ID for bindless access.
523    ///
524    /// C++ equivalent: `ResourceID gpuResourceID() const`
525    #[inline]
526    pub fn gpu_resource_id(&self) -> ResourceID {
527        unsafe { msg_send_0(self.as_ptr(), sel!(gpuResourceID)) }
528    }
529
530    // =========================================================================
531    // Buffer Methods
532    // =========================================================================
533
534    /// Set a buffer at the specified index.
535    ///
536    /// C++ equivalent: `void setBuffer(const MTL::Buffer* buffer, NS::UInteger offset, NS::UInteger index)`
537    pub fn set_buffer(&self, buffer: &Buffer, offset: UInteger, index: UInteger) {
538        unsafe {
539            let _: () = msg_send_3(
540                self.as_ptr(),
541                sel!(setBuffer:offset:atIndex:),
542                buffer.as_ptr(),
543                offset,
544                index,
545            );
546        }
547    }
548
549    /// Set multiple buffers at a range of indices.
550    ///
551    /// C++ equivalent: `void setBuffers(const MTL::Buffer* const buffers[], const NS::UInteger offsets[], NS::Range range)`
552    pub fn set_buffers(&self, buffers: &[&Buffer], offsets: &[UInteger], range: Range) {
553        let ptrs: Vec<*const c_void> = buffers.iter().map(|b| b.as_ptr()).collect();
554        unsafe {
555            let _: () = msg_send_3(
556                self.as_ptr(),
557                sel!(setBuffers:offsets:withRange:),
558                ptrs.as_ptr(),
559                offsets.as_ptr(),
560                range,
561            );
562        }
563    }
564
565    // =========================================================================
566    // Function Methods
567    // =========================================================================
568
569    /// Set a function at the specified index.
570    ///
571    /// C++ equivalent: `void setFunction(const MTL::FunctionHandle* function, NS::UInteger index)`
572    pub fn set_function(&self, function: &FunctionHandle, index: UInteger) {
573        unsafe {
574            let _: () = msg_send_2(
575                self.as_ptr(),
576                sel!(setFunction:atIndex:),
577                function.as_ptr(),
578                index,
579            );
580        }
581    }
582
583    /// Set multiple functions at a range of indices.
584    ///
585    /// C++ equivalent: `void setFunctions(const MTL::FunctionHandle* const functions[], NS::Range range)`
586    pub fn set_functions(&self, functions: &[&FunctionHandle], range: Range) {
587        let ptrs: Vec<*const c_void> = functions.iter().map(|f| f.as_ptr()).collect();
588        unsafe {
589            let _: () = msg_send_2(
590                self.as_ptr(),
591                sel!(setFunctions:withRange:),
592                ptrs.as_ptr(),
593                range,
594            );
595        }
596    }
597
598    // =========================================================================
599    // Opaque Intersection Function Methods
600    // =========================================================================
601
602    /// Set an opaque curve intersection function at the specified index.
603    ///
604    /// C++ equivalent: `void setOpaqueCurveIntersectionFunction(MTL::IntersectionFunctionSignature signature, NS::UInteger index)`
605    pub fn set_opaque_curve_intersection_function_at_index(
606        &self,
607        signature: IntersectionFunctionSignature,
608        index: UInteger,
609    ) {
610        unsafe {
611            let _: () = msg_send_2(
612                self.as_ptr(),
613                sel!(setOpaqueCurveIntersectionFunctionWithSignature:atIndex:),
614                signature,
615                index,
616            );
617        }
618    }
619
620    /// Set an opaque curve intersection function for a range of indices.
621    ///
622    /// C++ equivalent: `void setOpaqueCurveIntersectionFunction(MTL::IntersectionFunctionSignature signature, NS::Range range)`
623    pub fn set_opaque_curve_intersection_function_with_range(
624        &self,
625        signature: IntersectionFunctionSignature,
626        range: Range,
627    ) {
628        unsafe {
629            let _: () = msg_send_2(
630                self.as_ptr(),
631                sel!(setOpaqueCurveIntersectionFunctionWithSignature:withRange:),
632                signature,
633                range,
634            );
635        }
636    }
637
638    /// Set an opaque triangle intersection function at the specified index.
639    ///
640    /// C++ equivalent: `void setOpaqueTriangleIntersectionFunction(MTL::IntersectionFunctionSignature signature, NS::UInteger index)`
641    pub fn set_opaque_triangle_intersection_function_at_index(
642        &self,
643        signature: IntersectionFunctionSignature,
644        index: UInteger,
645    ) {
646        unsafe {
647            let _: () = msg_send_2(
648                self.as_ptr(),
649                sel!(setOpaqueTriangleIntersectionFunctionWithSignature:atIndex:),
650                signature,
651                index,
652            );
653        }
654    }
655
656    /// Set an opaque triangle intersection function for a range of indices.
657    ///
658    /// C++ equivalent: `void setOpaqueTriangleIntersectionFunction(MTL::IntersectionFunctionSignature signature, NS::Range range)`
659    pub fn set_opaque_triangle_intersection_function_with_range(
660        &self,
661        signature: IntersectionFunctionSignature,
662        range: Range,
663    ) {
664        unsafe {
665            let _: () = msg_send_2(
666                self.as_ptr(),
667                sel!(setOpaqueTriangleIntersectionFunctionWithSignature:withRange:),
668                signature,
669                range,
670            );
671        }
672    }
673
674    // =========================================================================
675    // Visible Function Table Methods
676    // =========================================================================
677
678    /// Set a visible function table at the specified buffer index.
679    ///
680    /// C++ equivalent: `void setVisibleFunctionTable(const MTL::VisibleFunctionTable* functionTable, NS::UInteger bufferIndex)`
681    pub fn set_visible_function_table(
682        &self,
683        function_table: &VisibleFunctionTable,
684        buffer_index: UInteger,
685    ) {
686        unsafe {
687            let _: () = msg_send_2(
688                self.as_ptr(),
689                sel!(setVisibleFunctionTable:atBufferIndex:),
690                function_table.as_ptr(),
691                buffer_index,
692            );
693        }
694    }
695
696    /// Set multiple visible function tables at a range of buffer indices.
697    ///
698    /// C++ equivalent: `void setVisibleFunctionTables(const MTL::VisibleFunctionTable* const functionTables[], NS::Range bufferRange)`
699    pub fn set_visible_function_tables(
700        &self,
701        function_tables: &[&VisibleFunctionTable],
702        buffer_range: Range,
703    ) {
704        let ptrs: Vec<*const c_void> = function_tables.iter().map(|t| t.as_ptr()).collect();
705        unsafe {
706            let _: () = msg_send_2(
707                self.as_ptr(),
708                sel!(setVisibleFunctionTables:withBufferRange:),
709                ptrs.as_ptr(),
710                buffer_range,
711            );
712        }
713    }
714}
715
716impl Clone for IntersectionFunctionTable {
717    fn clone(&self) -> Self {
718        unsafe {
719            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
720        }
721        Self(self.0)
722    }
723}
724
725impl Drop for IntersectionFunctionTable {
726    fn drop(&mut self) {
727        unsafe {
728            msg_send_0::<()>(self.as_ptr(), sel!(release));
729        }
730    }
731}
732
733impl Referencing for IntersectionFunctionTable {
734    #[inline]
735    fn as_ptr(&self) -> *const c_void {
736        self.0.as_ptr()
737    }
738}
739
740unsafe impl Send for IntersectionFunctionTable {}
741unsafe impl Sync for IntersectionFunctionTable {}
742
743impl std::fmt::Debug for IntersectionFunctionTable {
744    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
745        f.debug_struct("IntersectionFunctionTable").finish()
746    }
747}
748
749// ============================================================================
750// Tests
751// ============================================================================
752
753#[cfg(test)]
754mod tests {
755    use super::*;
756
757    #[test]
758    fn test_intersection_function_buffer_arguments_size() {
759        assert_eq!(
760            std::mem::size_of::<IntersectionFunctionBufferArguments>(),
761            24
762        );
763    }
764
765    #[test]
766    fn test_visible_function_table_descriptor_creation() {
767        let desc = VisibleFunctionTableDescriptor::new();
768        assert!(desc.is_some());
769    }
770
771    #[test]
772    fn test_visible_function_table_descriptor_class_method() {
773        let desc = VisibleFunctionTableDescriptor::visible_function_table_descriptor();
774        assert!(desc.is_some());
775    }
776
777    #[test]
778    fn test_visible_function_table_descriptor_function_count() {
779        let desc = VisibleFunctionTableDescriptor::new().unwrap();
780        // Default should be 0
781        assert_eq!(desc.function_count(), 0);
782
783        desc.set_function_count(10);
784        assert_eq!(desc.function_count(), 10);
785    }
786
787    #[test]
788    fn test_intersection_function_table_descriptor_creation() {
789        let desc = IntersectionFunctionTableDescriptor::new();
790        assert!(desc.is_some());
791    }
792
793    #[test]
794    fn test_intersection_function_table_descriptor_class_method() {
795        let desc = IntersectionFunctionTableDescriptor::intersection_function_table_descriptor();
796        assert!(desc.is_some());
797    }
798
799    #[test]
800    fn test_intersection_function_table_descriptor_function_count() {
801        let desc = IntersectionFunctionTableDescriptor::new().unwrap();
802        // Default should be 0
803        assert_eq!(desc.function_count(), 0);
804
805        desc.set_function_count(5);
806        assert_eq!(desc.function_count(), 5);
807    }
808}