Skip to main content

mtl_gpu/device/
io.rs

1//! IO-related Device methods.
2//!
3//! Corresponds to IO-related methods in `Metal/MTLDevice.hpp`.
4
5use std::ffi::c_void;
6
7use mtl_foundation::Referencing;
8use mtl_sys::{msg_send_2, msg_send_3, sel};
9
10use super::Device;
11use crate::enums::IOCompressionMethod;
12use crate::io::{IOCommandQueue, IOCommandQueueDescriptor, IOFileHandle};
13
14impl Device {
15    /// Create a new IO command queue.
16    ///
17    /// C++ equivalent: `IOCommandQueue* newIOCommandQueue(const IOCommandQueueDescriptor*, NS::Error**)`
18    pub fn new_io_command_queue(
19        &self,
20        descriptor: &IOCommandQueueDescriptor,
21    ) -> Result<IOCommandQueue, mtl_foundation::Error> {
22        unsafe {
23            let mut error: *mut c_void = std::ptr::null_mut();
24            let ptr: *mut c_void = msg_send_2(
25                self.as_ptr(),
26                sel!(newIOCommandQueueWithDescriptor:error:),
27                descriptor.as_ptr(),
28                &mut error as *mut _,
29            );
30
31            if ptr.is_null() {
32                if !error.is_null() {
33                    return Err(
34                        mtl_foundation::Error::from_ptr(error).expect("error should be valid")
35                    );
36                }
37                return Err(mtl_foundation::Error::error(
38                    std::ptr::null_mut(),
39                    -1,
40                    std::ptr::null_mut(),
41                )
42                .expect("failed to create error"));
43            }
44
45            Ok(IOCommandQueue::from_raw(ptr).expect("failed to create IO command queue"))
46        }
47    }
48
49    /// Create a new IO file handle.
50    ///
51    /// C++ equivalent: `IOFileHandle* newIOFileHandle(const NS::URL*, NS::Error**)`
52    pub fn new_io_file_handle(
53        &self,
54        url: &mtl_foundation::Url,
55    ) -> Result<IOFileHandle, mtl_foundation::Error> {
56        unsafe {
57            let mut error: *mut c_void = std::ptr::null_mut();
58            let ptr: *mut c_void = msg_send_2(
59                self.as_ptr(),
60                sel!(newIOFileHandleWithURL:error:),
61                url.as_ptr(),
62                &mut error as *mut _,
63            );
64
65            if ptr.is_null() {
66                if !error.is_null() {
67                    return Err(
68                        mtl_foundation::Error::from_ptr(error).expect("error should be valid")
69                    );
70                }
71                return Err(mtl_foundation::Error::error(
72                    std::ptr::null_mut(),
73                    -1,
74                    std::ptr::null_mut(),
75                )
76                .expect("failed to create error"));
77            }
78
79            Ok(IOFileHandle::from_raw(ptr).expect("failed to create IO file handle"))
80        }
81    }
82
83    /// Create a new IO file handle with compression.
84    ///
85    /// C++ equivalent: `IOFileHandle* newIOFileHandle(const NS::URL*, IOCompressionMethod, NS::Error**)`
86    pub fn new_io_file_handle_with_compression(
87        &self,
88        url: &mtl_foundation::Url,
89        compression_method: IOCompressionMethod,
90    ) -> Result<IOFileHandle, mtl_foundation::Error> {
91        unsafe {
92            let mut error: *mut c_void = std::ptr::null_mut();
93            let ptr: *mut c_void = msg_send_3(
94                self.as_ptr(),
95                sel!(newIOFileHandleWithURL:compressionMethod:error:),
96                url.as_ptr(),
97                compression_method,
98                &mut error as *mut _,
99            );
100
101            if ptr.is_null() {
102                if !error.is_null() {
103                    return Err(
104                        mtl_foundation::Error::from_ptr(error).expect("error should be valid")
105                    );
106                }
107                return Err(mtl_foundation::Error::error(
108                    std::ptr::null_mut(),
109                    -1,
110                    std::ptr::null_mut(),
111                )
112                .expect("failed to create error"));
113            }
114
115            Ok(IOFileHandle::from_raw(ptr).expect("failed to create IO file handle"))
116        }
117    }
118
119    /// Create a new IO handle (deprecated, use new_io_file_handle).
120    ///
121    /// C++ equivalent: `IOFileHandle* newIOHandle(const NS::URL*, NS::Error**)`
122    #[deprecated(note = "Use new_io_file_handle instead")]
123    pub fn new_io_handle(
124        &self,
125        url: &mtl_foundation::Url,
126    ) -> Result<IOFileHandle, mtl_foundation::Error> {
127        unsafe {
128            let mut error: *mut c_void = std::ptr::null_mut();
129            let ptr: *mut c_void = msg_send_2(
130                self.as_ptr(),
131                sel!(newIOHandleWithURL:error:),
132                url.as_ptr(),
133                &mut error as *mut _,
134            );
135
136            if ptr.is_null() {
137                if !error.is_null() {
138                    return Err(
139                        mtl_foundation::Error::from_ptr(error).expect("error should be valid")
140                    );
141                }
142                return Err(mtl_foundation::Error::error(
143                    std::ptr::null_mut(),
144                    -1,
145                    std::ptr::null_mut(),
146                )
147                .expect("failed to create error"));
148            }
149
150            Ok(IOFileHandle::from_raw(ptr).expect("failed to create IO handle"))
151        }
152    }
153
154    /// Create a new IO handle with compression (deprecated, use new_io_file_handle_with_compression).
155    ///
156    /// C++ equivalent: `IOFileHandle* newIOHandle(const NS::URL*, IOCompressionMethod, NS::Error**)`
157    #[deprecated(note = "Use new_io_file_handle_with_compression instead")]
158    pub fn new_io_handle_with_compression(
159        &self,
160        url: &mtl_foundation::Url,
161        compression_method: IOCompressionMethod,
162    ) -> Result<IOFileHandle, mtl_foundation::Error> {
163        unsafe {
164            let mut error: *mut c_void = std::ptr::null_mut();
165            let ptr: *mut c_void = msg_send_3(
166                self.as_ptr(),
167                sel!(newIOHandleWithURL:compressionMethod:error:),
168                url.as_ptr(),
169                compression_method,
170                &mut error as *mut _,
171            );
172
173            if ptr.is_null() {
174                if !error.is_null() {
175                    return Err(
176                        mtl_foundation::Error::from_ptr(error).expect("error should be valid")
177                    );
178                }
179                return Err(mtl_foundation::Error::error(
180                    std::ptr::null_mut(),
181                    -1,
182                    std::ptr::null_mut(),
183                )
184                .expect("failed to create error"));
185            }
186
187            Ok(IOFileHandle::from_raw(ptr).expect("failed to create IO handle"))
188        }
189    }
190}
191
192#[cfg(test)]
193mod tests {
194    use super::*;
195    use crate::device::system_default;
196
197    #[test]
198    fn test_new_io_command_queue() {
199        let device = system_default().expect("no Metal device");
200        let descriptor = IOCommandQueueDescriptor::new().expect("failed to create descriptor");
201
202        // This may fail on some systems that don't support IO commands
203        let _result = device.new_io_command_queue(&descriptor);
204    }
205}