use std::ffi::CStr;
use crate::{
error::Result,
utils::{guard::Guarded, SUCCESS},
};
#[derive(num_enum::IntoPrimitive, Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum DeviceType {
Cpu = safemlx_sys::mlx_device_type__MLX_CPU,
Gpu = safemlx_sys::mlx_device_type__MLX_GPU,
}
pub struct Device {
pub(crate) c_device: safemlx_sys::mlx_device,
}
impl PartialEq for Device {
fn eq(&self, other: &Self) -> bool {
unsafe { safemlx_sys::mlx_device_equal(self.c_device, other.c_device) }
}
}
impl Device {
pub fn new(device_type: DeviceType, index: i32) -> Device {
let c_device = unsafe { safemlx_sys::mlx_device_new_type(device_type.into(), index) };
Device { c_device }
}
pub fn get_index(&self) -> Result<i32> {
i32::try_from_op(|res| unsafe { safemlx_sys::mlx_device_get_index(res, self.c_device) })
}
pub fn get_type(&self) -> Result<DeviceType> {
DeviceType::try_from_op(|res| unsafe {
safemlx_sys::mlx_device_get_type(res, self.c_device)
})
}
fn describe(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
unsafe {
let mut mlx_str = safemlx_sys::mlx_string_new();
let result =
match safemlx_sys::mlx_device_tostring(&mut mlx_str as *mut _, self.c_device) {
SUCCESS => {
let ptr = safemlx_sys::mlx_string_data(mlx_str);
let c_str = CStr::from_ptr(ptr);
write!(f, "{}", c_str.to_string_lossy())
}
_ => Err(std::fmt::Error),
};
safemlx_sys::mlx_string_free(mlx_str);
result
}
}
}
impl Drop for Device {
fn drop(&mut self) {
let status = unsafe { safemlx_sys::mlx_device_free(self.c_device) };
debug_assert_eq!(status, SUCCESS);
}
}
impl std::fmt::Debug for Device {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.describe(f)
}
}
impl std::fmt::Display for Device {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.describe(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fmt() {
let device = Device::new(DeviceType::Gpu, 0);
let description = format!("{device}");
assert_eq!(description, "Device(gpu, 0)");
}
}