mlx_c_rust/types/
device.rs1use std::ffi::{CStr, CString};
5
6use crate::MlxCError;
7use crate::error::check_status;
8use crate::raw;
9use crate::types::vectors::MlxVectorString;
10
11#[derive(Debug)]
13pub struct MlxDeviceHandle(raw::mlx_device);
14
15impl MlxDeviceHandle {
16 pub(crate) fn empty() -> Self {
18 let raw_device = unsafe { raw::mlx_device_new() };
20 Self(raw_device)
21 }
22
23 pub fn of_type(
25 device_type: raw::mlx_device_type,
26 device_index: i32,
27 ) -> Result<Self, MlxCError> {
28 let operation: &'static str = "create an MLX device handle";
29 let raw_device = unsafe { raw::mlx_device_new_type(device_type, device_index) };
32 Self::from_live_raw(raw_device, operation)
33 }
34
35 pub fn default_device() -> Result<Self, MlxCError> {
37 let operation: &'static str = "acquire the MLX default device";
38 let mut output = Self::empty();
39 let status = unsafe { raw::mlx_get_default_device(output.raw_mut()) };
42 check_status(status, operation)?;
43 output.require_populated(operation)?;
44 Ok(output)
45 }
46
47 pub fn set_as_default(&self) -> Result<(), MlxCError> {
49 let status = unsafe { raw::mlx_set_default_device(self.0) };
51 check_status(status, "set the MLX default device")
52 }
53
54 pub fn set(&mut self, source: &Self) -> Result<(), MlxCError> {
56 let status = unsafe { raw::mlx_device_set(&mut self.0, source.0) };
59 check_status(status, "copy an MLX device handle")
60 }
61
62 #[must_use]
64 pub fn equals(&self, other: &Self) -> bool {
65 unsafe { raw::mlx_device_equal(self.0, other.0) }
67 }
68
69 pub fn index(&self) -> Result<i32, MlxCError> {
71 let operation: &'static str = "read the MLX device index";
72 let mut device_index: i32 = 0;
73 let status = unsafe { raw::mlx_device_get_index(&mut device_index, self.0) };
76 check_status(status, operation)?;
77 Ok(device_index)
78 }
79
80 pub fn device_type(&self) -> Result<raw::mlx_device_type, MlxCError> {
82 let operation: &'static str = "read the MLX device type";
83 let mut device_type = raw::mlx_device_type__MLX_CPU;
84 let status = unsafe { raw::mlx_device_get_type(&mut device_type, self.0) };
87 check_status(status, operation)?;
88 Ok(device_type)
89 }
90
91 pub fn is_available(&self) -> Result<bool, MlxCError> {
93 let operation: &'static str = "query MLX device availability";
94 let mut available = false;
95 let status = unsafe { raw::mlx_device_is_available(&mut available, self.0) };
98 check_status(status, operation)?;
99 Ok(available)
100 }
101
102 pub fn count_of_type(device_type: raw::mlx_device_type) -> Result<i32, MlxCError> {
104 let operation: &'static str = "count MLX devices";
105 let mut device_count: i32 = 0;
106 let status = unsafe { raw::mlx_device_count(&mut device_count, device_type) };
108 check_status(status, operation)?;
109 Ok(device_count)
110 }
111
112 pub fn to_string_lossy(&self) -> Result<String, MlxCError> {
114 let operation: &'static str = "describe an MLX device";
115 let mut output = crate::MlxString::empty();
116 let status = unsafe { raw::mlx_device_tostring(output.raw_mut(), self.0) };
119 check_status(status, operation)?;
120 output.require_populated(operation)?;
121 Ok(output.to_string_lossy())
122 }
123
124 pub fn information(&self) -> Result<MlxDeviceInfo, MlxCError> {
126 let operation: &'static str = "read MLX device information";
127 let mut output = MlxDeviceInfo::empty();
128 let status = unsafe { raw::mlx_device_info_get(output.raw_mut(), self.0) };
131 check_status(status, operation)?;
132 output.require_populated(operation)?;
133 Ok(output)
134 }
135
136 pub(crate) const fn raw(&self) -> raw::mlx_device {
137 self.0
138 }
139
140 pub(crate) fn raw_mut(&mut self) -> *mut raw::mlx_device {
141 &mut self.0
142 }
143
144 pub(crate) fn from_live_raw(
145 raw_device: raw::mlx_device,
146 operation: &'static str,
147 ) -> Result<Self, MlxCError> {
148 if raw_device.ctx.is_null() {
149 return Err(MlxCError {
150 operation,
151 description: "MLX returned an empty device handle".to_owned(),
152 });
153 }
154 Ok(Self(raw_device))
155 }
156
157 fn require_populated(&self, operation: &'static str) -> Result<(), MlxCError> {
158 if self.0.ctx.is_null() {
159 return Err(MlxCError {
160 operation,
161 description: "MLX returned an empty device handle".to_owned(),
162 });
163 }
164 Ok(())
165 }
166}
167
168impl Drop for MlxDeviceHandle {
169 fn drop(&mut self) {
170 unsafe {
173 raw::mlx_device_free(self.0);
174 }
175 }
176}
177
178#[derive(Debug)]
180pub struct MlxDeviceInfo(raw::mlx_device_info);
181
182impl MlxDeviceInfo {
183 pub(crate) fn empty() -> Self {
185 let raw_info = unsafe { raw::mlx_device_info_new() };
187 Self(raw_info)
188 }
189
190 pub fn has_key(&self, key: &str) -> Result<bool, MlxCError> {
192 let operation: &'static str = "query MLX device information keys";
193 let key_argument = CString::new(key).map_err(|_| MlxCError {
194 operation,
195 description: "key contains an interior null byte".to_owned(),
196 })?;
197 let mut exists = false;
198 let status =
201 unsafe { raw::mlx_device_info_has_key(&mut exists, self.0, key_argument.as_ptr()) };
202 check_status(status, operation)?;
203 Ok(exists)
204 }
205
206 pub fn is_string(&self, key: &str) -> Result<bool, MlxCError> {
208 let operation: &'static str = "query MLX device information value types";
209 let key_argument = CString::new(key).map_err(|_| MlxCError {
210 operation,
211 description: "key contains an interior null byte".to_owned(),
212 })?;
213 let mut is_string = false;
214 let status = unsafe {
217 raw::mlx_device_info_is_string(&mut is_string, self.0, key_argument.as_ptr())
218 };
219 check_status(status, operation)?;
220 Ok(is_string)
221 }
222
223 pub fn string_value(&self, key: &str) -> Result<String, MlxCError> {
225 let operation: &'static str = "read an MLX device information string";
226 let key_argument = CString::new(key).map_err(|_| MlxCError {
227 operation,
228 description: "key contains an interior null byte".to_owned(),
229 })?;
230 let mut value_pointer: *const std::os::raw::c_char = std::ptr::null();
231 let status = unsafe {
234 raw::mlx_device_info_get_string(&mut value_pointer, self.0, key_argument.as_ptr())
235 };
236 check_status(status, operation)?;
237 if value_pointer.is_null() {
238 return Err(MlxCError {
239 operation,
240 description: "MLX returned a null device information string".to_owned(),
241 });
242 }
243 let borrowed = unsafe { CStr::from_ptr(value_pointer) };
246 Ok(borrowed.to_string_lossy().into_owned())
247 }
248
249 pub fn size_value(&self, key: &str) -> Result<usize, MlxCError> {
251 let operation: &'static str = "read an MLX device information size";
252 let key_argument = CString::new(key).map_err(|_| MlxCError {
253 operation,
254 description: "key contains an interior null byte".to_owned(),
255 })?;
256 let mut value: usize = 0;
257 let status =
260 unsafe { raw::mlx_device_info_get_size(&mut value, self.0, key_argument.as_ptr()) };
261 check_status(status, operation)?;
262 Ok(value)
263 }
264
265 pub fn keys(&self) -> Result<MlxVectorString, MlxCError> {
267 let operation: &'static str = "list MLX device information keys";
268 let mut output = MlxVectorString::empty();
269 let status = unsafe { raw::mlx_device_info_get_keys(output.raw_mut(), self.0) };
272 check_status(status, operation)?;
273 Ok(output)
274 }
275
276 pub(crate) fn raw_mut(&mut self) -> *mut raw::mlx_device_info {
277 &mut self.0
278 }
279
280 fn require_populated(&self, operation: &'static str) -> Result<(), MlxCError> {
281 if self.0.ctx.is_null() {
282 return Err(MlxCError {
283 operation,
284 description: "MLX returned an empty device info handle".to_owned(),
285 });
286 }
287 Ok(())
288 }
289}
290
291impl Drop for MlxDeviceInfo {
292 fn drop(&mut self) {
293 unsafe {
296 raw::mlx_device_info_free(self.0);
297 }
298 }
299}