use crate::MlxCError;
use crate::error::check_status;
use crate::raw;
use crate::types::device::MlxDeviceHandle;
use crate::types::vectors::MlxVectorStream;
#[derive(Debug)]
pub struct MlxStream(raw::mlx_stream);
impl MlxStream {
pub fn default_cpu() -> Result<Self, MlxCError> {
let raw_stream = unsafe { raw::mlx_default_cpu_stream_new() };
Self::from_raw(raw_stream, "acquire the default MLX CPU stream")
}
pub fn default_gpu() -> Result<Self, MlxCError> {
let raw_stream = unsafe { raw::mlx_default_gpu_stream_new() };
Self::from_raw(raw_stream, "acquire the default MLX GPU stream")
}
pub fn to_string_lossy(&self) -> Result<String, MlxCError> {
let operation: &'static str = "describe an MLX stream";
let mut output = crate::MlxString::empty();
let status = unsafe { raw::mlx_stream_tostring(output.raw_mut(), self.0) };
check_status(status, operation)?;
output.require_populated(operation)?;
Ok(output.to_string_lossy())
}
pub const fn raw(&self) -> raw::mlx_stream {
self.0
}
fn from_raw(raw_stream: raw::mlx_stream, operation: &'static str) -> Result<Self, MlxCError> {
if raw_stream.ctx.is_null() {
return Err(MlxCError {
operation,
description: "MLX returned an empty stream handle".to_owned(),
});
}
Ok(Self(raw_stream))
}
pub(crate) fn from_live_raw(
raw_stream: raw::mlx_stream,
operation: &'static str,
) -> Result<Self, MlxCError> {
Self::from_raw(raw_stream, operation)
}
}
impl Drop for MlxStream {
fn drop(&mut self) {
unsafe {
raw::mlx_stream_free(self.0);
}
}
}
#[derive(Debug)]
pub struct MlxStreamThreadLocal(raw::mlx_stream_thread_local);
impl MlxStreamThreadLocal {
pub fn for_device(device: &MlxDeviceHandle) -> Result<Self, MlxCError> {
let operation: &'static str = "create an MLX thread-local stream slot";
let raw_slot = unsafe { raw::mlx_stream_thread_local_new(device.raw()) };
if raw_slot.ctx.is_null() {
return Err(MlxCError {
operation,
description: "MLX returned an empty thread-local stream handle".to_owned(),
});
}
Ok(Self(raw_slot))
}
pub fn set(&mut self, source: &Self) -> Result<(), MlxCError> {
let status = unsafe { raw::mlx_stream_thread_local_set(&mut self.0, source.0) };
check_status(status, "copy an MLX thread-local stream slot")
}
pub fn stream(&self) -> Result<MlxStream, MlxCError> {
let operation: &'static str = "read the MLX thread-local stream";
let mut raw_stream = raw::mlx_stream {
ctx: std::ptr::null_mut(),
};
let status = unsafe { raw::mlx_stream_from_thread_local(&mut raw_stream, self.0) };
check_status(status, operation)?;
MlxStream::from_live_raw(raw_stream, operation)
}
pub fn synchronize(&self) -> Result<(), MlxCError> {
let status = unsafe { raw::mlx_synchronize_thread_local(self.0) };
check_status(status, "synchronize the MLX thread-local stream")
}
}
impl Drop for MlxStreamThreadLocal {
fn drop(&mut self) {
unsafe {
raw::mlx_stream_thread_local_free(self.0);
}
}
}
impl MlxStream {
pub fn on_device(device: &MlxDeviceHandle) -> Result<Self, MlxCError> {
let raw_stream = unsafe { raw::mlx_stream_new_device(device.raw()) };
Self::from_raw(raw_stream, "create an MLX stream on a device")
}
pub fn set(&mut self, source: &Self) -> Result<(), MlxCError> {
let status = unsafe { raw::mlx_stream_set(&mut self.0, source.0) };
check_status(status, "copy an MLX stream")
}
#[must_use]
pub fn equals(&self, other: &Self) -> bool {
unsafe { raw::mlx_stream_equal(self.0, other.0) }
}
pub fn device(&self) -> Result<MlxDeviceHandle, MlxCError> {
let operation: &'static str = "read the MLX stream device";
let mut raw_device = raw::mlx_device {
ctx: std::ptr::null_mut(),
};
let status = unsafe { raw::mlx_stream_get_device(&mut raw_device, self.0) };
check_status(status, operation)?;
MlxDeviceHandle::from_live_raw(raw_device, operation)
}
pub fn index(&self) -> Result<i32, MlxCError> {
let operation: &'static str = "read the MLX stream index";
let mut stream_index: i32 = 0;
let status = unsafe { raw::mlx_stream_get_index(&mut stream_index, self.0) };
check_status(status, operation)?;
Ok(stream_index)
}
pub fn synchronize(&self) -> Result<(), MlxCError> {
let status = unsafe { raw::mlx_synchronize(self.0) };
check_status(status, "synchronize an MLX stream")
}
pub fn default_for_device(device: &MlxDeviceHandle) -> Result<Self, MlxCError> {
let operation: &'static str = "acquire the MLX device default stream";
let mut raw_stream = raw::mlx_stream {
ctx: std::ptr::null_mut(),
};
let status = unsafe { raw::mlx_get_default_stream(&mut raw_stream, device.raw()) };
check_status(status, operation)?;
Self::from_raw(raw_stream, operation)
}
pub fn all_streams() -> Result<MlxVectorStream, MlxCError> {
let operation: &'static str = "list the MLX streams";
let mut output = MlxVectorStream::empty();
let status = unsafe { raw::mlx_get_streams(output.raw_mut()) };
check_status(status, operation)?;
Ok(output)
}
}
pub fn clear_streams() -> Result<(), MlxCError> {
let status = unsafe { raw::mlx_clear_streams() };
check_status(status, "clear the MLX streams")
}
pub fn set_default_stream(stream: &MlxStream) -> Result<(), MlxCError> {
let status = unsafe { raw::mlx_set_default_stream(stream.raw()) };
check_status(status, "set the MLX default stream")
}
pub fn synchronize_all_defaults() -> Result<(), MlxCError> {
let status = unsafe { raw::mlx_synchronize_default() };
check_status(status, "synchronize the MLX default streams")
}