Skip to main content

mtl_gpu/
function_stitching.rs

1//! Metal function stitching for shader linking.
2//!
3//! Corresponds to `Metal/MTLFunctionStitching.hpp`.
4//!
5//! Function stitching allows creating new functions at runtime by combining
6//! existing function graphs.
7
8use std::ffi::c_void;
9use std::ptr::NonNull;
10
11use mtl_foundation::{Referencing, UInteger};
12use mtl_sys::{msg_send_0, msg_send_1, sel};
13
14// ============================================================================
15// StitchedLibraryOptions
16// ============================================================================
17
18/// Options for stitched library creation.
19///
20/// C++ equivalent: `MTL::StitchedLibraryOptions`
21#[repr(transparent)]
22#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
23pub struct StitchedLibraryOptions(pub UInteger);
24
25impl StitchedLibraryOptions {
26    pub const NONE: Self = Self(0);
27    pub const FAIL_ON_BINARY_ARCHIVE_MISS: Self = Self(1);
28    pub const STORE_LIBRARY_IN_METAL_PIPELINES_SCRIPT: Self = Self(1 << 1);
29}
30
31impl std::ops::BitOr for StitchedLibraryOptions {
32    type Output = Self;
33    fn bitor(self, rhs: Self) -> Self {
34        Self(self.0 | rhs.0)
35    }
36}
37
38impl std::ops::BitAnd for StitchedLibraryOptions {
39    type Output = Self;
40    fn bitand(self, rhs: Self) -> Self {
41        Self(self.0 & rhs.0)
42    }
43}
44
45impl std::ops::BitOrAssign for StitchedLibraryOptions {
46    fn bitor_assign(&mut self, rhs: Self) {
47        self.0 |= rhs.0;
48    }
49}
50
51// ============================================================================
52// FunctionStitchingAttribute
53// ============================================================================
54
55/// Base type for function stitching attributes.
56///
57/// C++ equivalent: `MTL::FunctionStitchingAttribute`
58#[repr(transparent)]
59pub struct FunctionStitchingAttribute(pub(crate) NonNull<c_void>);
60
61impl FunctionStitchingAttribute {
62    /// Create from a raw pointer.
63    ///
64    /// # Safety
65    ///
66    /// The pointer must be a valid Metal FunctionStitchingAttribute.
67    #[inline]
68    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
69        NonNull::new(ptr).map(Self)
70    }
71
72    /// Get the raw pointer.
73    #[inline]
74    pub fn as_raw(&self) -> *mut c_void {
75        self.0.as_ptr()
76    }
77}
78
79impl Clone for FunctionStitchingAttribute {
80    fn clone(&self) -> Self {
81        unsafe {
82            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
83        }
84        Self(self.0)
85    }
86}
87
88impl Drop for FunctionStitchingAttribute {
89    fn drop(&mut self) {
90        unsafe {
91            msg_send_0::<()>(self.as_ptr(), sel!(release));
92        }
93    }
94}
95
96impl Referencing for FunctionStitchingAttribute {
97    #[inline]
98    fn as_ptr(&self) -> *const c_void {
99        self.0.as_ptr()
100    }
101}
102
103unsafe impl Send for FunctionStitchingAttribute {}
104unsafe impl Sync for FunctionStitchingAttribute {}
105
106// ============================================================================
107// FunctionStitchingAttributeAlwaysInline
108// ============================================================================
109
110/// Attribute that marks a function for inlining.
111///
112/// C++ equivalent: `MTL::FunctionStitchingAttributeAlwaysInline`
113#[repr(transparent)]
114pub struct FunctionStitchingAttributeAlwaysInline(pub(crate) NonNull<c_void>);
115
116impl FunctionStitchingAttributeAlwaysInline {
117    /// Create a new always inline attribute.
118    ///
119    /// C++ equivalent: `FunctionStitchingAttributeAlwaysInline* alloc()->init()`
120    pub fn new() -> Option<Self> {
121        unsafe {
122            let class = mtl_sys::Class::get("MTLFunctionStitchingAttributeAlwaysInline")?;
123            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
124            if ptr.is_null() {
125                return None;
126            }
127            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
128            Self::from_raw(ptr)
129        }
130    }
131
132    /// Create from a raw pointer.
133    ///
134    /// # Safety
135    ///
136    /// The pointer must be a valid Metal FunctionStitchingAttributeAlwaysInline.
137    #[inline]
138    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
139        NonNull::new(ptr).map(Self)
140    }
141
142    /// Get the raw pointer.
143    #[inline]
144    pub fn as_raw(&self) -> *mut c_void {
145        self.0.as_ptr()
146    }
147}
148
149impl Clone for FunctionStitchingAttributeAlwaysInline {
150    fn clone(&self) -> Self {
151        unsafe {
152            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
153        }
154        Self(self.0)
155    }
156}
157
158impl Drop for FunctionStitchingAttributeAlwaysInline {
159    fn drop(&mut self) {
160        unsafe {
161            msg_send_0::<()>(self.as_ptr(), sel!(release));
162        }
163    }
164}
165
166impl Referencing for FunctionStitchingAttributeAlwaysInline {
167    #[inline]
168    fn as_ptr(&self) -> *const c_void {
169        self.0.as_ptr()
170    }
171}
172
173unsafe impl Send for FunctionStitchingAttributeAlwaysInline {}
174unsafe impl Sync for FunctionStitchingAttributeAlwaysInline {}
175
176// ============================================================================
177// FunctionStitchingNode
178// ============================================================================
179
180/// Base type for function stitching nodes.
181///
182/// C++ equivalent: `MTL::FunctionStitchingNode`
183#[repr(transparent)]
184pub struct FunctionStitchingNode(pub(crate) NonNull<c_void>);
185
186impl FunctionStitchingNode {
187    /// Create from a raw pointer.
188    ///
189    /// # Safety
190    ///
191    /// The pointer must be a valid Metal FunctionStitchingNode.
192    #[inline]
193    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
194        NonNull::new(ptr).map(Self)
195    }
196
197    /// Get the raw pointer.
198    #[inline]
199    pub fn as_raw(&self) -> *mut c_void {
200        self.0.as_ptr()
201    }
202}
203
204impl Clone for FunctionStitchingNode {
205    fn clone(&self) -> Self {
206        unsafe {
207            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
208            Self::from_raw(ptr).expect("copy should succeed")
209        }
210    }
211}
212
213impl Drop for FunctionStitchingNode {
214    fn drop(&mut self) {
215        unsafe {
216            msg_send_0::<()>(self.as_ptr(), sel!(release));
217        }
218    }
219}
220
221impl Referencing for FunctionStitchingNode {
222    #[inline]
223    fn as_ptr(&self) -> *const c_void {
224        self.0.as_ptr()
225    }
226}
227
228unsafe impl Send for FunctionStitchingNode {}
229unsafe impl Sync for FunctionStitchingNode {}
230
231// ============================================================================
232// FunctionStitchingInputNode
233// ============================================================================
234
235/// An input node in a function stitching graph.
236///
237/// C++ equivalent: `MTL::FunctionStitchingInputNode`
238#[repr(transparent)]
239pub struct FunctionStitchingInputNode(pub(crate) NonNull<c_void>);
240
241impl FunctionStitchingInputNode {
242    /// Create a new input node.
243    ///
244    /// C++ equivalent: `FunctionStitchingInputNode* alloc()->init()`
245    pub fn new() -> Option<Self> {
246        unsafe {
247            let class = mtl_sys::Class::get("MTLFunctionStitchingInputNode")?;
248            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
249            if ptr.is_null() {
250                return None;
251            }
252            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
253            Self::from_raw(ptr)
254        }
255    }
256
257    /// Create a new input node with an argument index.
258    ///
259    /// C++ equivalent: `FunctionStitchingInputNode* alloc()->init(NS::UInteger)`
260    pub fn with_argument_index(argument_index: UInteger) -> Option<Self> {
261        unsafe {
262            let class = mtl_sys::Class::get("MTLFunctionStitchingInputNode")?;
263            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
264            if ptr.is_null() {
265                return None;
266            }
267            let ptr: *mut c_void = msg_send_1(ptr, sel!(initWithArgumentIndex:), argument_index);
268            Self::from_raw(ptr)
269        }
270    }
271
272    /// Create from a raw pointer.
273    ///
274    /// # Safety
275    ///
276    /// The pointer must be a valid Metal FunctionStitchingInputNode.
277    #[inline]
278    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
279        NonNull::new(ptr).map(Self)
280    }
281
282    /// Get the raw pointer.
283    #[inline]
284    pub fn as_raw(&self) -> *mut c_void {
285        self.0.as_ptr()
286    }
287
288    /// Get the argument index.
289    ///
290    /// C++ equivalent: `NS::UInteger argumentIndex() const`
291    #[inline]
292    pub fn argument_index(&self) -> UInteger {
293        unsafe { msg_send_0(self.as_ptr(), sel!(argumentIndex)) }
294    }
295
296    /// Set the argument index.
297    ///
298    /// C++ equivalent: `void setArgumentIndex(NS::UInteger)`
299    pub fn set_argument_index(&self, argument_index: UInteger) {
300        unsafe {
301            let _: () = msg_send_1(self.as_ptr(), sel!(setArgumentIndex:), argument_index);
302        }
303    }
304}
305
306impl Clone for FunctionStitchingInputNode {
307    fn clone(&self) -> Self {
308        unsafe {
309            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
310        }
311        Self(self.0)
312    }
313}
314
315impl Drop for FunctionStitchingInputNode {
316    fn drop(&mut self) {
317        unsafe {
318            msg_send_0::<()>(self.as_ptr(), sel!(release));
319        }
320    }
321}
322
323impl Referencing for FunctionStitchingInputNode {
324    #[inline]
325    fn as_ptr(&self) -> *const c_void {
326        self.0.as_ptr()
327    }
328}
329
330unsafe impl Send for FunctionStitchingInputNode {}
331unsafe impl Sync for FunctionStitchingInputNode {}
332
333// ============================================================================
334// FunctionStitchingFunctionNode
335// ============================================================================
336
337/// A function node in a function stitching graph.
338///
339/// C++ equivalent: `MTL::FunctionStitchingFunctionNode`
340#[repr(transparent)]
341pub struct FunctionStitchingFunctionNode(pub(crate) NonNull<c_void>);
342
343impl FunctionStitchingFunctionNode {
344    /// Create a new function node.
345    ///
346    /// C++ equivalent: `FunctionStitchingFunctionNode* alloc()->init()`
347    pub fn new() -> Option<Self> {
348        unsafe {
349            let class = mtl_sys::Class::get("MTLFunctionStitchingFunctionNode")?;
350            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
351            if ptr.is_null() {
352                return None;
353            }
354            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
355            Self::from_raw(ptr)
356        }
357    }
358
359    /// Create from a raw pointer.
360    ///
361    /// # Safety
362    ///
363    /// The pointer must be a valid Metal FunctionStitchingFunctionNode.
364    #[inline]
365    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
366        NonNull::new(ptr).map(Self)
367    }
368
369    /// Get the raw pointer.
370    #[inline]
371    pub fn as_raw(&self) -> *mut c_void {
372        self.0.as_ptr()
373    }
374
375    /// Get the name of the function.
376    ///
377    /// C++ equivalent: `NS::String* name() const`
378    pub fn name(&self) -> Option<String> {
379        unsafe {
380            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(name));
381            if ptr.is_null() {
382                return None;
383            }
384            let utf8_ptr: *const std::ffi::c_char =
385                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
386            if utf8_ptr.is_null() {
387                return None;
388            }
389            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
390            Some(c_str.to_string_lossy().into_owned())
391        }
392    }
393
394    /// Set the name of the function.
395    ///
396    /// C++ equivalent: `void setName(const NS::String*)`
397    pub fn set_name(&self, name: &str) {
398        if let Some(ns_name) = mtl_foundation::String::from_str(name) {
399            unsafe {
400                let _: () = msg_send_1(self.as_ptr(), sel!(setName:), ns_name.as_ptr());
401            }
402        }
403    }
404
405    /// Get the arguments as a raw NS::Array pointer.
406    ///
407    /// C++ equivalent: `NS::Array* arguments() const`
408    #[inline]
409    pub fn arguments_ptr(&self) -> *const c_void {
410        unsafe { msg_send_0(self.as_ptr(), sel!(arguments)) }
411    }
412
413    /// Set the arguments.
414    ///
415    /// C++ equivalent: `void setArguments(const NS::Array*)`
416    pub fn set_arguments_ptr(&self, arguments: *const c_void) {
417        unsafe {
418            let _: () = msg_send_1(self.as_ptr(), sel!(setArguments:), arguments);
419        }
420    }
421
422    /// Get the control dependencies as a raw NS::Array pointer.
423    ///
424    /// C++ equivalent: `NS::Array* controlDependencies() const`
425    #[inline]
426    pub fn control_dependencies_ptr(&self) -> *const c_void {
427        unsafe { msg_send_0(self.as_ptr(), sel!(controlDependencies)) }
428    }
429
430    /// Set the control dependencies.
431    ///
432    /// C++ equivalent: `void setControlDependencies(const NS::Array*)`
433    pub fn set_control_dependencies_ptr(&self, control_dependencies: *const c_void) {
434        unsafe {
435            let _: () = msg_send_1(
436                self.as_ptr(),
437                sel!(setControlDependencies:),
438                control_dependencies,
439            );
440        }
441    }
442}
443
444impl Clone for FunctionStitchingFunctionNode {
445    fn clone(&self) -> Self {
446        unsafe {
447            msg_send_0::<*mut c_void>(self.as_ptr(), sel!(retain));
448        }
449        Self(self.0)
450    }
451}
452
453impl Drop for FunctionStitchingFunctionNode {
454    fn drop(&mut self) {
455        unsafe {
456            msg_send_0::<()>(self.as_ptr(), sel!(release));
457        }
458    }
459}
460
461impl Referencing for FunctionStitchingFunctionNode {
462    #[inline]
463    fn as_ptr(&self) -> *const c_void {
464        self.0.as_ptr()
465    }
466}
467
468unsafe impl Send for FunctionStitchingFunctionNode {}
469unsafe impl Sync for FunctionStitchingFunctionNode {}
470
471// ============================================================================
472// FunctionStitchingGraph
473// ============================================================================
474
475/// A graph defining how functions are stitched together.
476///
477/// C++ equivalent: `MTL::FunctionStitchingGraph`
478#[repr(transparent)]
479pub struct FunctionStitchingGraph(pub(crate) NonNull<c_void>);
480
481impl FunctionStitchingGraph {
482    /// Create a new stitching graph.
483    ///
484    /// C++ equivalent: `FunctionStitchingGraph* alloc()->init()`
485    pub fn new() -> Option<Self> {
486        unsafe {
487            let class = mtl_sys::Class::get("MTLFunctionStitchingGraph")?;
488            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
489            if ptr.is_null() {
490                return None;
491            }
492            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
493            Self::from_raw(ptr)
494        }
495    }
496
497    /// Create from a raw pointer.
498    ///
499    /// # Safety
500    ///
501    /// The pointer must be a valid Metal FunctionStitchingGraph.
502    #[inline]
503    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
504        NonNull::new(ptr).map(Self)
505    }
506
507    /// Get the raw pointer.
508    #[inline]
509    pub fn as_raw(&self) -> *mut c_void {
510        self.0.as_ptr()
511    }
512
513    /// Get the function name.
514    ///
515    /// C++ equivalent: `NS::String* functionName() const`
516    pub fn function_name(&self) -> Option<String> {
517        unsafe {
518            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(functionName));
519            if ptr.is_null() {
520                return None;
521            }
522            let utf8_ptr: *const std::ffi::c_char =
523                mtl_sys::msg_send_0(ptr as *const c_void, sel!(UTF8String));
524            if utf8_ptr.is_null() {
525                return None;
526            }
527            let c_str = std::ffi::CStr::from_ptr(utf8_ptr);
528            Some(c_str.to_string_lossy().into_owned())
529        }
530    }
531
532    /// Set the function name.
533    ///
534    /// C++ equivalent: `void setFunctionName(const NS::String*)`
535    pub fn set_function_name(&self, name: &str) {
536        if let Some(ns_name) = mtl_foundation::String::from_str(name) {
537            unsafe {
538                let _: () = msg_send_1(self.as_ptr(), sel!(setFunctionName:), ns_name.as_ptr());
539            }
540        }
541    }
542
543    /// Get the nodes as a raw NS::Array pointer.
544    ///
545    /// C++ equivalent: `NS::Array* nodes() const`
546    #[inline]
547    pub fn nodes_ptr(&self) -> *const c_void {
548        unsafe { msg_send_0(self.as_ptr(), sel!(nodes)) }
549    }
550
551    /// Set the nodes.
552    ///
553    /// C++ equivalent: `void setNodes(const NS::Array*)`
554    pub fn set_nodes_ptr(&self, nodes: *const c_void) {
555        unsafe {
556            let _: () = msg_send_1(self.as_ptr(), sel!(setNodes:), nodes);
557        }
558    }
559
560    /// Get the output node.
561    ///
562    /// C++ equivalent: `FunctionStitchingFunctionNode* outputNode() const`
563    pub fn output_node(&self) -> Option<FunctionStitchingFunctionNode> {
564        unsafe {
565            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(outputNode));
566            if ptr.is_null() {
567                return None;
568            }
569            // Retain for our reference
570            msg_send_0::<*mut c_void>(ptr as *const c_void, sel!(retain));
571            FunctionStitchingFunctionNode::from_raw(ptr)
572        }
573    }
574
575    /// Set the output node.
576    ///
577    /// C++ equivalent: `void setOutputNode(const MTL::FunctionStitchingFunctionNode*)`
578    pub fn set_output_node(&self, output_node: &FunctionStitchingFunctionNode) {
579        unsafe {
580            let _: () = msg_send_1(self.as_ptr(), sel!(setOutputNode:), output_node.as_ptr());
581        }
582    }
583
584    /// Get the attributes as a raw NS::Array pointer.
585    ///
586    /// C++ equivalent: `NS::Array* attributes() const`
587    #[inline]
588    pub fn attributes_ptr(&self) -> *const c_void {
589        unsafe { msg_send_0(self.as_ptr(), sel!(attributes)) }
590    }
591
592    /// Set the attributes.
593    ///
594    /// C++ equivalent: `void setAttributes(const NS::Array*)`
595    pub fn set_attributes_ptr(&self, attributes: *const c_void) {
596        unsafe {
597            let _: () = msg_send_1(self.as_ptr(), sel!(setAttributes:), attributes);
598        }
599    }
600}
601
602impl Clone for FunctionStitchingGraph {
603    fn clone(&self) -> Self {
604        unsafe {
605            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
606            Self::from_raw(ptr).expect("copy should succeed")
607        }
608    }
609}
610
611impl Drop for FunctionStitchingGraph {
612    fn drop(&mut self) {
613        unsafe {
614            msg_send_0::<()>(self.as_ptr(), sel!(release));
615        }
616    }
617}
618
619impl Referencing for FunctionStitchingGraph {
620    #[inline]
621    fn as_ptr(&self) -> *const c_void {
622        self.0.as_ptr()
623    }
624}
625
626unsafe impl Send for FunctionStitchingGraph {}
627unsafe impl Sync for FunctionStitchingGraph {}
628
629// ============================================================================
630// StitchedLibraryDescriptor
631// ============================================================================
632
633/// Descriptor for creating a stitched library.
634///
635/// C++ equivalent: `MTL::StitchedLibraryDescriptor`
636#[repr(transparent)]
637pub struct StitchedLibraryDescriptor(pub(crate) NonNull<c_void>);
638
639impl StitchedLibraryDescriptor {
640    /// Create a new stitched library descriptor.
641    ///
642    /// C++ equivalent: `StitchedLibraryDescriptor* alloc()->init()`
643    pub fn new() -> Option<Self> {
644        unsafe {
645            let class = mtl_sys::Class::get("MTLStitchedLibraryDescriptor")?;
646            let ptr: *mut c_void = msg_send_0(class.as_ptr(), sel!(alloc));
647            if ptr.is_null() {
648                return None;
649            }
650            let ptr: *mut c_void = msg_send_0(ptr, sel!(init));
651            Self::from_raw(ptr)
652        }
653    }
654
655    /// Create from a raw pointer.
656    ///
657    /// # Safety
658    ///
659    /// The pointer must be a valid Metal StitchedLibraryDescriptor.
660    #[inline]
661    pub unsafe fn from_raw(ptr: *mut c_void) -> Option<Self> {
662        NonNull::new(ptr).map(Self)
663    }
664
665    /// Get the raw pointer.
666    #[inline]
667    pub fn as_raw(&self) -> *mut c_void {
668        self.0.as_ptr()
669    }
670
671    /// Get the function graphs as a raw NS::Array pointer.
672    ///
673    /// C++ equivalent: `NS::Array* functionGraphs() const`
674    #[inline]
675    pub fn function_graphs_ptr(&self) -> *const c_void {
676        unsafe { msg_send_0(self.as_ptr(), sel!(functionGraphs)) }
677    }
678
679    /// Set the function graphs.
680    ///
681    /// C++ equivalent: `void setFunctionGraphs(const NS::Array*)`
682    pub fn set_function_graphs_ptr(&self, function_graphs: *const c_void) {
683        unsafe {
684            let _: () = msg_send_1(self.as_ptr(), sel!(setFunctionGraphs:), function_graphs);
685        }
686    }
687
688    /// Get the functions as a raw NS::Array pointer.
689    ///
690    /// C++ equivalent: `NS::Array* functions() const`
691    #[inline]
692    pub fn functions_ptr(&self) -> *const c_void {
693        unsafe { msg_send_0(self.as_ptr(), sel!(functions)) }
694    }
695
696    /// Set the functions.
697    ///
698    /// C++ equivalent: `void setFunctions(const NS::Array*)`
699    pub fn set_functions_ptr(&self, functions: *const c_void) {
700        unsafe {
701            let _: () = msg_send_1(self.as_ptr(), sel!(setFunctions:), functions);
702        }
703    }
704
705    /// Get the binary archives as a raw NS::Array pointer.
706    ///
707    /// C++ equivalent: `NS::Array* binaryArchives() const`
708    #[inline]
709    pub fn binary_archives_ptr(&self) -> *const c_void {
710        unsafe { msg_send_0(self.as_ptr(), sel!(binaryArchives)) }
711    }
712
713    /// Set the binary archives.
714    ///
715    /// C++ equivalent: `void setBinaryArchives(const NS::Array*)`
716    pub fn set_binary_archives_ptr(&self, binary_archives: *const c_void) {
717        unsafe {
718            let _: () = msg_send_1(self.as_ptr(), sel!(setBinaryArchives:), binary_archives);
719        }
720    }
721
722    /// Get the options.
723    ///
724    /// C++ equivalent: `StitchedLibraryOptions options() const`
725    #[inline]
726    pub fn options(&self) -> StitchedLibraryOptions {
727        unsafe { msg_send_0(self.as_ptr(), sel!(options)) }
728    }
729
730    /// Set the options.
731    ///
732    /// C++ equivalent: `void setOptions(MTL::StitchedLibraryOptions)`
733    pub fn set_options(&self, options: StitchedLibraryOptions) {
734        unsafe {
735            let _: () = msg_send_1(self.as_ptr(), sel!(setOptions:), options);
736        }
737    }
738}
739
740impl Default for StitchedLibraryDescriptor {
741    fn default() -> Self {
742        Self::new().expect("failed to create StitchedLibraryDescriptor")
743    }
744}
745
746impl Clone for StitchedLibraryDescriptor {
747    fn clone(&self) -> Self {
748        unsafe {
749            let ptr: *mut c_void = msg_send_0(self.as_ptr(), sel!(copy));
750            Self::from_raw(ptr).expect("copy should succeed")
751        }
752    }
753}
754
755impl Drop for StitchedLibraryDescriptor {
756    fn drop(&mut self) {
757        unsafe {
758            msg_send_0::<()>(self.as_ptr(), sel!(release));
759        }
760    }
761}
762
763impl Referencing for StitchedLibraryDescriptor {
764    #[inline]
765    fn as_ptr(&self) -> *const c_void {
766        self.0.as_ptr()
767    }
768}
769
770unsafe impl Send for StitchedLibraryDescriptor {}
771unsafe impl Sync for StitchedLibraryDescriptor {}
772
773#[cfg(test)]
774mod tests {
775    use super::*;
776
777    #[test]
778    fn test_stitched_library_options_values() {
779        assert_eq!(StitchedLibraryOptions::NONE.0, 0);
780        assert_eq!(StitchedLibraryOptions::FAIL_ON_BINARY_ARCHIVE_MISS.0, 1);
781        assert_eq!(
782            StitchedLibraryOptions::STORE_LIBRARY_IN_METAL_PIPELINES_SCRIPT.0,
783            2
784        );
785    }
786
787    #[test]
788    fn test_stitched_library_options_bitor() {
789        let options = StitchedLibraryOptions::FAIL_ON_BINARY_ARCHIVE_MISS
790            | StitchedLibraryOptions::STORE_LIBRARY_IN_METAL_PIPELINES_SCRIPT;
791        assert_eq!(options.0, 3);
792    }
793
794    #[test]
795    fn test_function_stitching_attribute_size() {
796        assert_eq!(
797            std::mem::size_of::<FunctionStitchingAttribute>(),
798            std::mem::size_of::<*mut c_void>()
799        );
800    }
801
802    #[test]
803    fn test_function_stitching_input_node_creation() {
804        let node = FunctionStitchingInputNode::new();
805        assert!(node.is_some());
806    }
807
808    #[test]
809    fn test_function_stitching_input_node_with_index() {
810        let node = FunctionStitchingInputNode::with_argument_index(5);
811        assert!(node.is_some());
812        if let Some(n) = node {
813            assert_eq!(n.argument_index(), 5);
814        }
815    }
816
817    #[test]
818    fn test_function_stitching_function_node_creation() {
819        let node = FunctionStitchingFunctionNode::new();
820        assert!(node.is_some());
821    }
822
823    #[test]
824    fn test_function_stitching_graph_creation() {
825        let graph = FunctionStitchingGraph::new();
826        assert!(graph.is_some());
827    }
828
829    #[test]
830    fn test_stitched_library_descriptor_creation() {
831        let descriptor = StitchedLibraryDescriptor::new();
832        assert!(descriptor.is_some());
833    }
834
835    #[test]
836    fn test_stitched_library_descriptor_options() {
837        let descriptor = StitchedLibraryDescriptor::new().unwrap();
838        descriptor.set_options(StitchedLibraryOptions::FAIL_ON_BINARY_ARCHIVE_MISS);
839        assert_eq!(
840            descriptor.options(),
841            StitchedLibraryOptions::FAIL_ON_BINARY_ARCHIVE_MISS
842        );
843    }
844}